Decompiled source of WhiteKnuckleItemTooltipsRU v0.3.0

BepInEx\plugins\WhiteKnuckleItemTooltipsRU\WhiteKnuckleItemTooltips.dll

Decompiled 7 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using WhiteKnuckleItemTooltips.Compatibility;
using WhiteKnuckleItemTooltips.Core;
using WhiteKnuckleItemTooltips.Detection;
using WhiteKnuckleItemTooltips.Localization;
using WhiteKnuckleItemTooltips.Runtime;
using WhiteKnuckleItemTooltips.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("WhiteKnuckleItemTooltips")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.0.0")]
[assembly: AssemblyInformationalVersion("0.3.0")]
[assembly: AssemblyProduct("WhiteKnuckleItemTooltips")]
[assembly: AssemblyTitle("WhiteKnuckleItemTooltips")]
[assembly: AssemblyVersion("0.3.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 WhiteKnuckleItemTooltips
{
	[BepInPlugin("kos.whiteknuckle.itemtooltipsru", "White Knuckle Item Tooltips", "0.3.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "kos.whiteknuckle.itemtooltipsru";

		public const string PluginName = "White Knuckle Item Tooltips";

		public const string PluginVersion = "0.3.0";

		private static MethodInfo? _itemObjectOnHoverTarget;

		private static int _instrumentedHoverCallSites;

		private void Awake()
		{
			RuntimeSettings settings = BindConfig();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"White Knuckle Item Tooltips 0.3.0 loading...");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Reference mode: exact assemblies from this White Knuckle installation.");
			try
			{
				RuntimeService.Install(new RuntimeService(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger, ((BaseUnityPlugin)this).Info.Location, settings));
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Could not initialize Item Tooltips runtime service: {arg}");
				return;
			}
			InstallNativeHoverBridge();
			RuntimeHost.RegisterSceneCallback();
			RuntimeHost.EnsureAlive();
		}

		private void InstallNativeHoverBridge()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Expected O, but got Unknown
			//IL_011f: Expected O, but got Unknown
			try
			{
				Harmony val = new Harmony("kos.whiteknuckle.itemtooltipsru.interactionbridge");
				Type type = AccessTools.TypeByName("Item_Object");
				_itemObjectOnHoverTarget = ((type == null) ? null : AccessTools.Method(type, "OnHover", (Type[])null, (Type[])null));
				if (_itemObjectOnHoverTarget == null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)"Interaction bridge failed: Item_Object.OnHover was not found.");
					return;
				}
				Type type2 = AccessTools.TypeByName("ENT_Player");
				MethodInfo methodInfo = ((type2 == null) ? null : AccessTools.Method(type2, "InteractCheck", new Type[1] { typeof(int) }, (Type[])null));
				if (methodInfo == null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)"Interaction bridge failed: ENT_Player.InteractCheck(int) was not found.");
					return;
				}
				MethodInfo methodInfo2 = AccessTools.Method(typeof(Plugin), "InteractCheckPrefix", (Type[])null, (Type[])null);
				MethodInfo methodInfo3 = AccessTools.Method(typeof(Plugin), "InteractCheckTranspiler", (Type[])null, (Type[])null);
				if (methodInfo2 == null || methodInfo3 == null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)"Interaction bridge failed: patch methods were not found.");
					return;
				}
				_instrumentedHoverCallSites = 0;
				val.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, new HarmonyMethod(methodInfo3), (HarmonyMethod)null, (HarmonyMethod)null);
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Interaction bridge installed on ENT_Player.InteractCheck(int). " + $"Instrumented Item_Object.OnHover call sites: {_instrumentedHoverCallSites}."));
				if (_instrumentedHoverCallSites == 0)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"No Item_Object.OnHover call sites were instrumented; runtime hover callbacks are unlikely to fire.");
				}
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Could not install interaction bridge: {arg}");
			}
		}

		public static void InteractCheckPrefix()
		{
			RuntimeService.Current?.InteractionTick();
		}

		public static IEnumerable<CodeInstruction> InteractCheckTranspiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo bridge = AccessTools.Method(typeof(Plugin), "ItemObjectHoverFromCallSite", (Type[])null, (Type[])null);
			MethodInfo target = _itemObjectOnHoverTarget;
			foreach (CodeInstruction instruction in instructions)
			{
				if (!(target != null) || !(bridge != null) || (!(instruction.opcode == OpCodes.Call) && !(instruction.opcode == OpCodes.Callvirt)) || !object.Equals(instruction.operand, target))
				{
					yield return instruction;
					continue;
				}
				CodeInstruction val = new CodeInstruction(OpCodes.Dup, (object)null);
				MoveInstructionMetadata(instruction, val, "labels");
				MoveInstructionMetadata(instruction, val, "blocks");
				yield return val;
				yield return instruction;
				yield return new CodeInstruction(OpCodes.Call, (object)bridge);
				_instrumentedHoverCallSites++;
			}
		}

		private static void MoveInstructionMetadata(CodeInstruction source, CodeInstruction destination, string fieldName)
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(CodeInstruction), fieldName);
			if (fieldInfo == null)
			{
				return;
			}
			IList list = fieldInfo.GetValue(source) as IList;
			IList list2 = fieldInfo.GetValue(destination) as IList;
			if (list != null && list2 != null && list.Count != 0)
			{
				object[] array = new object[list.Count];
				list.CopyTo(array, 0);
				object[] array2 = array;
				foreach (object value in array2)
				{
					list2.Add(value);
				}
				list.Clear();
			}
		}

		public static void ItemObjectHoverFromCallSite(object itemObject)
		{
			RuntimeService.Current?.ItemHover(itemObject);
		}

		private RuntimeSettings BindConfig()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			ConfigEntry<bool> enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable item tooltips.");
			ConfigEntry<string> language = ((BaseUnityPlugin)this).Config.Bind<string>("Language", "Language", string.Empty, "Item Tooltips language. Valid persisted values: English or Russian. Use the main-menu LANGUAGE button to change it.");
			ConfigEntry<bool> fullInformation = ((BaseUnityPlugin)this).Config.Bind<bool>("Information", "FullInformation", false, "Show spoiler-bearing detailed descriptions. Toggled in game with ToggleFullInformationKey.");
			ConfigEntry<KeyboardShortcut> toggleFullInformationKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Information", "ToggleFullInformationKey", new KeyboardShortcut((KeyCode)120, Array.Empty<KeyCode>()), "Hotkey that toggles spoiler-safe/full item descriptions.");
			ConfigEntry<bool> inventoryTooltipEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "InventoryTooltipEnabled", true, "Show tooltips when hovering items in the inventory.");
			ConfigEntry<bool> worldTooltipEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "WorldTooltipEnabled", true, "Show tooltips when aiming at pickup items in the world.");
			ConfigEntry<bool> useCustomTooltipCard = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "UseCustomTooltipCard", true, "Use the dedicated item tooltip card instead of White Knuckle's native description field.");
			ConfigEntry<int> tooltipMaxWidth = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "TooltipMaxWidth", 620, "Maximum tooltip card width in screen pixels.");
			return new RuntimeSettings(enabled, language, fullInformation, toggleFullInformationKey, inventoryTooltipEnabled, worldTooltipEnabled, useCustomTooltipCard, tooltipMaxWidth);
		}
	}
}
namespace WhiteKnuckleItemTooltips.UI
{
	public sealed class ResolvedTooltipFont
	{
		public Font Font { get; }

		public string Source { get; }

		public ResolvedTooltipFont(Font font, string source)
		{
			Font = font ?? throw new ArgumentNullException("font");
			Source = source ?? string.Empty;
		}
	}
	public sealed class FontResolver
	{
		private ResolvedTooltipFont? _cached;

		private const string CyrillicProbe = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя";

		public ResolvedTooltipFont Resolve()
		{
			if (_cached != null)
			{
				return _cached;
			}
			if (IsWkLocLoaded())
			{
				Font val = Resources.FindObjectsOfTypeAll<Font>().Where(IsCyrillicCapable).OrderBy(FontPriority)
					.FirstOrDefault();
				if ((Object)(object)val != (Object)null && FontPriority(val) < 100)
				{
					return _cached = new ResolvedTooltipFont(val, "WKLoc loaded font: " + ((Object)val).name);
				}
			}
			try
			{
				Font val2 = Font.CreateDynamicFontFromOSFont(new string[2] { "Segoe UI", "Arial" }, 18);
				if ((Object)(object)val2 != (Object)null && IsCyrillicCapable(val2))
				{
					return _cached = new ResolvedTooltipFont(val2, "Windows dynamic font: " + ((Object)val2).name);
				}
			}
			catch
			{
			}
			string[] array = new string[2] { "Arial.ttf", "LegacyRuntime.ttf" };
			foreach (string text in array)
			{
				try
				{
					Font builtinResource = Resources.GetBuiltinResource<Font>(text);
					if ((Object)(object)builtinResource != (Object)null && IsCyrillicCapable(builtinResource))
					{
						return _cached = new ResolvedTooltipFont(builtinResource, "Unity builtin font: " + text);
					}
				}
				catch
				{
				}
			}
			Font val3 = ((IEnumerable<Font>)Resources.FindObjectsOfTypeAll<Font>()).FirstOrDefault((Func<Font, bool>)IsCyrillicCapable);
			if ((Object)(object)val3 != (Object)null)
			{
				return _cached = new ResolvedTooltipFont(val3, "Loaded Cyrillic font: " + ((Object)val3).name);
			}
			Font val4 = Resources.FindObjectsOfTypeAll<Font>().FirstOrDefault();
			if ((Object)(object)val4 != (Object)null)
			{
				return _cached = new ResolvedTooltipFont(val4, "Last-resort loaded font: " + ((Object)val4).name);
			}
			throw new InvalidOperationException("No usable Unity font was found for the tooltip card.");
		}

		private static bool IsWkLocLoaded()
		{
			return Chainloader.PluginInfos.Values.Any((PluginInfo info) => string.Equals(info.Metadata.Name, "WKLoc", StringComparison.OrdinalIgnoreCase));
		}

		private static bool IsCyrillicCapable(Font font)
		{
			try
			{
				font.RequestCharactersInTexture("АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя", 18, (FontStyle)0);
				return ((IEnumerable<char>)"АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя").All((Func<char, bool>)font.HasCharacter);
			}
			catch
			{
				return false;
			}
		}

		private static int FontPriority(Font font)
		{
			string text = ((Object)font).name ?? string.Empty;
			if (text.Equals("main-legacy", StringComparison.OrdinalIgnoreCase))
			{
				return 0;
			}
			if (text.Equals("main-legacy-os", StringComparison.OrdinalIgnoreCase))
			{
				return 1;
			}
			if (text.IndexOf("main", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return 10;
			}
			return 100;
		}
	}
	public static class MenuCreditsContent
	{
		public const string TwitchPurpleHex = "#9146FF";

		public const string AuthorMarkup = "Item Tooltips Mod by <color=#9146FF><b>KoshGamer</b></color>";

		public const string TwitchUrl = "twitch.tv/koshgamer";

		public const float TopOffsetPixels = 132f;

		public const float OverallOpacity = 0.9f;

		public static bool IsMainMenuScene(string? sceneName)
		{
			return string.Equals(sceneName, "Main-Menu", StringComparison.OrdinalIgnoreCase);
		}
	}
	public sealed class MenuCreditsView
	{
		private const float Width = 430f;

