Decompiled source of Eclipse by FAiNEL v1.2.9

BepInEx/plugins/Eclipse.dll

Decompiled 3 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Eclipse")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Eclipse")]
[assembly: AssemblyTitle("Eclipse")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 Eclipse
{
	[BepInPlugin("fix.eclipseplus.ui", "Eclipse by FAiNEL", "1.2.9")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class EclipsePlugin : BasePlugin
	{
		public const string GUID = "fix.eclipseplus.ui";

		public const string NAME = "Eclipse by FAiNEL";

		public const string VERSION = "1.2.9";

		public const string EP_GUID = "com.dinasor.eclipseplus";

		internal static ManualLogSource Logger;

		internal static Harmony HarmonyInst;

		internal static ConfigEntry<bool> CfgCoreUi;

		internal static ConfigEntry<bool> CfgIcons;

		internal static ConfigEntry<bool> CfgMarker;

		internal static ConfigEntry<bool> CfgFamiliars;

		internal static ConfigEntry<bool> CfgDiag;

		internal static ConfigEntry<bool> CfgTabGlow;

		internal static ConfigEntry<bool> CfgQuickPrestige;

		public override void Load()
		{
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Expected O, but got Unknown
			Logger = ((BasePlugin)this).Log;
			CfgCoreUi = ((BasePlugin)this).Config.Bind<bool>("Features", "CoreUiFixes", true, "Vanilla menu fixes: 4/4 expertise slots, 4 legacy choices, 4th HUD stat, phantom-row filter.");
			CfgIcons = ((BasePlugin)this).Config.Bind<bool>("Features", "WeaponIcons", true, "Real game icons for new weapons/bloods in Stat Bonuses (sprite scan on first panel open).");
			CfgMarker = ((BasePlugin)this).Config.Bind<bool>("Features", "SynergyMarker", true, "Yellow x1.5 marker centered on class-synergy rows in Expertise/Legacies lists.");
			CfgFamiliars = ((BasePlugin)this).Config.Bind<bool>("Features", "FamiliarsTabFix", true, "Hide unused Familiars mode tabs and clip the character menu scroll.");
			CfgDiag = ((BasePlugin)this).Config.Bind<bool>("Features", "Diagnostics", false, "Verbose click/update diagnostics in the log (troubleshooting only).");
			CfgTabGlow = ((BasePlugin)this).Config.Bind<bool>("Features", "TabGlow", true, "Bright contour on the selected mode tab (Weapon Expertise / Blood Legacies / Professions / Class).");
			CfgQuickPrestige = ((BasePlugin)this).Config.Bind<bool>("Features", "QuickPrestige", true, "Prestige quick-buttons: .prestige me in the Stat Bonuses header + Experience/ExoForm on the Prestige Leaderboard card.");
			try
			{
				string text = EclipseTypes.Validate();
				if (text != null)
				{
					((BasePlugin)this).Log.LogWarning((object)("Eclipse: EclipsePlus types not resolved yet (" + text + "), skipping patches."));
					return;
				}
				if (CfgIcons.Value)
				{
					StatBonusesIconSynth.Apply();
				}
				HarmonyInst = new Harmony("fix.eclipseplus.ui");
				foreach (Type patchType in GetPatchTypes())
				{
					if (!ShouldPatch(patchType))
					{
						((BasePlugin)this).Log.LogInfo((object)("Eclipse: patch " + patchType.Name + " disabled by config."));
						continue;
					}
					try
					{
						HarmonyInst.CreateClassProcessor(patchType).Patch();
					}
					catch (Exception ex)
					{
						((BasePlugin)this).Log.LogError((object)("Eclipse: patch " + patchType.Name + " failed: " + ex));
					}
				}
				((BasePlugin)this).Log.LogInfo((object)"Eclipse loaded: weapon panel synthesis + 4/4 slots + 4th HUD stat + icon healing + locale caps repair.");
			}
			catch (Exception ex2)
			{
				((BasePlugin)this).Log.LogError((object)("Eclipse patch failure: " + ex2));
			}
		}

		private static bool ShouldPatch(Type t)
		{
			switch (t.Name)
			{
			case "QuipsDiagPatch":
			case "UpdateRowClickDiagPostfix":
				return CfgDiag.Value;
			case "WireParseDiagPatch":
				return false;
			case "StatPanelKindWeaponPatch":
			case "StatPanelKindBloodPatch":
			case "StatSynergyMarker":
				return CfgMarker.Value;
			case "FamiliarsTabCleanupPatch":
				return CfgFamiliars.Value;
			case "WeaponIconGameSprites":
				return CfgIcons.Value;
			default:
				return CfgCoreUi.Value;
			}
		}

		private static IEnumerable<Type> GetPatchTypes()
		{
			Type[] types = typeof(EclipsePlugin).Assembly.GetTypes();
			foreach (Type type in types)
			{
				if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0)
				{
					yield return type;
				}
			}
		}

		public override bool Unload()
		{
			return true;
		}
	}
	internal static class EclipseTypes
	{
		internal static Type Tab = AccessTools.TypeByName("Eclipse.Services.CharacterMenu.Tabs.StatBonusesTab");

		internal static Type DataService = AccessTools.TypeByName("Eclipse.Services.DataService");

		internal static Type DataHUD = AccessTools.TypeByName("Eclipse.Services.CanvasService+DataHUD");

		internal static Type HudUpdateManager = AccessTools.TypeByName("Eclipse.Services.HUD.HudUpdateManager");

		internal static Type HudUtilities = AccessTools.TypeByName("Eclipse.Services.HUD.Shared.HudUtilities");

		internal static Type Quips = AccessTools.TypeByName("Eclipse.Utilities.Quips");

		internal static Type WeaponStatType = AccessTools.TypeByName("Eclipse.Services.DataService+WeaponStatType");

		internal static Type BloodStatType = AccessTools.TypeByName("Eclipse.Services.DataService+BloodStatType");

		internal static Type CharacterMenuService = AccessTools.TypeByName("Eclipse.Services.CharacterMenuService");

		internal static Type HudData = AccessTools.TypeByName("Eclipse.Services.HUD.Shared.HudData");

		internal static Type LayoutService = AccessTools.TypeByName("Eclipse.Services.LayoutService");

		internal static string Validate()
		{
			if (Tab == null)
			{
				return "StatBonusesTab";
			}
			if (DataService == null)
			{
				return "DataService";
			}
			if (DataHUD == null)
			{
				return "DataHUD";
			}
			if (HudUpdateManager == null)
			{
				return "HudUpdateManager";
			}
			if (HudUtilities == null)
			{
				return "HudUtilities";
			}
			if (Quips == null)
			{
				return "Quips";
			}
			if (WeaponStatType == null)
			{
				return "WeaponStatType";
			}
			if (BloodStatType == null)
			{
				return "BloodStatType";
			}
			if (CharacterMenuService == null)
			{
				return "CharacterMenuService";
			}
			return null;
		}
	}
	[HarmonyPatch]
	internal class WeaponExpertisePanelPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(EclipseTypes.Tab, "UpdateWeaponExpertisePanel", (Type[])null, (Type[])null);
		}

		private static bool Prefix(object __instance)
		{
			try
			{
				bool num = Convert.ToBoolean(AccessTools.Field(EclipseTypes.DataService, "_statBonusDataReady").GetValue(null));
				object value = AccessTools.Field(EclipseTypes.DataService, "_weaponStatBonusData").GetValue(null);
				if (num && value != null)
				{
					return true;
				}
			}
			catch
			{
				return true;
			}
			try
			{
				WeaponPanelSynth.Synthesize(__instance);
			}
			catch (Exception ex)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogError((object)("Weapon panel synthesis failed: " + ex));
				}
			}
			return false;
		}
	}
	internal static class WeaponPanelSynth
	{
		private static readonly Type TabT;

		private static readonly Type DsT;

		private static readonly Type HudT;

		private static readonly Type HuT;

		private static readonly Type EntryT;

		private static readonly FieldInfo FRows;

		private static readonly MethodInfo MUpdateHeader;

		private static readonly MethodInfo MUpdateHeaderIcon;

		private static readonly MethodInfo MEnsureRows;

		private static readonly MethodInfo MUpdateRow;

		private static readonly MethodInfo MWeaponIcons;

		private static readonly MethodInfo MFormatWeaponValue;

		private static readonly FieldInfo FWeaponValues;

		private static readonly FieldInfo FSynergies;

		private static readonly FieldInfo FPrestigeMult;

		private static readonly FieldInfo FExpType;

		private static readonly FieldInfo FExpLevel;

		private static readonly FieldInfo FExpMax;

		private static readonly FieldInfo FExpProg;

		private static readonly FieldInfo FExpPrestige;

		private static readonly FieldInfo FClassType;

		private static readonly FieldInfo FExpBonus;

		private static float _nextDiag;

		private static readonly MethodInfo MSplitPascal;

		private static readonly MethodInfo MClassSynergy;

		internal static volatile string CurrentWeaponType;

		static WeaponPanelSynth()
		{
			TabT = EclipseTypes.Tab;
			DsT = EclipseTypes.DataService;
			HudT = EclipseTypes.DataHUD;
			HuT = EclipseTypes.HudUtilities;
			EntryT = TabT.GetNestedType("StatBonusEntry", BindingFlags.NonPublic);
			FRows = AccessTools.Field(TabT, "_rows");
			MUpdateHeader = AccessTools.Method(TabT, "UpdateHeader", (Type[])null, (Type[])null);
			MUpdateHeaderIcon = AccessTools.Method(TabT, "UpdateHeaderIcon", (Type[])null, (Type[])null);
			MEnsureRows = AccessTools.Method(TabT, "EnsureRows", (Type[])null, (Type[])null);
			MUpdateRow = AccessTools.Method(TabT, "UpdateRow", (Type[])null, (Type[])null);
			MWeaponIcons = AccessTools.Method(TabT, "GetWeaponTypeIconSprites", (Type[])null, (Type[])null);
			MFormatWeaponValue = AccessTools.Method(TabT, "FormatWeaponStatValue", (Type[])null, (Type[])null);
			FWeaponValues = AccessTools.Field(DsT, "_weaponStatValues");
			FSynergies = AccessTools.Field(DsT, "_classStatSynergies");
			FPrestigeMult = AccessTools.Field(DsT, "_prestigeStatMultiplier");
			FExpType = AccessTools.Field(HudT, "_expertiseType");
			FExpLevel = AccessTools.Field(HudT, "_expertiseLevel");
			FExpMax = AccessTools.Field(HudT, "_expertiseMaxLevel");
			FExpProg = AccessTools.Field(HudT, "_expertiseProgress");
			FExpPrestige = AccessTools.Field(HudT, "_expertisePrestige");
			FClassType = AccessTools.Field(HudT, "_classType");
			FExpBonus = AccessTools.Field(HudT, "_expertiseBonusStats");
			MSplitPascal = AccessTools.Method(HuT, "SplitPascalCase", (Type[])null, (Type[])null);
			MethodInfo methodInfo = AccessTools.GetDeclaredMethods(HuT).FirstOrDefault((MethodInfo m) => m.Name == "ClassSynergy" && m.IsGenericMethodDefinition && m.GetParameters().Length == 3);
			if (methodInfo != null && EclipseTypes.WeaponStatType != null)
			{
				try
				{
					MClassSynergy = methodInfo.MakeGenericMethod(EclipseTypes.WeaponStatType);
				}
				catch (Exception ex)
				{
					ManualLogSource logger = EclipsePlugin.Logger;
					if (logger != null)
					{
						logger.LogWarning((object)("WeaponPanelSynth: ClassSynergy<WeaponStatType> resolve failed: " + ex.Message));
					}
				}
			}
			if (MClassSynergy == null)
			{
				ManualLogSource logger2 = EclipsePlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)"WeaponPanelSynth: ClassSynergy method not resolved — x1.5 synergy will NOT be applied.");
				}
			}
		}

		internal static void Synthesize(object tab)
		{
			WeaponIconGameSprites.Ensure();
			string text = (string)FExpType.GetValue(null);
			int num = Convert.ToInt32(FExpLevel.GetValue(null));
			int num2 = Convert.ToInt32(FExpMax.GetValue(null));
			float num3 = Convert.ToSingle(FExpProg.GetValue(null));
			int num4 = Convert.ToInt32(FExpPrestige.GetValue(null));
			object value = FClassType.GetValue(null);
			IEnumerable<string> enumerable = FExpBonus.GetValue(null) as IEnumerable<string>;
			int num5 = 0;
			if (enumerable != null)
			{
				foreach (string item2 in enumerable)
				{
					if (!string.IsNullOrWhiteSpace(item2) && Enum.TryParse(EclipseTypes.WeaponStatType, item2, ignoreCase: true, out object result) && Convert.ToInt32(result) != 0)
					{
						num5++;
					}
				}
			}
			float num6 = Convert.ToSingle(FPrestigeMult.GetValue(null));
			object value2 = FSynergies.GetValue(null);
			IDictionary dictionary = FWeaponValues.GetValue(null) as IDictionary;
			float num7 = ((num2 > 0) ? ((float)num / (float)num2) : 0f);
			List<object> list = new List<object>();
			foreach (object value3 in Enum.GetValues(EclipseTypes.WeaponStatType))
			{
				if (Convert.ToInt32(value3) != 0)
				{
					string text2 = value3.ToString();
					string text3 = (string)MSplitPascal.Invoke(null, new object[1] { text2 });
					bool flag = enumerable?.Contains(text2) ?? false;
					float num8 = ((dictionary != null && dictionary.Contains(value3)) ? Convert.ToSingle(dictionary[value3]) : 0f);
					float num9 = ((MClassSynergy != null && value != null && value2 != null) ? Convert.ToSingle(MClassSynergy.Invoke(null, new object[3] { value3, value, value2 })) : 1f);
					float num10 = num8 * (1f + num6 * (float)num4) * num9 * num7;
					object item = Activator.CreateInstance(EntryT, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new object[4]
					{
						Convert.ToInt32(value3),
						text3,
						num10,
						flag
					}, null);
					list.Add(item);
				}
			}
			CurrentWeaponType = text;
			try
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (realtimeSinceStartup >= _nextDiag)
				{
					_nextDiag = realtimeSinceStartup + 10f;
					int num11 = list.Count((object e) => Convert.ToInt32(EntryT.GetProperty("IsSelected")?.GetValue(e) ?? ((object)false)) != 0);
					ManualLogSource logger = EclipsePlugin.Logger;
					if (logger != null)
					{
						logger.LogInfo((object)("[DiagTab] selNames=[" + ((enumerable == null) ? "<null>" : string.Join("|", enumerable)) + "] selected=" + num5 + " green=" + num11 + " capKeys=" + (dictionary?.Count ?? (-1))));
					}
				}
			}
			catch
			{
			}
			object obj2 = MWeaponIcons.Invoke(null, new object[1] { text });
			MUpdateHeaderIcon.Invoke(tab, new object[1] { obj2 });
			MUpdateHeader.Invoke(tab, new object[5]
			{
				text ?? string.Empty,
				num5,
				4,
				num,
				num3
			});
			MEnsureRows.Invoke(tab, new object[1] { list.Count });
			if (FRows.GetValue(tab) is IList list2)
			{
				int num12 = Math.Min(list.Count, list2.Count);
				Delegate obj3 = BuildFormatter();
				Delegate obj4 = Delegate.CreateDelegate(typeof(Action<int>), typeof(WeaponPanelSynth).GetMethod("SendWeaponCust", BindingFlags.Static | BindingFlags.Public));
				for (int num13 = 0; num13 < num12; num13++)
				{
					MUpdateRow.Invoke(null, new object[4]
					{
						list2[num13],
						list[num13],
						obj3,
						obj4
					});
				}
			}
		}

		public static void SendWeaponCust(int statIndex)
		{
			try
			{
				MethodInfo methodInfo = AccessTools.Method(EclipseTypes.Quips, "SendCommand", (Type[])null, (Type[])null);
				string currentWeaponType = CurrentWeaponType;
				string text = (string.IsNullOrWhiteSpace(currentWeaponType) ? $".wep cst {statIndex}" : $".wep cst {currentWeaponType} {statIndex}");
				methodInfo?.Invoke(null, new object[1] { text });
			}
			catch (Exception ex)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogError((object)("SendWeaponCust: " + ex));
				}
			}
		}

		private static Delegate BuildFormatter()
		{
			DynamicMethod dynamicMethod = new DynamicMethod("EfFmtWeapon", typeof(string), new Type[1] { EntryT }, typeof(WeaponPanelSynth).Module, skipVisibility: true);
			ILGenerator iLGenerator = dynamicMethod.GetILGenerator();
			MethodInfo method = EntryT.GetMethod("get_StatIndex", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			MethodInfo method2 = EntryT.GetMethod("get_Value", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			iLGenerator.Emit(OpCodes.Ldarga_S, (byte)0);
			iLGenerator.Emit(OpCodes.Call, method);
			iLGenerator.Emit(OpCodes.Ldarga_S, (byte)0);
			iLGenerator.Emit(OpCodes.Call, method2);
			iLGenerator.Emit(OpCodes.Call, MFormatWeaponValue);
			iLGenerator.Emit(OpCodes.Ret);
			return dynamicMethod.CreateDelegate(typeof(Func<, >).MakeGenericType(EntryT, typeof(string)));
		}
	}
	[HarmonyPatch]
	internal class LegacyPanelMaxChoicesPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(EclipseTypes.Tab, "UpdateBloodLegaciesPanel", (Type[])null, (Type[])null);
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			List<CodeInstruction> list = instructions.ToList();
			for (int i = 3; i < list.Count; i++)
			{
				if (list[i].opcode == OpCodes.Call && list[i].operand is MethodInfo { Name: "UpdateHeader" } methodInfo && methodInfo.DeclaringType == EclipseTypes.Tab && list[i - 3].opcode == OpCodes.Ldc_I4_3)
				{
					list[i - 3].opcode = OpCodes.Ldc_I4_4;
					ManualLogSource logger = EclipsePlugin.Logger;
					if (logger != null)
					{
						logger.LogInfo((object)"Legacy panel max choices: 3 -> 4.");
					}
				}
			}
			return list;
		}
	}
	[HarmonyPatch]
	internal class HudFourthStatPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			MethodInfo methodInfo = AccessTools.Method(EclipseTypes.HudUpdateManager, "UpdateWeaponStats", (Type[])null, (Type[])null);
			MethodInfo m2 = AccessTools.Method(EclipseTypes.HudUpdateManager, "UpdateBloodStats", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				yield return methodInfo;
			}
			if (m2 != null)
			{
				yield return m2;
			}
		}

		private static void Postfix(object[] __args)
		{
			try
			{
				FourthStat.Apply(__args);
			}
			catch (Exception e)
			{
				FourthStat.NoteError(e);
			}
			try
			{
				StatLineDiag.MaybeDump(__args);
			}
			catch
			{
			}
		}
	}
	internal static class StatLineDiag
	{
		private static readonly FieldInfo FCaps = AccessTools.Field(EclipseTypes.DataService, "_weaponStatValues");

		private static readonly FieldInfo FBonusW = AccessTools.Field(EclipseTypes.DataHUD, "_expertiseBonusStats");

		private static readonly FieldInfo FBonusB = AccessTools.Field(EclipseTypes.DataHUD, "_legacyBonusStats");

		private static float _next;

		internal static void MaybeDump(object[] args)
		{
			WireParseDiagPatch.TryApplyOnce();
			TabGlow.TryApplyOnce();
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup < _next)
			{
				return;
			}
			_next = realtimeSinceStartup + 10f;
			try
			{
				IEnumerable enumerable = args[0] as IEnumerable;
				string text = ((enumerable == null) ? "<null-list>" : string.Join("|", from object x in enumerable
					select (x != null) ? ("'" + x?.ToString() + "'") : "<null>"));
				object[] array = (args[1] as IEnumerable)?.Cast<object>().ToArray();
				Func<int, string, string> func = args[3] as Func<int, string, string>;
				string text2 = "<n/a>";
				object obj = enumerable?.Cast<object>().FirstOrDefault();
				if (func != null && obj is string text3 && !string.IsNullOrWhiteSpace(text3))
				{
					try
					{
						text2 = "'" + func(0, text3) + "'";
					}
					catch (Exception ex)
					{
						text2 = "THROW:" + ex.GetType().Name + ":" + ex.Message;
					}
				}
				string text4 = "<null-texts>";
				if (array != null)
				{
					List<string> list = new List<string>();
					for (int num = 0; num < array.Length && num < 3; num++)
					{
						object obj2 = array[num];
						if (obj2 == null)
						{
							list.Add(num + "=<null>");
							continue;
						}
						string text5 = "?";
						try
						{
							object obj3 = obj2.GetType().GetProperty("String")?.GetValue(obj2) ?? obj2.GetType().GetProperty("Text")?.GetValue(obj2);
							text5 = ((obj3 == null) ? "?" : ((obj3.ToString()?.Length ?? 0) + "ch"));
						}
						catch
						{
						}
						bool flag = false;
						bool flag2 = false;
						try
						{
							Component val = (Component)((obj2 is Component) ? obj2 : null);
							flag = (Object)(object)val != (Object)null && val.gameObject.activeInHierarchy;
							flag2 = Convert.ToBoolean(obj2.GetType().GetProperty("enabled")?.GetValue(obj2));
						}
						catch
						{
						}
						list.Add(num + "=act:" + flag + ",en:" + flag2 + "," + text5);
					}
					text4 = string.Join(" ", list);
				}
				int num2 = 0;
				try
				{
					num2 = (FCaps?.GetValue(null) as IDictionary)?.Count ?? (-1);
				}
				catch
				{
					num2 = -2;
				}
				string text6 = ((FBonusW?.GetValue(null) is IEnumerable<string> values) ? string.Join("|", values) : "<err>");
				string text7 = ((FBonusB?.GetValue(null) is IEnumerable<string> values2) ? string.Join("|", values2) : "<err>");
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)("[Diag4] bonus=[" + text + "] caps=" + num2 + " sample=" + text2 + " texts=[" + text4 + "] expB=[" + text6 + "] legB=[" + text7 + "]"));
				}
			}
			catch (Exception ex2)
			{
				ManualLogSource logger2 = EclipsePlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("[Diag4] dump failed: " + ex2.Message));
				}
			}
		}
	}
	[HarmonyPatch]
	internal class WireParseDiagPatch
	{
		private static readonly FieldInfo FEnabled = AccessTools.Field(EclipseTypes.DataService, "_familiarSystemEnabled");

		private static readonly FieldInfo FBattles = AccessTools.Field(EclipseTypes.DataService, "_familiarBattlesEnabled");

		private static readonly FieldInfo FReady = AccessTools.Field(EclipseTypes.DataService, "_familiarBattleDataReady");

		private static float _nextPlayer;

		private static float _nextConfig;

		private static float _next6;

		private static float _next7;

		private static float _nextMac;

		private static bool _applied;

		internal static void TryApplyOnce()
		{
			if (_applied)
			{
				return;
			}
			_applied = true;
			try
			{
				EclipsePlugin.HarmonyInst.CreateClassProcessor(typeof(WireParseDiagPatch)).Patch();
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)"[DiagWire] parse-diag patched (lazy, in-world).");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = EclipsePlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("[DiagWire] lazy patch failed: " + ex.Message));
				}
			}
		}

		private static IEnumerable<MethodBase> TargetMethods()
		{
			string[] array = new string[5] { "ParsePlayerData", "ParseConfigData", "ParseFamiliarBattleData", "ParseWeaponStatBonusData", "TryParseFamiliarBoxChatMessage" };
			foreach (string text in array)
			{
				MethodInfo methodInfo = AccessTools.Method(EclipseTypes.DataService, text, (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					yield return methodInfo;
				}
			}
		}

		private static void Prefix(MethodBase __originalMethod, object[] __args)
		{
			try
			{
				string name = __originalMethod.Name;
				string text;
				if (__args == null || __args.Length == 0)
				{
					text = "noargs";
				}
				else if (__args[0] is string text2)
				{
					text = text2;
				}
				else if (__args[0] is IEnumerable enumerable)
				{
					List<string> list = new List<string>();
					int num = 0;
					bool flag = false;
					foreach (object item in enumerable)
					{
						string text3 = item?.ToString() ?? "<null>";
						num += text3.Length;
						list.Add(text3);
						if (list.Count >= 60 || num > 1400)
						{
							flag = true;
							break;
						}
					}
					string text4 = string.Join(" ‖ ", list);
					if (text4.Length > 1200)
					{
						text4 = text4.Substring(0, 1200) + "…";
						flag = true;
					}
					text = "<" + __args[0].GetType().Name + " n=" + (flag ? "≥" : "") + list.Count + "> " + text4;
				}
				else
				{
					text = "<" + (__args[0]?.GetType().Name ?? "null") + ">";
				}
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				switch (name)
				{
				case "ParsePlayerData":
					if (!(realtimeSinceStartup < _nextPlayer))
					{
						_nextPlayer = realtimeSinceStartup + 10f;
						ManualLogSource logger4 = EclipsePlugin.Logger;
						if (logger4 != null)
						{
							logger4.LogInfo((object)("[DiagWire] evt=1 playerData " + Cut(text, 1300)));
						}
					}
					break;
				case "ParseConfigData":
					if (!(realtimeSinceStartup < _nextConfig))
					{
						_nextConfig = realtimeSinceStartup + 10f;
						ManualLogSource logger3 = EclipsePlugin.Logger;
						if (logger3 != null)
						{
							logger3.LogInfo((object)("[DiagWire] evt=2 config " + Cut(text, 1300)));
						}
					}
					break;
				case "ParseFamiliarBattleData":
					if (!(realtimeSinceStartup < _next6))
					{
						_next6 = realtimeSinceStartup + 5f;
						ManualLogSource logger5 = EclipsePlugin.Logger;
						if (logger5 != null)
						{
							logger5.LogInfo((object)("[DiagWire] evt=6 familiarBattle " + Cut(text, 300)));
						}
					}
					break;
				case "ParseWeaponStatBonusData":
					if (!(realtimeSinceStartup < _next7))
					{
						_next7 = realtimeSinceStartup + 5f;
						ManualLogSource logger2 = EclipsePlugin.Logger;
						if (logger2 != null)
						{
							logger2.LogInfo((object)("[DiagWire] evt=7 statBonus " + Cut(text, 300)));
						}
					}
					break;
				case "TryParseFamiliarBoxChatMessage":
					if (text.Length != 0 && text[0] == '[' && !(realtimeSinceStartup < _nextMac))
					{
						_nextMac = realtimeSinceStartup + 5f;
						ManualLogSource logger = EclipsePlugin.Logger;
						if (logger != null)
						{
							logger.LogInfo((object)("[DiagWire] nonVerified " + Cut(text, 300)));
						}
					}
					break;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger6 = EclipsePlugin.Logger;
				if (logger6 != null)
				{
					logger6.LogWarning((object)("[DiagWire] prefix failed: " + ex.Message));
				}
			}
		}

		private static void Postfix(MethodBase __originalMethod, object[] __args)
		{
			try
			{
				string name = __originalMethod.Name;
				if (!(name == "ParseFamiliarBattleData"))
				{
					if (!(name == "ParseConfigData"))
					{
						return;
					}
					List<string> list = ((__args != null && __args.Length != 0) ? (__args[0] as List<string>) : null);
					if (list == null || list.Count <= 5 || !(FEnabled != null) || !int.TryParse(list[5], out var result) || result <= 0)
					{
						return;
					}
					object value = FEnabled.GetValue(null);
					if (value is bool && !(bool)value)
					{
						FEnabled.SetValue(null, true);
						ManualLogSource logger = EclipsePlugin.Logger;
						if (logger != null)
						{
							logger.LogInfo((object)("[DiagWire] familiar gate fallback: MaxFamiliarLevel=" + result + " -> _familiarSystemEnabled=true (server sends no [6])."));
						}
					}
				}
				else
				{
					ManualLogSource logger2 = EclipsePlugin.Logger;
					if (logger2 != null)
					{
						logger2.LogInfo((object)("[DiagWire] evt=6 parsed -> system=" + (FEnabled?.GetValue(null))?.ToString() + " battles=" + (FBattles?.GetValue(null))?.ToString() + " ready=" + FReady?.GetValue(null)));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger3 = EclipsePlugin.Logger;
				if (logger3 != null)
				{
					logger3.LogWarning((object)("[DiagWire] postfix failed: " + ex.Message));
				}
			}
		}

		private static string Cut(string s, int n)
		{
			if (s == null)
			{
				return "len=?";
			}
			if (s.Length > n)
			{
				return "len=" + s.Length + " head='" + s.Substring(0, n) + "…'";
			}
			return "len=" + s.Length + " head='" + s + "'";
		}
	}
	internal static class FourthStat
	{
		private class CacheEntry
		{
			public GameObject Go;

			public object Lt;

			public MethodInfo ForceSet;

			public string Last;
		}

		private static readonly Dictionary<object, CacheEntry> Cache;

		private static bool _loggedError;

		private static readonly Type DsT;

		private static readonly Type HudT;

		private static readonly Type HuT;

		private static readonly FieldInfo FWeaponValues;

		private static readonly FieldInfo FBloodValues;

		private static readonly FieldInfo FSynergies;

		private static readonly FieldInfo FPrestigeMult;

		private static readonly FieldInfo FAbbrev;

		private static readonly FieldInfo FExpLevel;

		private static readonly FieldInfo FExpMax;

		private static readonly FieldInfo FExpPrestige;

		private static readonly FieldInfo FLegLevel;

		private static readonly FieldInfo FLegMax;

		private static readonly FieldInfo FLegPrestige;

		private static readonly FieldInfo FClassType;

		private static readonly MethodInfo MFormatWeaponBar;

		private static readonly MethodInfo MClassSynWeapon;

		private static readonly MethodInfo MClassSynBlood;

		private static readonly HashSet<object> _loggedParents;

		static FourthStat()
		{
			Cache = new Dictionary<object, CacheEntry>();
			DsT = EclipseTypes.DataService;
			HudT = EclipseTypes.DataHUD;
			HuT = EclipseTypes.HudUtilities;
			FWeaponValues = AccessTools.Field(DsT, "_weaponStatValues");
			FBloodValues = AccessTools.Field(DsT, "_bloodStatValues");
			FSynergies = AccessTools.Field(DsT, "_classStatSynergies");
			FPrestigeMult = AccessTools.Field(DsT, "_prestigeStatMultiplier");
			FAbbrev = AccessTools.Field(HuT, "BloodStatTypeAbbreviations");
			FExpLevel = AccessTools.Field(HudT, "_expertiseLevel");
			FExpMax = AccessTools.Field(HudT, "_expertiseMaxLevel");
			FExpPrestige = AccessTools.Field(HudT, "_expertisePrestige");
			FLegLevel = AccessTools.Field(HudT, "_legacyLevel");
			FLegMax = AccessTools.Field(HudT, "_legacyMaxLevel");
			FLegPrestige = AccessTools.Field(HudT, "_legacyPrestige");
			FClassType = AccessTools.Field(HudT, "_classType");
			MFormatWeaponBar = AccessTools.Method(HuT, "FormatWeaponStatBar", (Type[])null, (Type[])null);
			_loggedParents = new HashSet<object>();
			MethodInfo methodInfo = AccessTools.GetDeclaredMethods(HuT).FirstOrDefault((MethodInfo m) => m.Name == "ClassSynergy" && m.IsGenericMethodDefinition && m.GetParameters().Length == 3);
			if (methodInfo != null)
			{
				try
				{
					if (EclipseTypes.WeaponStatType != null)
					{
						MClassSynWeapon = methodInfo.MakeGenericMethod(EclipseTypes.WeaponStatType);
					}
					if (EclipseTypes.BloodStatType != null)
					{
						MClassSynBlood = methodInfo.MakeGenericMethod(EclipseTypes.BloodStatType);
					}
				}
				catch (Exception ex)
				{
					ManualLogSource logger = EclipsePlugin.Logger;
					if (logger != null)
					{
						logger.LogWarning((object)("FourthStat: ClassSynergy<T> specialize failed: " + ex.Message));
					}
				}
			}
			if (MClassSynWeapon == null || MClassSynBlood == null)
			{
				ManualLogSource logger2 = EclipsePlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("FourthStat: ClassSynergy not resolved (weapon=" + ((MClassSynWeapon != null) ? "ok" : "null") + ", blood=" + ((MClassSynBlood != null) ? "ok" : "null") + ") — x1.5 synergy will NOT be applied."));
				}
			}
		}

		internal static void Apply(object[] args)
		{
			IEnumerable<string> enumerable = args[0] as IEnumerable<string>;
			IEnumerable enumerable2 = args[1] as IEnumerable;
			if (enumerable == null || enumerable2 == null)
			{
				return;
			}
			List<string> list = (enumerable as List<string>) ?? enumerable.ToList();
			object[] array = enumerable2.Cast<object>().ToArray();
			if (array.Length < 3 || array[0] == null || array[2] == null)
			{
				return;
			}
			if (!Cache.TryGetValue(array[0], out var value))
			{
				value = CreateClone(array[0], array[2]);
				if (value == null)
				{
					return;
				}
				Cache[array[0]] = value;
			}
			string text = ((list.Count > 3) ? list[3] : null);
			if (string.IsNullOrWhiteSpace(text) || text.Equals("None", StringComparison.OrdinalIgnoreCase))
			{
				SetText(value, null);
				return;
			}
			string text2 = ((args[3] is Func<int, string, string> func && func.Method.Name.IndexOf("Blood", StringComparison.OrdinalIgnoreCase) >= 0) ? BuildBlood(text) : BuildWeapon(text));
			SetText(value, string.IsNullOrEmpty(text2) ? null : text2);
		}

		private static CacheEntry CreateClone(object firstLt, object thirdLt)
		{
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			Component val = (Component)((thirdLt is Component) ? thirdLt : null);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject gameObject = val.gameObject;
			if ((Object)(object)gameObject == (Object)null)
			{
				return null;
			}
			Transform parent = gameObject.transform.parent;
			GameObject val2 = Object.Instantiate<GameObject>(gameObject, parent);
			((Object)val2).name = ((Object)gameObject).name + "_Stat4";
			val2.transform.SetSiblingIndex(gameObject.transform.GetSiblingIndex() + 1);
			try
			{
				if ((Object)(object)(((Object)(object)parent != (Object)null) ? ((Component)parent).GetComponent<HorizontalOrVerticalLayoutGroup>() : null) == (Object)null)
				{
					RectTransform component = val2.GetComponent<RectTransform>();
					object obj = ((firstLt is Component) ? firstLt : null);
					object obj2;
					if (obj == null)
					{
						obj2 = null;
					}
					else
					{
						GameObject gameObject2 = ((Component)obj).gameObject;
						obj2 = ((gameObject2 != null) ? gameObject2.GetComponent<RectTransform>() : null);
					}
					if (obj2 == null)
					{
						obj2 = gameObject.GetComponent<RectTransform>();
					}
					RectTransform val3 = (RectTransform)obj2;
					if ((Object)(object)component != (Object)null && (Object)(object)val3 != (Object)null)
					{
						component.anchorMin = val3.anchorMin;
						component.anchorMax = val3.anchorMax;
						component.pivot = val3.pivot;
						component.sizeDelta = val3.sizeDelta;
						Vector2 anchoredPosition = val3.anchoredPosition;
						Rect rect = val3.rect;
						component.anchoredPosition = anchoredPosition + new Vector2(0f, 0f - (((Rect)(ref rect)).height + 4f));
					}
				}
				LogPanelLayoutOnce(parent, gameObject, firstLt);
			}
			catch (Exception ex)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)("FourthStat layout tweak failed: " + ex.Message));
				}
			}
			Type type = thirdLt.GetType();
			object obj3 = null;
			try
			{
				MethodInfo methodInfo = typeof(GameObject).GetMethods(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault((MethodInfo x) => x.Name == "GetComponent" && x.IsGenericMethodDefinition && x.GetParameters().Length == 0);
				if (methodInfo != null)
				{
					obj3 = methodInfo.MakeGenericMethod(type).Invoke(val2, null);
				}
			}
			catch (Exception ex2)
			{
				ManualLogSource logger2 = EclipsePlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("[FourthStat] generic GetComponent failed: " + ex2.Message));
				}
			}
			if (obj3 == null)
			{
				int num = Array.IndexOf(Il2CppArrayBase<Component>.op_Implicit(gameObject.GetComponents<Component>()), val);
				Il2CppArrayBase<Component> components = val2.GetComponents<Component>();
				if (num >= 0 && num < components.Length)
				{
					obj3 = components[num];
				}
			}
			Behaviour val4 = (Behaviour)((obj3 is Behaviour) ? obj3 : null);
			if (val4 != null)
			{
				val4.enabled = true;
			}
			ManualLogSource logger3 = EclipsePlugin.Logger;
			if (logger3 != null)
			{
				logger3.LogInfo((object)("[FourthStat] lt resolved: " + ((obj3 != null) ? obj3.GetType().FullName : "NULL")));
			}
			MethodInfo forceSet = AccessTools.Method(type, "ForceSet", (Type[])null, (Type[])null);
			val2.SetActive(false);
			return new CacheEntry
			{
				Go = val2,
				Lt = obj3,
				ForceSet = forceSet,
				Last = null
			};
		}

		private static void LogPanelLayoutOnce(object parentObj, GameObject thirdGo, object firstLt)
		{
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			Component val = (Component)((parentObj is Component) ? parentObj : null);
			if ((Object)(object)val == (Object)null || !_loggedParents.Add(val))
			{
				return;
			}
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.Append("[FourthStat] panel '").Append(((Object)val.gameObject).name).Append("' components: ");
				foreach (Component component3 in val.GetComponents<Component>())
				{
					stringBuilder.Append(((object)component3).GetType().Name).Append(", ");
				}
				object obj = ((firstLt is Component) ? firstLt : null);
				GameObject val2 = ((obj != null) ? ((Component)obj).gameObject : null);
				if ((Object)(object)val2 != (Object)null)
				{
					RectTransform component = val2.GetComponent<RectTransform>();
					RectTransform component2 = thirdGo.GetComponent<RectTransform>();
					StringBuilder stringBuilder2 = stringBuilder.Append("| first='").Append(((Object)val2).name).Append("' pos=");
					Vector2 val3 = component.anchoredPosition;
					StringBuilder stringBuilder3 = stringBuilder2.Append(((Vector2)(ref val3)).ToString("F0")).Append(" size=");
					Rect rect = component.rect;
					val3 = ((Rect)(ref rect)).size;
					StringBuilder stringBuilder4 = stringBuilder3.Append(((Vector2)(ref val3)).ToString("F0")).Append(" anchorMin=");
					val3 = component.anchorMin;
					StringBuilder stringBuilder5 = stringBuilder4.Append(((Vector2)(ref val3)).ToString("F2")).Append(" anchorMax=");
					val3 = component.anchorMax;
					StringBuilder stringBuilder6 = stringBuilder5.Append(((Vector2)(ref val3)).ToString("F2")).Append("| third='").Append(((Object)thirdGo).name)
						.Append("' pos=");
					val3 = component2.anchoredPosition;
					StringBuilder stringBuilder7 = stringBuilder6.Append(((Vector2)(ref val3)).ToString("F0")).Append(" size=");
					rect = component2.rect;
					val3 = ((Rect)(ref rect)).size;
					stringBuilder7.Append(((Vector2)(ref val3)).ToString("F0"));
				}
				if ((Object)(object)val != (Object)null)
				{
					stringBuilder.Append("| children: ");
					for (int i = 0; i < val.transform.childCount; i++)
					{
						stringBuilder.Append(((Object)val.transform.GetChild(i)).name).Append(", ");
					}
				}
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)stringBuilder.ToString());
				}
			}
			catch
			{
			}
		}

		private static void SetText(CacheEntry ce, string text)
		{
			if (text == null)
			{
				if ((Object)(object)ce.Go != (Object)null && ce.Go.activeSelf)
				{
					ce.Go.SetActive(false);
				}
				ce.Last = null;
				return;
			}
			if ((Object)(object)ce.Go != (Object)null && !ce.Go.activeSelf)
			{
				ce.Go.SetActive(true);
			}
			if (ce.Last != text)
			{
				ce.ForceSet?.Invoke(ce.Lt, new object[1] { text });
				ce.Last = text;
			}
		}

		private static float ComputeValue(FieldInfo valuesField, Type enumT, MethodInfo classSyn, object stat, FieldInfo fPrestige, FieldInfo fLevel, FieldInfo fMax)
		{
			if (!(valuesField.GetValue(null) is IDictionary dictionary) || !dictionary.Contains(stat))
			{
				return -1f;
			}
			float num = Convert.ToSingle(dictionary[stat]);
			float num2 = Convert.ToSingle(FPrestigeMult.GetValue(null));
			int num3 = Convert.ToInt32(fPrestige.GetValue(null));
			int num4 = Convert.ToInt32(fLevel.GetValue(null));
			int num5 = Convert.ToInt32(fMax.GetValue(null));
			object value = FClassType.GetValue(null);
			object value2 = FSynergies.GetValue(null);
			float num6 = ((classSyn != null && value != null && value2 != null) ? Convert.ToSingle(classSyn.Invoke(null, new object[3] { stat, value, value2 })) : 1f);
			float num7 = ((num5 > 0) ? ((float)num4 / (float)num5) : 0f);
			return num * (1f + num2 * (float)num3) * num6 * num7;
		}

		private static string BuildWeapon(string statName)
		{
			if (!Enum.TryParse(EclipseTypes.WeaponStatType, statName, ignoreCase: true, out object result))
			{
				return null;
			}
			float num = ComputeValue(FWeaponValues, EclipseTypes.WeaponStatType, MClassSynWeapon, result, FExpPrestige, FExpLevel, FExpMax);
			if (num < 0f)
			{
				return null;
			}
			return (string)MFormatWeaponBar.Invoke(null, new object[2] { result, num });
		}

		private static string BuildBlood(string statName)
		{
			if (!Enum.TryParse(EclipseTypes.BloodStatType, statName, ignoreCase: true, out object result))
			{
				return null;
			}
			float num = ComputeValue(FBloodValues, EclipseTypes.BloodStatType, MClassSynBlood, result, FLegPrestige, FLegLevel, FLegMax);
			if (num < 0f)
			{
				return null;
			}
			string value = ((FAbbrev.GetValue(null) is IDictionary dictionary && dictionary.Contains(result)) ? dictionary[result].ToString() : statName);
			return $"<color=#00FFFF>{value}</color>: <color=#90EE90>{(num * 100f).ToString("F0", CultureInfo.InvariantCulture)}%</color>";
		}

		internal static void NoteError(Exception e)
		{
			if (!_loggedError)
			{
				_loggedError = true;
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogError((object)("FourthStat error: " + e));
				}
			}
		}
	}
	[HarmonyPatch]
	internal class QuestIconBridgePatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(EclipseTypes.HudUtilities, "FindSprites", (Type[])null, (Type[])null);
		}

		private static void Postfix()
		{
			QuestIconBridge.Run();
		}
	}
	internal static class QuestIconBridge
	{
		private static readonly FieldInfo FSrcStd = AccessTools.Field(EclipseTypes.HudData, "QuestKillStandardUnit");

		private static readonly FieldInfo FSrcVB = AccessTools.Field(EclipseTypes.HudData, "QuestKillVBloodUnit");

		private static readonly FieldInfo FDstStd = AccessTools.Field(EclipseTypes.DataHUD, "_questKillStandardUnit");

		private static readonly FieldInfo FDstVB = AccessTools.Field(EclipseTypes.DataHUD, "_questKillVBloodUnit");

		private static bool _logged;

		internal static void Run()
		{
			try
			{
				if (!(FSrcStd == null) && !(FDstStd == null) && !(FSrcVB == null) && !(FDstVB == null) && (Copy(FSrcStd, FDstStd) | Copy(FSrcVB, FDstVB)) && !_logged)
				{
					_logged = true;
					ManualLogSource logger = EclipsePlugin.Logger;
					if (logger != null)
					{
						logger.LogInfo((object)"QuestIconBridge: wired DataHUD._questKill* from HudData (1.4.0 dead-field fix).");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = EclipsePlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("QuestIconBridge: " + ex.Message));
				}
			}
		}

		private static bool Copy(FieldInfo src, FieldInfo dst)
		{
			object obj = src.GetValue(null);
			if (obj != null)
			{
				Sprite val = (Sprite)((obj is Sprite) ? obj : null);
				if (val == null || !((Object)(object)val == (Object)null))
				{
					goto IL_004d;
				}
			}
			Sprite val2 = SpriteRepair.Get(((object)src == FSrcVB) ? "BloodIcon_Cursed" : "BloodIcon_Warrior");
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			src.SetValue(null, val2);
			obj = val2;
			goto IL_004d;
			IL_004d:
			if (dst.GetValue(null) == obj)
			{
				return false;
			}
			dst.SetValue(null, obj);
			return true;
		}
	}
	[HarmonyPatch]
	internal class ProfessionIconCapturePatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(EclipseTypes.LayoutService, "RegisterElement", (Type[])null, (Type[])null);
		}

		private static void Prefix(string __0, RectTransform __1)
		{
			WireParseDiagPatch.TryApplyOnce();
			TabGlow.TryApplyOnce();
			if (__0 == null || !__0.StartsWith("Profession."))
			{
				return;
			}
			try
			{
				ProfessionIconHealer.Capture(__0, __1);
			}
			catch (Exception ex)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)("ProfessionIconCapture: " + ex.Message));
				}
			}
		}
	}
	[HarmonyPatch]
	internal class ProfessionIconRescanPatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			MethodInfo methodInfo = AccessTools.Method(EclipseTypes.HudUpdateManager, "UpdateProfessions", (Type[])null, (Type[])null);
			MethodInfo m2 = AccessTools.Method(EclipseTypes.HudUpdateManager, "UpdateQuests", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				yield return methodInfo;
			}
			if (m2 != null)
			{
				yield return m2;
			}
		}

		private static void Postfix()
		{
			try
			{
				ProfessionIconHealer.Tick();
			}
			catch (Exception ex)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)("ProfessionIconRescan: " + ex.Message));
				}
			}
		}
	}
	internal static class SpriteRepair
	{
		private static readonly FieldInfo FHudSprites = AccessTools.Field(EclipseTypes.HudData, "Sprites");

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

		internal static Sprite Get(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return null;
			}
			IDictionary dictionary = null;
			try
			{
				dictionary = FHudSprites?.GetValue(null) as IDictionary;
			}
			catch
			{
			}
			try
			{
				if (dictionary != null && dictionary.Contains(name))
				{
					object? obj2 = dictionary[name];
					Sprite val = (Sprite)((obj2 is Sprite) ? obj2 : null);
					if (val != null && (Object)(object)val != (Object)null)
					{
						_cache[name] = val;
						return val;
					}
				}
			}
			catch
			{
			}
			try
			{
				if (_cache.TryGetValue(name, out var value) && (Object)(object)value != (Object)null)
				{
					try
					{
						if (dictionary != null)
						{
							dictionary[name] = value;
						}
					}
					catch
					{
					}
					return value;
				}
			}
			catch
			{
			}
			try
			{
				foreach (Sprite item in Resources.FindObjectsOfTypeAll<Sprite>())
				{
					if (!((Object)(object)item != (Object)null) || !(((Object)item).name == name))
					{
						continue;
					}
					_cache[name] = item;
					try
					{
						if (dictionary != null)
						{
							dictionary[name] = item;
						}
					}
					catch
					{
					}
					return item;
				}
			}
			catch
			{
			}
			return null;
		}
	}
	internal static class ProfessionIconHealer
	{
		private static readonly Dictionary<object, Image> Icons = new Dictionary<object, Image>();

		private static readonly HashSet<object> Pending = new HashSet<object>();

		private static readonly FieldInfo FProfIcons = AccessTools.Field(EclipseTypes.DataHUD, "ProfessionIcons");

		private static readonly FieldInfo FHudSprites = AccessTools.Field(EclipseTypes.HudData, "Sprites");

		private static readonly MethodInfo MFindSprites = AccessTools.Method(EclipseTypes.HudUtilities, "FindSprites", (Type[])null, (Type[])null);

		private static float _nextScan = float.NegativeInfinity;

		private static float _nextStatus;

		private static bool _loggedHeal;

		private static bool _loggedTick;

		private const float ScanCooldown = 5f;

		internal static void Capture(string layoutKey, RectTransform rect)
		{
			if (FProfIcons == null || (Object)(object)rect == (Object)null || !(FProfIcons.GetValue(null) is IDictionary dictionary))
			{
				return;
			}
			string b = layoutKey.Substring("Profession.".Length);
			object obj = null;
			foreach (object key in dictionary.Keys)
			{
				if (string.Equals(key.ToString(), b, StringComparison.OrdinalIgnoreCase))
				{
					obj = key;
					break;
				}
			}
			if (obj == null)
			{
				return;
			}
			Image val = FindChildImage(((Component)rect).gameObject.transform, "LevelBackground");
			if (!((Object)(object)val == (Object)null))
			{
				Icons[obj] = val;
				if (!Resolve(obj))
				{
					Pending.Add(obj);
				}
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)("[DiagHeal] capture: prof=" + obj?.ToString() + " pending=" + Pending.Count));
				}
			}
		}

		internal static void Tick()
		{
			if (Pending.Count == 0)
			{
				_loggedTick = false;
			}
			else
			{
				if (MFindSprites == null)
				{
					return;
				}
				if (!_loggedTick)
				{
					_loggedTick = true;
					ManualLogSource logger = EclipsePlugin.Logger;
					if (logger != null)
					{
						logger.LogInfo((object)("[DiagHeal] tick: pending=" + Pending.Count + " [" + string.Join(",", Pending.Select((object p) => p.ToString())) + "]"));
					}
				}
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (!float.IsNegativeInfinity(_nextScan) && realtimeSinceStartup - _nextScan < 5f)
				{
					return;
				}
				_nextScan = realtimeSinceStartup + 5f;
				MFindSprites.Invoke(null, null);
				object[] array = Pending.ToArray();
				foreach (object obj in array)
				{
					if (Resolve(obj))
					{
						Pending.Remove(obj);
					}
				}
				if (Pending.Count == 0 && !_loggedHeal)
				{
					_loggedHeal = true;
					ManualLogSource logger2 = EclipsePlugin.Logger;
					if (logger2 != null)
					{
						logger2.LogInfo((object)"ProfessionIconHealer: all profession icons resolved via rescan.");
					}
				}
				if (Pending.Count <= 0 || !(realtimeSinceStartup >= _nextStatus))
				{
					return;
				}
				_nextStatus = realtimeSinceStartup + 15f;
				try
				{
					IDictionary dictionary = FProfIcons?.GetValue(null) as IDictionary;
					object key = Pending.First();
					string text = ((dictionary != null && dictionary.Contains(key)) ? (dictionary[key] as string) : null);
					int num2 = -1;
					try
					{
						num2 = ((!(FHudSprites?.GetValue(null) is IDictionary dictionary2)) ? (-1) : dictionary2.Count);
					}
					catch
					{
					}
					ManualLogSource logger3 = EclipsePlugin.Logger;
					if (logger3 != null)
					{
						logger3.LogInfo((object)("[DiagHeal] status pend=" + Pending.Count + " key='" + text + "' live=" + (text != null && (Object)(object)SpriteRepair.Get(text) != (Object)null) + " dict=" + num2));
					}
				}
				catch (Exception ex)
				{
					ManualLogSource logger4 = EclipsePlugin.Logger;
					if (logger4 != null)
					{
						logger4.LogWarning((object)("[DiagHeal] status: " + ex.Message));
					}
				}
			}
		}

		private static bool Resolve(object prof)
		{
			try
			{
				if (!Icons.TryGetValue(prof, out var value) || (Object)(object)value == (Object)null)
				{
					return false;
				}
				if (!(FProfIcons?.GetValue(null) is IDictionary dictionary) || !dictionary.Contains(prof))
				{
					return false;
				}
				if (!(dictionary[prof] is string name))
				{
					return false;
				}
				Sprite val = SpriteRepair.Get(name);
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				if ((Object)(object)value.sprite != (Object)(object)val)
				{
					value.sprite = val;
				}
				return true;
			}
			catch
			{
				return false;
			}
		}

		private static Image FindChildImage(Transform root, string name)
		{
			for (int i = 0; i < root.childCount; i++)
			{
				Transform child = root.GetChild(i);
				if (((Object)((Component)child).gameObject).name == name)
				{
					return ((Component)child).gameObject.GetComponent<Image>();
				}
				if (child.childCount > 0)
				{
					Image val = FindChildImage(child, name);
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
			}
			return null;
		}
	}
	[HarmonyPatch]
	internal class LocaleCapsRepairPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(EclipseTypes.DataService, "ParseConfigData", (Type[])null, (Type[])null);
		}

		private static void Prefix(ref List<string> configData)
		{
			try
			{
				configData = LocaleCapsRepair.Repair(configData);
			}
			catch (Exception ex)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)("LocaleCapsRepair: " + ex.Message));
				}
			}
		}
	}
	internal static class LocaleCapsRepair
	{
		private const int Scalars = 9;

		private const int Caps = 24;

		private static bool _logged;

		internal static List<string> Repair(List<string> list)
		{
			if (list == null || list.Count <= 9 || list[9] == null || list[9].Contains("."))
			{
				return list;
			}
			List<string> list2 = new List<string>(list.Count);
			for (int i = 0; i < 9; i++)
			{
				list2.Add(list[i]);
			}
			int num = 0;
			int num2 = 9;
			while (num2 < list.Count && num < 24)
			{
				string text = list[num2];
				if (text.Contains("."))
				{
					list2.Add(text);
					num2++;
					num++;
					continue;
				}
				string text2 = ((num2 + 1 < list.Count) ? list[num2 + 1] : null);
				if (!IsDigits(text) || text2 == null || !IsDigits(text2) || text2.Length != 2)
				{
					ManualLogSource logger = EclipsePlugin.Logger;
					if (logger != null)
					{
						logger.LogWarning((object)("LocaleCapsRepair: ambiguous token '" + text + "' at index " + num2 + " — leaving message as-is."));
					}
					return list;
				}
				list2.Add(text + "." + text2);
				num2 += 2;
				num++;
			}
			while (num2 < list.Count)
			{
				list2.Add(list[num2++]);
			}
			if (!_logged)
			{
				_logged = true;
				ManualLogSource logger2 = EclipsePlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogInfo((object)("LocaleCapsRepair: merged " + num + " locale-decimal caps (server uses a comma-decimal locale — vanilla Bloodcraft bug)."));
				}
			}
			return list2;
		}

		private static bool IsDigits(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return false;
			}
			for (int i = 0; i < s.Length; i++)
			{
				if (!char.IsDigit(s[i]))
				{
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch]
	internal class BonusStatsPhantomFilterPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(EclipseTypes.DataService, "ParsePlayerData", (Type[])null, (Type[])null);
		}

		private static void Postfix()
		{
			Filter("_legacyBonusStats");
			Filter("_expertiseBonusStats");
		}

		private static void Filter(string fieldName)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			try
			{
				if (!(AccessTools.Field(EclipseTypes.DataHUD, fieldName)?.GetValue(null) is List<string> list))
				{
					return;
				}
				bool flag = false;
				for (int num = list.Count - 1; num >= 0; num--)
				{
					string text = list[num];
					if (!string.IsNullOrEmpty(text) && (text == "0" || text.Equals("None", StringComparison.OrdinalIgnoreCase)))
					{
						list.RemoveAt(num);
						flag = true;
					}
				}
				while (list.Count < 3)
				{
					list.Add(string.Empty);
				}
				if (!flag)
				{
					return;
				}
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					bool flag2 = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(52, 2, ref flag2);
					if (flag2)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[PhantomFilter] ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(fieldName);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": dropped D8 zero-pad entries, ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(list.Count);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" left");
					}
					logger.LogInfo(val);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = EclipsePlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogError((object)("[PhantomFilter] " + fieldName + ": " + ex));
				}
			}
		}
	}
	internal static class TabGlow
	{
		internal static readonly Color GlowColor = new Color(1f, 0.22f, 0.24f, 1f);

		internal static readonly Vector2 GlowDistance = new Vector2(3f, -3f);

		internal static readonly Vector2 RestDistance = new Vector2(1f, -1f);

		internal const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static bool _applied;

		private static bool _probed;

		private static PropertyInfo _fhProp;

		private static FieldInfo _fhField;

		internal static void TryApplyOnce()
		{
			if (!_applied)
			{
				_applied = true;
				ApplyOne(typeof(ModeTabGlowPatch));
				ApplyOne(typeof(SubTabGlowPatch));
			}
		}

		private static void ApplyOne(Type patchType)
		{
			try
			{
				EclipsePlugin.HarmonyInst.CreateClassProcessor(patchType).Patch();
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)("[DiagTab] " + patchType.Name + " patched (lazy, in-world)."));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = EclipsePlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("[DiagTab] " + patchType.Name + " failed: " + ex.Message));
				}
			}
		}

		internal static object GetMember(object obj, string name)
		{
			Type type = obj.GetType();
			PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null)
			{
				return property.GetValue(obj);
			}
			FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(field != null))
			{
				return null;
			}
			return field.GetValue(obj);
		}

		internal static void TryForceHighlight(object btn, bool on)
		{
			try
			{
				if (btn == null)
				{
					return;
				}
				if (!_probed)
				{
					_probed = true;
					Type type = btn.GetType();
					_fhProp = type.GetProperty("ForceHighlight", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					_fhField = type.GetField("ForceHighlight", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					ManualLogSource logger = EclipsePlugin.Logger;
					if (logger != null)
					{
						logger.LogInfo((object)("[DiagTab] ForceHighlight on " + type.Name + ": " + ((_fhProp != null) ? "property" : ((_fhField != null) ? "field" : "MISSING (outline-only)"))));
					}
				}
				if (_fhProp != null)
				{
					_fhProp.SetValue(btn, on);
				}
				else if (_fhField != null)
				{
					_fhField.SetValue(btn, on);
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch]
	internal class ModeTabGlowPatch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("Eclipse.Services.CharacterMenu.Tabs.StatBonusesTab");
			if (!(type != null))
			{
				return null;
			}
			return AccessTools.Method(type, "ConfigureModeTabVisual", (Type[])null, (Type[])null);
		}

		private static void Postfix(object __0, bool __1)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (__0 == null || EclipsePlugin.CfgTabGlow == null || !EclipsePlugin.CfgTabGlow.Value)
				{
					return;
				}
				object member = TabGlow.GetMember(__0, "Border");
				Outline val = (Outline)((member is Outline) ? member : null);
				if ((Object)(object)val != (Object)null)
				{
					((Shadow)val).effectDistance = (__1 ? TabGlow.GlowDistance : TabGlow.RestDistance);
					if (__1)
					{
						((Shadow)val).effectColor = TabGlow.GlowColor;
					}
				}
				TabGlow.TryForceHighlight(TabGlow.GetMember(__0, "Button"), __1);
			}
			catch (Exception ex)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)("[DiagTab] mode-tab glow: " + ex.Message));
				}
			}
		}
	}
	[HarmonyPatch]
	internal class SubTabGlowPatch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("Eclipse.Services.CharacterMenu.Tabs.ProgressionTab");
			if (!(type != null))
			{
				return null;
			}
			return AccessTools.Method(type, "UpdateSubTabSelection", (Type[])null, (Type[])null);
		}

		private static void Postfix(object __instance)
		{
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (__instance == null || EclipsePlugin.CfgTabGlow == null || !EclipsePlugin.CfgTabGlow.Value)
				{
					return;
				}
				Type type = __instance.GetType();
				FieldInfo field = type.GetField("_subTabButtons", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				FieldInfo field2 = type.GetField("_activeSubTab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field == null || field2 == null)
				{
					return;
				}
				object value = field.GetValue(__instance);
				if (value == null)
				{
					return;
				}
				int num = Convert.ToInt32(field2.GetValue(__instance));
				Type type2 = value.GetType();
				PropertyInfo property = type2.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				PropertyInfo property2 = type2.GetProperty("Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property == null || property2 == null)
				{
					return;
				}
				int num2 = (int)property.GetValue(value);
				for (int i = 0; i < num2; i++)
				{
					object value2 = property2.GetValue(value, new object[1] { i });
					Component val = (Component)((value2 is Component) ? value2 : null);
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					bool flag = i == num;
					Outline val2 = val.GetComponent<Outline>();
					if (flag)
					{
						if ((Object)(object)val2 == (Object)null)
						{
							val2 = val.gameObject.AddComponent<Outline>();
						}
						((Shadow)val2).effectColor = TabGlow.GlowColor;
						((Shadow)val2).effectDistance = TabGlow.GlowDistance;
						((Behaviour)val2).enabled = true;
					}
					else if ((Object)(object)val2 != (Object)null)
					{
						((Behaviour)val2).enabled = false;
					}
					TabGlow.TryForceHighlight(value2, flag);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)("[DiagTab] sub-tab glow: " + ex.Message));
				}
			}
		}
	}
	internal static class PrestigeButton
	{
		internal static readonly Color BtnBg = new Color(0.08f, 0.08f, 0.1f, 0.95f);

		internal static readonly Color BtnBorder = new Color(1f, 1f, 1f, 0.15f);

		internal static readonly Color BtnText = new Color(0.95f, 0.84f, 0.7f, 1f);

		private static FieldInfo _fHeaderName;

		private static FieldInfo _fSlots;

		private static FieldInfo _fMode;

		private static bool _warned;

		private static GameObject _btn;

		private static object _tab;

		internal static void Ensure(object tab)
		{
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Expected O, but got Unknown
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (tab == null)
				{
					return;
				}
				_tab = tab;
				if (_fHeaderName == null)
				{
					_fHeaderName = AccessTools.Field(EclipseTypes.Tab, "_headerNameText");
				}
				if (_fSlots == null)
				{
					_fSlots = AccessTools.Field(EclipseTypes.Tab, "_headerSlotsText");
				}
				if (_fHeaderName == null && _fSlots == null)
				{
					if (!_warned)
					{
						_warned = true;
						ManualLogSource logger = EclipsePlugin.Logger;
						if (logger != null)
						{
							logger.LogWarning((object)"[PrestigeBtn] header text fields unresolved - button disabled.");
						}
					}
					return;
				}
				object obj = ((_fHeaderName != null) ? _fHeaderName.GetValue(tab) : null);
				if (obj == null && _fSlots != null)
				{
					obj = _fSlots.GetValue(tab);
				}
				Component val = (Component)((obj is Component) ? obj : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				Transform val2 = (((Object)(object)val.transform.parent != (Object)null) ? val.transform.parent.parent : null);
				if ((Object)(object)val2 == (Object)null)
				{
					return;
				}
				if ((Object)(object)_btn != (Object)null)
				{
					if ((Object)(object)_btn.transform.parent == (Object)(object)val2)
					{
						return;
					}
					Object.Destroy((Object)(object)_btn);
					_btn = null;
				}
				GameObject val3 = new GameObject("EF_PrestigeButton");
				val3.transform.SetParent(val2, false);
				val3.transform.SetAsLastSibling();
				((Graphic)val3.AddComponent<Image>()).color = BtnBg;
				Outline obj2 = val3.AddComponent<Outline>();
				((Shadow)obj2).effectColor = BtnBorder;
				((Shadow)obj2).effectDistance = new Vector2(1f, -1f);
				LayoutElement obj3 = val3.AddComponent<LayoutElement>();
				obj3.preferredWidth = 92f;
				obj3.minWidth = 92f;
				obj3.preferredHeight = 28f;
				obj3.minHeight = 28f;
				if (StatSynergyMarker.CreateStyledLabel(val3.transform, obj, "Prestige", 12f, BtnText) == null)
				{
					Object.Destroy((Object)(object)val3);
					return;
				}
				Button obj4 = val3.AddComponent<Button>();
				((Selectable)obj4).transition = (Transition)0;
				((UnityEvent)obj4.onClick).AddListener(UnityAction.op_Implicit((Action)SendForCurrent));
				_btn = val3;
				ManualLogSource logger2 = EclipsePlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogInfo((object)"[PrestigeBtn] button created in the Stat Bonuses header.");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger3 = EclipsePlugin.Logger;
				if (logger3 != null)
				{
					logger3.LogWarning((object)("[PrestigeBtn] Ensure failed: " + ex));
				}
			}
		}

		internal static void SendForCurrent()
		{
			try
			{
				if (EclipsePlugin.CfgQuickPrestige == null || !EclipsePlugin.CfgQuickPrestige.Value || _tab == null)
				{
					return;
				}
				if (_fMode == null)
				{
					_fMode = AccessTools.Field(EclipseTypes.Tab, "_mode");
				}
				string text = ((!(_fMode != null)) ? null : _fMode.GetValue(_tab)?.ToString());
				string text2 = null;
				string text3 = "";
				if (text == "BloodLegacies")
				{
					object obj = AccessTools.Field(EclipseTypes.DataHUD, "_legacyType")?.GetValue(null);
					text3 = "legacy=" + ((obj as string) ?? "<null>");
					if (!string.IsNullOrWhiteSpace(obj as string))
					{
						text2 = ".prestige me " + obj?.ToString() + "Legacy";
					}
				}
				else if (text == "WeaponExpertise")
				{
					string text4 = AccessTools.Field(EclipseTypes.DataHUD, "_expertiseType")?.GetValue(null) as string;
					text3 = "hud=" + (text4 ?? "<null>");
					if (string.IsNullOrWhiteSpace(text4))
					{
						object obj2 = AccessTools.Field(EclipseTypes.DataService, "_weaponStatBonusData")?.GetValue(null);
						if (obj2 != null)
						{
							PropertyInfo propertyInfo = AccessTools.Property(obj2.GetType(), "WeaponType");
							text4 = ((propertyInfo != null) ? propertyInfo.GetValue(obj2) : null) as string;
						}
						text3 = text3 + " data=" + (text4 ?? ((obj2 != null) ? "<empty>" : "<null>"));
					}
					if (string.IsNullOrWhiteSpace(text4))
					{
						text4 = WeaponPanelSynth.CurrentWeaponType;
					}
					text3 = text3 + " cache=" + (text4 ?? "<null>");
					if (!string.IsNullOrWhiteSpace(text4))
					{
						text2 = ".prestige me " + text4 + "Expertise";
					}
				}
				else
				{
					text3 = "<unrecognized mode>";
				}
				if (text2 == null)
				{
					ManualLogSource logger = EclipsePlugin.Logger;
					if (logger != null)
					{
						logger.LogInfo((object)("[PrestigeBtn] click ignored: mode=" + (text ?? "<null>") + " " + text3));
					}
					return;
				}
				AccessTools.Method(EclipseTypes.Quips, "SendCommand", (Type[])null, (Type[])null)?.Invoke(null, new object[1] { text2 });
				ManualLogSource logger2 = EclipsePlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogInfo((object)("[PrestigeBtn] sent: " + text2));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger3 = EclipsePlugin.Logger;
				if (logger3 != null)
				{
					logger3.LogWarning((object)("[PrestigeBtn] send failed: " + ex));
				}
			}
		}
	}
	[HarmonyPatch]
	internal class PrestigeButtonPatch
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(EclipseTypes.Tab, "UpdateHeader", (Type[])null, (Type[])null);
		}

		private static void Postfix(object __instance)
		{
			try
			{
				if (EclipsePlugin.CfgQuickPrestige != null && EclipsePlugin.CfgQuickPrestige.Value)
				{
					PrestigeButton.Ensure(__instance);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)("[PrestigeBtn] patch: " + ex));
				}
			}
		}
	}
	internal static class PrestigeBoardButtons
	{
		internal static void Ensure(Transform header, object sourceText)
		{
			try
			{
				if (!((Object)(object)header == (Object)null) && sourceText != null && !((Object)(object)header.Find("EF_BoardExperience") != (Object)null))
				{
					Build(header, sourceText, "EF_BoardExperience", "Experience", 96f, -94f, ".prestige me experience");
					Build(header, sourceText, "EF_BoardExoForm", "ExoForm", 80f, -8f, ".prestige me exo");
					ManualLogSource logger = EclipsePlugin.Logger;
					if (logger != null)
					{
						logger.LogInfo((object)"[PrestigeBtn] Experience/ExoForm buttons created on the leaderboard card.");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = EclipsePlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("[PrestigeBtn] board Ensure failed: " + ex));
				}
			}
		}

		private static void Build(Transform header, object sourceText, string name, string label, float width, float xFromRight, string cmd)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_0026: 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_0050: 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_0074: 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_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_00c6: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name);
			RectTransform obj = val.AddComponent<RectTransform>();
			((Transform)obj).SetParent(header, false);
			obj.anchorMin = new Vector2(1f, 0.5f);
			obj.anchorMax = new Vector2(1f, 0.5f);
			obj.pivot = new Vector2(1f, 0.5f);
			obj.anchoredPosition = new Vector2(xFromRight, 0f);
			obj.sizeDelta = new Vector2(width, 20f);
			val.AddComponent<LayoutElement>().ignoreLayout = true;
			((Graphic)val.AddComponent<Image>()).color = PrestigeButton.BtnBg;
			Outline obj2 = val.AddComponent<Outline>();
			((Shadow)obj2).effectColor = PrestigeButton.BtnBorder;
			((Shadow)obj2).effectDistance = new Vector2(1f, -1f);
			if (StatSynergyMarker.CreateStyledLabel((Transform)(object)obj, sourceText, label, 11f, PrestigeButton.BtnText) == null)
			{
				Object.Destroy((Object)(object)val);
				return;
			}
			Button obj3 = val.AddComponent<Button>();
			((Selectable)obj3).transition = (Transition)0;
			string captured = cmd;
			((UnityEvent)obj3.onClick).AddListener(UnityAction.op_Implicit((Action)delegate
			{
				Send(captured);
			}));
		}

		private static void Send(string cmd)
		{
			try
			{
				if (EclipsePlugin.CfgQuickPrestige != null && EclipsePlugin.CfgQuickPrestige.Value)
				{
					AccessTools.Method(EclipseTypes.Quips, "SendCommand", (Type[])null, (Type[])null)?.Invoke(null, new object[1] { cmd });
					ManualLogSource logger = EclipsePlugin.Logger;
					if (logger != null)
					{
						logger.LogInfo((object)("[PrestigeBtn] sent: " + cmd));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = EclipsePlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("[PrestigeBtn] board send failed: " + ex));
				}
			}
		}
	}
	[HarmonyPatch]
	internal class PrestigeBoardButtonsPatch
	{
		private static MethodBase TargetMethod()
		{
			Type type = AccessTools.TypeByName("Eclipse.Services.CharacterMenu.Tabs.PrestigeTab");
			if (!(type != null))
			{
				return null;
			}
			return AccessTools.Method(type, "CreateCardHeader", (Type[])null, (Type[])null);
		}

		private static void Postfix(RectTransform __result, object __1, string __2)
		{
			try
			{
				if (EclipsePlugin.CfgQuickPrestige != null && EclipsePlugin.CfgQuickPrestige.Value && !(__2 != "Prestige Leaderboard"))
				{
					PrestigeBoardButtons.Ensure((Transform)(object)__result, __1);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)("[PrestigeBtn] board patch: " + ex));
				}
			}
		}
	}
	internal static class QuipsDiagPatch
	{
		private static bool _attempted;

		internal static void EnsureApplied()
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			if (_attempted)
			{
				return;
			}
			_attempted = true;
			try
			{
				MethodInfo methodInfo = AccessTools.Method(EclipseTypes.Quips, "SendCommand", new Type[1] { typeof(string) }, (Type[])null);
				if (methodInfo == null)
				{
					ManualLogSource logger = EclipsePlugin.Logger;
					if (logger != null)
					{
						logger.LogWarning((object)"[ClickDiag] Quips.SendCommand not found.");
					}
					return;
				}
				MethodInfo method = typeof(QuipsDiagPatch).GetMethod("Prefix", BindingFlags.Static | BindingFlags.NonPublic);
				if (method == null)
				{
					ManualLogSource logger2 = EclipsePlugin.Logger;
					if (logger2 != null)
					{
						logger2.LogWarning((object)"[ClickDiag] prefix method not found.");
					}
					return;
				}
				EclipsePlugin.HarmonyInst.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				ManualLogSource logger3 = EclipsePlugin.Logger;
				if (logger3 != null)
				{
					logger3.LogInfo((object)"[ClickDiag] Quips.SendCommand prefix applied lazily (world ready).");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger4 = EclipsePlugin.Logger;
				if (logger4 != null)
				{
					logger4.LogError((object)("[ClickDiag] lazy Quips patch failed: " + ex));
				}
			}
		}

		private static void Prefix(string command)
		{
			ManualLogSource logger = EclipsePlugin.Logger;
			if (logger != null)
			{
				logger.LogInfo((object)("[ClickDiag] Quips.SendCommand: " + command));
			}
		}
	}
	[HarmonyPatch]
	internal class UpdateRowClickDiagPostfix
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(EclipseTypes.Tab, "UpdateRow", (Type[])null, (Type[])null);
		}

		private static void Postfix(object[] __args)
		{
			try
			{
				RowClickDiag.Apply(__args);
			}
			catch (Exception ex)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogError((object)("[ClickDiag] UpdateRow postfix failed: " + ex));
				}
			}
		}
	}
	internal static class RowClickDiag
	{
		private static readonly Type RowT = ((EclipseTypes.Tab != null) ? EclipseTypes.Tab.GetNestedType("StatBonusRow", BindingFlags.NonPublic) : null);

		private static readonly PropertyInfo PButton = RowT?.GetProperty("Button", BindingFlags.Instance | BindingFlags.Public);

		private static readonly PropertyInfo PRoot = RowT?.GetProperty("Root", BindingFlags.Instance | BindingFlags.Public);

		private static readonly PropertyInfo PStatIndex = RowT?.GetProperty("StatIndex", BindingFlags.Instance | BindingFlags.Public);

		private static readonly HashSet<object> _fallbackAttached = new HashSet<object>();

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

		private const float ClickDebounceSeconds = 0.3f;

		internal static void Apply(object[] args)
		{
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Expected O, but got Unknown
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Expected O, but got Unknown
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Expected O, but got Unknown
			QuipsDiagPatch.EnsureApplied();
			object obj = ((args.Length != 0) ? args[0] : null);
			Action<int> action = ((args.Length > 3) ? (args[3] as Action<int>) : null);
			if (obj == null || RowT == null || PButton == null)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)"[ClickDiag] UpdateRow: row=NULL or StatBonusRow type unresolved.");
				}
				return;
			}
			object value = PButton.GetValue(obj);
			object obj2 = ((PRoot != null) ? PRoot.GetValue(obj) : null);
			object obj3 = ((obj2 is Component) ? obj2 : null);
			GameObject val = (GameObject)(((obj3 != null) ? ((Component)obj3).gameObject : null) ?? ((obj2 is GameObject) ? obj2 : null));
			string text = (((Object)(object)val != (Object)null) ? ((Object)val).name : "?");
			int num = Convert.ToInt32((PStatIndex != null) ? PStatIndex.GetValue(obj) : ((object)(-1)));
			bool flag = default(bool);
			ManualLogSource logger2;
			if (value != null)
			{
				Object val2 = (Object)((value is Object) ? value : null);
				if (val2 == null || !(val2 == (Object)null))
				{
					object obj4 = value.GetType().GetProperty("onClick", BindingFlags.Instance | BindingFlags.Public)?.GetValue(value);
					UnityEvent val3 = (UnityEvent)((obj4 is UnityEvent) ? obj4 : null);
					if (val3 == null)
					{
						logger2 = EclipsePlugin.Logger;
						if (logger2 != null)
						{
							BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(50, 2, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[ClickDiag] UpdateRow: onClick unavailable (");
								((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(obj4?.GetType().FullName ?? "null");
								((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", go=");
								((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(text);
								((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(")");
							}
							logger2.LogInfo(val4);
						}
						return;
					}
					((UnityEventBase)val3).RemoveAllListeners();
					AttachClickHandler(val3, obj, text, action);
					logger2 = EclipsePlugin.Logger;
					if (logger2 != null)
					{
						BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(79, 4, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[ClickDiag] UpdateRow stat=");
							((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(num);
							((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" go=");
							((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(text);
							((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" button=OK onClick=");
							((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(obj4.GetType().Name);
							((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" ");
							((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("listener attached (handler=");
							((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>((action != null) ? action.Method.Name : "NULL");
							((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(")");
						}
						logger2.LogInfo(val4);
					}
					return;
				}
			}
			logger2 = EclipsePlugin.Logger;
			if (logger2 != null)
			{
				BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(83, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[ClickDiag] UpdateRow: row.Button == NULL (stat=");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", go=");
					((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(") — original never subscribes.");
				}
				logger2.LogInfo(val4);
			}
			AttachFallback(obj, val, action);
		}

		private static void AttachClickHandler(UnityEvent ue, object row, string goName, Action<int> onClicked)
		{
			ue.AddListener(UnityAction.op_Implicit((Action)delegate
			{
				//IL_004d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0054: Expected O, but got Unknown
				//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f2: Expected O, but got Unknown
				int num = -1;
				try
				{
					num = Convert.ToInt32(PStatIndex.GetValue(row));
				}
				catch
				{
				}
				string text = ((onClicked != null) ? onClicked.Method.Name : "NULL");
				ManualLogSource logger = EclipsePlugin.Logger;
				bool flag = default(bool);
				if (logger != null)
				{
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(43, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[ClickDiag] row click: stat=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", go=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(goName);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", handler=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
					}
					logger.LogInfo(val);
				}
				string key = text + ":" + num;
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (_lastAcceptedClick.TryGetValue(key, out var value) && realtimeSinceStartup - value < 0.3f)
				{
					logger = EclipsePlugin.Logger;
					if (logger != null)
					{
						BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(84, 3, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[ClickDiag] debounced duplicate click: stat=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", handler=");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("(");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(0.3f, "0.0");
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("s window) - command NOT sent");
						}
						logger.LogInfo(val);
					}
				}
				else
				{
					_lastAcceptedClick[key] = realtimeSinceStartup;
					if (onClicked != null)
					{
						try
						{
							onClicked(num);
						}
						catch (Exception ex)
						{
							ManualLogSource logger2 = EclipsePlugin.Logger;
							if (logger2 != null)
							{
								logger2.LogError((object)("[ClickDiag] click handler threw: " + ex));
							}
						}
					}
				}
			}));
		}

		private static void AttachFallback(object row, GameObject go, Action<int> onClicked)
		{
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			if ((Object)(object)go == (Object)null)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)"[ClickDiag] fallback: row has no GameObject, cannot attach.");
				}
			}
			else
			{
				if (!_fallbackAttached.Add(go))
				{
					return;
				}
				try
				{
					Type type = FindType("SimpleStunButton");
					if (type == null)
					{
						ManualLogSource logger2 = EclipsePlugin.Logger;
						if (logger2 != null)
						{
							logger2.LogInfo((object)"[ClickDiag] fallback: SimpleStunButton type not found.");
						}
						return;
					}
					MethodInfo methodInfo = typeof(GameObject).GetMethods(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault((MethodInfo m) => m.Name == "AddComponent" && m.IsGenericMethodDefinition && m.GetParameters().Length == 0);
					if (methodInfo == null)
					{
						ManualLogSource logger3 = EclipsePlugin.Logger;
						if (logger3 != null)
						{
							logger3.LogInfo((object)"[ClickDiag] fallback: AddComponent<T> not found.");
						}
						return;
					}
					object obj = methodInfo.MakeGenericMethod(type).Invoke(go, null);
					object obj2 = obj?.GetType().GetProperty("onClick", BindingFlags.Instance | BindingFlags.Public)?.GetValue(obj);
					UnityEvent val = (UnityEvent)((obj2 is UnityEvent) ? obj2 : null);
					bool flag = default(bool);
					ManualLogSource logger4;
					if (val == null)
					{
						logger4 = EclipsePlugin.Logger;
						if (logger4 != null)
						{
							BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(57, 2, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[ClickDiag] fallback: created ");
								((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(type.Name);
								((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" but onClick unavailable (");
								((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(obj2?.GetType().FullName ?? "null");
								((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(")");
							}
							logger4.LogInfo(val2);
						}
						return;
					}
					AttachClickHandler(val, row, ((Object)go).name, onClicked);
					logger4 = EclipsePlugin.Logger;
					if (logger4 != null)
					{
						BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(48, 2, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[ClickDiag] fallback: added ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(type.Name);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" to ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(((Object)go).name);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" and subscribed.");
						}
						logger4.LogInfo(val2);
					}
				}
				catch (Exception ex)
				{
					ManualLogSource logger5 = EclipsePlugin.Logger;
					if (logger5 != null)
					{
						logger5.LogError((object)("[ClickDiag] fallback failed: " + ex));
					}
				}
			}
		}

		private static Type FindType(string shortName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				Type[] types;
				try
				{
					types = assembly.GetTypes();
				}
				catch
				{
					continue;
				}
				Type[] array = types;
				foreach (Type type in array)
				{
					if (type.Name == shortName)
					{
						return type;
					}
				}
			}
			return null;
		}
	}
	internal static class StatBonusesIconSynth
	{
		private static bool _applied;

		internal static void Apply()
		{
			if (_applied)
			{
				return;
			}
			try
			{
				Extend("WeaponTypeIconSpriteNames", new Dictionary<string, string[]>
				{
					["Unarmed"] = new string[2] { "strength_level_icon", "Poneti_Icon_Sword_v2_48" },
					["FishingPole"] = new string[2] { "Poneti_Icon_Engineering_59_mega_fishingrod", "Stunlock_Icon_Bag_Background_Fish" },
					["TwinBlades"] = new string[2] { "Poneti_Icon_Sword_v2_48", "Poneti_Icon_Dagger_v2_01" },
					["Daggers"] = new string[2] { "Poneti_Icon_Dagger_v2_01", "Poneti_Icon_Sword_v2_48" },
					["Claws"] = new string[2] { "Poneti_Icon_Dagger_v2_01", "Poneti_Icon_Sword_v2_48" }
				});
				Extend("BloodTypeIconSpriteNames", new Dictionary<string, string[]>
				{
					["Immortal"] = new string[3] { "BloodType_Draculin_Big", "BloodType_Draculin_Small", "Stunlock_Icons_spellbook_blood" },
					["VBlood"] = new string[3] { "MobLevel_Skull", "BloodType_Draculin_Small", "Stunlock_Icons_spellbook_blood" },
					["GateBoss"] = new string[3] { "MobLevel_Skull", "BloodType_Draculin_Small", "Stunlock_Icons_spellbook_blood" }
				});
				_applied = true;
			}
			catch (Exception ex)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogError((object)("StatBonusesIconSynth: " + ex));
				}
			}
		}

		private static void Extend(string fieldName, Dictionary<string, string[]> additions)
		{
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected O, but got Unknown
			FieldInfo fieldInfo = AccessTools.Field(EclipseTypes.Tab, fieldName);
			if (fieldInfo == null)
			{
				ManualLogSource logger = EclipsePlugin.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)("StatBonusesIconSynth: field " + fieldName + " not found."));
				}
				return;
			}
			if (!(fieldInfo.GetValue(null) is IDictionary dictionary))
			{
				ManualLogSource logger2 = EclipsePlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("StatBonusesIconSynth: " + fieldName + " is not an IDictionary."));
				}
				return;
			}
			int num = 0;
			foreach (KeyValuePair<string, string[]> addition in additions)
			{
				if (!dictionary.Contains(addition.Key))
				{
					dictionary.Add(addition.Key, addition.Value);
					num++;
				}
			}
			ManualLogSource logger3 = EclipsePlugin.Logger;
			if (logger3 != null)
			{
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(53, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("StatBonusesIconSynth: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(fieldName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": +");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" entries (");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(additions.Count - num);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" already present).");
				}
				logger3.LogInfo(val);
			}
		}
	}
	internal static class WeaponIconGameSprites
	{
		private static readonly Type HudDataT = AccessTools.TypeByName("Eclipse.Services.HUD.Shared.HudData");

		private static readonly string[] Plan0 = new string[16]
		{
			"Sword", "Axe", "Mace", "Spear", "Crossbow", "GreatSword", "Slashers", "Pistols", "Reaper", "Longbow",
			"Whip", "TwinBlades", "Daggers", "Claws", "FishingPole", "Unarmed"
		};

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

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

		private static float _lastScanTime = float.NegativeInfinity;

		private const float RescanCooldown = 30f;

		private static readonly (string WeaponType, string[][] Tiers)[] Plan = new(string, string[][])[16]
		{
			("Sword", new string[2][]
			{
				new string[3] { "stunlock_icon_ironsword", "stunlock_icon_weapon_sword", "stunlock_icon_sword" },
				new string[2] { "icon_sword", "iconsword" }
			}),
			("Axe", new string[2][]
			{
				new string[3] { "stunlock_icon_ironaxe", "stunlock_icon_weapon_axe", "stunlock_icon_axe" },
				new string[3] { "icon_axe", "iconaxe", "axes" }
			}),
			("Mace", new string[2][]
			{
				new string[3] { "stunlock_icon_ironmace", "stunlock_icon_weapon_mace", "stunlock_icon_hammer" },
				new string[4] { "icon_hammer", "iconhammer", "icon_mace", "mace" }
			}),
			("Spear", new string[2][]
			{
				new string[3] { "stunlock_icon_ironspear", "stunlock_icon_weapon_spear", "stunlock_icon_spear" },
				new string[2] { "icon_spear", "spear" }
			}),
			("Crossbow", new string[2][]
			{
				new string[3] { "stunlock_icon_ironcrossbow", "stunlock_icon_weapon_crossbow", "stunlock_icon_crossbow" },
				new string[2] { "icon_crossbow", "crossbow" }
			}),
			("GreatSword", new string[2][]
			{
				new string[3] { "stunlock_icon_irongreatsword", "stunlock_icon_weapon_greatsword", "stunlock_icon_greatsword" },
				new string[2] { "icon_greatsword", "greatsword" }
			}),
			("Slashers", new string[2][]
			{
				new string[3] { "stunlock_icon_ironslashers", "stunlock_icon_weapon_slashers", "stunlock_icon_slasher" },
				new string[2] { "icon_slasher", "slasher" }
			}),
			("Pistols", new string[2][]
			{
				new string[3] { "stunlock_icon_ironpistols", "stunlock_icon_weapon_pistols", "stunlock_icon_pistol" },
				new string[2] { "icon_pistol", "pistol" }
			}),
			("Reaper", new string[2][]
			{
				new string[3] { "stunlock_icon_ironreaper", "stunlock_icon_weapon_reaper", "stunlock_icon_reaper" },
				new string[4] { "icon_scythe", "icon_reaper", "scythe", "reaper" }
			}),
			("Longbow", new string[2][]
			{
				new string[3] { "stunlock_icon_ironlongbow", "stunlock_icon_weapon_longbow", "stunlock_icon_longbow" },
				new string[2] { "icon_bow", "longbow" }
			}),
			("Whip", new string[2][]
			{
				new string[3] { "stunlock_icon_ironwhip", "stunlock_icon_weapon_whip", "stunlock_icon_whip" },
				new string[2] { "icon_whip", "whip" }
			}),
			("TwinBlades", new string[2][]
			{
				new string[3] { "stunlock_icon_irontwinblades", "stunlock_icon_weapon_twinblades", "stunlock_icon_twinblade" },
				new string[3] { "twinblade", "dualblade", "twinsword" }
			}),
			("Daggers", new string[2][]
			{
				new string[3] { "stunlock_icon_irondagger", "stunlock_icon_weapon_daggers", "stunlock_icon_dagger" },
				new string[1] { "dagger" }
			}),
			("Claws", new string[2][]
			{
				new string[3] { "stunlock_icon_ironclaw", "stunlock_icon_weapon_claws", "stunlock_icon_claw" },
				new string[1] { "claw" }
			}),
			("FishingPole", new string[3][]
			{
				new string[3] { "stunlock_icon_fishingrod", "stunlock_icon_fishingpole", "stunlock_icon_fishing" },
				new string[4] { "fishingrod", "fishrod", "fishingpole", "fishpole" },
				new string[1] { "fishing" }
			}),
			("Unarmed", new string[2][]
			{
				new string[2] { "stunlock_icon_ability_unarmed", "stunlock_icon_unarmed" },
				new string[4] { "unarmed", "barehand", "fist", "punch" }
			})
		};

		internal static void Ensure()
		{
			//IL_0419: Unknown result type (might be due to invalid IL or missing references)
			//IL_0420: Expected O, but got Unknown
			try
			{
				if (_pending.Count == 0)
				{
					return;
				}
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (!float.IsNegativeInfinity(_lastScanTime) && realtimeSinceStartup - _lastScanTime < 30f)
				{
					return;
				}
				_lastScanTime = realtimeSinceStartup;
				if (HudDataT == null)
				{
					ManualLogSource logger = EclipsePlugin.Logger;
					if (logger != null)
					{
						logger.LogWarning((object)"WeaponIconGameSprites: HudData not found.");
					}
					return;
				}
				if (!(AccessTools.Field(HudDataT, "Sprites")?.GetValue(null) is Dictionary<string, Sprite> dictionary))
				{
					ManualLogSource logger2 = EclipsePlugin.Logger;
					if (logger2 != null)
					{
						logger2.LogWarning((object)"WeaponIconGameSprites: HudData.Sprites not found.");
					}
					return;
				}
				if (!(AccessTools.Field(EclipseTypes.Tab, "WeaponTypeIconSpriteNames")?.GetValue(null) is IDictionary dictionary2))
				{
					ManualLogSource logger3 = EclipsePlugin.Logger;
					if (logger3 != null)
					{
						logger3.LogWarning((object)"WeaponIconGameSprites: weapon icon dictionary not found.");
					}
					return;
				}
				Sprite[] array = Il2CppArrayBase<Sprite>.op_Implicit(Resources.FindObjectsOfTypeAll<Sprite>());
				(string, string[][])[] plan = Plan;
				bool flag2 = default(bool);
				for (int i = 0; i < plan.Length; i++)
				{
					(string, string[][]) tuple = plan[i];
					if (!_pending.Contains(tuple.Item1))
					{
						continue;
					}
					List<Sprite> list = null;
					string[][] item = tuple.Item2;
					string[] array4;
					foreach (string[] array2 in item)
					{
						list = new List<Sprite>();
						Sprite[] array3 = array;
						foreach (Sprite val in array3)
						{
							string text = (((Object)(object)val != (Object)null) ? ((Object)val).name : null);
							if (string.IsNullOrEmpty(text))
							{
								continue;
							}
							array4 = array2;
							foreach (string value in array4)
							{
								if (text.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
								{
									list.Add(val);
									break;
								}
							}
						}
						if (list.Count > 0)
						{
							break;
						}
					}
					if (list == null || list.Count == 0)
					{
						if (!_satisfied.Contains(tuple.Item1))
						{
							_satisfied.Add(tuple.Item1);
							ManualLogSource logger4 = EclipsePlugin.Logger;
							if (logger4 != null)
							{
								logger4.LogInfo((object)("WeaponIconGameSprites: no game sprite candidates for " + tuple.Item1));
							}
						}
						continue;
					}
					Sprite val2 = (from s in list
						orderby ArtRank(((Object)s).name), (((Object)s).name.IndexOf("icon", StringComparison.OrdinalIgnoreCase) < 0) ? 1 : 0, ((Object)s).name.Length
						select s).ThenBy<Sprite, string>((Sprite s) => ((Object)s).name, StringComparer.OrdinalIgnoreCase).First();
					string text2 = "Eclipse_" + tuple.Item1;
					Sprite value2;
					bool flag = !dictionary.TryGetValue(text2, out value2) || (Object)(object)value2 != (Object)(object)val2;
					dictionary[text2] = val2;
					string[] obj = ((dictionary2.Contains(tuple.Item1) ? dictionary2[tuple.Item1] : null) as string[]) ?? new string[1] { "Poneti_Icon_Sword_v2_48" };
					List<string> list2 = new List<string>(obj.Length + 1) { text2 };
					array4 = obj;
					foreach (string text3 in array4)
					{
						if (!string.IsNullOrEmpty(text3) && text3 != text2 && !list2.Contains(text3))
						{
							list2.Add(text3);
						}
					}
					dictionary2[tuple.Item1] = list2.ToArray();
					if (((Object)val2).name.StartsWith("Stunlock_Icon", StringComparison.OrdinalIgnoreCase))
					{
						_pending.Remove(tuple.Item1);
					}
					if (!flag)
					{
						continue;
					}
					string text4 = string.Join(", ", list.Select((Sprite c) => ((Object)c).name).Take(10));
					ManualLogSource logger5 = EclipsePlugin.Logger;
					if (logger5 != null)
					{
						BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(45, 4, ref flag2);
						if (flag2)
						{
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("WeaponIconGameSprites: ");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(tuple.Item1);
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" -> '");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(((Object)val2).name);
							((BepInExLogInterpolatedStringHandler)val3).AppendLitera