Decompiled source of SyncDiskLabels v1.4.0

plugins/SoDDiskLabels/SoDDiskLabels.dll

Decompiled 6 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
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 System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
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("SoDDiskLabels")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.5.0")]
[assembly: AssemblyInformationalVersion("0.2.5")]
[assembly: AssemblyProduct("SoDDiskLabels")]
[assembly: AssemblyTitle("SoDDiskLabels")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.5.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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 SoDDiskLabels
{
	public enum DiskOrder
	{
		Newest,
		Oldest,
		Name,
		MostUpgraded,
		LeastUpgraded
	}
	internal static class DiskSorter
	{
		internal static ConfigEntry<DiskOrder> Order = null;

		internal static ConfigEntry<bool> Enabled = null;

		private static GameObject? button;

		private static float lastClick = -10f;

		private static bool loggedParts;

		private static bool toldWaiting;

		private static bool toldApply;

		private static TextMeshProUGUI? label;

		private const float FrameHeight = 26f;

		internal static bool HasButton => (Object)(object)button != (Object)null;

		internal static void Bind(ConfigFile cfg)
		{
			Enabled = cfg.Bind<bool>("Sort", "Enabled", true, "Show a sort button on the sync disk screen.");
			Order = cfg.Bind<DiskOrder>("Sort", "Order", DiskOrder.Newest, "How installed sync disks are listed: Newest (just installed at the top), Oldest (the game's own order), Name, MostUpgraded or LeastUpgraded. The sort button changes it and it is remembered.");
		}

		private static string Pretty(DiskOrder o)
		{
			return o switch
			{
				DiskOrder.Newest => "newest", 
				DiskOrder.Oldest => "oldest", 
				DiskOrder.Name => "name", 
				DiskOrder.MostUpgraded => "most upgraded", 
				_ => "least upgraded", 
			};
		}

		internal static List<SyncDiskElementController> Rows(UpgradesController uc)
		{
			List<SyncDiskElementController> list = new List<SyncDiskElementController>();
			if (((uc != null) ? uc.spawnedDisks : null) != null)
			{
				Enumerator<SyncDiskElementController> enumerator = uc.spawnedDisks.GetEnumerator();
				while (enumerator.MoveNext())
				{
					SyncDiskElementController current = enumerator.Current;
					if ((Object)(object)current != (Object)null && (Object)(object)current.rect != (Object)null && ((Component)current).gameObject.activeInHierarchy)
					{
						list.Add(current);
					}
				}
			}
			if (list.Count == 0)
			{
				foreach (SyncDiskElementController item in Object.FindObjectsOfType<SyncDiskElementController>())
				{
					if ((Object)(object)item != (Object)null && (Object)(object)item.rect != (Object)null && ((Component)item).gameObject.activeInHierarchy)
					{
						list.Add(item);
					}
				}
			}
			return list;
		}

		internal static void Apply(UpgradesController uc)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled.Value)
			{
				return;
			}
			try
			{
				if (!toldApply)
				{
					toldApply = true;
					ManualLogSource l = Plugin.L;
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(36, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SORT] sorting ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(Rows(uc).Count);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" disks (");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(uc.spawnedDisks?.Count ?? (-1));
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" in list) by ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<DiskOrder>(Order.Value);
					}
					l.LogInfo(val);
				}
				EnsureButton(uc);
				List<SyncDiskElementController> list = Rows(uc);
				if (list.Count >= 2)
				{
					List<Vector2> list2 = (from e in list
						select e.rect.anchoredPosition into p
						orderby p.y descending
						select p).ToList();
					List<SyncDiskElementController> list3 = list.OrderByDescending((SyncDiskElementController e) => e.rect.anchoredPosition.y).ToList();
					Dictionary<IntPtr, int> index = new Dictionary<IntPtr, int>();
					for (int num = 0; num < list.Count; num++)
					{
						index[((Il2CppObjectBase)list[num]).Pointer] = num;
					}
					bool installedFirst = Installed(list3[0]);
					IOrderedEnumerable<SyncDiskElementController> source = list3.OrderBy((SyncDiskElementController e) => (Installed(e) != installedFirst) ? 1 : 0);
					List<SyncDiskElementController> list4 = (Order.Value switch
					{
						DiskOrder.Newest => source.ThenByDescending((SyncDiskElementController e) => index[((Il2CppObjectBase)e).Pointer]), 
						DiskOrder.Name => source.ThenBy<SyncDiskElementController, string>(Name, StringComparer.OrdinalIgnoreCase), 
						DiskOrder.MostUpgraded => source.ThenByDescending(delegate(SyncDiskElementController e)
						{
							Upgrades upgrade = e.upgrade;
							return (upgrade != null) ? upgrade.level : 0;
						}).ThenBy<SyncDiskElementController, string>(Name, StringComparer.OrdinalIgnoreCase), 
						DiskOrder.LeastUpgraded => source.ThenBy(delegate(SyncDiskElementController e)
						{
							Upgrades upgrade = e.upgrade;
							return (upgrade != null) ? upgrade.level : 0;
						}).ThenBy<SyncDiskElementController, string>(Name, StringComparer.OrdinalIgnoreCase), 
						_ => source.ThenBy((SyncDiskElementController e) => index[((Il2CppObjectBase)e).Pointer]), 
					}).ToList();
					for (int num2 = 0; num2 < list4.Count; num2++)
					{
						list4[num2].rect.anchoredPosition = list2[num2];
						((Component)list4[num2]).transform.SetSiblingIndex(num2);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[SORT] " + ex.Message));
			}
			static bool Installed(SyncDiskElementController e)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Invalid comparison between Unknown and I4
				if (e.upgrade != null)
				{
					return (int)e.upgrade.state > 0;
				}
				return false;
			}
			static string Name(SyncDiskElementController e)
			{
				object obj;
				if (!((Object)(object)e.titleText != (Object)null))
				{
					SyncDiskPreset preset = e.preset;
					obj = ((preset != null) ? ((Object)preset).name : null);
					if (obj == null)
					{
						return "";
					}
				}
				else
				{
					obj = Regex.Replace(((TMP_Text)e.titleText).text ?? "", "<[^>]*>", "");
				}
				return (string)obj;
			}
		}

		private static void EnsureButton(UpgradesController uc)
		{
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Expected O, but got Unknown
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0368: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_0398: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_042e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0435: Expected O, but got Unknown
			//IL_03ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f4: Expected O, but got Unknown
			//IL_0467: Unknown result type (might be due to invalid IL or missing references)
			//IL_0481: Unknown result type (might be due to invalid IL or missing references)
			//IL_0486: Unknown result type (might be due to invalid IL or missing references)
			string text = "Sort: " + Pretty(Order.Value);
			if ((Object)(object)button != (Object)null)
			{
				if ((Object)(object)label != (Object)null && ((TMP_Text)label).text != text)
				{
					((TMP_Text)label).text = text;
				}
				return;
			}
			ButtonController val = null;
			foreach (SyncDiskElementController item in Rows(uc))
			{
				if ((Object)(object)((item != null) ? item.uninstallButton : null) != (Object)null)
				{
					val = item.uninstallButton;
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				foreach (ButtonController componentsInChild in ((Component)uc).GetComponentsInChildren<ButtonController>(true))
				{
					if ((Object)(object)((componentsInChild != null) ? componentsInChild.text : null) != (Object)null && ((TMP_Text)componentsInChild.text).text.Trim().Equals("Uninstall", StringComparison.OrdinalIgnoreCase))
					{
						val = componentsInChild;
						break;
					}
				}
			}
			TextMeshProUGUI installedDisksText = uc.installedDisksText;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2;
			if ((Object)(object)val == (Object)null || (Object)(object)installedDisksText == (Object)null)
			{
				if (!toldWaiting)
				{
					toldWaiting = true;
					ManualLogSource l = Plugin.L;
					val2 = new BepInExInfoLogInterpolatedStringHandler(46, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[SORT] no button to copy yet (disks ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(Rows(uc).Count);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", header ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>((Object)(object)installedDisksText != (Object)null);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(")");
					}
					l.LogInfo(val2);
				}
				return;
			}
			button = Object.Instantiate<GameObject>(((Component)val).gameObject, ((TMP_Text)installedDisksText).transform.parent);
			((Object)button).name = "DiskSortButton";
			button.SetActive(true);
			(button.GetComponent<LayoutElement>() ?? button.AddComponent<LayoutElement>()).ignoreLayout = true;
			ButtonController component = button.GetComponent<ButtonController>();
			label = (((Object)(object)component != (Object)null && (Object)(object)component.text != (Object)null) ? component.text : button.GetComponentInChildren<TextMeshProUGUI>(true));
			Button val3 = (((Object)(object)component != (Object)null && (Object)(object)component.button != (Object)null) ? component.button : button.GetComponentInChildren<Button>(true));
			if ((Object)(object)component != (Object)null)
			{
				((Behaviour)component).enabled = false;
			}
			RectTransform component2 = button.GetComponent<RectTransform>();
			RectTransform rectTransform = ((TMP_Text)installedDisksText).rectTransform;
			component2.anchorMin = new Vector2(0.5f, rectTransform.anchorMin.y);
			component2.anchorMax = new Vector2(0.5f, rectTransform.anchorMax.y);
			component2.pivot = new Vector2(0.5f, rectTransform.pivot.y);
			((Transform)component2).localScale = Vector3.one;
			float num = 240f;
			if ((Object)(object)label != (Object)null)
			{
				((TMP_Text)label).enableAutoSizing = false;
				((TMP_Text)label).fontSize = ((TMP_Text)installedDisksText).fontSize;
				((TMP_Text)label).alignment = (TextAlignmentOptions)514;
				num = ((TMP_Text)label).GetPreferredValues("Sort: least upgraded").x + 30f;
				((TMP_Text)label).text = text;
			}
			float num2 = num;
			Rect rect = rectTransform.rect;
			component2.sizeDelta = new Vector2(num2, Mathf.Min(((Rect)(ref rect)).height, ((TMP_Text)installedDisksText).fontSize * 1.15f));
			if ((Object)(object)label != (Object)null)
			{
				((Graphic)label).color = ((Graphic)installedDisksText).color;
			}
			component2.anchoredPosition = new Vector2(0f, rectTransform.anchoredPosition.y);
			component2.sizeDelta = new Vector2(component2.sizeDelta.x, component2.sizeDelta.y * 0.42f);
			if ((Object)(object)val3 != (Object)null)
			{
				((Selectable)val3).interactable = true;
				val3.onClick = new ButtonClickedEvent();
				((UnityEvent)val3.onClick).AddListener(UnityAction.op_Implicit((Action)delegate
				{
					if (!(Time.unscaledTime - lastClick < 0.35f))
					{
						lastClick = Time.unscaledTime;
						Order.Value = (DiskOrder)((int)(Order.Value + 1) % 5);
						Plugin.L.LogInfo((object)("[SORT] order " + Order.Value));
						Apply(UpgradesController.Instance);
					}
				}));
			}
			ManualLogSource l2 = Plugin.L;
			val2 = new BepInExInfoLogInterpolatedStringHandler(57, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[SORT] sort button made from ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Object)((Component)val).gameObject).name);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", size ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Vector2>(component2.sizeDelta);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", header text height ");
				BepInExInfoLogInterpolatedStringHandler obj = val2;
				rect = rectTransform.rect;
				((BepInExLogInterpolatedStringHandler)obj).AppendFormatted<float>(((Rect)(ref rect)).height);
			}
			l2.LogInfo(val2);
		}

		private static void FitFrame(RectTransform rt)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				float num = float.MaxValue;
				float num2 = float.MinValue;
				Vector3[] array = (Vector3[])(object)new Vector3[4];
				foreach (Image componentsInChild in ((Component)rt).GetComponentsInChildren<Image>(true))
				{
					if (!((Object)(object)componentsInChild == (Object)null) && ((Behaviour)componentsInChild).enabled)
					{
						((Graphic)componentsInChild).rectTransform.GetWorldCorners(Il2CppStructArray<Vector3>.op_Implicit(array));
						Vector3[] array2 = array;
						foreach (Vector3 val in array2)
						{
							float y = ((Transform)rt).InverseTransformPoint(val).y;
							num = Mathf.Min(num, y);
							num2 = Mathf.Max(num2, y);
						}
					}
				}
				if (num != float.MaxValue)
				{
					float num3 = num2 - num;
					Rect rect = rt.rect;
					float num4 = num3 - ((Rect)(ref rect)).height;
					float num5 = Mathf.Max(4f, 26f - num4);
					ManualLogSource l = Plugin.L;
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(50, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[SORT] frame drawn ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(num3, "0.0");
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" high on a box of ");
						rect = rt.rect;
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(((Rect)(ref rect)).height, "0.0");
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", box set to ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<float>(num5, "0.0");
					}
					l.LogInfo(val2);
					rt.sizeDelta = new Vector2(rt.sizeDelta.x, num5);
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[SORT] fit: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(UpgradesController), "UpdateUpgrades")]
	internal static class SortAfterUpdate
	{
		private static void Postfix(UpgradesController __instance)
		{
			DiskSorter.Apply(__instance);
		}
	}
	public class SortWatch : MonoBehaviour
	{
		private float next;

		private int lastCount = -1;

		private static bool told;

		public SortWatch(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Update()
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			if (Time.unscaledTime < next)
			{
				return;
			}
			next = Time.unscaledTime + 0.5f;
			try
			{
				UpgradesController instance = UpgradesController.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					lastCount = -1;
					return;
				}
				if (instance.isOpen)
				{
					InstalledMark.Rows(instance);
				}
				int count = DiskSorter.Rows(instance).Count;
				if (count <= 0)
				{
					lastCount = -1;
				}
				else
				{
					if (count == lastCount && DiskSorter.HasButton)
					{
						return;
					}
					if (!told)
					{
						told = true;
						ManualLogSource l = Plugin.L;
						bool flag = default(bool);
						BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(45, 2, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SORT] screen found with ");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(count);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" rows (");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(instance.spawnedDisks?.Count ?? (-1));
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" in the list)");
						}
						l.LogInfo(val);
					}
					lastCount = count;
					DiskSorter.Apply(instance);
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(UpgradesController), "OpenUpgrades")]
	internal static class SortOnOpen
	{
		private static void Postfix(UpgradesController __instance)
		{
			DiskSorter.Apply(__instance);
		}
	}
	internal static class InstalledMark
	{
		private const string Tag = "(already installed)";

		private static int logged;

		internal static void Rows(UpgradesController uc)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.MarkInstalled.Value)
			{
				return;
			}
			foreach (SyncDiskElementController item in DiskSorter.Rows(uc))
			{
				try
				{
					if ((Object)(object)item == (Object)null || (Object)(object)item.titleText == (Object)null || (SoCustomComparison)(object)item.preset == (SoCustomComparison)null || item.upgrade == null || (int)item.upgrade.state != 0)
					{
						continue;
					}
					string text = ((TMP_Text)item.titleText).text ?? "";
					if (!text.Contains("(already installed)") && ShopLabel.Installed(item.preset))
					{
						((TMP_Text)item.titleText).text = "<color=#8C8C8C>" + text + "</color> <color=#E0B040>(already installed)</color>";
						if (logged < 6)
						{
							logged++;
							Plugin.L.LogInfo((object)("[LIST] marked already installed: " + ((Object)item.preset).name));
						}
					}
				}
				catch
				{
				}
			}
		}
	}
	internal class TrackedWindow
	{
		internal InfoWindow Window;

		internal SyncDiskPreset Disk;

		internal string Body;
	}
	internal static class InspectText
	{
		internal const string Generic = "SyncDisk";

		internal const string GenericBody = "Sync disks contain DNA";

		internal const string Currency = "¢r";

		internal static readonly Dictionary<long, TrackedWindow> Tracked = new Dictionary<long, TrackedWindow>();

		private static readonly Dictionary<string, string> names = new Dictionary<string, string>();

		private static readonly HashSet<string> logged = new HashSet<string>();

		private static TrackedWindow lastTracked;

		private static float lastTime;

		private static int scopeDepth;

		private static long scopeKey;

		private static int scopeFrame = -1;

		internal const bool DiagEnabled = false;

		internal static float DiagUntil = -1f;

		internal static int DiagLines;

		private static readonly Regex KeyPrefix = new Regex("^\\d+_\\d+_(?:(?:True|False)_)?", RegexOptions.Compiled);

		internal static bool Diag
		{
			get
			{
				if (Time.realtimeSinceStartup < DiagUntil)
				{
					return DiagLines < 40;
				}
				return false;
			}
		}

		internal static void DiagLog(string msg)
		{
			DiagLines++;
			Plugin.L.LogInfo((object)("[SDL] DIAG " + msg));
		}

		internal static string Short(string s)
		{
			if (s != null)
			{
				return ((s.Length > 70) ? s.Substring(0, 70) : s).Replace("\n", " ");
			}
			return "null";
		}

		internal static string BodyState()
		{
			if (scopeDepth <= 0)
			{
				if (lastTracked == null)
				{
					return "no window";
				}
				return "fallback age " + (Time.realtimeSinceStartup - lastTime).ToString("0.00", CultureInfo.InvariantCulture) + "s";
			}
			return "scope depth " + scopeDepth + (Tracked.ContainsKey(scopeKey) ? " tracked" : " not tracked");
		}

		internal static object Prop(object o, string n)
		{
			if (o == null)
			{
				return null;
			}
			try
			{
				PropertyInfo property = o.GetType().GetProperty(n, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				return (property == null) ? null : property.GetValue(o, null);
			}
			catch (Exception)
			{
				return null;
			}
		}

		internal static void SetProp(object o, string n, object v)
		{
			if (o == null)
			{
				return;
			}
			try
			{
				PropertyInfo property = o.GetType().GetProperty(n, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.CanWrite)
				{
					property.SetValue(o, v, null);
				}
				else
				{
					Plugin.L.LogInfo((object)("[SDL] no writable property " + n + " on " + o.GetType().Name));
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[SDL] set " + n + " failed: " + ex.GetType().Name));
			}
		}

		internal static string DiskName(SyncDiskPreset d)
		{
			string name = ((Object)d).name;
			if (names.TryGetValue(name, out var value))
			{
				return value;
			}
			value = null;
			try
			{
				string text = Strings.Get("evidence.syncdisks", name, (Casing)0, false, true, false, (Human)null);
				if (!string.IsNullOrEmpty(text) && text != name)
				{
					value = text;
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[SDL] name lookup failed: " + ex.GetType().Name));
			}
			if (value != null)
			{
				names[name] = value;
			}
			return value;
		}

		private static string Num(float v)
		{
			return v.ToString("0.##", CultureInfo.InvariantCulture);
		}

		internal static string Fill(SyncDiskPreset d, string desc, float value)
		{
			if (string.IsNullOrEmpty(desc))
			{
				return "";
			}
			desc = Resolve(desc);
			string text = desc.Replace("|value%|", Num(Math.Abs(value) * 100f)).Replace("|value|", Num(Math.Abs(value)));
			string text2 = text;
			string text3 = null;
			try
			{
				text3 = Strings.ComposeText(text, (Object)(object)d, (LinkSetting)0, (List<DataKey>)null, (Object)null, false);
				if (!string.IsNullOrEmpty(text3))
				{
					text2 = text3;
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[SDL] ComposeText failed: " + ex.GetType().Name));
			}
			bool flag = text2.IndexOf("|city.currency|", StringComparison.Ordinal) >= 0;
			if (flag)
			{
				text2 = text2.Replace("|city.currency|", "¢r");
			}
			if (logged.Add(desc))
			{
				Plugin.L.LogInfo((object)("[SDL] TOKENS raw=" + desc.Replace("\n", "\\n")));
				Plugin.L.LogInfo((object)("[SDL] TOKENS final=" + text2.Replace("\n", "\\n") + " value=" + value + " currencyFallback=" + flag));
			}
			return text2;
		}

		private static string Resolve(string desc)
		{
			if (!KeyPrefix.IsMatch(desc))
			{
				return desc;
			}
			try
			{
				string text = Strings.Get("evidence.syncdisks", desc, (Casing)0, false, true, false, (Human)null);
				if (!string.IsNullOrEmpty(text) && text != desc && !KeyPrefix.IsMatch(text))
				{
					return text;
				}
			}
			catch
			{
			}
			return KeyPrefix.Replace(desc, "");
		}

		private static string CleanName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return name;
			}
			return KeyPrefix.Replace(name, "");
		}

		private static void AddEffect(StringBuilder sb, SyncDiskPreset d, string title, string name, string desc, float value)
		{
			if (!string.IsNullOrEmpty(name) || !string.IsNullOrEmpty(desc))
			{
				if (sb.Length > 0)
				{
					sb.Append("\n\n");
				}
				string text = CleanName(name);
				bool flag = !string.IsNullOrEmpty(title) && string.Equals(title, text, StringComparison.OrdinalIgnoreCase);
				if (!string.IsNullOrEmpty(text) && !flag)
				{
					sb.Append(text).Append("\n");
				}
				sb.Append(Fill(d, desc, value));
			}
		}

		internal static string BuildBody(SyncDiskPreset d)
		{
			StringBuilder stringBuilder = new StringBuilder();
			string title = DiskName(d);
			if (Plugin.BadgeInstalled.Value && ShopLabel.Installed(d))
			{
				stringBuilder.Append("You already have this disk installed.\n\n");
			}
			AddEffect(stringBuilder, d, title, d.mainEffect1Name, d.mainEffect1Description, d.mainEffect1Value);
			AddEffect(stringBuilder, d, title, d.mainEffect2Name, d.mainEffect2Description, d.mainEffect2Value);
			AddEffect(stringBuilder, d, title, d.mainEffect3Name, d.mainEffect3Description, d.mainEffect3Value);
			string text = Fill(d, d.sideEffectDescription, d.sideEffectValue);
			if (text.Length > 0)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append("\n\n");
				}
				stringBuilder.Append("Side effect\n").Append(text);
			}
			return stringBuilder.ToString();
		}

		internal static void ApplyTitle(InfoWindow w, SyncDiskPreset d)
		{
			string text = DiskName(d);
			if (text != null)
			{
				object obj = Prop(w, "titleText");
				if (obj != null && Prop(obj, "text") as string == "SyncDisk")
				{
					SetProp(obj, "text", text);
					Plugin.L.LogInfo((object)("[SDL] title SyncDisk -> " + text));
				}
			}
		}

		internal static void MarkLast(TrackedWindow tw)
		{
			lastTracked = tw;
			lastTime = Time.realtimeSinceStartup;
			if (Tracked.Count > 40)
			{
				Prune();
			}
		}

		private static void Prune()
		{
			List<long> list = new List<long>();
			foreach (KeyValuePair<long, TrackedWindow> item in Tracked)
			{
				bool flag = false;
				try
				{
					flag = (Object)(object)item.Value.Window != (Object)null && (Object)(object)((Component)item.Value.Window).gameObject != (Object)null;
				}
				catch (Exception)
				{
					flag = false;
				}
				if (!flag)
				{
					list.Add(item.Key);
				}
			}
			for (int i = 0; i < list.Count; i++)
			{
				Tracked.Remove(list[i]);
			}
		}

		internal static void EnterScope(WindowContentController wcc)
		{
			try
			{
				int frameCount = Time.frameCount;
				if (frameCount != scopeFrame)
				{
					scopeDepth = 0;
					scopeKey = 0L;
					scopeFrame = frameCount;
				}
				InfoWindow window = wcc.window;
				long num = (((Object)(object)window == (Object)null) ? 0 : ((Il2CppObjectBase)window).Pointer.ToInt64());
				if (scopeDepth == 0)
				{
					scopeKey = num;
				}
				scopeDepth++;
			}
			catch (Exception)
			{
			}
		}

		internal static void ExitScope()
		{
			if (scopeDepth > 0)
			{
				scopeDepth--;
			}
			if (scopeDepth == 0)
			{
				scopeKey = 0L;
			}
		}

		internal static string CurrentBody()
		{
			if (scopeDepth > 0 && scopeKey != 0L)
			{
				if (Tracked.TryGetValue(scopeKey, out var value))
				{
					return value.Body;
				}
				return null;
			}
			if (lastTracked != null && Time.realtimeSinceStartup - lastTime < 5f)
			{
				return lastTracked.Body;
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(InfoWindow), "Setup", new Type[]
	{
		typeof(WindowStylePreset),
		typeof(Evidence),
		typeof(List<DataKey>),
		typeof(bool),
		typeof(Interactable),
		typeof(Case),
		typeof(CaseElement),
		typeof(bool)
	})]
	public static class InspectSetupPatch
	{
		private static void Prefix(InfoWindow __instance, Interactable newInteractable)
		{
			try
			{
				long key = ((Il2CppObjectBase)__instance).Pointer.ToInt64();
				if (newInteractable != null && (SoCustomComparison)(object)newInteractable.syncDisk != (SoCustomComparison)null)
				{
					SyncDiskPreset syncDisk = newInteractable.syncDisk;
					TrackedWindow trackedWindow = new TrackedWindow
					{
						Window = __instance,
						Disk = syncDisk,
						Body = InspectText.BuildBody(syncDisk)
					};
					InspectText.Tracked[key] = trackedWindow;
					InspectText.MarkLast(trackedWindow);
				}
				else
				{
					InspectText.Tracked.Remove(key);
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[SDL] inspect prefix failed: " + ex.GetType().Name + " " + ex.Message));
			}
		}

		private static void Postfix(InfoWindow __instance)
		{
			try
			{
				if (InspectText.Tracked.TryGetValue(((Il2CppObjectBase)__instance).Pointer.ToInt64(), out var value))
				{
					Plugin.L.LogInfo((object)("[SDL] inspect on disk " + ((Object)value.Disk).name));
					InspectText.ApplyTitle(__instance, value.Disk);
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[SDL] inspect postfix failed: " + ex.GetType().Name + " " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(InfoWindow), "SetName")]
	public static class InspectSetNamePatch
	{
		private static void Postfix(InfoWindow __instance)
		{
			try
			{
				if (InspectText.Tracked.TryGetValue(((Il2CppObjectBase)__instance).Pointer.ToInt64(), out var value))
				{
					InspectText.ApplyTitle(__instance, value.Disk);
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[SDL] SetName postfix failed: " + ex.GetType().Name));
			}
		}
	}
	[HarmonyPatch(typeof(WindowContentController), "ConstructContent")]
	public static class InspectConstructPatch
	{
		private static void Prefix(WindowContentController __instance)
		{
			InspectText.EnterScope(__instance);
		}

		private static void Postfix()
		{
			InspectText.ExitScope();
		}
	}
	[HarmonyPatch(typeof(WindowContentController), "LoadContent")]
	public static class InspectLoadContentPatch
	{
		private static void Prefix(WindowContentController __instance)
		{
			InspectText.EnterScope(__instance);
		}

		private static void Postfix()
		{
			InspectText.ExitScope();
		}
	}
	[HarmonyPatch(typeof(Strings), "ComposeText")]
	public static class InspectComposePatch
	{
		private static int logged;

		private static void Postfix(ref string __result)
		{
			try
			{
				if (__result == null)
				{
					return;
				}
				bool flag = __result.IndexOf("Sync disks contain DNA", StringComparison.Ordinal) >= 0;
				if (InspectText.Diag && (flag || __result.IndexOf("DNA", StringComparison.Ordinal) >= 0 || __result.IndexOf("ync disk", StringComparison.OrdinalIgnoreCase) >= 0))
				{
					InspectText.DiagLog("ComposeText result (generic " + flag + ", " + InspectText.BodyState() + "): " + InspectText.Short(__result));
				}
				if (!flag)
				{
					return;
				}
				string text = InspectText.CurrentBody();
				if (text == null)
				{
					if (InspectText.Diag)
					{
						InspectText.DiagLog("ComposeText: generic text but no body to put in");
					}
					return;
				}
				__result = text;
				if (logged < 8)
				{
					logged++;
					Plugin.L.LogInfo((object)("[SDL] REPLACED generic text via ComposeText, chars=" + text.Length));
				}
			}
			catch (Exception)
			{
			}
		}
	}
	[HarmonyPatch(typeof(Strings), "Get")]
	public static class InspectGetPatch
	{
		private const string BlockKey = "48759cc9-e501-4dbe-b5d8-ac151c684bdc";

		private static int logged;

		private static void Postfix(string dictionary, string key, ref string __result)
		{
			try
			{
				if (InspectText.Diag && dictionary == "dds.blocks")
				{
					InspectText.DiagLog("Get dds.blocks " + key + ((key == "48759cc9-e501-4dbe-b5d8-ac151c684bdc") ? " (the sync disk block)" : "") + " (" + InspectText.BodyState() + "): " + InspectText.Short(__result));
				}
				if (key != "48759cc9-e501-4dbe-b5d8-ac151c684bdc" || dictionary != "dds.blocks")
				{
					return;
				}
				string text = InspectText.CurrentBody();
				if (text == null)
				{
					if (InspectText.Diag)
					{
						InspectText.DiagLog("Get: sync disk block but no body to put in");
					}
					return;
				}
				__result = text;
				if (logged < 8)
				{
					logged++;
					Plugin.L.LogInfo((object)("[SDL] REPLACED generic text via Strings.Get, chars=" + text.Length));
				}
			}
			catch (Exception)
			{
			}
		}
	}
	internal static class InstalledBadge
	{
		private const string Name = "SDLInstalledBadge";

		private const int Size = 48;

		private static Sprite sprite;

		private static bool told;

		internal static void Apply(InventorySquareController sq)
		{
			try
			{
				if (!((Object)(object)sq == (Object)null) && Plugin.BadgeInstalled.Value)
				{
					Interactable val = ((sq.slot != null) ? sq.slot.GetInteractable() : null);
					SyncDiskPreset disk = ((val != null) ? val.syncDisk : null);
					Show(((Component)sq).transform, disk);
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BADGE] " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		internal static void ApplyShop(ShopSelectButtonController b)
		{
			try
			{
				if (!((Object)(object)b == (Object)null) && Plugin.BadgeInstalled.Value)
				{
					SyncDiskPreset disk = null;
					if (b.sellMode && b.sellInteractable != null)
					{
						disk = b.sellInteractable.syncDisk;
					}
					Show(((Component)b).transform, disk);
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[BADGE] shop " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private static void Show(Transform t, SyncDiskPreset disk)
		{
			bool flag = (SoCustomComparison)(object)disk != (SoCustomComparison)null && ShopLabel.Installed(disk);
			Transform val = t.Find("SDLInstalledBadge");
			if ((Object)(object)val == (Object)null)
			{
				if (!flag)
				{
					return;
				}
				val = Make(t);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
			}
			if (((Component)val).gameObject.activeSelf != flag)
			{
				((Component)val).gameObject.SetActive(flag);
			}
			if (flag && !told)
			{
				told = true;
				Plugin.L.LogInfo((object)("[BADGE] marked an installed disk: " + ((Object)disk).name));
			}
		}

		private static Transform Make(Transform parent)
		{
			//IL_001c: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)sprite == (Object)null)
			{
				sprite = MakeSprite();
			}
			GameObject val = new GameObject("SDLInstalledBadge");
			Image obj = val.AddComponent<Image>();
			obj.sprite = sprite;
			((Graphic)obj).raycastTarget = false;
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			component.anchorMin = new Vector2(1f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(0f, 1f);
			component.sizeDelta = new Vector2(20f, 20f);
			component.anchoredPosition = new Vector2(-2f, -2f);
			((Transform)component).localScale = new Vector3(-1f, 1f, 1f);
			val.AddComponent<LayoutElement>().ignoreLayout = true;
			val.transform.SetAsLastSibling();
			return val.transform;
		}

		private static Sprite MakeSprite()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(48, 48, (TextureFormat)4, false);
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(1f, 0.82f, 0.1f, 1f);
			Color val3 = default(Color);
			((Color)(ref val3))..ctor(0f, 0f, 0f, 0f);
			for (int i = 0; i < 48; i++)
			{
				for (int j = 0; j < 48; j++)
				{
					float num = Mathf.Clamp01(((float)(i - j) + 1f) / 1.5f);
					val.SetPixel(j, i, (Color)((num <= 0f) ? val3 : new Color(val2.r, val2.g, val2.b, num)));
				}
			}
			((Texture)val).filterMode = (FilterMode)1;
			((Texture)val).wrapMode = (TextureWrapMode)1;
			val.Apply();
			return Sprite.Create(val, new Rect(0f, 0f, 48f, 48f), new Vector2(0f, 1f), 100f);
		}
	}
	[BepInPlugin("sm3gm.sod.disklabels", "Sync Disk Labels", "1.4.0")]
	public class Plugin : BasePlugin
	{
		public const string VER = "1.4.0";

		internal static ManualLogSource L;

		internal static ConfigEntry<bool> MarkInstalled;

		internal static ConfigEntry<bool> BadgeInstalled;

		public override void Load()
		{
			L = ((BasePlugin)this).Log;
			DiskSorter.Bind(((BasePlugin)this).Config);
			BadgeInstalled = ((BasePlugin)this).Config.Bind<bool>("Inventory", "MarkInstalled", true, "In your inventory, put a small yellow triangle in the top right corner of a sync disk you already have installed.");
			MarkInstalled = ((BasePlugin)this).Config.Bind<bool>("Shop", "MarkInstalled", true, "In a shop's buy list, grey out and mark sync disks you already have installed.");
			try
			{
				Harmony.CreateAndPatchAll(typeof(SortAfterUpdate), (string)null);
				Harmony.CreateAndPatchAll(typeof(SortOnOpen), (string)null);
				((BasePlugin)this).AddComponent<SortWatch>();
			}
			catch (Exception ex)
			{
				L.LogWarning((object)("[SORT] patch failed: " + ex.Message));
			}
			Harmony.CreateAndPatchAll(typeof(UpdateContentPatch), (string)null);
			Harmony.CreateAndPatchAll(typeof(SetupPatch), (string)null);
			Harmony.CreateAndPatchAll(typeof(HoverStartPatch), (string)null);
			Harmony.CreateAndPatchAll(typeof(HoverEndPatch), (string)null);
			Harmony.CreateAndPatchAll(typeof(InspectSetupPatch), (string)null);
			Harmony.CreateAndPatchAll(typeof(InspectSetNamePatch), (string)null);
			try
			{
				Harmony.CreateAndPatchAll(typeof(ShopTextPatch), (string)null);
				Harmony.CreateAndPatchAll(typeof(ShopTooltipPatch), (string)null);
			}
			catch (Exception ex2)
			{
				L.LogWarning((object)("[SHOP] patch failed: " + ex2.GetType().Name + " " + ex2.Message));
			}
			try
			{
				Harmony.CreateAndPatchAll(typeof(InspectComposePatch), (string)null);
				Harmony.CreateAndPatchAll(typeof(InspectGetPatch), (string)null);
				Harmony.CreateAndPatchAll(typeof(InspectConstructPatch), (string)null);
				Harmony.CreateAndPatchAll(typeof(InspectLoadContentPatch), (string)null);
			}
			catch (Exception ex3)
			{
				L.LogWarning((object)("[SDL] text patches failed: " + ex3.GetType().Name + " " + ex3.Message));
			}
			try
			{
				Harmony.CreateAndPatchAll(typeof(LookAtPatch), (string)null);
			}
			catch (Exception ex4)
			{
				L.LogWarning((object)("[LOOK] patch failed: " + ex4.GetType().Name + " " + ex4.Message));
			}
			L.LogInfo((object)"Sync Disk Labels 1.4.0 loaded, 5 hooks registered, text patches on.");
		}
	}
	internal static class Labeler
	{
		private const string Dict = "evidence.syncdisks";

		private static readonly Dictionary<string, string> Cache = new Dictionary<string, string>();

		private static readonly HashSet<string> FiredHooks = new HashSet<string>();

		internal static void Apply(InventorySquareController sq, string hook)
		{
			ApplyLabel(sq, hook);
			ApplyMark(sq);
		}

		private static void ApplyMark(InventorySquareController sq)
		{
			try
			{
				if ((Object)(object)sq == (Object)null || !Plugin.BadgeInstalled.Value)
				{
					return;
				}
				Interactable val = ((sq.slot != null) ? sq.slot.GetInteractable() : null);
				SyncDiskPreset val2 = ((val != null) ? val.syncDisk : null);
				if ((SoCustomComparison)(object)val2 == (SoCustomComparison)null || !ShopLabel.Installed(val2))
				{
					return;
				}
				object prop = GetProp(sq, "text");
				if (prop == null)
				{
					return;
				}
				PropertyInfo property = prop.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public);
				if (!(property == null) && property.CanWrite)
				{
					string text = property.GetValue(prop, null) as string;
					if (!string.IsNullOrEmpty(text) && !text.Contains("(installed)"))
					{
						property.SetValue(prop, text + " <color=#E0B040>(installed)</color>", null);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[LABEL] mark failed: " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private static void ApplyLabel(InventorySquareController sq, string hook)
		{
			try
			{
				if (FiredHooks.Add(hook))
				{
					Plugin.L.LogInfo((object)("[LABEL] hook " + hook + " fired for the first time"));
				}
				if ((Object)(object)sq == (Object)null)
				{
					return;
				}
				InstalledBadge.Apply(sq);
				InventorySlot slot = sq.slot;
				if (slot == null)
				{
					return;
				}
				Interactable interactable = slot.GetInteractable();
				if (interactable == null)
				{
					return;
				}
				SyncDiskPreset syncDisk = interactable.syncDisk;
				if ((SoCustomComparison)(object)syncDisk == (SoCustomComparison)null)
				{
					return;
				}
				string text = Lookup(((Object)syncDisk).name);
				if (text == null)
				{
					return;
				}
				object prop = GetProp(sq, "text");
				if (prop == null)
				{
					return;
				}
				PropertyInfo property = prop.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public);
				if (!(property == null) && property.CanWrite)
				{
					string text2 = property.GetValue(prop, null) as string;
					string name = interactable.GetName();
					if (!string.IsNullOrEmpty(text2) && !string.IsNullOrEmpty(name) && text2.Contains(name))
					{
						property.SetValue(prop, text2.Replace(name, text), null);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[LABEL] error in " + hook + ": " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private static string Lookup(string key)
		{
			if (string.IsNullOrEmpty(key))
			{
				return null;
			}
			if (Cache.TryGetValue(key, out var value))
			{
				return value;
			}
			string text = null;
			try
			{
				text = Strings.Get("evidence.syncdisks", key, (Casing)0, false, true, false, (Human)null);
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[LABEL] Strings.Get threw for " + key + ": " + ex.GetType().Name + ": " + ex.Message));
			}
			string text2 = ((string.IsNullOrEmpty(text) || text == key || text.Contains(key)) ? null : text);
			Cache[key] = text2;
			Plugin.L.LogInfo((object)("[LABEL] lookup evidence.syncdisks / " + key + " -> '" + (text ?? "null") + "'" + ((text2 == null) ? " (not used, label left as is)" : "")));
			return text2;
		}

		private static object GetProp(object o, string prop)
		{
			if (o == null)
			{
				return null;
			}
			PropertyInfo property = o.GetType().GetProperty(prop, BindingFlags.Instance | BindingFlags.Public);
			if (!(property == null))
			{
				return property.GetValue(o, null);
			}
			return null;
		}
	}
	internal static class ShopLabel
	{
		private static int logged;

		private const string Tag = " <color=#E0B040>(installed)</color>";

		private static int marks;

		internal static void Apply(ShopSelectButtonController b)
		{
			try
			{
				if ((Object)(object)b == (Object)null)
				{
					return;
				}
				InstalledBadge.ApplyShop(b);
				SyncDiskPreset syncDisk = b.syncDisk;
				if ((SoCustomComparison)(object)syncDisk == (SoCustomComparison)null && b.sellInteractable != null)
				{
					syncDisk = b.sellInteractable.syncDisk;
				}
				if ((SoCustomComparison)(object)syncDisk == (SoCustomComparison)null)
				{
					return;
				}
				string text = InspectText.DiskName(syncDisk);
				if (text == null)
				{
					return;
				}
				object obj = InspectText.Prop(b, "text");
				if (obj == null)
				{
					return;
				}
				string text2 = InspectText.Prop(obj, "text") as string;
				if (string.IsNullOrEmpty(text2))
				{
					return;
				}
				if (text2.Contains(text))
				{
					Mark(b, syncDisk, obj, text2);
					return;
				}
				string text3 = null;
				try
				{
					if (b.sellInteractable != null)
					{
						text3 = b.sellInteractable.GetName();
					}
				}
				catch
				{
				}
				string text4 = null;
				string[] array = new string[4] { text3, "SyncDisk", "Sync Disk", "Sync disk" };
				foreach (string text5 in array)
				{
					if (!string.IsNullOrEmpty(text5) && text2.Contains(text5))
					{
						text4 = text2.Replace(text5, text);
						break;
					}
				}
				if (logged < 12)
				{
					logged++;
					Plugin.L.LogInfo((object)("[SHOP] " + (b.sellMode ? "sell" : "buy") + " '" + text2.Replace("\n", " ") + "' -> " + ((text4 == null) ? "no generic name found" : ("'" + text4.Replace("\n", " ") + "'"))));
				}
				if (text4 != null)
				{
					InspectText.SetProp(obj, "text", text4);
				}
				Mark(b, syncDisk, obj, text4 ?? text2);
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[SHOP] label failed: " + ex.GetType().Name + " " + ex.Message));
			}
		}

		private static void Mark(ShopSelectButtonController b, SyncDiskPreset disk, object txt, string cur)
		{
			if (cur.Contains("(installed)") || !Installed(disk))
			{
				return;
			}
			if (b.sellMode)
			{
				if (Plugin.BadgeInstalled.Value)
				{
					InspectText.SetProp(txt, "text", cur + " <color=#E0B040>(installed)</color>");
				}
			}
			else if (Plugin.MarkInstalled.Value)
			{
				string v = "<color=#8C8C8C>" + cur + "</color> <color=#E0B040>(installed)</color>";
				InspectText.SetProp(txt, "text", v);
				if (marks < 6)
				{
					marks++;
					Plugin.L.LogInfo((object)("[SHOP] marked installed: " + ((Object)disk).name));
				}
			}
		}

		internal static bool Installed(SyncDiskPreset disk)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				UpgradesController instance = UpgradesController.Instance;
				if ((Object)(object)instance == (Object)null || instance.upgrades == null || (SoCustomComparison)(object)disk == (SoCustomComparison)null)
				{
					return false;
				}
				Enumerator<Upgrades> enumerator = instance.upgrades.GetEnumerator();
				while (enumerator.MoveNext())
				{
					Upgrades current = enumerator.Current;
					if (current != null && (int)current.state != 0)
					{
						SyncDiskPreset val = current.preset ?? current.GetPreset();
						if ((SoCustomComparison)(object)val != (SoCustomComparison)null && (((Il2CppObjectBase)val).Pointer == ((Il2CppObjectBase)disk).Pointer || ((Object)val).name == ((Object)disk).name))
						{
							return true;
						}
					}
				}
			}
			catch
			{
			}
			return false;
		}
	}
	internal static class ShopTip
	{
		private static int logged;

		internal static void Apply(ShopSelectButtonController b)
		{
			try
			{
				if ((Object)(object)b == (Object)null || (Object)(object)((ButtonController)b).tooltip == (Object)null)
				{
					return;
				}
				SyncDiskPreset syncDisk = b.syncDisk;
				if ((SoCustomComparison)(object)syncDisk == (SoCustomComparison)null && b.sellInteractable != null)
				{
					syncDisk = b.sellInteractable.syncDisk;
				}
				if ((SoCustomComparison)(object)syncDisk == (SoCustomComparison)null)
				{
					return;
				}
				string text = InspectText.BuildBody(syncDisk);
				if (string.IsNullOrEmpty(text))
				{
					return;
				}
				TooltipController tooltip = ((ButtonController)b).tooltip;
				if (!(tooltip.mainText == text) || tooltip.useMainDictionaryEntry)
				{
					tooltip.useMainDictionaryEntry = false;
					tooltip.mainText = text;
					tooltip.useDetailDictionaryEntry = false;
					tooltip.detailText = "";
					if (logged < 6)
					{
						logged++;
						Plugin.L.LogInfo((object)("[SHOP] tooltip " + ((Object)syncDisk).name + ": " + text.Length + " chars"));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.L.LogWarning((object)("[SHOP] tooltip failed: " + ex.GetType().Name + " " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(InteractionController), "UpdateReadingModeText")]
	public static class LookAtPatch
	{
		private const string Tag = " <color=#E0B040>(installed)</color>";

		private static int errs;

		private static void Postfix()
		{
			try
			{
				if (!Plugin.BadgeInstalled.Value)
				{
					return;
				}
				InteractionController instance = InteractionController.Instance;
				object obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					InteractableController currentLookingAtInteractable = instance.currentLookingAtInteractable;
					obj = ((currentLookingAtInteractable != null) ? currentLookingAtInteractable.interactable : null);
				}
				Interactable val = (Interactable)obj;
				SyncDiskPreset val2 = ((val != null) ? val.syncDisk : null);
				if ((SoCustomComparison)(object)val2 == (SoCustomComparison)null || !ShopLabel.Installed(val2))
				{
					return;
				}
				InterfaceControls instance2 = InterfaceControls.Instance;
				TextMeshProUGUI val3 = ((instance2 != null) ? instance2.readingText : null);
				if (!((Object)(object)val3 == (Object)null))
				{
					string text = InspectText.Prop(val3, "text") as string;
					if (!string.IsNullOrEmpty(text) && !text.Contains("(installed)"))
					{
						int num = text.IndexOf('\n');
						InspectText.SetProp(val3, "text", (num < 0) ? (text + " <color=#E0B040>(installed)</color>") : (text.Substring(0, num) + " <color=#E0B040>(installed)</color>" + text.Substring(num)));
					}
				}
			}
			catch (Exception ex)
			{
				if (errs++ < 3)
				{
					Plugin.L.LogWarning((object)("[LOOK] " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}
	}
	[HarmonyPatch(typeof(ShopSelectButtonController), "UpdateTooltip")]
	public static class ShopTooltipPatch
	{
		private static void Postfix(ShopSelectButtonController __instance)
		{
			ShopTip.Apply(__instance);
		}
	}
	[HarmonyPatch(typeof(ShopSelectButtonController), "UpdateButtonText")]
	public static class ShopTextPatch
	{
		private static void Postfix(ShopSelectButtonController __instance)
		{
			ShopLabel.Apply(__instance);
			ShopTip.Apply(__instance);
		}
	}
	[HarmonyPatch(typeof(InventorySquareController), "OnUpdateContent")]
	public static class UpdateContentPatch
	{
		private static void Postfix(InventorySquareController __instance)
		{
			Labeler.Apply(__instance, "OnUpdateContent");
		}
	}
	[HarmonyPatch(typeof(InventorySquareController), "Setup")]
	public static class SetupPatch
	{
		private static void Postfix(InventorySquareController __instance)
		{
			Labeler.Apply(__instance, "Setup");
		}
	}
	[HarmonyPatch(typeof(InventorySquareController), "OnHoverStart")]
	public static class HoverStartPatch
	{
		private static void Postfix(InventorySquareController __instance)
		{
			Labeler.Apply(__instance, "OnHoverStart");
		}
	}
	[HarmonyPatch(typeof(InventorySquareController), "OnHoverEnd")]
	public static class HoverEndPatch
	{
		private static void Postfix(InventorySquareController __instance)
		{
			Labeler.Apply(__instance, "OnHoverEnd");
		}
	}
}