		private const float Height = 54f;

		private const float RightMargin = 18f;

		private static readonly Color TwitchPurple = new Color(29f / 51f, 14f / 51f, 1f, 1f);

		private static readonly Color UrlPurple = new Color(0.82f, 0.74f, 1f, 0.96f);

		private readonly GameObject _canvasObject;

		private readonly GameObject _creditsObject;

		private readonly Texture2D _twitchIconTexture;

		public bool IsVisible
		{
			get
			{
				if ((Object)(object)_creditsObject != (Object)null)
				{
					return _creditsObject.activeSelf;
				}
				return false;
			}
		}

		public MenuCreditsView(Font font)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)font == (Object)null)
			{
				throw new ArgumentNullException("font");
			}
			_canvasObject = new GameObject("WK Item Tooltips Menu Credits Canvas", new Type[1] { typeof(RectTransform) });
			Object.DontDestroyOnLoad((Object)(object)_canvasObject);
			Canvas obj = _canvasObject.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 31990;
			CanvasScaler obj2 = _canvasObject.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)0;
			obj2.scaleFactor = 1f;
			_creditsObject = new GameObject("KoshGamer Menu Credit", new Type[1] { typeof(RectTransform) });
			_creditsObject.transform.SetParent(_canvasObject.transform, false);
			RectTransform component = _creditsObject.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(1f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(1f, 1f);
			component.anchoredPosition = new Vector2(-18f, -132f);
			component.sizeDelta = new Vector2(430f, 54f);
			CanvasGroup obj3 = _creditsObject.AddComponent<CanvasGroup>();
			obj3.alpha = 0.9f;
			obj3.interactable = false;
			obj3.blocksRaycasts = false;
			Text obj4 = CreateText("Author", font, 16, (TextAnchor)2, new Color(0.96f, 0.96f, 0.94f, 0.96f));
			obj4.text = "Item Tooltips Mod by <color=#9146FF><b>KoshGamer</b></color>";
			obj4.supportRichText = true;
			SetTopRightRect(((Graphic)obj4).rectTransform, 0f, 0f, 430f, 23f);
			_twitchIconTexture = CreateTwitchIconTexture();
			GameObject val = new GameObject("Twitch Icon", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(_creditsObject.transform, false);
			RawImage obj5 = val.AddComponent<RawImage>();
			obj5.texture = (Texture)(object)_twitchIconTexture;
			((Graphic)obj5).color = Color.white;
			((Graphic)obj5).raycastTarget = false;
			SetTopRightRect(((Graphic)obj5).rectTransform, -194f, -28f, 18f, 18f);
			Text obj6 = CreateText("Twitch URL", font, 15, (TextAnchor)2, UrlPurple);
			obj6.text = "twitch.tv/koshgamer";
			SetTopRightRect(((Graphic)obj6).rectTransform, 0f, -26f, 188f, 22f);
			_creditsObject.SetActive(false);
		}

		public void SetVisible(bool visible)
		{
			if ((Object)(object)_creditsObject != (Object)null && _creditsObject.activeSelf != visible)
			{
				_creditsObject.SetActive(visible);
			}
		}

		public void Destroy()
		{
			if ((Object)(object)_twitchIconTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_twitchIconTexture);
			}
			if ((Object)(object)_canvasObject != (Object)null)
			{
				Object.Destroy((Object)(object)_canvasObject);
			}
		}

		private Text CreateText(string name, Font font, int size, TextAnchor alignment, Color color)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(_creditsObject.transform, false);
			Text obj = val.AddComponent<Text>();
			obj.font = font;
			obj.fontSize = size;
			obj.alignment = alignment;
			((Graphic)obj).color = color;
			obj.horizontalOverflow = (HorizontalWrapMode)1;
			obj.verticalOverflow = (VerticalWrapMode)1;
			((Graphic)obj).raycastTarget = false;
			obj.supportRichText = true;
			Shadow obj2 = val.AddComponent<Shadow>();
			obj2.effectColor = new Color(0f, 0f, 0f, 0.72f);
			obj2.effectDistance = new Vector2(1f, -1f);
			obj2.useGraphicAlpha = true;
			return obj;
		}

		private static void SetTopRightRect(RectTransform rect, float x, float y, float width, float height)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(1f, 1f);
			rect.anchorMax = new Vector2(1f, 1f);
			rect.pivot = new Vector2(1f, 1f);
			rect.anchoredPosition = new Vector2(x, y);
			rect.sizeDelta = new Vector2(width, height);
		}

		private static Texture2D CreateTwitchIconTexture()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false)
			{
				name = "KoshGamer Twitch Icon",
				filterMode = (FilterMode)0,
				wrapMode = (TextureWrapMode)1
			};
			Color32 val2 = default(Color32);
			((Color32)(ref val2))..ctor((byte)0, (byte)0, (byte)0, (byte)0);
			Color32 color = default(Color32);
			((Color32)(ref color))..ctor((byte)145, (byte)70, byte.MaxValue, byte.MaxValue);
			Color32 color2 = default(Color32);
			((Color32)(ref color2))..ctor(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
			Color32[] array = (Color32[])(object)new Color32[1024];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = val2;
			}
			FillRect(array, 32, 4, 5, 27, 26, color);
			FillRect(array, 32, 7, 2, 12, 7, color);
			FillRect(array, 32, 10, 0, 12, 4, color);
			FillRect(array, 32, 8, 9, 23, 22, color2);
			FillRect(array, 32, 12, 13, 14, 19, color);
			FillRect(array, 32, 18, 13, 20, 19, color);
			val.SetPixels32(array);
			val.Apply(false, false);
			return val;
		}

		private static void FillRect(Color32[] pixels, int stride, int minX, int minY, int maxX, int maxY, Color32 color)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			for (int i = minY; i <= maxY; i++)
			{
				for (int j = minX; j <= maxX; j++)
				{
					pixels[i * stride + j] = color;
				}
			}
		}
	}
	public static class MenuLanguageButtonContent
	{
		public const float Width = 230f;

		public const float Height = 54f;

		public const float RightMargin = 18f;

		public const float TopOffsetPixels = 198f;

		public const int FontSize = 20;

		public const int HoverHintFontSize = 13;

		public static string Label(TooltipLanguage language)
		{
			if (language != TooltipLanguage.Russian)
			{
				return "LANGUAGE: EN";
			}
			return "LANGUAGE: RU";
		}

		public static string HoverHint(TooltipLanguage language)
		{
			if (language != TooltipLanguage.Russian)
			{
				return "Click to switch language";
			}
			return "Нажми, чтобы сменить язык";
		}
	}
	public sealed class MenuLanguageButtonView
	{
		private readonly GameObject _canvasObject;

		private readonly GameObject _rootObject;

		private readonly Text _label;

		private readonly Text _hoverHint;

		private readonly Action _onClick;

		private TooltipLanguage _language;

		public bool IsVisible
		{
			get
			{
				if ((Object)(object)_rootObject != (Object)null)
				{
					return _rootObject.activeSelf;
				}
				return false;
			}
		}

		public MenuLanguageButtonView(Font font, Action onClick)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Expected O, but got Unknown
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Expected O, but got Unknown
			//IL_033a: Unknown result type (might be due to invalid IL or missing references)
			//IL_036f: Unknown result type (might be due to invalid IL or missing references)
			//IL_037a: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0409: Expected O, but got Unknown
			//IL_0475: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_050c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)font == (Object)null)
			{
				throw new ArgumentNullException("font");
			}
			_onClick = onClick ?? throw new ArgumentNullException("onClick");
			_canvasObject = new GameObject("WK Item Tooltips Language Canvas", new Type[1] { typeof(RectTransform) });
			Object.DontDestroyOnLoad((Object)(object)_canvasObject);
			Canvas obj = _canvasObject.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 31995;
			CanvasScaler obj2 = _canvasObject.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)0;
			obj2.scaleFactor = 1f;
			_canvasObject.AddComponent<GraphicRaycaster>();
			_rootObject = new GameObject("LanguageButton", new Type[1] { typeof(RectTransform) });
			_rootObject.transform.SetParent(_canvasObject.transform, false);
			RectTransform component = _rootObject.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(1f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(1f, 1f);
			component.anchoredPosition = new Vector2(-18f, -198f);
			component.sizeDelta = new Vector2(230f, 54f);
			Image val = _rootObject.AddComponent<Image>();
			((Graphic)val).color = new Color(0.045f, 0.035f, 0.065f, 0.88f);
			((Graphic)val).raycastTarget = true;
			Outline outline = _rootObject.AddComponent<Outline>();
			((Shadow)outline).effectColor = new Color(29f / 51f, 14f / 51f, 1f, 0.95f);
			((Shadow)outline).effectDistance = new Vector2(2f, -2f);
			((Shadow)outline).useGraphicAlpha = true;
			Button obj3 = _rootObject.AddComponent<Button>();
			((Selectable)obj3).interactable = true;
			((Selectable)obj3).targetGraphic = (Graphic)(object)val;
			((Selectable)obj3).transition = (Transition)1;
			ColorBlock defaultColorBlock = ColorBlock.defaultColorBlock;
			((ColorBlock)(ref defaultColorBlock)).normalColor = new Color(0.88f, 0.84f, 0.95f, 1f);
			((ColorBlock)(ref defaultColorBlock)).highlightedColor = new Color(1f, 0.84f, 1f, 1f);
			((ColorBlock)(ref defaultColorBlock)).pressedColor = new Color(0.67f, 0.52f, 0.82f, 1f);
			((ColorBlock)(ref defaultColorBlock)).disabledColor = new Color(0.45f, 0.45f, 0.45f, 0.5f);
			((ColorBlock)(ref defaultColorBlock)).colorMultiplier = 1.2f;
			((ColorBlock)(ref defaultColorBlock)).fadeDuration = 0.08f;
			((Selectable)obj3).colors = defaultColorBlock;
			((UnityEvent)obj3.onClick).AddListener((UnityAction)delegate
			{
				_onClick();
			});
			GameObject val2 = new GameObject("Label", new Type[1] { typeof(RectTransform) });
			val2.transform.SetParent(_rootObject.transform, false);
			_label = val2.AddComponent<Text>();
			_label.font = font;
			_label.fontSize = 20;
			_label.fontStyle = (FontStyle)1;
			_label.alignment = (TextAnchor)4;
			((Graphic)_label).color = Color.white;
			((Graphic)_label).raycastTarget = false;
			_label.horizontalOverflow = (HorizontalWrapMode)1;
			_label.verticalOverflow = (VerticalWrapMode)1;
			RectTransform component2 = val2.GetComponent<RectTransform>();
			component2.anchorMin = Vector2.zero;
			component2.anchorMax = Vector2.one;
			component2.offsetMin = new Vector2(10f, 6f);
			component2.offsetMax = new Vector2(-10f, -6f);
			Shadow obj4 = val2.AddComponent<Shadow>();
			obj4.effectColor = new Color(0f, 0f, 0f, 0.8f);
			obj4.effectDistance = new Vector2(1f, -1f);
			GameObject hintObject = new GameObject("HoverHint", new Type[1] { typeof(RectTransform) });
			hintObject.transform.SetParent(_rootObject.transform, false);
			_hoverHint = hintObject.AddComponent<Text>();
			_hoverHint.font = font;
			_hoverHint.fontSize = 13;
			_hoverHint.alignment = (TextAnchor)2;
			((Graphic)_hoverHint).color = new Color(0.92f, 0.86f, 1f, 0.95f);
			((Graphic)_hoverHint).raycastTarget = false;
			_hoverHint.horizontalOverflow = (HorizontalWrapMode)1;
			_hoverHint.verticalOverflow = (VerticalWrapMode)1;
			RectTransform component3 = hintObject.GetComponent<RectTransform>();
			component3.anchorMin = new Vector2(1f, 0f);
			component3.anchorMax = new Vector2(1f, 0f);
			component3.pivot = new Vector2(1f, 1f);
			component3.anchoredPosition = new Vector2(0f, -7f);
			component3.sizeDelta = new Vector2(260f, 24f);
			hintObject.SetActive(false);
			EventTrigger obj5 = _rootObject.AddComponent<EventTrigger>();
			obj5.triggers = new List<Entry>();
			obj5.triggers.Add(CreateTrigger((EventTriggerType)0, delegate
			{
				hintObject.SetActive(true);
			}));
			obj5.triggers.Add(CreateTrigger((EventTriggerType)1, delegate
			{
				hintObject.SetActive(false);
			}));
			obj5.triggers.Add(CreateTrigger((EventTriggerType)2, delegate
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				((Shadow)outline).effectColor = new Color(0.72f, 0.55f, 1f, 1f);
			}));
			obj5.triggers.Add(CreateTrigger((EventTriggerType)3, delegate
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				((Shadow)outline).effectColor = new Color(29f / 51f, 14f / 51f, 1f, 0.95f);
			}));
			SetLanguage(TooltipLanguage.English);
			_rootObject.SetActive(false);
		}

		public void SetLanguage(TooltipLanguage language)
		{
			_language = language;
			_label.text = MenuLanguageButtonContent.Label(language);
			_hoverHint.text = MenuLanguageButtonContent.HoverHint(language);
		}

		public void SetVisible(bool visible)
		{
			if ((Object)(object)_rootObject != (Object)null && _rootObject.activeSelf != visible)
			{
				_rootObject.SetActive(visible);
			}
		}

		public void Destroy()
		{
			if ((Object)(object)_canvasObject != (Object)null)
			{
				Object.Destroy((Object)(object)_canvasObject);
			}
		}

		private static Entry CreateTrigger(EventTriggerType type, UnityAction<BaseEventData> callback)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			Entry val = new Entry
			{
				eventID = type,
				callback = new TriggerEvent()
			};
			((UnityEvent<BaseEventData>)(object)val.callback).AddListener(callback);
			return val;
		}
	}
	public static class NativeDescriptionFormatter
	{
		public static string Format(ResolvedItemInfo info, bool fullInformation, string? statusLine = null)
		{
			return Format(info, fullInformation, TooltipLanguage.Russian, statusLine);
		}

		public static string Format(ResolvedItemInfo info, bool fullInformation, TooltipLanguage language, string? statusLine = null)
		{
			if (info == null)
			{
				return string.Empty;
			}
			StringBuilder stringBuilder = new StringBuilder(512);
			if (!string.IsNullOrWhiteSpace(statusLine))
			{
				stringBuilder.Append("<color=#D6C58A><b>").Append(Escape(statusLine.Trim())).AppendLine("</b></color>");
			}
			string value = (string.IsNullOrWhiteSpace(info.Name) ? LocalizedStrings.UnknownItemName(language) : info.Name.Trim());
			stringBuilder.Append("<size=110%><b>").Append(Escape(value)).AppendLine("</b></size>");
			if (!string.IsNullOrWhiteSpace(info.Category))
			{
				stringBuilder.Append("<color=#B7B3AC><i>").Append(Escape(info.Category.Trim())).AppendLine("</i></color>");
			}
			string value2 = info.DescriptionFor(fullInformation);
			if (!string.IsNullOrWhiteSpace(value2))
			{
				stringBuilder.AppendLine();
				stringBuilder.Append(Escape(value2));
			}
			foreach (ItemStat stat in info.Stats)
			{
				if (stat != null && !string.IsNullOrWhiteSpace(stat.Label) && !string.IsNullOrWhiteSpace(stat.Value))
				{
					stringBuilder.AppendLine();
					stringBuilder.Append("<b>").Append(Escape(stat.Label.Trim())).Append(":</b> ")
						.Append(Escape(stat.Value.Trim()));
				}
			}
			return stringBuilder.ToString().TrimEnd();
		}

		private static string Escape(string value)
		{
			return (value ?? string.Empty).Replace("&", "&").Replace("<", "<").Replace(">", ">");
		}
	}
	public sealed class ToastView
	{
		private readonly GameObject _canvasObject;

		private readonly GameObject _panelObject;

		private readonly Text _text;

		private float _remaining;

		public ToastView(Font font)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Expected O, but got Unknown
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)font == (Object)null)
			{
				throw new ArgumentNullException("font");
			}
			_canvasObject = new GameObject("WK Item Tooltips Toast Canvas", new Type[1] { typeof(RectTransform) });
			Object.DontDestroyOnLoad((Object)(object)_canvasObject);
			Canvas obj = _canvasObject.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 32001;
			CanvasScaler obj2 = _canvasObject.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)0;
			obj2.scaleFactor = 1f;
			_panelObject = new GameObject("Toast", new Type[1] { typeof(RectTransform) });
			_panelObject.transform.SetParent(_canvasObject.transform, false);
			Image obj3 = _panelObject.AddComponent<Image>();
			((Graphic)obj3).color = new Color(0.045f, 0.04f, 0.04f, 0.9f);
			((Graphic)obj3).raycastTarget = false;
			RectTransform component = _panelObject.GetComponent<RectTransform>();
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.86f);
			component.anchorMax = val;
			component.anchorMin = val;
			component.pivot = new Vector2(0.5f, 0.5f);
			component.sizeDelta = new Vector2(340f, 48f);
			GameObject val2 = new GameObject("Text", new Type[1] { typeof(RectTransform) });
			val2.transform.SetParent(_panelObject.transform, false);
			_text = val2.AddComponent<Text>();
			_text.font = font;
			_text.fontSize = 18;
			_text.alignment = (TextAnchor)4;
			((Graphic)_text).color = Color.white;
			((Graphic)_text).raycastTarget = false;
			RectTransform component2 = val2.GetComponent<RectTransform>();
			component2.anchorMin = Vector2.zero;
			component2.anchorMax = Vector2.one;
			component2.offsetMin = new Vector2(10f, 4f);
			component2.offsetMax = new Vector2(-10f, -4f);
			_panelObject.SetActive(false);
		}

		public void Show(string text, float seconds = 1.4f)
		{
			_text.text = text ?? string.Empty;
			_remaining = Mathf.Max(0.1f, seconds);
			_panelObject.SetActive(true);
		}

		public void Tick(float unscaledDeltaTime)
		{
			if (_panelObject.activeSelf)
			{
				_remaining -= Mathf.Max(0f, unscaledDeltaTime);
				if (_remaining <= 0f)
				{
					_panelObject.SetActive(false);
				}
			}
		}

		public void Destroy()
		{
			if ((Object)(object)_canvasObject != (Object)null)
			{
				Object.Destroy((Object)(object)_canvasObject);
			}
		}
	}
	public sealed class TooltipCardView
	{
		private readonly Font _font;

		private readonly GameObject _canvasObject;

		private readonly GameObject _panelObject;

		private readonly RectTransform _panelRect;

		private readonly Text _nameText;

		private readonly Text _categoryText;

		private readonly Text _descriptionText;

		private readonly List<Text> _statRows = new List<Text>();

		private Vector2 _anchor;

		private TooltipAnchorMode _mode;

		private float _maxWidth = 620f;

		public bool IsVisible
		{
			get
			{
				if ((Object)(object)_panelObject != (Object)null)
				{
					return _panelObject.activeSelf;
				}
				return false;
			}
		}

		public TooltipCardView(Font font)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Expected O, but got Unknown
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			_font = font ?? throw new ArgumentNullException("font");
			_canvasObject = new GameObject("WK Item Tooltips Card Canvas", new Type[1] { typeof(RectTransform) });
			Object.DontDestroyOnLoad((Object)(object)_canvasObject);
			Canvas obj = _canvasObject.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 32000;
			CanvasScaler obj2 = _canvasObject.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)0;
			obj2.scaleFactor = 1f;
			_panelObject = new GameObject("Item Tooltip Card", new Type[1] { typeof(RectTransform) });
			_panelObject.transform.SetParent(_canvasObject.transform, false);
			Image obj3 = _panelObject.AddComponent<Image>();
			((Graphic)obj3).color = new Color(0.045f, 0.04f, 0.04f, 0.93f);
			((Graphic)obj3).raycastTarget = false;
			_panelRect = _panelObject.GetComponent<RectTransform>();
			_panelRect.anchorMin = Vector2.zero;
			_panelRect.anchorMax = Vector2.zero;
			_panelRect.pivot = new Vector2(0f, 1f);
			VerticalLayoutGroup obj4 = _panelObject.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj4).padding = new RectOffset(16, 16, 14, 14);
			((HorizontalOrVerticalLayoutGroup)obj4).spacing = 5f;
			((HorizontalOrVerticalLayoutGroup)obj4).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj4).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj4).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj4).childForceExpandWidth = true;
			ContentSizeFitter obj5 = _panelObject.AddComponent<ContentSizeFitter>();
			obj5.horizontalFit = (FitMode)0;
			obj5.verticalFit = (FitMode)2;
			_nameText = CreateText("Name", 22, (TextAnchor)0, new Color(0.98f, 0.97f, 0.94f, 1f));
			_nameText.fontStyle = (FontStyle)1;
			_categoryText = CreateText("Category", 15, (TextAnchor)0, new Color(0.72f, 0.7f, 0.67f, 1f));
			_categoryText.fontStyle = (FontStyle)2;
			_descriptionText = CreateText("Description", 18, (TextAnchor)0, new Color(0.94f, 0.94f, 0.92f, 1f));
			_panelObject.SetActive(false);
		}

		public void Show(TooltipDisplayModel model, Vector2 anchor, TooltipAnchorMode mode, float maxWidth)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (model == null)
			{
				Hide();
				return;
			}
			_anchor = anchor;
			_mode = mode;
			_maxWidth = maxWidth;
			ApplyModel(model);
			_panelObject.SetActive(true);
			RebuildAndPosition();
		}

		public void Refresh(TooltipDisplayModel model)
		{
			if (model == null)
			{
				Hide();
			}
			else if (IsVisible)
			{
				ApplyModel(model);
				RebuildAndPosition();
			}
		}

		public void Reposition(Vector2 anchor, TooltipAnchorMode mode)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			_anchor = anchor;
			_mode = mode;
			if (IsVisible)
			{
				RebuildAndPosition();
			}
		}

		public void Hide()
		{
			if ((Object)(object)_panelObject != (Object)null)
			{
				_panelObject.SetActive(false);
			}
		}

		public void Destroy()
		{
			if ((Object)(object)_canvasObject != (Object)null)
			{
				Object.Destroy((Object)(object)_canvasObject);
			}
		}

		private Text CreateText(string objectName, int size, TextAnchor alignment, Color color)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: 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)
			GameObject val = new GameObject(objectName, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(_panelObject.transform, false);
			Text obj = val.AddComponent<Text>();
			obj.font = _font;
			obj.fontSize = size;
			obj.alignment = alignment;
			((Graphic)obj).color = color;
			obj.horizontalOverflow = (HorizontalWrapMode)0;
			obj.verticalOverflow = (VerticalWrapMode)1;
			((Graphic)obj).raycastTarget = false;
			obj.supportRichText = true;
			obj.lineSpacing = 1.05f;
			return obj;
		}

		private void ApplyModel(TooltipDisplayModel model)
		{
			_nameText.text = Escape(model.Name).ToUpperInvariant();
			_categoryText.text = Escape(model.Category);
			((Component)_categoryText).gameObject.SetActive(!string.IsNullOrWhiteSpace(model.Category));
			_descriptionText.text = Escape(model.Description);
			((Component)_descriptionText).gameObject.SetActive(!string.IsNullOrWhiteSpace(model.Description));
			for (int i = 0; i < model.Stats.Count; i++)
			{
				Text orCreateStatRow = GetOrCreateStatRow(i);
				orCreateStatRow.text = "<b>" + Escape(model.Stats[i].Label) + ":</b> " + Escape(model.Stats[i].Value);
				((Component)orCreateStatRow).gameObject.SetActive(true);
			}
			for (int j = model.Stats.Count; j < _statRows.Count; j++)
			{
				((Component)_statRows[j]).gameObject.SetActive(false);
			}
		}

		private Text GetOrCreateStatRow(int index)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			while (_statRows.Count <= index)
			{
				Text item = CreateText($"Stat {_statRows.Count + 1}", 17, (TextAnchor)0, new Color(0.9f, 0.89f, 0.86f, 1f));
				_statRows.Add(item);
			}
			return _statRows[index];
		}

		private void RebuildAndPosition()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Max(320f, (float)Screen.width - 24f);
			float num2 = Mathf.Clamp(_maxWidth, 320f, num);
			float num3 = Mathf.Min(360f, num2);
			float num4 = Mathf.Clamp((float)Screen.width * 0.28f, num3, num2);
			_panelRect.SetSizeWithCurrentAnchors((Axis)0, num4);
			Canvas.ForceUpdateCanvases();
			LayoutRebuilder.ForceRebuildLayoutImmediate(_panelRect);
			Canvas.ForceUpdateCanvases();
			Rect rect = _panelRect.rect;
			Vector2 size = ((Rect)(ref rect)).size;
			TooltipPosition tooltipPosition = TooltipLayout.CalculatePosition(_anchor.x, _anchor.y, _mode, size.x, size.y, Screen.width, Screen.height);
			_panelRect.anchoredPosition = new Vector2(tooltipPosition.X, tooltipPosition.Y);
		}

		private static string Escape(string value)
		{
			return (value ?? string.Empty).Replace("<", "(").Replace(">", ")");
		}
	}
	public sealed class TooltipController
	{
		private readonly ItemResolver _resolver;

		private readonly InventoryItemDetector _inventoryDetector;

		private readonly WorldItemDetector _worldDetector;

		private readonly TooltipView _view;

		private readonly Dictionary<string, ResolvedItemInfo> _cache = new Dictionary<string, ResolvedItemInfo>(StringComparer.OrdinalIgnoreCase);

		private string _renderedStableId = string.Empty;

		private bool _renderedFullInformation;

		private TooltipAnchorMode _renderedMode;

		public TooltipController(ItemResolver resolver, InventoryItemDetector inventoryDetector, WorldItemDetector worldDetector, TooltipView view)
		{
			_resolver = resolver ?? throw new ArgumentNullException("resolver");
			_inventoryDetector = inventoryDetector ?? throw new ArgumentNullException("inventoryDetector");
			_worldDetector = worldDetector ?? throw new ArgumentNullException("worldDetector");
			_view = view ?? throw new ArgumentNullException("view");
		}

		public void Tick(bool enabled, bool inventoryEnabled, bool worldEnabled, bool fullInformation, float worldInspectionDistance)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (!enabled)
			{
				Hide();
				return;
			}
			if (inventoryEnabled && _inventoryDetector.TryGetHoveredItem(out RuntimeItemSnapshot snapshot, out Vector2 screenPosition))
			{
				Render(snapshot, fullInformation, screenPosition, TooltipAnchorMode.Inventory);
				return;
			}
			bool flag = Cursor.visible && (int)Cursor.lockState != 1;
			if (worldEnabled && !flag && _worldDetector.TryGetAimedItem(worldInspectionDistance, out RuntimeItemSnapshot snapshot2, out Vector2 screenPosition2))
			{
				Render(snapshot2, fullInformation, screenPosition2, TooltipAnchorMode.World);
			}
			else
			{
				Hide();
			}
		}

		public void ForceRefresh()
		{
			_renderedStableId = string.Empty;
		}

		public void ClearCache()
		{
			_cache.Clear();
			ForceRefresh();
		}

		private void Render(RuntimeItemSnapshot snapshot, bool fullInformation, Vector2 anchor, TooltipAnchorMode mode)
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			string text = ItemIdNormalizer.Normalize(snapshot.StableIdCandidate);
			if (string.IsNullOrEmpty(text))
			{
				Hide();
				return;
			}
			if (!_cache.TryGetValue(text, out ResolvedItemInfo value) || HasRicherRuntimeData(snapshot, value))
			{
				value = _resolver.Resolve(snapshot);
				_cache[text] = value;
			}
			if (_view.IsVisible && string.Equals(_renderedStableId, text, StringComparison.OrdinalIgnoreCase) && _renderedFullInformation == fullInformation && _renderedMode == mode)
			{
				_view.Reposition(anchor, mode);
				return;
			}
			_view.Show(value, fullInformation, anchor, mode);
			_renderedStableId = text;
			_renderedFullInformation = fullInformation;
			_renderedMode = mode;
		}

		private static bool HasRicherRuntimeData(RuntimeItemSnapshot snapshot, ResolvedItemInfo cached)
		{
			int num = 0;
			foreach (ItemStat stat in cached.Stats)
			{
				if (stat.Source == ItemStatSource.Runtime)
				{
					num++;
				}
			}
			return snapshot.Stats.Count > num;
		}

		private void Hide()
		{
			_view.Hide();
			_renderedStableId = string.Empty;
		}
	}
	public sealed class TooltipDisplayModel
	{
		public string Name { get; set; } = "Unknown item";

		public string Category { get; set; } = string.Empty;

		public string Description { get; set; } = string.Empty;

		public IReadOnlyList<TooltipStatRow> Stats { get; set; } = new List<TooltipStatRow>();
	}
	public sealed class TooltipStatRow
	{
		public string Label { get; }

		public string Value { get; }

		public TooltipStatRow(string label, string value)
		{
			Label = label;
			Value = value;
		}
	}
	public static class TooltipFormatter
	{
		public static TooltipDisplayModel Format(ResolvedItemInfo info, bool fullInformation)
		{
			return Format(info, fullInformation, TooltipLanguage.Russian);
		}

		public static TooltipDisplayModel Format(ResolvedItemInfo info, bool fullInformation, TooltipLanguage language)
		{
			if (info == null)
			{
				throw new ArgumentNullException("info");
			}
			List<TooltipStatRow> list = new List<TooltipStatRow>();
			foreach (ItemStat stat in info.Stats)
			{
				if (stat != null && !string.IsNullOrWhiteSpace(stat.Label) && !string.IsNullOrWhiteSpace(stat.Value))
				{
					list.Add(new TooltipStatRow(Sanitize(stat.Label.Trim()), Sanitize(stat.Value.Trim())));
				}
			}
			return new TooltipDisplayModel
			{
				Name = Sanitize(string.IsNullOrWhiteSpace(info.Name) ? LocalizedStrings.UnknownItemName(language) : info.Name.Trim()),
				Category = Sanitize(info.Category?.Trim() ?? string.Empty),
				Description = Sanitize(info.DescriptionFor(fullInformation)),
				Stats = list
			};
		}

		internal static string Sanitize(string value)
		{
			return (value ?? string.Empty).Replace("•", "-").Replace("—", "-").Replace("–", "-")
				.Replace("−", "-")
				.Replace("→", "->")
				.Replace("\r\n", "\n")
				.Trim();
		}
	}
	public enum TooltipAnchorMode
	{
		Inventory,
		World
	}
	public readonly struct TooltipPosition
	{
		public float X { get; }

		public float Y { get; }

		public TooltipPosition(float x, float y)
		{
			X = x;
			Y = y;
		}
	}
	public static class TooltipLayout
	{
		public static TooltipPosition CalculatePosition(float anchorX, float anchorY, TooltipAnchorMode mode, float cardWidth, float cardHeight, float screenWidth, float screenHeight, float margin = 12f)
		{
			if (IsInvalid(anchorX) || IsInvalid(anchorY) || cardWidth <= 0f || cardHeight <= 0f || screenWidth <= 0f || screenHeight <= 0f)
			{
				return new TooltipPosition(margin, Max(margin + cardHeight, screenHeight - margin));
			}
			float value = ((mode == TooltipAnchorMode.Inventory) ? (anchorX + 26f) : (anchorX + 54f));
			float value2 = ((mode == TooltipAnchorMode.Inventory) ? (anchorY - 22f) : (anchorY + 170f));
			float max = Max(margin, screenWidth - cardWidth - margin);
			float num = cardHeight + margin;
			return new TooltipPosition(y: Clamp(value2, num, Max(num, screenHeight - margin)), x: Clamp(value, margin, max));
		}

		private static bool IsInvalid(float value)
		{
			if (!float.IsNaN(value))
			{
				return float.IsInfinity(value);
			}
			return true;
		}

		private static float Max(float left, float right)
		{
			if (!(left > right))
			{
				return right;
			}
			return left;
		}

		private static float Clamp(float value, float min, float max)
		{
			if (value < min)
			{
				return min;
			}
			if (value > max)
			{
				return max;
			}
			return value;
		}
	}
	public sealed class TooltipView
	{
		private const float CardWidth = 400f;

		private const float HorizontalPadding = 16f;

		private const float VerticalPadding = 14f;

		private const float ScreenMargin = 12f;

		private readonly GameObject _canvasObject;

		private readonly GameObject _panelObject;

		private readonly RectTransform _panelRect;

		private readonly Text _text;

		private float _currentHeight = 100f;

		public bool IsVisible => _panelObject.activeSelf;

		public TooltipView()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: 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)
			//IL_0131: Expected O, but got Unknown
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			_canvasObject = new GameObject("WK Item Tooltips Canvas");
			Object.DontDestroyOnLoad((Object)(object)_canvasObject);
			Canvas obj = _canvasObject.AddComponent<Canvas>();
			obj.renderMode = (RenderMode)0;
			obj.sortingOrder = 32000;
			CanvasScaler obj2 = _canvasObject.AddComponent<CanvasScaler>();
			obj2.uiScaleMode = (ScaleMode)0;
			obj2.scaleFactor = 1f;
			_panelObject = new GameObject("Item Tooltip");
			_panelObject.transform.SetParent(_canvasObject.transform, false);
			Image obj3 = _panelObject.AddComponent<Image>();
			((Graphic)obj3).color = new Color(0.045f, 0.04f, 0.04f, 0.93f);
			((Graphic)obj3).raycastTarget = false;
			_panelRect = _panelObject.GetComponent<RectTransform>();
			_panelRect.anchorMin = Vector2.zero;
			_panelRect.anchorMax = Vector2.zero;
			_panelRect.pivot = new Vector2(0f, 1f);
			_panelRect.sizeDelta = new Vector2(400f, _currentHeight);
			GameObject val = new GameObject("Text");
			val.transform.SetParent(_panelObject.transform, false);
			_text = val.AddComponent<Text>();
			_text.font = LoadBuiltinFont();
			_text.fontSize = 18;
			((Graphic)_text).color = new Color(0.94f, 0.94f, 0.92f, 1f);
			_text.alignment = (TextAnchor)0;
			_text.horizontalOverflow = (HorizontalWrapMode)0;
			_text.verticalOverflow = (VerticalWrapMode)1;
			_text.supportRichText = true;
			((Graphic)_text).raycastTarget = false;
			_text.lineSpacing = 1.05f;
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 0f);
			component.anchorMax = new Vector2(1f, 1f);
			component.offsetMin = new Vector2(16f, 14f);
			component.offsetMax = new Vector2(-16f, -14f);
			_panelObject.SetActive(false);
		}

		public void Show(ResolvedItemInfo info, bool fullInformation, Vector2 anchor, TooltipAnchorMode mode)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if (info == null)
			{
				Hide();
				return;
			}
			_text.text = BuildMarkup(info, fullInformation);
			_panelObject.SetActive(true);
			Canvas.ForceUpdateCanvases();
			float num = _text.preferredHeight + 28f;
			_currentHeight = Mathf.Clamp(num, 88f, 620f);
			_panelRect.sizeDelta = new Vector2(400f, _currentHeight);
			Reposition(anchor, mode);
		}

		public void Reposition(Vector2 anchor, TooltipAnchorMode mode)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			if (_panelObject.activeSelf)
			{
				Vector2 val = default(Vector2);
				if (mode == TooltipAnchorMode.Inventory)
				{
					((Vector2)(ref val))..ctor(anchor.x + 26f, anchor.y - 22f);
				}
				else
				{
					((Vector2)(ref val))..ctor(anchor.x + 54f, anchor.y + 170f);
				}
				float num = Mathf.Max(12f, (float)Screen.width - 400f - 12f);
				float num2 = _currentHeight + 12f;
				float num3 = Mathf.Max(num2, (float)Screen.height - 12f);
				val.x = Mathf.Clamp(val.x, 12f, num);
				val.y = Mathf.Clamp(val.y, num2, num3);
				_panelRect.anchoredPosition = val;
			}
		}

		public void Hide()
		{
			if ((Object)(object)_panelObject != (Object)null)
			{
				_panelObject.SetActive(false);
			}
		}

		public void Destroy()
		{
			if ((Object)(object)_canvasObject != (Object)null)
			{
				Object.Destroy((Object)(object)_canvasObject);
			}
		}

		private static string BuildMarkup(ResolvedItemInfo info, bool fullInformation)
		{
			StringBuilder stringBuilder = new StringBuilder(512);
			string value = EscapeRichText(string.IsNullOrWhiteSpace(info.Name) ? "Unknown item" : info.Name.ToUpperInvariant());
			stringBuilder.Append("<size=22><b>").Append(value).AppendLine("</b></size>");
			if (!string.IsNullOrWhiteSpace(info.Category))
			{
				stringBuilder.Append("<size=15><color=#B7B3AC><i>").Append(EscapeRichText(info.Category)).AppendLine("</i></color></size>");
			}
			string text = info.DescriptionFor(fullInformation);
			if (!string.IsNullOrWhiteSpace(text))
			{
				stringBuilder.AppendLine();
				stringBuilder.Append(EscapeRichText(text.Trim()));
			}
			if (info.Stats.Count > 0)
			{
				stringBuilder.AppendLine().AppendLine();
				for (int i = 0; i < info.Stats.Count; i++)
				{
					ItemStat itemStat = info.Stats[i];
					if (!string.IsNullOrWhiteSpace(itemStat.Label) && !string.IsNullOrWhiteSpace(itemStat.Value))
					{
						stringBuilder.Append("<b>").Append(EscapeRichText(itemStat.Label.Trim())).Append(":</b> ")
							.Append(EscapeRichText(itemStat.Value.Trim()));
						if (i < info.Stats.Count - 1)
						{
							stringBuilder.AppendLine();
						}
					}
				}
			}
			return stringBuilder.ToString().TrimEnd();
		}

		private static string EscapeRichText(string value)
		{
			return value.Replace("<", "<").Replace(">", ">");
		}

		private static Font LoadBuiltinFont()
		{
			try
			{
				Font builtinResource = Resources.GetBuiltinResource<Font>("Arial.ttf");
				if ((Object)(object)builtinResource != (Object)null)
				{
					return builtinResource;
				}
			}
			catch
			{
			}
			try
			{
				Font builtinResource2 = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
				if ((Object)(object)builtinResource2 != (Object)null)
				{
					return builtinResource2;
				}
			}
			catch
			{
			}
			Font[] array = Resources.FindObjectsOfTypeAll<Font>();
			if (array.Length != 0 && (Object)(object)array[0] != (Object)null)
			{
				return array[0];
			}
			throw new InvalidOperationException("No usable Unity font was found for item tooltips.");
		}
	}
}
namespace WhiteKnuckleItemTooltips.Runtime
{
	public static class RuntimeHost
	{
		private static readonly RuntimeHostState State = new RuntimeHostState();

		private static RuntimeHostBehaviour? _behaviour;

		private static bool _sceneCallbackRegistered;

		private static int _nextGeneration = 1;

		public static RuntimeHostBehaviour EnsureAlive()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			if ((Object)(object)_behaviour != (Object)null)
			{
				return _behaviour;
			}
			GameObject val = new GameObject("WhiteKnuckleItemTooltips.RuntimeHost")
			{
				hideFlags = (HideFlags)61
			};
			Object.DontDestroyOnLoad((Object)val);
			_behaviour = val.AddComponent<RuntimeHostBehaviour>();
			State.MarkCreated(_nextGeneration++);
			return _behaviour;
		}

		public static void RegisterSceneCallback()
		{
			if (!_sceneCallbackRegistered)
			{
				SceneManager.sceneLoaded += HandleSceneLoaded;
				_sceneCallbackRegistered = true;
			}
		}

		public static void HandleSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			EnsureAlive();
			RuntimeService.Current?.SceneLoaded(((Scene)(ref scene)).name);
		}

		internal static void NotifyDestroyed(RuntimeHostBehaviour behaviour)
		{
			if (_behaviour == behaviour)
			{
				_behaviour = null;
				State.MarkLost();
			}
		}
	}
	public sealed class RuntimeHostBehaviour : MonoBehaviour
	{
		private void Start()
		{
			RuntimeService.Current?.InitializeAfterPluginLoad();
		}

		private void Update()
		{
			RuntimeService.Current?.Tick();
		}

		private void OnDestroy()
		{
			RuntimeHost.NotifyDestroyed(this);
		}
	}
	public sealed class RuntimeHostState
	{
		public int Generation { get; private set; }

		public bool NeedsHost { get; private set; } = true;

		public void MarkCreated(int generation)
		{
			Generation = generation;
			NeedsHost = false;
		}

		public void MarkLost()
		{
			NeedsHost = true;
		}
	}
	public sealed class RuntimeItemSnapshot
	{
		public string StableIdCandidate { get; set; } = string.Empty;

		public string RuntimeName { get; set; } = string.Empty;

		public string RuntimeCategory { get; set; } = string.Empty;

		public string RuntimeSafeDescription { get; set; } = string.Empty;

		public string RuntimeSpoilerDescription { get; set; } = string.Empty;

		public float? Weight { get; set; }

		public int? Worth { get; set; }

		public bool? Pocketable { get; set; }

		public bool? Pouchable { get; set; }

		public List<ItemStat> Stats { get; } = new List<ItemStat>();

		public object? RuntimeObject { get; set; }
	}
	public sealed class RuntimeSettings
	{
		public ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<string> Language { get; }

		public ConfigEntry<bool> FullInformation { get; }

		public ConfigEntry<KeyboardShortcut> ToggleFullInformationKey { get; }

		public ConfigEntry<bool> InventoryTooltipEnabled { get; }

		public ConfigEntry<bool> WorldTooltipEnabled { get; }

		public ConfigEntry<bool> UseCustomTooltipCard { get; }

		public ConfigEntry<int> TooltipMaxWidth { get; }

		public RuntimeSettings(ConfigEntry<bool> enabled, ConfigEntry<string> language, ConfigEntry<bool> fullInformation, ConfigEntry<KeyboardShortcut> toggleFullInformationKey, ConfigEntry<bool> inventoryTooltipEnabled, ConfigEntry<bool> worldTooltipEnabled, ConfigEntry<bool> useCustomTooltipCard, ConfigEntry<int> tooltipMaxWidth)
		{
			Enabled = enabled;
			Language = language;
			FullInformation = fullInformation;
			ToggleFullInformationKey = toggleFullInformationKey;
			InventoryTooltipEnabled = inventoryTooltipEnabled;
			WorldTooltipEnabled = worldTooltipEnabled;
			UseCustomTooltipCard = useCustomTooltipCard;
			TooltipMaxWidth = tooltipMaxWidth;
		}
	}
	public sealed class RuntimeService
	{
		private readonly ConfigFile _config;

		private readonly ManualLogSource _log;

		private readonly RuntimeSettings _settings;

		private readonly Dictionary<TooltipLanguage, ItemResolver> _resolvers = new Dictionary<TooltipLanguage, ItemResolver>();

		private readonly Dictionary<string, ResolvedItemInfo> _cache = new Dictionary<string, ResolvedItemInfo>(StringComparer.OrdinalIgnoreCase);

		private readonly FontResolver _fontResolver = new FontResolver();

		private LanguageController? _languageController;

		private IWKLocAdapter? _wkLocAdapter;

		private FieldInfo? _uiManagerInstanceField;

		private MethodInfo? _setDescriptionMethod;

		private MethodInfo? _inventoryIsShowingMethod;

		private MethodInfo? _getLocalizationMethod;

		private TooltipCardView? _tooltipCard;

		private ToastView? _toastView;

		private MenuCreditsView? _menuCreditsView;

		private MenuLanguageButtonView? _menuLanguageButtonView;

		private ResolvedItemInfo? _currentInfo;

		private TooltipAnchorMode _currentMode;

		private Vector2 _currentAnchor;

		private bool _initializedAfterPluginLoad;

		private bool _hoverCallbackLogged;

		private bool _interactionBridgeLogged;

		private bool _nativeUiReadyLogged;

		private bool _hoverErrorLogged;

		private bool _menuCreditsFailed;

		private bool _menuCreditsLogged;

		private bool _menuLanguageButtonFailed;

		private bool _menuLanguageButtonLogged;

		private bool _customUiFailed;

		private bool _fontSourceLogged;

		private bool _customUiReadyLogged;

		private int _lastToggleFrame = -1;

		private int _lastInputFrame = -1;

		private int _lastHoverFrame = -1000;

		private string? _pendingToggleStatus;

		public static RuntimeService? Current { get; private set; }

		public TooltipLanguage CurrentLanguage => _languageController?.Current ?? TooltipLanguage.English;

		public RuntimeService(ConfigFile config, ManualLogSource log, string pluginAssemblyLocation, RuntimeSettings settings)
		{
			_config = config ?? throw new ArgumentNullException("config");
			_log = log ?? throw new ArgumentNullException("log");
			_settings = settings ?? throw new ArgumentNullException("settings");
			LocaleDatabaseLoader localeDatabaseLoader = new LocaleDatabaseLoader(pluginAssemblyLocation, ReadEmbeddedDatabase, delegate(string message)
			{
				_log.LogWarning((object)message);
			});
			ItemDatabase itemDatabase = localeDatabaseLoader.Load(TooltipLanguage.English);
			ItemDatabase itemDatabase2 = localeDatabaseLoader.Load(TooltipLanguage.Russian);
			LocalizedItemDatabaseRegistry localizedItemDatabaseRegistry = new LocalizedItemDatabaseRegistry(itemDatabase, itemDatabase2);
			_resolvers[TooltipLanguage.English] = new ItemResolver(localizedItemDatabaseRegistry.English, TooltipLanguage.English);
			_resolvers[TooltipLanguage.Russian] = new ItemResolver(localizedItemDatabaseRegistry.Russian, TooltipLanguage.Russian);
			_log.LogInfo((object)$"Item databases loaded: EN={itemDatabase.Count}, RU={itemDatabase2.Count} records.");
			ResolveNativeGameApi();
		}

		public static RuntimeService Install(RuntimeService service)
		{
			Current = service ?? throw new ArgumentNullException("service");
			return service;
		}

		public void InitializeAfterPluginLoad()
		{
			if (_initializedAfterPluginLoad)
			{
				return;
			}
			_initializedAfterPluginLoad = true;
			try
			{
				_wkLocAdapter = WKLocAdapter.DiscoverLoaded(delegate(string message)
				{
					_log.LogInfo((object)message);
				});
				_languageController = new LanguageController(() => _settings.Language.Value, delegate(string value)
				{
					_settings.Language.Value = value;
					_config.Save();
				}, _wkLocAdapter, ShowUserMessage, delegate(string message)
				{
					_log.LogWarning((object)message);
				}, RequestMainMenuReload);
				_languageController.Initialize();
				_log.LogInfo((object)$"Item Tooltips language: {_languageController.Current}.");
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"Language integration failed safely; English item tooltips will remain available: {arg}");
				_languageController = null;
			}
		}

		public void InteractionTick()
		{
			if (!_interactionBridgeLogged)
			{
				_interactionBridgeLogged = true;
				_log.LogInfo((object)"Interaction bridge is ticking through ENT_Player.InteractCheck(int).");
			}
			if (_settings.Enabled.Value)
			{
				TryToggleFullInformation();
			}
		}

		public void ItemHover(object itemObject)
		{
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			if (!_hoverCallbackLogged)
			{
				_hoverCallbackLogged = true;
				_log.LogInfo((object)"Native hover callback is firing from ENT_Player.InteractCheck call sites.");
			}
			if (!_settings.Enabled.Value || itemObject == null)
			{
				return;
			}
			try
			{
				bool flag = IsInventoryShowing();
				if ((flag && !_settings.InventoryTooltipEnabled.Value) || (!flag && !_settings.WorldTooltipEnabled.Value))
				{
					return;
				}
				TooltipLanguage currentLanguage = CurrentLanguage;
				if (!_resolvers.TryGetValue(currentLanguage, out ItemResolver value) || !WhiteKnuckleItemAdapter.TrySnapshot(itemObject, currentLanguage, out RuntimeItemSnapshot snapshot))
				{
					return;
				}
				FillNativeLocalizedDescription(snapshot);
				string text = ItemIdNormalizer.Normalize(snapshot.StableIdCandidate);
				if (string.IsNullOrWhiteSpace(text))
				{
					return;
				}
				string key = TooltipLanguageCodec.Serialize(currentLanguage) + ":" + text;
				if (!_cache.TryGetValue(key, out ResolvedItemInfo value2) || HasRicherRuntimeData(snapshot, value2))
				{
					value2 = value.Resolve(snapshot);
					_cache[key] = value2;
				}
				_lastHoverFrame = Time.frameCount;
				_currentInfo = value2;
				_currentMode = ((!flag) ? TooltipAnchorMode.World : TooltipAnchorMode.Inventory);
				_currentAnchor = (Vector2)(flag ? Vector2.op_Implicit(Input.mousePosition) : new Vector2((float)Screen.width * 0.5f, (float)Screen.height * 0.5f));
				if (_settings.UseCustomTooltipCard.Value && EnsureCustomUi())
				{
					TooltipDisplayModel model = TooltipFormatter.Format(value2, _settings.FullInformation.Value, currentLanguage);
					_tooltipCard.Show(model, _currentAnchor, _currentMode, _settings.TooltipMaxWidth.Value);
					if (!string.IsNullOrWhiteSpace(_pendingToggleStatus))
					{
						_toastView?.Show(_pendingToggleStatus);
						_pendingToggleStatus = null;
					}
					TrySetNativeDescription(string.Empty);
					if (!_customUiReadyLogged)
					{
						_customUiReadyLogged = true;
						_log.LogInfo((object)("Custom item tooltip card displayed successfully. First item: " + snapshot.StableIdCandidate + "."));
					}
				}
				else
				{
					string pendingToggleStatus = _pendingToggleStatus;
					_pendingToggleStatus = null;
					string text2 = NativeDescriptionFormatter.Format(value2, _settings.FullInformation.Value, currentLanguage, pendingToggleStatus);
					if (!string.IsNullOrWhiteSpace(text2) && TrySetNativeDescription(text2) && !_nativeUiReadyLogged)
					{
						_nativeUiReadyLogged = true;
						_log.LogInfo((object)("Native item tooltip displayed successfully. First item: " + snapshot.StableIdCandidate + "."));
					}
				}
			}
			catch (Exception arg)
			{
				if (!_hoverErrorLogged)
				{
					_hoverErrorLogged = true;
					_log.LogError((object)$"Native item hover handling failed; later hovers will keep retrying: {arg}");
				}
			}
		}

		public void Tick()
		{
			UpdateMenuCredits();
			_toastView?.Tick(Time.unscaledDeltaTime);
			TooltipCardView? tooltipCard = _tooltipCard;
			if (tooltipCard != null && tooltipCard.IsVisible && Time.frameCount - _lastHoverFrame > 1)
			{
				_tooltipCard.Hide();
				_currentInfo = null;
			}
		}

		public void SceneLoaded(string sceneName)
		{
			_currentInfo = null;
			_lastHoverFrame = -1000;
			_tooltipCard?.Hide();
			_log.LogDebug((object)("Item Tooltips runtime survived scene load: " + sceneName + "."));
		}

		public void ShutdownViews()
		{
			_tooltipCard?.Destroy();
			_toastView?.Destroy();
			_menuCreditsView?.Destroy();
			_menuLanguageButtonView?.Destroy();
			_tooltipCard = null;
			_toastView = null;
			_menuCreditsView = null;
			_menuLanguageButtonView = null;
		}

		private void ResolveNativeGameApi()
		{
			try
			{
				Type type = AccessTools.TypeByName("CL_UIManager");
				_uiManagerInstanceField = ((type == null) ? null : AccessTools.Field(type, "instance"));
				_setDescriptionMethod = ((type == null) ? null : AccessTools.Method(type, "SetDescription", new Type[1] { typeof(string) }, (Type[])null));
				Type type2 = AccessTools.TypeByName("Inventory");
				_inventoryIsShowingMethod = ((type2 == null) ? null : AccessTools.Method(type2, "IsShowingInventory", (Type[])null, (Type[])null));
				Type type3 = AccessTools.TypeByName("CL_LocalizationManager");
				_getLocalizationMethod = ((type3 == null) ? null : AccessTools.Method(type3, "GetLocalization", new Type[2]
				{
					typeof(string),
					typeof(string)
				}, (Type[])null));
				if (_uiManagerInstanceField == null || _setDescriptionMethod == null)
				{
					_log.LogWarning((object)"Native descriptor API was not fully resolved. Hover callbacks will still be logged for diagnosis.");
				}
				else
				{
					_log.LogInfo((object)"Native descriptor API resolved: CL_UIManager.SetDescription(string).");
				}
			}
			catch (Exception arg)
			{
				_log.LogError((object)$"Could not resolve White Knuckle native UI API: {arg}");
			}
		}

		private bool EnsureCustomUi()
		{
			if (_customUiFailed)
			{
				return false;
			}
			if (_tooltipCard != null)
			{
				return true;
			}
			try
			{
				ResolvedTooltipFont resolvedTooltipFont = _fontResolver.Resolve();
				_tooltipCard = new TooltipCardView(resolvedTooltipFont.Font);
				if (_toastView == null)
				{
					_toastView = new ToastView(resolvedTooltipFont.Font);
				}
				if (!_fontSourceLogged)
				{
					_fontSourceLogged = true;
					_log.LogInfo((object)("Tooltip font source: " + resolvedTooltipFont.Source + "."));
				}
				return true;
			}
			catch (Exception arg)
			{
				_customUiFailed = true;
				_log.LogError((object)$"Custom tooltip UI creation failed; native description fallback will be used: {arg}");
				return false;
			}
		}

		private void TryToggleFullInformation()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			int frameCount = Time.frameCount;
			if (_lastInputFrame == frameCount)
			{
				return;
			}
			_lastInputFrame = frameCount;
			KeyboardShortcut value = _settings.ToggleFullInformationKey.Value;
			KeyCode mainKey = ((KeyboardShortcut)(ref value)).MainKey;
			if ((int)mainKey == 0 || !Input.GetKeyDown(mainKey))
			{
				return;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
			{
				if (!Input.GetKey(modifier))
				{
					return;
				}
			}
			if (_lastToggleFrame != frameCount)
			{
				_lastToggleFrame = frameCount;
				_settings.FullInformation.Value = !_settings.FullInformation.Value;
				_config.Save();
				_cache.Clear();
				string text = LocalizedStrings.FullInformationStatus(CurrentLanguage, _settings.FullInformation.Value);
				TooltipCardView? tooltipCard = _tooltipCard;
				if (tooltipCard != null && tooltipCard.IsVisible && _currentInfo != null)
				{
					_tooltipCard.Refresh(TooltipFormatter.Format(_currentInfo, _settings.FullInformation.Value, CurrentLanguage));
					_toastView?.Show(text);
					_pendingToggleStatus = null;
				}
				else
				{
					_pendingToggleStatus = text;
				}
				_log.LogInfo((object)$"Full information toggled: {_settings.FullInformation.Value}.");
			}
		}

		private bool IsInventoryShowing()
		{
			try
			{
				object obj = _inventoryIsShowingMethod?.Invoke(null, null);
				if (obj is bool)
				{
					return (bool)obj;
				}
			}
			catch
			{
			}
			return false;
		}

		private void FillNativeLocalizedDescription(RuntimeItemSnapshot snapshot)
		{
			if (!string.IsNullOrWhiteSpace(snapshot.RuntimeSafeDescription) || _getLocalizationMethod == null || string.IsNullOrWhiteSpace(snapshot.StableIdCandidate))
			{
				return;
			}
			try
			{
				string text = _getLocalizationMethod.Invoke(null, new object[2]
				{
					"items",
					"desc-" + snapshot.StableIdCandidate
				}) as string;
				if (!string.IsNullOrWhiteSpace(text))
				{
					snapshot.RuntimeSafeDescription = text.Trim();
				}
			}
			catch
			{
			}
		}

		private bool TrySetNativeDescription(string text)
		{
			try
			{
				object obj = _uiManagerInstanceField?.GetValue(null);
				if (obj == null || _setDescriptionMethod == null)
				{
					return false;
				}
				_setDescriptionMethod.Invoke(obj, new object[1] { text });
				return true;
			}
			catch (Exception arg)
			{
				if (!_hoverErrorLogged)
				{
					_hoverErrorLogged = true;
					_log.LogError((object)$"CL_UIManager.SetDescription failed: {arg}");
				}
				return false;
			}
		}

		private static bool HasRicherRuntimeData(RuntimeItemSnapshot snapshot, ResolvedItemInfo cached)
		{
			int num = 0;
			foreach (ItemStat stat in cached.Stats)
			{
				if (stat.Source == ItemStatSource.Runtime)
				{
					num++;
				}
			}
			return snapshot.Stats.Count > num;
		}

		private void UpdateMenuCredits()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			if (!MenuCreditsContent.IsMainMenuScene(((Scene)(ref activeScene)).name))
			{
				_menuCreditsView?.SetVisible(visible: false);
				_menuLanguageButtonView?.SetVisible(visible: false);
				return;
			}
			Font val = null;
			if ((_menuCreditsView == null && !_menuCreditsFailed) || (_menuLanguageButtonView == null && !_menuLanguageButtonFailed) || _toastView == null)
			{
				try
				{
					val = _fontResolver.Resolve().Font;
				}
				catch (Exception ex)
				{
					_log.LogWarning((object)("Main-menu UI font could not be resolved: " + ex.Message));
				}
			}
			if (_menuCreditsView == null && !_menuCreditsFailed && (Object)(object)val != (Object)null)
			{
				try
				{
					_menuCreditsView = new MenuCreditsView(val);
					if (!_menuCreditsLogged)
					{
						_menuCreditsLogged = true;
						_log.LogInfo((object)"Main-menu credit enabled for KoshGamer / twitch.tv/koshgamer.");
					}
				}
				catch (Exception ex2)
				{
					_menuCreditsFailed = true;
					_log.LogWarning((object)("Main-menu credit UI could not be created; item tooltips remain enabled: " + ex2.Message));
				}
			}
			if (_menuLanguageButtonView == null && !_menuLanguageButtonFailed && _languageController != null && (Object)(object)val != (Object)null)
			{
				try
				{
					_menuLanguageButtonView = new MenuLanguageButtonView(val, OnLanguageButtonClicked);
					_menuLanguageButtonView.SetLanguage(_languageController.Current);
					if (!_menuLanguageButtonLogged)
					{
						_menuLanguageButtonLogged = true;
						_log.LogInfo((object)"Main-menu LANGUAGE button enabled.");
					}
				}
				catch (Exception ex3)
				{
					_menuLanguageButtonFailed = true;
					_log.LogWarning((object)("Main-menu language button could not be created; language remains configurable through saved state: " + ex3.Message));
				}
			}
			if (_toastView == null && (Object)(object)val != (Object)null)
			{
				try
				{
					_toastView = new ToastView(val);
				}
				catch (Exception ex4)
				{
					_log.LogWarning((object)("Menu toast UI could not be created: " + ex4.Message));
				}
			}
			_menuCreditsView?.SetVisible(visible: true);
			if (_languageController != null)
			{
				_menuLanguageButtonView?.SetLanguage(_languageController.Current);
				_menuLanguageButtonView?.SetVisible(visible: true);
			}
		}

		private void OnLanguageButtonClicked()
		{
			_languageController?.TryToggle();
		}

		private void ShowUserMessage(string message)
		{
			if (_toastView == null)
			{
				try
				{
					Font font = _fontResolver.Resolve().Font;
					_toastView = new ToastView(font);
				}
				catch (Exception ex)
				{
					_log.LogWarning((object)("Could not show language message in UI: " + ex.Message));
				}
			}
			if (_toastView != null)
			{
				_toastView.Show(message, 2.2f);
			}
			else
			{
				_log.LogWarning((object)message);
			}
		}

		private void RequestMainMenuReload()
		{
			_cache.Clear();
			_currentInfo = null;
			_tooltipCard?.Hide();
			_log.LogInfo((object)$"Language switched to {CurrentLanguage}; reloading Main-Menu.");
			SceneManager.LoadScene("Main-Menu");
		}

		private string? ReadEmbeddedDatabase(string fileName)
		{
			string text = "WhiteKnuckleItemTooltips.Data." + fileName;
			try
			{
				using Stream stream = typeof(RuntimeService).Assembly.GetManifestResourceStream(text);
				if (stream == null)
				{
					return null;
				}
				using StreamReader streamReader = new StreamReader(stream);
				return streamReader.ReadToEnd();
			}
			catch (Exception ex)
			{
				_log.LogWarning((object)("Could not read embedded item database '" + text + "': " + ex.Message));
				return null;
			}
		}
	}
	public static class WhiteKnuckleItemAdapter
	{
		private sealed class ReferenceComparer : IEqualityComparer<object>
		{
			public static readonly ReferenceComparer Instance = new ReferenceComparer();

			public new bool Equals(object? x, object? y)
			{
				return x == y;
			}

			public int GetHashCode(object obj)
			{
				return RuntimeHelpers.GetHashCode(obj);
			}
		}

		private static readonly string[] ItemWrapperMembers = new string[6] { "itemData", "item", "currentItem", "Raw", "pickupItem", "pickupable" };

		private static readonly string[] EffectWrapperMembers = new string[6] { "handItemAsset", "handItem", "buff", "buffContainer", "effect", "effects" };

		public static bool TrySnapshot(object? source, out RuntimeItemSnapshot snapshot)
		{
			return TrySnapshot(source, TooltipLanguage.Russian, out snapshot);
		}

		public static bool TrySnapshot(object? source, TooltipLanguage language, out RuntimeItemSnapshot snapshot)
		{
			snapshot = new RuntimeItemSnapshot();
			if (source == null)
			{
				return false;
			}
			if (!TryFindItemData(source, out object itemData))
			{
				return false;
			}
			string text = ReadString(itemData, "prefabName");
			if (string.IsNullOrWhiteSpace(text))
			{
				return false;
			}
			snapshot.StableIdCandidate = text.Trim();
			snapshot.RuntimeName = FirstUseful(ReadString(itemData, "itemName"), ReadString(itemData, "displayName"));
			snapshot.RuntimeCategory = FirstUseful(ReadString(itemData, "itemTag"), ReadFirstStringFromEnumerable(itemData, "itemTags"), ReadFirstStringFromEnumerable(itemData, "tags"));
			snapshot.RuntimeSafeDescription = FirstUseful(ReadString(itemData, "itemDescription"), ReadString(itemData, "description"), ReadString(itemData, "desc"));
			snapshot.Weight = ReadNullableFloat(itemData, "itemWeight") ?? ReadNullableFloat(itemData, "weight");
			snapshot.Worth = ReadNullableInt(itemData, "worth") ?? ReadNullableInt(itemData, "value");
			snapshot.Pocketable = ReadNullableBool(itemData, "pocketable");
			snapshot.Pouchable = ReadNullableBool(itemData, "pouchable");
			snapshot.RuntimeObject = itemData;
			ExtractConfiguredStats(itemData, snapshot.Stats, language);
			return true;
		}

		private static bool TryFindItemData(object source, out object itemData)
		{
			Queue<(object, int)> queue = new Queue<(object, int)>();
			HashSet<object> hashSet = new HashSet<object>(ReferenceComparer.Instance);
			EnqueueUnityContext(source, queue, 0);
			queue.Enqueue((source, 0));
			while (queue.Count > 0)
			{
				var (obj, num) = queue.Dequeue();
				if (obj == null || !hashSet.Add(obj))
				{
					continue;
				}
				if (LooksLikeItemData(obj))
				{
					itemData = obj;
					return true;
				}
				if (num >= 4)
				{
					continue;
				}
				string[] itemWrapperMembers = ItemWrapperMembers;
				foreach (string memberName in itemWrapperMembers)
				{
					if (TryReadMember(obj, memberName, out object value) && value != null)
					{
						queue.Enqueue((value, num + 1));
					}
				}
				EnqueueUnityContext(obj, queue, num + 1);
			}
			itemData = null;
			return false;
		}

		private static void EnqueueUnityContext(object source, Queue<(object Value, int Depth)> queue, int depth)
		{
			try
			{
				Type type = Type.GetType("UnityEngine.GameObject, UnityEngine.CoreModule", throwOnError: false);
				Type type2 = Type.GetType("UnityEngine.Component, UnityEngine.CoreModule", throwOnError: false);
				if ((object)type == null || (object)type2 == null)
				{
					return;
				}
				if (type.IsInstanceOfType(source))
				{
					EnqueueGameObjectComponents(source, type2, queue, depth);
					EnqueueParentGameObject(source, queue, depth + 1);
				}
				else if (type2.IsInstanceOfType(source))
				{
					if (TryReadMember(source, "gameObject", out object value) && value != null)
					{
						queue.Enqueue((value, depth));
					}
					EnqueueParentGameObject(source, queue, depth + 1);
				}
			}
			catch
			{
			}
		}

		private static void EnqueueGameObjectComponents(object gameObject, Type componentType, Queue<(object Value, int Depth)> queue, int depth)
		{
			try
			{
				if (!(gameObject.GetType().GetMethod("GetComponents", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(Type) }, null)?.Invoke(gameObject, new object[1] { componentType }) is IEnumerable enumerable))
				{
					return;
				}
				foreach (object item in enumerable)
				{
					if (item != null)
					{
						queue.Enqueue((item, depth));
					}
				}
			}
			catch
			{
			}
		}

		private static void EnqueueParentGameObject(object source, Queue<(object Value, int Depth)> queue, int depth)
		{
			if (TryReadMember(source, "transform", out object value) && value != null && TryReadMember(value, "parent", out object value2) && value2 != null && TryReadMember(value2, "gameObject", out object value3) && value3 != null)
			{
				queue.Enqueue((value3, depth));
			}
		}

		private static void ExtractConfiguredStats(object itemData, List<ItemStat> destination, TooltipLanguage language)
		{
			List<object> list = FindBuffContainers(itemData);
			if (list.Count == 0)
			{
				return;
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			foreach (object item in list)
			{
				ExtractDuration(item, destination, hashSet, language);
				if (!TryReadMember(item, "buffs", out object value) || !(value is IEnumerable enumerable))
				{
					continue;
				}
				foreach (object item2 in enumerable)
				{
					if (item2 == null)
					{
						continue;
					}
					string text = ReadString(item2, "id");
					if (!string.IsNullOrWhiteSpace(text))
					{
						float valueOrDefault = ReadNullableFloat(item2, "maxAmount").GetValueOrDefault();
						if (Math.Abs(valueOrDefault) < 1E-05f)
						{
							valueOrDefault = ReadNullableFloat(item2, "amount").GetValueOrDefault();
						}
						if (TryFormatBuff(text, valueOrDefault, language, out string label, out string value2) && hashSet.Add(label))
						{
							destination.Add(new ItemStat(label, value2, ItemStatSource.Runtime));
						}
					}
				}
			}
		}

		private static List<object> FindBuffContainers(object itemData)
		{
			List<object> list = new List<object>();
			Queue<(object, int)> queue = new Queue<(object, int)>();
			HashSet<object> hashSet = new HashSet<object>(ReferenceComparer.Instance);
			queue.Enqueue((itemData, 0));
			while (queue.Count > 0)
			{
				var (obj, num) = queue.Dequeue();
				if (obj == null || !hashSet.Add(obj))
				{
					continue;
				}
				if (LooksLikeBuffContainer(obj))
				{
					list.Add(obj);
				}
				else
				{
					if (num >= 4)
					{
						continue;
					}
					string[] effectWrapperMembers = EffectWrapperMembers;
					foreach (string memberName in effectWrapperMembers)
					{
						if (!TryReadMember(obj, memberName, out object value) || value == null)
						{
							continue;
						}
						Type type = Type.GetType("UnityEngine.GameObject, UnityEngine.CoreModule", throwOnError: false);
						Type type2 = Type.GetType("UnityEngine.Component, UnityEngine.CoreModule", throwOnError: false);
						if ((object)type != null && (object)type2 != null && type.IsInstanceOfType(value))
						{
							EnqueueGameObjectComponents(value, type2, queue, num + 1);
						}
						else if (value is IEnumerable enumerable && !(value is string))
						{
							foreach (object item in enumerable)
							{
								if (item != null)
								{
									queue.Enqueue((item, num + 1));
								}
							}
						}
						else
						{
							queue.Enqueue((value, num + 1));
						}
					}
				}
			}
			return list;
		}

		private static bool LooksLikeItemData(object candidate)
		{
			if (string.IsNullOrWhiteSpace(ReadString(candidate, "prefabName")))
			{
				return false;
			}
			string name = candidate.GetType().Name;
			if (!string.Equals(name, "Item", StringComparison.OrdinalIgnoreCase) && !string.Equals(name, "ItemData", StringComparison.OrdinalIgnoreCase) && !HasMember(candidate, "itemName") && !HasMember(candidate, "itemWeight") && !HasMember(candidate, "handItemAsset") && !HasMember(candidate, "pocketable"))
			{
				return HasMember(candidate, "pouchable");
			}
			return true;
		}

		private static bool LooksLikeBuffContainer(object candidate)
		{
			if (HasMember(candidate, "buffTime") && HasMember(candidate, "loseRate") && TryReadMember(candidate, "buffs", out object value))
			{
				return value is IEnumerable;
			}
			return false;
		}

		private static void ExtractDuration(object container, List<ItemStat> destination, HashSet<string> seenLabels, TooltipLanguage language)
		{
			if (!(ReadNullableBool(container, "loseOverTime") ?? true))
			{
				return;
			}
			float? num = ReadNullableFloat(container, "buffTime");
			float? num2 = ReadNullableFloat(container, "loseRate");
			if (!num.HasValue || !num2.HasValue || num.Value <= 0f || num2.Value <= 0f)
			{
				return;
			}
			float num3 = num.Value / num2.Value;
			if (!float.IsNaN(num3) && !float.IsInfinity(num3) && !(num3 <= 0f) && !(num3 > 86400f))
			{
				string text = LocalizedStrings.BaseDurationLabel(language);
				if (seenLabels.Add(text))
				{
					destination.Add(new ItemStat(text, FormatSeconds(num3, language), ItemStatSource.Runtime));
				}
			}
		}

		private static bool TryFormatBuff(string id, float amount, TooltipLanguage language, out string label, out string value)
		{
			label = LocalizedStrings.BuffLabel(id.Trim(), language);
			value = string.Empty;
			if (label.Length == 0)
			{
				return false;
			}
			string text = id.Trim();
			if (!(text == "addExtraJumps"))
			{
				if (text == "grabAnything")
				{
					value = LocalizedStrings.AnySurfaces(language);
					return true;
				}
				value = FormatPercent(amount, language);
				return true;
			}
			value = FormatSignedNumber(amount, language);
			return true;
		}

		private static string FormatPercent(float amount, TooltipLanguage language)
		{
			float num = amount * 100f;
			string text = FormatNumber(Math.Abs(num), language);
			return ((num > 0.0001f) ? "+" : ((num < -0.0001f) ? "-" : string.Empty)) + text + "%";
		}

		private static string FormatSignedNumber(float amount, TooltipLanguage language)
		{
			return ((amount > 0.0001f) ? "+" : ((amount < -0.0001f) ? "-" : string.Empty)) + FormatNumber(Math.Abs(amount), language);
		}

		private static string FormatSeconds(float seconds, TooltipLanguage language)
		{
			return FormatNumber(seconds, language) + LocalizedStrings.SecondsSuffix(language);
		}

		private static string FormatNumber(float number, TooltipLanguage language)
		{
			float num = MathF.Round(number);
			if (Math.Abs(number - num) < 0.005f)
			{
				return num.ToString("0", CultureInfo.InvariantCulture);
			}
			string text = number.ToString("0.##", CultureInfo.InvariantCulture);
			if (language != TooltipLanguage.Russian)
			{
				return text;
			}
			return text.Replace('.', ',');
		}

		private static string ReadString(object source, string memberName)
		{
			if (!TryReadMember(source, memberName, out object value) || value == null)
			{
				return string.Empty;
			}
			return (value as string) ?? value.ToString() ?? string.Empty;
		}

		private static string ReadFirstStringFromEnumerable(object source, string memberName)
		{
			if (!TryReadMember(source, memberName, out object value) || !(value is IEnumerable enumerable) || value is string)
			{
				return string.Empty;
			}
			foreach (object item in enumerable)
			{
				string text = item?.ToString();
				if (!string.IsNullOrWhiteSpace(text))
				{
					return text.Trim();
				}
			}
			return string.Empty;
		}

		private static float? ReadNullableFloat(object source, string memberName)
		{
			if (!TryReadMember(source, memberName, out object value) || value == null)
			{
				return null;
			}
			try
			{
				return Convert.ToSingle(value, CultureInfo.InvariantCulture);
			}
			catch
			{
				return null;
			}
		}

		private static int? ReadNullableInt(object source, string memberName)
		{
			if (!TryReadMember(source, memberName, out object value) || value == null)
			{
				return null;
			}
			try
			{
				return Convert.ToInt32(value, CultureInfo.InvariantCulture);
			}
			catch
			{
				return null;
			}
		}

		private static bool? ReadNullableBool(object source, string memberName)
		{
			if (!TryReadMember(source, memberName, out object value) || value == null)
			{
				return null;
			}
			try
			{
				return Convert.ToBoolean(value, CultureInfo.InvariantCulture);
			}
			catch
			{
				return null;
			}
		}

		private static string FirstUseful(params string[] candidates)
		{
			foreach (string text in candidates)
			{
				if (!string.IsNullOrWhiteSpace(text))
				{
					return text.Trim();
				}
			}
			return string.Empty;
		}

		private static bool HasMember(object source, string memberName)
		{
			Type type = source.GetType();
			if (type.GetField(memberName, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null)
			{
				return true;
			}
			PropertyInfo property = type.GetProperty(memberName, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null)
			{
				return property.GetIndexParameters().Length == 0;
			}
			return false;
		}

		private static bool TryReadMember(object source, string memberName, out object? value)
		{
			value = null;
			if (source == null)
			{
				return false;
			}
			try
			{
				Type type = source.GetType();
				FieldInfo field = type.GetField(memberName, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					value = field.GetValue(source);
					return true;
				}
				PropertyInfo property = type.GetProperty(memberName, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && property.GetIndexParameters().Length == 0 && property.CanRead)
				{
					value = property.GetValue(source, null);
					return true;
				}
			}
			catch
			{
			}
			return false;
		}
	}
}
namespace WhiteKnuckleItemTooltips.Localization
{
	public sealed class LanguageController
	{
		public const string MissingWKLocMessage = "Russian localization requires WKLoc";

		private readonly Func<string?> _loadSaved;

		private readonly Action<string> _save;

		private readonly IWKLocAdapter _wkLoc;

		private readonly Action<string> _showUserMessage;

		private readonly Action<string> _logDiagnostic;

		private readonly Action _requestMainMenuReload;

		public TooltipLanguage Current { get; private set; }

		public LanguageController(Func<string?> loadSaved, Action<string> save, IWKLocAdapter wkLoc, Action<string> showUserMessage, Action<string> logDiagnostic, Action requestMainMenuReload)
		{
			_loadSaved = loadSaved ?? throw new ArgumentNullException("loadSaved");
			_save = save ?? throw new ArgumentNullException("save");
			_wkLoc = wkLoc ?? throw new ArgumentNullException("wkLoc");
			_showUserMessage = showUserMessage ?? throw new ArgumentNullException("showUserMessage");
			_logDiagnostic = logDiagnostic ?? throw new ArgumentNullException("logDiagnostic");
			_requestMainMenuReload = requestMainMenuReload ?? throw new ArgumentNullException("requestMainMenuReload");
		}

		public void Initialize()
		{
			if (!TooltipLanguageCodec.TryParse(_loadSaved(), out var language))
			{
				Current = (_wkLoc.IsAvailable ? TooltipLanguage.Russian : TooltipLanguage.English);
				bool flag = false;
				if (Current == TooltipLanguage.Russian)
				{
					if (!TrySynchronizeWKLoc(enabled: true, out var changed))
					{
						Current = TooltipLanguage.English;
						_logDiagnostic("WKLoc was detected but could not be enabled during language initialization; falling back to English.");
					}
					else
					{
						flag = changed;
					}
				}
				SaveCurrent();
				if (flag)
				{
					_requestMainMenuReload();
				}
			}
			else if (language == TooltipLanguage.Russian)
			{
				if (!_wkLoc.IsAvailable || !TrySynchronizeWKLoc(enabled: true, out var changed2))
				{
					Current = TooltipLanguage.English;
					SaveCurrent();
					_logDiagnostic("Saved Russian language could not be restored because compatible WKLoc is unavailable; recovered to English.");
					return;
				}
				Current = TooltipLanguage.Russian;
				if (changed2)
				{
					_requestMainMenuReload();
				}
			}
			else
			{
				Current = TooltipLanguage.English;
				bool changed3 = default(bool);
				if (_wkLoc.IsAvailable && TrySynchronizeWKLoc(enabled: false, out changed3) && changed3)
				{
					_requestMainMenuReload();
				}
			}
		}

		public bool TryToggle()
		{
			if (Current == TooltipLanguage.English)
			{
				return TrySwitchToRussian();
			}
			return TrySwitchToEnglish();
		}

		private bool TrySwitchToRussian()
		{
			if (!_wkLoc.IsAvailable)
			{
				_showUserMessage("Russian localization requires WKLoc");
				return false;
			}
			if (!_wkLoc.TrySetTranslationEnabled(enabled: true, out bool _, out string diagnostic))
			{
				_logDiagnostic(diagnostic);
				_showUserMessage("Russian localization requires WKLoc");
				return false;
			}
			Current = TooltipLanguage.Russian;
			SaveCurrent();
			_requestMainMenuReload();
			return true;
		}

		private bool TrySwitchToEnglish()
		{
			if (_wkLoc.IsAvailable && !_wkLoc.TrySetTranslationEnabled(enabled: false, out bool _, out string diagnostic))
			{
				_logDiagnostic(diagnostic);
				return false;
			}
			Current = TooltipLanguage.English;
			SaveCurrent();
			_requestMainMenuReload();
			return true;
		}

		private bool TrySynchronizeWKLoc(bool enabled, out bool changed)
		{
			changed = false;
			if (!_wkLoc.IsAvailable)
			{
				return false;
			}
			if (_wkLoc.