Decompiled source of RamCraftFilterModLabels v0.3.21

RamCraftFilterModLabels.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Utils;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace JustinRampage.ModOrigin;

[BepInPlugin("justinrampage.modorigin", "RamCraftFilterModLabels", "0.3.21")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class ModOriginPlugin : BaseUnityPlugin
{
	[Serializable]
	[CompilerGenerated]
	private sealed class <>c
	{
		public static readonly <>c <>9 = new <>c();

		public static UnityAction <>9__50_0;

		public static UnityAction <>9__50_1;

		internal void <CreateControl>b__50_0()
		{
			OpenPopup(showSources: true);
		}

		internal void <CreateControl>b__50_1()
		{
			OpenPopup(showSources: false);
		}
	}

	public const string PluginGuid = "justinrampage.modorigin";

	private Harmony harmony;

	private static ConfigEntry<bool> previewNew;

	private static Player discoveryOwner;

	private static string persistenceFile;

	private static readonly HashSet<string> NewlyDiscoveredNames = new HashSet<string>(StringComparer.Ordinal);

	private static readonly HashSet<string> PreviewDismissedNames = new HashSet<string>(StringComparer.Ordinal);

	private static readonly HashSet<string> PreviewTargetNames = new HashSet<string>(StringComparer.Ordinal);

	private static string activeViewedRecipeKey;

	private static RecipeRowNewMarker activeViewedRecipeRow;

	private static readonly HashSet<string> KeepAtTopUntilMenuClose = new HashSet<string>(StringComparer.Ordinal);

	internal static ModOriginPlugin Instance;

	internal static string Selection = "All";

	internal static string TypeSelection = "All";

	internal static readonly List<string> AvailableSources = new List<string>();

	internal static readonly List<string> AvailableTypes = new List<string>();

	internal static bool UiReady;

	private static readonly HashSet<string> VanillaItemNames = new HashSet<string>(StringComparer.Ordinal);

	private static GameObject sourceControl;

	private static GameObject typeControl;

	private static GameObject overlayRoot;

	private static RectTransform adjustedViewport;

	private static Vector2 originalOffsetMax;

	private static TextMeshProUGUI sourceLabel;

	private static TextMeshProUGUI typeLabel;

	private static InventoryGui gui;

	private static int padFilterFocus = -1;

	private static bool padPopupOpen;

	private static int padOptionIndex;

	private static readonly List<string> padOptionChoices = new List<string>();

	private static readonly List<Image> padOptionBackgrounds = new List<Image>();

	private static MethodInfo zPadDown;

	private static MethodInfo zPadActive;

	private static MethodInfo zPadReset;

	private static bool padInputResolved;

	private static bool padWarningLogged;

	private static bool benchStartFilterPending;

	private static bool suppressAutomaticRecipeViewing;

	private static Button guardedStyleButton;

	private static bool styleWasInteractable;

	private static bool localizationSearched;

	private static MethodInfo localizationLocalize;

	private static FieldInfo localizationInstanceField;

	private static PropertyInfo localizationInstanceProperty;

	private const string TmpNewPrefix = "<color=#39FF14><b>*</b></color> ";

	private const string LegacyNewPrefix = "<color=#39FF14><b>*</b></color> ";

	private const string PriorSmallStarPrefix = "<color=#A3CE3C><size=85%><b>*</b></size></color> ";

	private const string PriorStarPrefix = "<color=#A3CE3C><b>*</b></color> ";

	private const string PriorTmpNewPrefix = "<color=#A3CE3C><size=75%><b>NEW</b></size></color> ";

	private const string PriorLegacyNewPrefix = "<color=#A3CE3C><b>NEW</b></color> ";

	private void Awake()
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Expected O, but got Unknown
		Instance = this;
		ModQuery.Enable();
		previewNew = ((BaseUnityPlugin)this).Config.Bind<bool>("Testing", "PreviewNewMarkers", false, "Temporary visual test: show a green * on the first three available crafting recipes. Does not unlock recipes or change character progression. Disable after testing.");
		harmony = new Harmony("justinrampage.modorigin");
		harmony.PatchAll(typeof(ModOriginPlugin).Assembly);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"RamCraftFilterModLabels 0.3.21 loaded: TMP font initialization fix; 0.3.20 features preserved.");
	}

	private void OnDestroy()
	{
		ResetUi();
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		Instance = null;
	}

	internal static void CaptureVanillaItems(ObjectDB source)
	{
		if (VanillaItemNames.Count != 0 || (Object)(object)source == (Object)null || source.m_items == null || source.m_items.Count < 100)
		{
			return;
		}
		foreach (GameObject item in source.m_items)
		{
			if ((Object)(object)item != (Object)null && !string.IsNullOrEmpty(((Object)item).name))
			{
				string text = ((Object)item).name;
				if (text.EndsWith("(Clone)", StringComparison.Ordinal))
				{
					text = text.Substring(0, text.Length - 7);
				}
				VanillaItemNames.Add(text);
			}
		}
		if ((Object)(object)Instance != (Object)null)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)("Captured " + VanillaItemNames.Count + " original item prefab names for Valheim attribution."));
		}
	}

	public static string SourceForItem(ItemData item)
	{
		if (item == null || (Object)(object)item.m_dropPrefab == (Object)null)
		{
			return "Unknown";
		}
		return SourceForPrefab(((Object)item.m_dropPrefab).name);
	}

	public static string SourceForPrefab(string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return "Unknown";
		}
		if (name.EndsWith("(Clone)", StringComparison.Ordinal))
		{
			name = name.Substring(0, name.Length - 7);
		}
		try
		{
			IModPrefab prefab = ModQuery.GetPrefab(name);
			if (prefab != null && prefab.SourceMod != null && !string.IsNullOrEmpty(prefab.SourceMod.Name))
			{
				string name2 = prefab.SourceMod.Name;
				if (name2.Equals("Valheim", StringComparison.OrdinalIgnoreCase) || name2.Equals("IronGate", StringComparison.OrdinalIgnoreCase) || name2.Equals("Iron Gate", StringComparison.OrdinalIgnoreCase))
				{
					return "Valheim";
				}
				return name2;
			}
		}
		catch (Exception ex)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogDebug((object)("Source lookup: " + ex.Message));
			}
		}
		if (VanillaItemNames.Contains(name))
		{
			return "Valheim";
		}
		return "Unknown";
	}

	private static string SourceForRecipe(Recipe recipe)
	{
		if ((Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null)
		{
			return "Unknown";
		}
		return SourceForPrefab(((Object)recipe.m_item).name);
	}

	private static string FilterLabel(string choice, bool isSource)
	{
		if (!(choice == "All"))
		{
			return choice;
		}
		if (!isSource)
		{
			return "Type (All)";
		}
		return "Source (All)";
	}

	private static bool UiBelongsTo(InventoryGui current)
	{
		if (UiReady && (Object)(object)current != (Object)null && (Object)(object)gui == (Object)(object)current && (Object)(object)typeControl != (Object)null && (Object)(object)sourceControl != (Object)null && (Object)(object)overlayRoot != (Object)null)
		{
			return (Object)(object)adjustedViewport != (Object)null;
		}
		return false;
	}

	private static void ReleaseUiFromOldSession(InventoryGui current)
	{
		if (UiReady && !UiBelongsTo(current))
		{
			EndCraftingMenuSession();
			ResetUi();
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)"Crafting UI session changed; rebuilding filters for current character.");
			}
		}
	}

	internal static void EnsureUi(InventoryGui current)
	{
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_016f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Expected O, but got Unknown
		//IL_0239: 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)
		//IL_023f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0249: Unknown result type (might be due to invalid IL or missing references)
		//IL_024a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0254: Unknown result type (might be due to invalid IL or missing references)
		//IL_0255: Unknown result type (might be due to invalid IL or missing references)
		//IL_025f: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)current == (Object)null)
		{
			return;
		}
		ReleaseUiFromOldSession(current);
		if (UiReady)
		{
			return;
		}
		try
		{
			RectTransform value = Traverse.Create((object)current).Field("m_recipeListRoot").GetValue<RectTransform>();
			object value2 = Traverse.Create((object)current).Field("m_tabCraft").GetValue();
			Component val = (Component)((value2 is Component) ? value2 : null);
			if ((Object)(object)value == (Object)null || (Object)(object)val == (Object)null || (Object)(object)((Transform)value).parent == (Object)null || (Object)(object)val.transform.parent == (Object)null)
			{
				throw new InvalidOperationException("Crafting UI anchors not found");
			}
			Transform parent = ((Transform)value).parent;
			RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			Transform parent2 = val.transform.parent;
			RectTransform val3 = (RectTransform)(object)((parent2 is RectTransform) ? parent2 : null);
			Transform transform = val.transform;
			RectTransform val4 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val2 == (Object)(object)val3)
			{
				throw new InvalidOperationException("Crafting panel structure not supported");
			}
			TMP_Text componentInChildren = ((Component)current).GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren == (Object)null || (Object)(object)componentInChildren.font == (Object)null)
			{
				throw new InvalidOperationException("Existing Valheim TMP font not found");
			}
			Canvas componentInParent = ((Component)val3).GetComponentInParent<Canvas>();
			if ((Object)(object)componentInParent == (Object)null || (Object)(object)componentInParent.rootCanvas == (Object)null)
			{
				throw new InvalidOperationException("Root Canvas missing; popup cannot be shown safely");
			}
			gui = current;
			adjustedViewport = val2;
			originalOffsetMax = val2.offsetMax;
			val2.offsetMax = new Vector2(val2.offsetMax.x, val2.offsetMax.y - 29f);
			typeControl = CreateControl(val3, val2, componentInChildren, FilterLabel(TypeSelection, isSource: false), 0f, isSource: false);
			sourceControl = CreateControl(val3, val2, componentInChildren, FilterLabel(Selection, isSource: true), 82f, isSource: true);
			typeLabel = typeControl.GetComponentInChildren<TextMeshProUGUI>(true);
			sourceLabel = sourceControl.GetComponentInChildren<TextMeshProUGUI>(true);
			overlayRoot = new GameObject("RamCraftFilterModLabelsOptionsCanvas", new Type[3]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(GraphicRaycaster)
			});
			overlayRoot.transform.SetParent(((Component)componentInParent.rootCanvas).transform, false);
			RectTransform val5 = (RectTransform)overlayRoot.transform;
			val5.anchorMin = Vector2.zero;
			val5.anchorMax = Vector2.one;
			val5.offsetMin = Vector2.zero;
			val5.offsetMax = Vector2.zero;
			Canvas component = overlayRoot.GetComponent<Canvas>();
			component.overrideSorting = true;
			component.sortingOrder = 15000;
			overlayRoot.SetActive(false);
			UiReady = true;
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)"RamCraftFilterModLabels controls ready; root Canvas dropdown enabled.");
			}
		}
		catch (Exception ex)
		{
			ResetUi();
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)("Crafting filters unavailable; original recipe list preserved: " + ex));
			}
		}
	}

	private static GameObject CreateControl(RectTransform parent, RectTransform viewport, TMP_Text fontSample, string title, float xOffset, bool isSource)
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Expected O, but got Unknown
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: 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)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		//IL_0162: Unknown result type (might be due to invalid IL or missing references)
		//IL_0167: Unknown result type (might be due to invalid IL or missing references)
		//IL_016d: Expected O, but got Unknown
		//IL_0131: Unknown result type (might be due to invalid IL or missing references)
		//IL_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: Expected O, but got Unknown
		GameObject val = new GameObject(isSource ? "RamSourceFilter" : "RamItemTypeFilter", new Type[3]
		{
			typeof(RectTransform),
			typeof(Image),
			typeof(Button)
		});
		val.transform.SetParent((Transform)(object)parent, false);
		RectTransform val2 = (RectTransform)val.transform;
		val2.anchorMin = Vector2.zero;
		val2.anchorMax = Vector2.zero;
		val2.pivot = Vector2.zero;
		val2.sizeDelta = new Vector2(81f, 24f);
		Vector3[] array = (Vector3[])(object)new Vector3[4];
		viewport.GetWorldCorners(array);
		Vector3 val3 = ((Transform)parent).InverseTransformPoint(array[1]);
		float x = val3.x;
		Rect rect = parent.rect;
		float num = x - ((Rect)(ref rect)).xMin + xOffset;
		float y = val3.y;
		rect = parent.rect;
		val2.anchoredPosition = new Vector2(num, y - ((Rect)(ref rect)).yMin + 2f);
		((Graphic)val.GetComponent<Image>()).color = new Color(0.12f, 0.1f, 0.08f, 0.96f);
		if (isSource)
		{
			ButtonClickedEvent onClick = val.GetComponent<Button>().onClick;
			object obj = <>c.<>9__50_0;
			if (obj == null)
			{
				UnityAction val4 = delegate
				{
					OpenPopup(showSources: true);
				};
				<>c.<>9__50_0 = val4;
				obj = (object)val4;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj);
		}
		else
		{
			ButtonClickedEvent onClick2 = val.GetComponent<Button>().onClick;
			object obj2 = <>c.<>9__50_1;
			if (obj2 == null)
			{
				UnityAction val5 = delegate
				{
					OpenPopup(showSources: false);
				};
				<>c.<>9__50_1 = val5;
				obj2 = (object)val5;
			}
			((UnityEvent)onClick2).AddListener((UnityAction)obj2);
		}
		CreateLabel(val.transform, fontSample, title);
		return val;
	}

	private static TextMeshProUGUI CreateLabel(Transform parent, TMP_Text fontSample, string value)
	{
		//IL_0018: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Expected O, but got Unknown
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: 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_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("Text", new Type[1] { typeof(RectTransform) });
		val.SetActive(false);
		val.transform.SetParent(parent, false);
		RectTransform val2 = (RectTransform)val.transform;
		val2.anchorMin = Vector2.zero;
		val2.anchorMax = Vector2.one;
		val2.offsetMin = new Vector2(3f, 0f);
		val2.offsetMax = new Vector2(-2f, 0f);
		TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>();
		((TMP_Text)obj).font = fontSample.font;
		((TMP_Text)obj).fontSize = 13f;
		((TMP_Text)obj).enableAutoSizing = true;
		((TMP_Text)obj).fontSizeMin = 10f;
		((TMP_Text)obj).fontSizeMax = 13f;
		((Graphic)obj).color = new Color(0.94f, 0.77f, 0.41f);
		((TMP_Text)obj).alignment = (TextAlignmentOptions)4097;
		((TMP_Text)obj).overflowMode = (TextOverflowModes)1;
		((Graphic)obj).raycastTarget = false;
		((TMP_Text)obj).text = value;
		val.SetActive(true);
		return obj;
	}

	private static void ClosePopup()
	{
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		padPopupOpen = false;
		padOptionChoices.Clear();
		padOptionBackgrounds.Clear();
		if (!((Object)(object)overlayRoot != (Object)null))
		{
			return;
		}
		overlayRoot.SetActive(false);
		foreach (Transform item in overlayRoot.transform)
		{
			Object.Destroy((Object)(object)((Component)item).gameObject);
		}
	}

	private static void OpenPopup(bool showSources)
	{
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Expected O, but got Unknown
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: 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_0114: 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_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0158: Unknown result type (might be due to invalid IL or missing references)
		//IL_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Expected O, but got Unknown
		//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: Expected O, but got Unknown
		//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ce: Expected O, but got Unknown
		//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dc: 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_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_021a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0240: Unknown result type (might be due to invalid IL or missing references)
		//IL_0265: Unknown result type (might be due to invalid IL or missing references)
		//IL_0291: Unknown result type (might be due to invalid IL or missing references)
		//IL_029e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0307: Unknown result type (might be due to invalid IL or missing references)
		//IL_0322: Unknown result type (might be due to invalid IL or missing references)
		//IL_032a: Unknown result type (might be due to invalid IL or missing references)
		//IL_032f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0339: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c8: Expected O, but got Unknown
		//IL_03e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0408: Unknown result type (might be due to invalid IL or missing references)
		//IL_0412: Unknown result type (might be due to invalid IL or missing references)
		//IL_041d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0427: Unknown result type (might be due to invalid IL or missing references)
		//IL_0432: Unknown result type (might be due to invalid IL or missing references)
		//IL_044a: Unknown result type (might be due to invalid IL or missing references)
		//IL_049f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0484: Unknown result type (might be due to invalid IL or missing references)
		//IL_04fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0507: Expected O, but got Unknown
		//IL_04dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e7: Expected O, but got Unknown
		if (!UiReady || (Object)(object)overlayRoot == (Object)null)
		{
			return;
		}
		if (overlayRoot.activeSelf)
		{
			ClosePopup();
			return;
		}
		GameObject val = typeControl;
		List<string> list = new List<string>(showSources ? AvailableSources : AvailableTypes);
		if (!list.Contains("All"))
		{
			list.Insert(0, "All");
		}
		if ((Object)(object)val == (Object)null || (Object)(object)(showSources ? sourceControl : typeControl) == (Object)null)
		{
			return;
		}
		overlayRoot.SetActive(true);
		RectTransform val2 = (RectTransform)overlayRoot.transform;
		Canvas component = ((Component)overlayRoot.transform.parent).GetComponent<Canvas>();
		if ((Object)(object)component == (Object)null)
		{
			ClosePopup();
			return;
		}
		GameObject val3 = new GameObject("OutsideClick", new Type[3]
		{
			typeof(RectTransform),
			typeof(Image),
			typeof(Button)
		});
		val3.transform.SetParent(overlayRoot.transform, false);
		RectTransform val4 = (RectTransform)val3.transform;
		val4.anchorMin = Vector2.zero;
		val4.anchorMax = Vector2.one;
		val4.offsetMin = Vector2.zero;
		val4.offsetMax = Vector2.zero;
		((Graphic)val3.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0f);
		((UnityEvent)val3.GetComponent<Button>().onClick).AddListener(new UnityAction(ClosePopup));
		GameObject val5 = new GameObject("Options", new Type[2]
		{
			typeof(RectTransform),
			typeof(Image)
		});
		val5.transform.SetParent(overlayRoot.transform, false);
		RectTransform val6 = (RectTransform)val5.transform;
		val6.anchorMin = Vector2.zero;
		val6.anchorMax = Vector2.zero;
		val6.pivot = new Vector2(0f, 1f);
		float num;
		Rect rect;
		if (!((Object)(object)adjustedViewport != (Object)null))
		{
			num = 164f;
		}
		else
		{
			rect = adjustedViewport.rect;
			num = ((Rect)(ref rect)).width;
		}
		float num2 = num;
		val6.sizeDelta = new Vector2(Mathf.Max(120f, num2), (float)list.Count * 26f);
		((Graphic)val5.GetComponent<Image>()).color = new Color(0.09f, 0.08f, 0.07f, 0.99f);
		padOptionChoices.Clear();
		padOptionBackgrounds.Clear();
		Vector3[] array = (Vector3[])(object)new Vector3[4];
		((RectTransform)val.transform).GetWorldCorners(array);
		Camera val7 = (((int)component.renderMode == 0) ? null : component.worldCamera);
		Vector2 val8 = RectTransformUtility.WorldToScreenPoint(val7, array[0]);
		Vector2 val9 = default(Vector2);
		if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(val2, val8, val7, ref val9))
		{
			ClosePopup();
			return;
		}
		float x = val9.x;
		rect = val2.rect;
		float num3 = x - ((Rect)(ref rect)).xMin;
		rect = val2.rect;
		float num4 = Mathf.Clamp(num3, 0f, Mathf.Max(0f, ((Rect)(ref rect)).width - val6.sizeDelta.x));
		float y = val9.y;
		rect = val2.rect;
		val6.anchoredPosition = new Vector2(num4, y - ((Rect)(ref rect)).yMin);
		TMP_Text fontSample = (TMP_Text)(object)(showSources ? sourceLabel : typeLabel);
		string value = (showSources ? Selection : TypeSelection);
		for (int i = 0; i < list.Count; i++)
		{
			string chosen = list[i];
			GameObject val10 = new GameObject("Option-" + chosen, new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(Button)
			});
			val10.transform.SetParent(val5.transform, false);
			RectTransform val11 = (RectTransform)val10.transform;
			val11.anchorMin = new Vector2(0f, 1f);
			val11.anchorMax = new Vector2(1f, 1f);
			val11.pivot = new Vector2(0.5f, 1f);
			val11.sizeDelta = new Vector2(0f, 26f);
			val11.anchoredPosition = new Vector2(0f, -26f * (float)i);
			Image component2 = val10.GetComponent<Image>();
			((Graphic)component2).color = (chosen.Equals(value, StringComparison.OrdinalIgnoreCase) ? new Color(0.28f, 0.21f, 0.1f, 1f) : new Color(0.15f, 0.13f, 0.11f, 1f));
			padOptionChoices.Add(chosen);
			padOptionBackgrounds.Add(component2);
			if (showSources)
			{
				((UnityEvent)val10.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
				{
					ChooseSource(chosen);
				});
			}
			else
			{
				((UnityEvent)val10.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
				{
					ChooseType(chosen);
				});
			}
			CreateLabel(val10.transform, fontSample, (chosen == "All") ? (showSources ? "Source (All)" : "Type (All)") : chosen);
		}
		val5.transform.SetAsLastSibling();
		if (padPopupOpen)
		{
			PaintPadOptions();
		}
	}

	private static void ChooseSource(string choice)
	{
		Selection = choice;
		if ((Object)(object)sourceLabel != (Object)null)
		{
			((TMP_Text)sourceLabel).text = FilterLabel(Selection, isSource: true);
		}
		ClosePopup();
		RefreshCrafting();
		ReturnGamepadRecipeToTopAfterFilterChange();
	}

	private static void ChooseType(string choice)
	{
		TypeSelection = choice;
		if ((Object)(object)typeLabel != (Object)null)
		{
			((TMP_Text)typeLabel).text = FilterLabel(TypeSelection, isSource: false);
		}
		ClosePopup();
		RefreshCrafting();
		ReturnGamepadRecipeToTopAfterFilterChange();
	}

	internal static void ResetFilterSelections()
	{
		benchStartFilterPending = false;
		LeavePadFilterFocus();
		TypeSelection = "All";
		Selection = "All";
		if ((Object)(object)typeLabel != (Object)null)
		{
			((TMP_Text)typeLabel).text = FilterLabel(TypeSelection, isSource: false);
		}
		if ((Object)(object)sourceLabel != (Object)null)
		{
			((TMP_Text)sourceLabel).text = FilterLabel(Selection, isSource: true);
		}
		ClosePopup();
	}

	private static void RefreshCrafting()
	{
		if ((Object)(object)gui == (Object)null)
		{
			return;
		}
		MethodInfo methodInfo = AccessTools.Method(typeof(InventoryGui), "UpdateCraftingPanel", new Type[1] { typeof(bool) }, (Type[])null);
		if (methodInfo == null)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)"UpdateCraftingPanel(bool) not found.");
			}
			return;
		}
		try
		{
			methodInfo.Invoke(gui, new object[1] { false });
		}
		catch (Exception ex)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)("Crafting refresh failed: " + ex));
			}
		}
	}

	private static void ReturnGamepadRecipeToTopAfterFilterChange()
	{
		if (padFilterFocus < 0 || (Object)(object)gui == (Object)null || !UiReady || !GamepadIsActive())
		{
			return;
		}
		try
		{
			IList gameRecipePairs = GetGameRecipePairs(gui);
			if (gameRecipePairs != null && gameRecipePairs.Count != 0)
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(InventoryGui), "SetRecipe", new Type[2]
				{
					typeof(int),
					typeof(bool)
				}, (Type[])null);
				if (methodInfo != null)
				{
					methodInfo.Invoke(gui, new object[2] { 0, false });
				}
				ScrollRect val = (((Object)(object)adjustedViewport == (Object)null) ? null : ((Component)adjustedViewport).GetComponentInParent<ScrollRect>());
				if ((Object)(object)val != (Object)null)
				{
					val.StopMovement();
					val.verticalNormalizedPosition = 1f;
				}
			}
		}
		catch (Exception ex)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)("Gamepad recipe return-to-top skipped: " + ex.Message));
			}
		}
	}

	private static HashSet<string> CategoriesForRecipe(Recipe recipe, string source)
	{
		HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
		if ((Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null || recipe.m_item.m_itemData == null || recipe.m_item.m_itemData.m_shared == null)
		{
			hashSet.Add("Other");
			return hashSet;
		}
		string text = ((object)Unsafe.As<ItemType, ItemType>(ref recipe.m_item.m_itemData.m_shared.m_itemType)/*cast due to .constrained prefix*/).ToString();
		string name = ((Object)recipe.m_item).name;
		string text2 = null;
		bool flag = source.IndexOf("Backpack", StringComparison.OrdinalIgnoreCase) >= 0;
		if (!flag)
		{
			switch (text)
			{
			case "Shoulder":
			case "Utility":
			case "Tool":
				text2 = DisplayName(recipe).ToLowerInvariant();
				flag = text2.EndsWith(" backpack", StringComparison.Ordinal) || text2.EndsWith(" pack", StringComparison.Ordinal) || text2.EndsWith(" knapsack", StringComparison.Ordinal) || text2.EndsWith(" wisppack", StringComparison.Ordinal) || text2.EndsWith(" satchel", StringComparison.Ordinal) || text2 == "backpack" || text2 == "knapsack";
				break;
			}
		}
		if (flag)
		{
			hashSet.Add("Backpacks");
			return hashSet;
		}
		if (text2 == null)
		{
			text2 = DisplayName(recipe).ToLowerInvariant();
		}
		string text3 = name.Replace("_", "").Replace("-", "").ToLowerInvariant();
		string text4 = text2.Replace(" ", "").Replace("-", "").Replace("_", "");
		if (Regex.IsMatch(text2, "^cast\\s*[:\\-]\\s*\\S", RegexOptions.IgnoreCase) || Regex.IsMatch(name, "^cast[_-]", RegexOptions.IgnoreCase))
		{
			hashSet.Add("Casts");
			return hashSet;
		}
		bool num = Regex.IsMatch(text2, "\\b(?:potions?|tonics?|elixirs?)\\b", RegexOptions.IgnoreCase);
		bool flag2 = text3.StartsWith("potion", StringComparison.Ordinal) || text3.StartsWith("tonic", StringComparison.Ordinal) || text3.StartsWith("elixir", StringComparison.Ordinal);
		if (num || flag2)
		{
			hashSet.Add("Potions");
			return hashSet;
		}
		bool num2 = Regex.IsMatch(text2, "\\b(?:meads?|barley\\s+wine|wine\\s+base)\\b", RegexOptions.IgnoreCase);
		bool flag3 = text3.StartsWith("mead", StringComparison.Ordinal) || text3.StartsWith("barleywine", StringComparison.Ordinal) || text3.StartsWith("winebase", StringComparison.Ordinal);
		if (num2 || flag3)
		{
			hashSet.Add("Meads");
			return hashSet;
		}
		bool num3 = Regex.IsMatch(text2, "\\b(?:rings?|necklaces?|pendants?|bracelets?|amulets?|earrings?|brooches?)\\b", RegexOptions.IgnoreCase);
		bool flag4 = text3.StartsWith("jcring", StringComparison.Ordinal) || text3.StartsWith("jcnecklace", StringComparison.Ordinal) || text3.StartsWith("jcpendant", StringComparison.Ordinal) || text3.StartsWith("jcbracelet", StringComparison.Ordinal) || text3.StartsWith("jcamulet", StringComparison.Ordinal) || text3.StartsWith("jcearring", StringComparison.Ordinal) || Regex.IsMatch(name, "(?:^|[_-])(?:rings?|necklaces?|pendants?|bracelets?|amulets?|earrings?|brooches?)(?:$|[_-])", RegexOptions.IgnoreCase);
		if (num3 || flag4)
		{
			hashSet.Add("Jewelry");
			return hashSet;
		}
		bool flag5 = Regex.IsMatch(text2, "\\b(?:gems?|gemstones?)\\b", RegexOptions.IgnoreCase) || Regex.IsMatch(text2, "^(?:(?:simple|advanced|perfect|uncut|raw|shattered|merged|boss)\\s+)?(?:onyx|sapphire|sulfur|spinel|ruby|emerald|humite|diamond|topaz)(?:\\s+(?:gemstones?|gems?|shards?|formations?))?$", RegexOptions.IgnoreCase) || Regex.IsMatch(text2, "^(?:onyx|sapphire|sulfur|spinel|ruby|emerald|humite|diamond|topaz)(?:\\s+(?:onyx|sapphire|sulfur|spinel|ruby|emerald|humite|diamond|topaz))?\\s+(?:shards?|formations?)$", RegexOptions.IgnoreCase);
		bool flag6 = text3.StartsWith("jcsocket", StringComparison.Ordinal) || text3.StartsWith("jcgemstone", StringComparison.Ordinal) || text3.StartsWith("jcuncut", StringComparison.Ordinal) || text3.StartsWith("jcraw", StringComparison.Ordinal) || text3.StartsWith("jcshattered", StringComparison.Ordinal) || Regex.IsMatch(name, "^jc_(?:.*(?:socket|gemstone|shard|uncut|merged_gemstone).*)$", RegexOptions.IgnoreCase);
		switch (text)
		{
		default:
			if (!(text == "Trophie"))
			{
				break;
			}
			goto case "Material";
		case "Material":
		case "Utility":
		case "Consumable":
			if (flag5 || flag6)
			{
				hashSet.Add("Gems");
				return hashSet;
			}
			break;
		}
		if (text3.Contains("bloodthirster") || text4.Contains("bloodthirster"))
		{
			hashSet.Add("Weapons");
			return hashSet;
		}
		if (text.Equals("Saddle", StringComparison.OrdinalIgnoreCase) || text3.Contains("saddle") || text4.Contains("saddle"))
		{
			hashSet.Add("Saddles");
			return hashSet;
		}
		if (text.Equals("Trinket", StringComparison.OrdinalIgnoreCase) || text3.Contains("trinket") || text4.Contains("trinket"))
		{
			hashSet.Add("Trinkets");
			return hashSet;
		}
		int num4;
		switch (text)
		{
		default:
			num4 = ((text == "Ammo") ? 1 : 0);
			break;
		case "OneHandedWeapon":
		case "TwoHandedWeapon":
		case "TwoHandedWeaponLeft":
		case "Bow":
			num4 = 1;
			break;
		}
		bool flag7 = (byte)num4 != 0;
		bool flag8 = text4 == "bell" || text4 == "bellfragment" || text3 == "bell" || text3 == "bellfragment" || Regex.IsMatch(text2, "\\bkeys?\\b", RegexOptions.IgnoreCase) || text4.Contains("sealbreaker");
		bool flag9 = text3.StartsWith("key", StringComparison.Ordinal) || text3.EndsWith("key", StringComparison.Ordinal) || text3.Contains("keyfragment") || text3.Contains("sealbreaker") || Regex.IsMatch(name, "(?:^|[_-])key(?:[_-]|$)", RegexOptions.IgnoreCase);
		if (text.Equals("Key", StringComparison.OrdinalIgnoreCase) || (!flag7 && (flag8 || flag9)))
		{
			hashSet.Add("Keys");
			return hashSet;
		}
		bool num5 = Regex.IsMatch(text2, "\\bmiss(?:ile|le)s?\\b", RegexOptions.IgnoreCase);
		bool flag10 = text3.EndsWith("missile", StringComparison.Ordinal) || text3.EndsWith("missiles", StringComparison.Ordinal) || text3.EndsWith("missle", StringComparison.Ordinal) || text3.EndsWith("missles", StringComparison.Ordinal);
		bool flag11 = Regex.IsMatch(text2, "\\b(?:launcher|staff|wand)\\b", RegexOptions.IgnoreCase) || text3.Contains("launcher") || text3.Contains("staff") || text3.Contains("wand");
		if ((num5 || flag10) && !flag11)
		{
			hashSet.Add("Ammo");
			return hashSet;
		}
		if (Regex.IsMatch(text2, "\\bbaits?\\b", RegexOptions.IgnoreCase) || text3.Contains("fishingbait") || text3.StartsWith("bait", StringComparison.Ordinal) || text3.EndsWith("bait", StringComparison.Ordinal))
		{
			hashSet.Add("Baits");
			return hashSet;
		}
		if (text == "Ammo")
		{
			hashSet.Add("Ammo");
			return hashSet;
		}
		if (text.Equals("Quiver", StringComparison.OrdinalIgnoreCase) || text3.Contains("quiver") || text4.Contains("quiver"))
		{
			hashSet.Add("Archery");
			return hashSet;
		}
		if (text == "Bow" || text.Equals("Crossbow", StringComparison.OrdinalIgnoreCase) || text3.Contains("crossbow") || text4.Contains("crossbow") || (text3.StartsWith("bow", StringComparison.Ordinal) && !text3.Contains("bowstring")) || text2.EndsWith(" bow", StringComparison.Ordinal) || text2.EndsWith(" longbow", StringComparison.Ordinal))
		{
			hashSet.Add("Archery");
			hashSet.Add("Weapons");
			return hashSet;
		}
		if (text3.Contains("snowshovel") || text4.Contains("snowshovel") || text3.Contains("butcherknife") || text4.Contains("butcherknife") || text3.Contains("fishingrod") || text4.Contains("fishingrod") || text3.Contains("fishingpole") || text4.Contains("fishingpole") || text3.Contains("scythe") || text4.Contains("scythe"))
		{
			hashSet.Add("Tools");
			return hashSet;
		}
		bool flag12 = name.IndexOf("pickaxe", StringComparison.OrdinalIgnoreCase) >= 0;
		if (!flag12 && (text == "OneHandedWeapon" || text == "Tool"))
		{
			if (text2 == null)
			{
				text2 = DisplayName(recipe).ToLowerInvariant();
			}
			flag12 = text2.Contains("pickaxe");
		}
		if (flag12)
		{
			hashSet.Add("Tools");
			return hashSet;
		}
		string text5 = (((Object)(object)recipe.m_craftingStation != (Object)null) ? ((Object)recipe.m_craftingStation).name : "").Replace("_", "").Replace("-", "").Replace(" ", "")
			.ToLowerInvariant();
		bool num6 = text5.Contains("foodprep") || text5.Contains("foodpreparation");
		bool flag13 = Regex.IsMatch(text2, "\\b(?:uncooked|unbaked|dough|picnic|feast|pies?|platter|soups?|stews?|jerky|roasted|cooked|breads?|raw fish|stuffed mushroom|salad|porridge|omelette|omelet)\\b", RegexOptions.IgnoreCase);
		bool flag14 = text == "Material" || text == "Consumable" || text == "Fish";
		if (num6 || (flag13 && flag14))
		{
			hashSet.Add("Foods");
			return hashSet;
		}
		switch (text)
		{
		case "Shoulder":
			hashSet.Add("Back");
			break;
		case "Helmet":
			hashSet.Add("Helmets");
			break;
		case "Chest":
			hashSet.Add("Chest");
			break;
		case "Legs":
			hashSet.Add("Legs");
			break;
		case "Shield":
			hashSet.Add("Shields");
			break;
		case "OneHandedWeapon":
			hashSet.Add("Weapons");
			if (text2 == null)
			{
				text2 = DisplayName(recipe).ToLowerInvariant();
			}
			if (text2.EndsWith(" axe", StringComparison.Ordinal) || text2.EndsWith(" hatchet", StringComparison.Ordinal) || (name.StartsWith("Axe", StringComparison.OrdinalIgnoreCase) && name.IndexOf("Battle", StringComparison.OrdinalIgnoreCase) < 0))
			{
				hashSet.Add("Tools");
			}
			break;
		case "TwoHandedWeapon":
		case "TwoHandedWeaponLeft":
		case "Bow":
			hashSet.Add("Weapons");
			break;
		case "Tool":
		case "Torch":
			hashSet.Add("Tools");
			break;
		case "Ammo":
			hashSet.Add("Ammo");
			break;
		case "Material":
			hashSet.Add("Materials");
			break;
		case "Consumable":
		case "Fish":
			hashSet.Add("Foods");
			break;
		case "Utility":
			hashSet.Add("Utility");
			break;
		case "Trophie":
			hashSet.Add("Trophies");
			break;
		default:
			hashSet.Add("Other");
			break;
		}
		return hashSet;
	}

	internal static bool IsStationCrafting()
	{
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer != (Object)null)
		{
			return (Object)(object)localPlayer.GetCurrentCraftingStation() != (Object)null;
		}
		return false;
	}

	internal static void UpdateRecipes(ref List<Recipe> recipes)
	{
		if (!IsStationCrafting() || !UiReady || recipes == null)
		{
			return;
		}
		EnsureDiscoveryOwner(Player.m_localPlayer);
		SortedSet<string> sortedSet = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
		string[] array = new string[24]
		{
			"Back", "Backpacks", "Helmets", "Chest", "Legs", "Shields", "Archery", "Weapons", "Tools", "Ammo",
			"Baits", "Casts", "Foods", "Meads", "Potions", "Gems", "Jewelry", "Materials", "Keys", "Saddles",
			"Trinkets", "Utility", "Trophies", "Other"
		};
		HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
		Dictionary<Recipe, string> dictionary = new Dictionary<Recipe, string>();
		Dictionary<Recipe, HashSet<string>> dictionary2 = new Dictionary<Recipe, HashSet<string>>();
		foreach (Recipe recipe in recipes)
		{
			if ((Object)(object)recipe == (Object)null)
			{
				continue;
			}
			string text = SourceForRecipe(recipe);
			sortedSet.Add(text);
			HashSet<string> hashSet2 = CategoriesForRecipe(recipe, text);
			foreach (string item2 in hashSet2)
			{
				hashSet.Add(item2);
			}
			dictionary[recipe] = text;
			dictionary2[recipe] = hashSet2;
		}
		AvailableSources.Clear();
		AvailableSources.Add("All");
		if (sortedSet.Contains("Valheim"))
		{
			AvailableSources.Add("Valheim");
		}
		foreach (string item3 in sortedSet)
		{
			if (!item3.Equals("Valheim", StringComparison.OrdinalIgnoreCase) && !item3.Equals("Unknown", StringComparison.OrdinalIgnoreCase) && !item3.Equals("All", StringComparison.OrdinalIgnoreCase))
			{
				AvailableSources.Add(item3);
			}
		}
		if (sortedSet.Contains("Unknown"))
		{
			AvailableSources.Add("Unknown");
		}
		AvailableTypes.Clear();
		AvailableTypes.Add("All");
		string[] array2 = array;
		foreach (string item in array2)
		{
			if (hashSet.Contains(item))
			{
				AvailableTypes.Add(item);
			}
		}
		List<Recipe> list = new List<Recipe>(recipes.Count);
		if (Selection == "All" && TypeSelection == "All")
		{
			list.AddRange(recipes);
		}
		else
		{
			foreach (Recipe recipe2 in recipes)
			{
				if (!((Object)(object)recipe2 == (Object)null) && (!(Selection != "All") || dictionary[recipe2].Equals(Selection, StringComparison.OrdinalIgnoreCase)) && (!(TypeSelection != "All") || dictionary2[recipe2].Contains(TypeSelection)))
				{
					list.Add(recipe2);
				}
			}
		}
		if (Selection != "All" || TypeSelection != "All")
		{
			recipes = list;
		}
	}

	private static void EnsureDiscoveryOwner(Player player)
	{
		if ((Object)(object)player == (Object)null || (Object)(object)Player.m_localPlayer != (Object)(object)player || ((Object)(object)discoveryOwner == (Object)(object)player && !string.IsNullOrEmpty(persistenceFile)))
		{
			return;
		}
		if ((Object)(object)discoveryOwner != (Object)(object)player)
		{
			discoveryOwner = player;
			NewlyDiscoveredNames.Clear();
			PreviewDismissedNames.Clear();
			PreviewTargetNames.Clear();
			activeViewedRecipeKey = null;
			activeViewedRecipeRow = null;
			KeepAtTopUntilMenuClose.Clear();
		}
		persistenceFile = null;
		try
		{
			string playerName = player.GetPlayerName();
			if (string.IsNullOrEmpty(playerName))
			{
				return;
			}
			string text = Convert.ToBase64String(Encoding.UTF8.GetBytes(playerName.Trim().ToLowerInvariant())).TrimEnd('=').Replace('+', '-')
				.Replace('/', '_');
			string text2 = Path.Combine(Paths.ConfigPath, "RamCraftFilterModLabels");
			Directory.CreateDirectory(text2);
			persistenceFile = Path.Combine(text2, "new-" + text + ".txt");
			if (!File.Exists(persistenceFile))
			{
				return;
			}
			string[] array = File.ReadAllLines(persistenceFile);
			foreach (string text3 in array)
			{
				if (!string.IsNullOrEmpty(text3))
				{
					NewlyDiscoveredNames.Add(text3);
				}
			}
		}
		catch (Exception ex)
		{
			persistenceFile = null;
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)("Local NEW tracking unavailable: " + ex.Message));
			}
		}
	}

	private static void SaveNewMarkers()
	{
		if (string.IsNullOrEmpty(persistenceFile))
		{
			return;
		}
		try
		{
			string text = persistenceFile + ".tmp";
			File.WriteAllLines(text, NewlyDiscoveredNames);
			File.Copy(text, persistenceFile, overwrite: true);
			File.Delete(text);
		}
		catch (Exception ex)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)("Could not save local NEW markers: " + ex.Message));
			}
		}
	}

	internal static HashSet<string> SnapshotKnownRecipes(Player player)
	{
		if ((Object)(object)player == (Object)null || (Object)(object)Player.m_localPlayer != (Object)(object)player)
		{
			return null;
		}
		EnsureDiscoveryOwner(player);
		try
		{
			HashSet<string> value = Traverse.Create((object)player).Field("m_knownRecipes").GetValue<HashSet<string>>();
			if (value == null)
			{
				return null;
			}
			return new HashSet<string>(value, StringComparer.Ordinal);
		}
		catch (Exception ex)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogDebug((object)("NEW snapshot unavailable: " + ex.Message));
			}
			return null;
		}
	}

	internal static void TrackRecipeDiscovery(Player player, HashSet<string> prior)
	{
		if (prior == null || (Object)(object)player == (Object)null || (Object)(object)discoveryOwner != (Object)(object)player)
		{
			return;
		}
		try
		{
			HashSet<string> value = Traverse.Create((object)player).Field("m_knownRecipes").GetValue<HashSet<string>>();
			if (value == null)
			{
				return;
			}
			int num = 0;
			foreach (string item in value)
			{
				if (!prior.Contains(item) && NewlyDiscoveredNames.Add(item))
				{
					num++;
				}
			}
			if (num != 0)
			{
				SaveNewMarkers();
				if ((Object)(object)Instance != (Object)null)
				{
					((BaseUnityPlugin)Instance).Logger.LogDebug((object)("RamCraftFilterModLabels noticed " + num + " newly discovered recipe(s)."));
				}
			}
		}
		catch (Exception ex)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogDebug((object)("NEW discovery unavailable: " + ex.Message));
			}
		}
	}

	private static string RecipeKnowledgeKey(Recipe recipe)
	{
		if ((Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null || recipe.m_item.m_itemData == null || recipe.m_item.m_itemData.m_shared == null)
		{
			return null;
		}
		return recipe.m_item.m_itemData.m_shared.m_name;
	}

	private static string CleanDisplayName(string input)
	{
		if (string.IsNullOrEmpty(input))
		{
			return "";
		}
		return Regex.Replace(input, "<[^>]*>", "").Trim();
	}

	private static string DisplayName(Recipe recipe)
	{
		string text = RecipeKnowledgeKey(recipe);
		if (string.IsNullOrEmpty(text))
		{
			return "";
		}
		try
		{
			if (!localizationSearched)
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				for (int i = 0; i < assemblies.Length; i++)
				{
					Type type = assemblies[i].GetType("Localization", throwOnError: false);
					if (!(type == null))
					{
						MethodInfo method = type.GetMethod("Localize", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null);
						if (!(method == null))
						{
							localizationLocalize = method;
							localizationInstanceField = type.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
							localizationInstanceProperty = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) ?? type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
							break;
						}
					}
				}
				localizationSearched = true;
			}
			if (localizationLocalize != null)
			{
				object obj = null;
				if (!localizationLocalize.IsStatic)
				{
					if (localizationInstanceField != null)
					{
						obj = localizationInstanceField.GetValue(null);
					}
					else if (localizationInstanceProperty != null)
					{
						obj = localizationInstanceProperty.GetValue(null, null);
					}
					if (obj == null)
					{
						return CleanDisplayName(text);
					}
				}
				string text2 = localizationLocalize.Invoke(obj, new object[1] { text }) as string;
				if (!string.IsNullOrEmpty(text2))
				{
					return CleanDisplayName(text2);
				}
			}
		}
		catch (Exception)
		{
		}
		return CleanDisplayName(text);
	}

	private static TMP_Text FindNameText(Transform row)
	{
		if ((Object)(object)row == (Object)null)
		{
			return null;
		}
		TMP_Text[] componentsInChildren = ((Component)row).GetComponentsInChildren<TMP_Text>(true);
		foreach (TMP_Text val in componentsInChildren)
		{
			if ((Object)(object)val != (Object)null && ((Object)((Component)val).gameObject).name.Equals("name", StringComparison.OrdinalIgnoreCase))
			{
				return val;
			}
		}
		return null;
	}

	private static Text FindLegacyNameText(Transform row)
	{
		if ((Object)(object)row == (Object)null)
		{
			return null;
		}
		Text[] componentsInChildren = ((Component)row).GetComponentsInChildren<Text>(true);
		foreach (Text val in componentsInChildren)
		{
			if ((Object)(object)val != (Object)null && ((Object)((Component)val).gameObject).name.Equals("name", StringComparison.OrdinalIgnoreCase))
			{
				return val;
			}
		}
		return null;
	}

	internal static string WithoutOurNewPrefix(string text)
	{
		if (string.IsNullOrEmpty(text))
		{
			return text;
		}
		if (text.StartsWith("<color=#39FF14><b>*</b></color> ", StringComparison.Ordinal))
		{
			return text.Substring("<color=#39FF14><b>*</b></color> ".Length);
		}
		if (text.StartsWith("<color=#39FF14><b>*</b></color> ", StringComparison.Ordinal))
		{
			return text.Substring("<color=#39FF14><b>*</b></color> ".Length);
		}
		if (text.StartsWith("<color=#A3CE3C><size=85%><b>*</b></size></color> ", StringComparison.Ordinal))
		{
			return text.Substring("<color=#A3CE3C><size=85%><b>*</b></size></color> ".Length);
		}
		if (text.StartsWith("<color=#A3CE3C><b>*</b></color> ", StringComparison.Ordinal))
		{
			return text.Substring("<color=#A3CE3C><b>*</b></color> ".Length);
		}
		if (text.StartsWith("<color=#A3CE3C><size=75%><b>NEW</b></size></color> ", StringComparison.Ordinal))
		{
			return text.Substring("<color=#A3CE3C><size=75%><b>NEW</b></size></color> ".Length);
		}
		if (text.StartsWith("<color=#A3CE3C><b>NEW</b></color> ", StringComparison.Ordinal))
		{
			return text.Substring("<color=#A3CE3C><b>NEW</b></color> ".Length);
		}
		return text;
	}

	internal static string WithNewPrefix(string text, bool useTmp)
	{
		return (useTmp ? "<color=#39FF14><b>*</b></color> " : "<color=#39FF14><b>*</b></color> ") + WithoutOurNewPrefix(text);
	}

	internal static void BeganViewingRecipe(string key, bool wasStarred, RecipeRowNewMarker row)
	{
		if (string.IsNullOrEmpty(key))
		{
			return;
		}
		if (!string.IsNullOrEmpty(activeViewedRecipeKey) && activeViewedRecipeKey != key)
		{
			DismissNew(activeViewedRecipeKey);
			if ((Object)(object)activeViewedRecipeRow != (Object)null)
			{
				activeViewedRecipeRow.RemoveStarFromText();
			}
			activeViewedRecipeKey = null;
			activeViewedRecipeRow = null;
		}
		if (wasStarred)
		{
			activeViewedRecipeKey = key;
			activeViewedRecipeRow = row;
		}
	}

	internal static bool LeftViewedRecipe(string key)
	{
		if (string.IsNullOrEmpty(key) || activeViewedRecipeKey != key)
		{
			return false;
		}
		activeViewedRecipeKey = null;
		activeViewedRecipeRow = null;
		return DismissNew(key);
	}

	private static bool DismissNew(string key)
	{
		if (string.IsNullOrEmpty(key))
		{
			return false;
		}
		bool num = NewlyDiscoveredNames.Remove(key);
		if (num)
		{
			SaveNewMarkers();
		}
		bool flag = PreviewTargetNames.Contains(key) && !PreviewDismissedNames.Contains(key);
		PreviewDismissedNames.Add(key);
		if (num || flag)
		{
			KeepAtTopUntilMenuClose.Add(key);
		}
		return num || flag;
	}

	internal static void EndCraftingMenuSession()
	{
		activeViewedRecipeKey = null;
		activeViewedRecipeRow = null;
		KeepAtTopUntilMenuClose.Clear();
	}

	private static IList GetGameRecipePairs(InventoryGui current)
	{
		FieldInfo fieldInfo = AccessTools.Field(typeof(InventoryGui), "m_availableRecipes");
		if (!(fieldInfo == null))
		{
			return fieldInfo.GetValue(current) as IList;
		}
		return null;
	}

	private static PropertyInfo FindPairProperty(object pair, string propertyName)
	{
		return pair?.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
	}

	private static Recipe GetPairedRecipe(object pair)
	{
		PropertyInfo propertyInfo = FindPairProperty(pair, "Recipe") ?? FindPairProperty(pair, "Key");
		if (!(propertyInfo == null))
		{
			object? value = propertyInfo.GetValue(pair, null);
			return (Recipe)((value is Recipe) ? value : null);
		}
		return null;
	}

	private static GameObject GetPairedRow(object pair)
	{
		PropertyInfo propertyInfo = FindPairProperty(pair, "InterfaceElement");
		if (!(propertyInfo == null))
		{
			object? value = propertyInfo.GetValue(pair, null);
			return (GameObject)((value is GameObject) ? value : null);
		}
		return null;
	}

	internal static void SortActualRecipeRows(InventoryGui current)
	{
		//IL_017a: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_018f: Unknown result type (might be due to invalid IL or missing references)
		if (!IsStationCrafting() || (Object)(object)current == (Object)null || !UiReady)
		{
			return;
		}
		try
		{
			IList gameRecipePairs = GetGameRecipePairs(current);
			if (gameRecipePairs == null || gameRecipePairs.Count < 2)
			{
				return;
			}
			List<object> list = new List<object>();
			List<object> list2 = new List<object>();
			for (int i = 0; i < gameRecipePairs.Count; i++)
			{
				object obj = gameRecipePairs[i];
				Recipe pairedRecipe = GetPairedRecipe(obj);
				GameObject pairedRow = GetPairedRow(obj);
				if ((Object)(object)pairedRecipe == (Object)null || (Object)(object)pairedRow == (Object)null || (Object)(object)pairedRow.GetComponent<RectTransform>() == (Object)null)
				{
					if ((Object)(object)Instance != (Object)null)
					{
						((BaseUnityPlugin)Instance).Logger.LogWarning((object)"NEW-first: recipe pair layout differs; leaving vanilla order unchanged.");
					}
					return;
				}
				string text = RecipeKnowledgeKey(pairedRecipe);
				if (!string.IsNullOrEmpty(text) && (NewlyDiscoveredNames.Contains(text) || KeepAtTopUntilMenuClose.Contains(text)))
				{
					list.Add(obj);
				}
				else
				{
					list2.Add(obj);
				}
			}
			if (list.Count != 0 && list2.Count != 0)
			{
				list.AddRange(list2);
				float num = Traverse.Create((object)current).Field("m_recipeListSpace").GetValue<float>();
				if (num <= 0f)
				{
					num = 30f;
				}
				for (int j = 0; j < list.Count; j++)
				{
					gameRecipePairs[j] = list[j];
				}
				for (int k = 0; k < list.Count; k++)
				{
					RectTransform component = GetPairedRow(list[k]).GetComponent<RectTransform>();
					Vector2 anchoredPosition = component.anchoredPosition;
					anchoredPosition.y = (float)(-k) * num;
					component.anchoredPosition = anchoredPosition;
					((Transform)component).SetSiblingIndex(k);
				}
			}
		}
		catch (Exception ex)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)("NEW-first sort skipped: " + ex));
			}
		}
	}

	internal static void OnGameRecipeSelected(InventoryGui current, int index)
	{
		if (suppressAutomaticRecipeViewing || (Object)(object)current == (Object)null || index < 0)
		{
			return;
		}
		try
		{
			IList gameRecipePairs = GetGameRecipePairs(current);
			if (gameRecipePairs != null && index < gameRecipePairs.Count)
			{
				object pair = gameRecipePairs[index];
				Recipe pairedRecipe = GetPairedRecipe(pair);
				if (!((Object)(object)pairedRecipe == (Object)null))
				{
					string text = RecipeKnowledgeKey(pairedRecipe);
					GameObject pairedRow = GetPairedRow(pair);
					RecipeRowNewMarker row = (((Object)(object)pairedRow == (Object)null) ? null : pairedRow.GetComponent<RecipeRowNewMarker>());
					bool wasStarred = !string.IsNullOrEmpty(text) && (NewlyDiscoveredNames.Contains(text) || (previewNew != null && previewNew.Value && PreviewTargetNames.Contains(text) && !PreviewDismissedNames.Contains(text)));
					BeganViewingRecipe(text, wasStarred, row);
				}
			}
		}
		catch (Exception ex)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)("Recipe selection tracking skipped: " + ex));
			}
		}
	}

	internal static void DecorateRecipeRows(InventoryGui current, List<Recipe> recipes)
	{
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Expected O, but got Unknown
		if ((Object)(object)current == (Object)null || recipes == null)
		{
			return;
		}
		EnsureDiscoveryOwner(Player.m_localPlayer);
		try
		{
			RectTransform value = Traverse.Create((object)current).Field("m_recipeListRoot").GetValue<RectTransform>();
			if ((Object)(object)value == (Object)null)
			{
				return;
			}
			Dictionary<string, List<Recipe>> dictionary = new Dictionary<string, List<Recipe>>(StringComparer.OrdinalIgnoreCase);
			foreach (Recipe recipe in recipes)
			{
				string text = DisplayName(recipe);
				if (!string.IsNullOrEmpty(text))
				{
					if (!dictionary.TryGetValue(text, out var value2))
					{
						value2 = new List<Recipe>();
						dictionary.Add(text, value2);
					}
					value2.Add(recipe);
				}
			}
			bool flag = previewNew != null && previewNew.Value;
			foreach (Transform item in (Transform)value)
			{
				Transform val = item;
				TMP_Text val2 = FindNameText(val);
				Text val3 = (((Object)(object)val2 == (Object)null) ? FindLegacyNameText(val) : null);
				if ((Object)(object)val2 == (Object)null && (Object)(object)val3 == (Object)null)
				{
					continue;
				}
				string text2 = (((Object)(object)val2 != (Object)null) ? val2.text : val3.text);
				string text3 = WithoutOurNewPrefix(text2);
				if (string.IsNullOrEmpty(text3))
				{
					continue;
				}
				if (!dictionary.TryGetValue(CleanDisplayName(text3), out var value3) || value3.Count != 1)
				{
					if (text3 != text2)
					{
						if ((Object)(object)val2 != (Object)null)
						{
							val2.text = text3;
						}
						else
						{
							val3.text = text3;
						}
					}
					continue;
				}
				string text4 = RecipeKnowledgeKey(value3[0]);
				bool flag2 = !string.IsNullOrEmpty(text4) && NewlyDiscoveredNames.Contains(text4);
				if (flag && !string.IsNullOrEmpty(text4) && PreviewTargetNames.Count < 3)
				{
					PreviewTargetNames.Add(text4);
				}
				bool flag3 = flag && !string.IsNullOrEmpty(text4) && PreviewTargetNames.Contains(text4) && !PreviewDismissedNames.Contains(text4);
				RecipeRowNewMarker recipeRowNewMarker = ((Component)val).GetComponent<RecipeRowNewMarker>();
				if ((Object)(object)recipeRowNewMarker == (Object)null)
				{
					recipeRowNewMarker = ((Component)val).gameObject.AddComponent<RecipeRowNewMarker>();
				}
				recipeRowNewMarker.Show(val2, val3, text4, flag2 || flag3, text3);
			}
		}
		catch (Exception ex)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)("Recipe NEW markers skipped: " + ex.Message));
			}
		}
	}

	private static void ResolvePadInput()
	{
		if (padInputResolved)
		{
			return;
		}
		padInputResolved = true;
		Type type = AccessTools.TypeByName("ZInput");
		if (!(type == null))
		{
			zPadDown = AccessTools.Method(type, "GetButtonDown", new Type[1] { typeof(string) }, (Type[])null);
			zPadActive = AccessTools.Method(type, "IsGamepadActive", Type.EmptyTypes, (Type[])null);
			zPadReset = AccessTools.Method(type, "ResetButtonStatus", new Type[1] { typeof(string) }, (Type[])null);
			if ((zPadDown == null || zPadActive == null || zPadReset == null) && (Object)(object)Instance != (Object)null && !padWarningLogged)
			{
				padWarningLogged = true;
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)"Gamepad filter controls unavailable: missing ZInput method; normal crafting is untouched.");
			}
		}
	}

	private static bool GamepadIsActive()
	{
		ResolvePadInput();
		try
		{
			return zPadActive != null && (bool)zPadActive.Invoke(null, null);
		}
		catch
		{
			return false;
		}
	}

	private static bool PadDown(string button)
	{
		if (zPadDown == null)
		{
			return false;
		}
		try
		{
			return (bool)zPadDown.Invoke(null, new object[1] { button });
		}
		catch
		{
			return false;
		}
	}

	private static bool PadVerticalUp()
	{
		if (!PadDown("JoyDPadUp") && !PadDown("JoyRStickUp"))
		{
			return PadDown("JoyLStickUp");
		}
		return true;
	}

	private static bool PadVerticalDown()
	{
		if (!PadDown("JoyDPadDown") && !PadDown("JoyRStickDown"))
		{
			return PadDown("JoyLStickDown");
		}
		return true;
	}

	private static bool CraftingGroupActive(InventoryGui current)
	{
		try
		{
			if (!(Traverse.Create((object)current).Field("m_uiGroups").GetValue() is Array { Length: >3 } array) || array.GetValue(3) == null)
			{
				return false;
			}
			object value = array.GetValue(3);
			PropertyInfo propertyInfo = AccessTools.Property(value.GetType(), "IsActive");
			return propertyInfo != null && (bool)propertyInfo.GetValue(value, null);
		}
		catch
		{
			return false;
		}
	}

	private static bool OnCraftTab(InventoryGui current)
	{
		try
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(InventoryGui), "InCraftTab", Type.EmptyTypes, (Type[])null);
			if (methodInfo == null)
			{
				return false;
			}
			return (bool)methodInfo.Invoke(current, null);
		}
		catch
		{
			return false;
		}
	}

	private static void RestoreStyleButton()
	{
		if ((Object)(object)guardedStyleButton != (Object)null)
		{
			((Selectable)guardedStyleButton).interactable = styleWasInteractable;
		}
		guardedStyleButton = null;
	}

	private static void GuardStyleButton(InventoryGui current)
	{
		if (padFilterFocus < 0 || !((Object)(object)current != (Object)null) || !((Object)(object)current == (Object)(object)gui) || !UiReady || !GamepadIsActive())
		{
			RestoreStyleButton();
			return;
		}
		Button val = null;
		try
		{
			val = Traverse.Create((object)current).Field("m_variantButton").GetValue<Button>();
		}
		catch
		{
		}
		if ((Object)(object)guardedStyleButton != (Object)(object)val)
		{
			RestoreStyleButton();
		}
		if (!((Object)(object)val == (Object)null))
		{
			if ((Object)(object)guardedStyleButton == (Object)null)
			{
				guardedStyleButton = val;
				styleWasInteractable = ((Selectable)val).interactable;
			}
			((Selectable)val).interactable = false;
		}
	}

	private static void ResetGamepadRecipePosition(InventoryGui current)
	{
		try
		{
			IList gameRecipePairs = GetGameRecipePairs(current);
			if (gameRecipePairs != null && gameRecipePairs.Count > 0)
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(InventoryGui), "SetRecipe", new Type[2]
				{
					typeof(int),
					typeof(bool)
				}, (Type[])null);
				if (methodInfo != null)
				{
					suppressAutomaticRecipeViewing = true;
					try
					{
						methodInfo.Invoke(current, new object[2] { 0, false });
					}
					finally
					{
						suppressAutomaticRecipeViewing = false;
					}
				}
			}
			ScrollRect val = (((Object)(object)adjustedViewport == (Object)null) ? null : ((Component)adjustedViewport).GetComponentInParent<ScrollRect>());
			if ((Object)(object)val != (Object)null)
			{
				val.StopMovement();
				val.verticalNormalizedPosition = 1f;
			}
		}
		catch (Exception ex)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)("New station controller positioning skipped: " + ex.Message));
			}
		}
		finally
		{
			suppressAutomaticRecipeViewing = false;
		}
	}

	internal static void OnCraftingWindowShown(InventoryGui current)
	{
		if (!((Object)(object)current == (Object)null))
		{
			ReleaseUiFromOldSession(current);
			if (IsStationCrafting() && GamepadIsActive())
			{
				benchStartFilterPending = true;
				BeginBenchFilterFocus(current);
			}
		}
	}

	private static void BeginBenchFilterFocus(InventoryGui current)
	{
		if (benchStartFilterPending && !((Object)(object)current == (Object)null) && UiReady && GamepadIsActive() && CraftingGroupActive(current) && OnCraftTab(current))
		{
			benchStartFilterPending = false;
			ResetGamepadRecipePosition(current);
			activeViewedRecipeKey = null;
			activeViewedRecipeRow = null;
			padPopupOpen = false;
			padFilterFocus = 0;
			PaintPadFocus();
		}
	}

	private static void PaintPadFocus()
	{
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)typeControl != (Object)null)
		{
			Image component = typeControl.GetComponent<Image>();
			if ((Object)(object)component != (Object)null)
			{
				((Graphic)component).color = ((padFilterFocus == 0) ? new Color(0.34f, 0.26f, 0.13f, 0.98f) : new Color(0.12f, 0.1f, 0.08f, 0.96f));
			}
		}
		if ((Object)(object)sourceControl != (Object)null)
		{
			Image component2 = sourceControl.GetComponent<Image>();
			if ((Object)(object)component2 != (Object)null)
			{
				((Graphic)component2).color = ((padFilterFocus == 1) ? new Color(0.34f, 0.26f, 0.13f, 0.98f) : new Color(0.12f, 0.1f, 0.08f, 0.96f));
			}
		}
		GuardStyleButton(gui);
	}

	private static void PaintPadOptions()
	{
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		for (int i = 0; i < padOptionBackgrounds.Count; i++)
		{
			Image val = padOptionBackgrounds[i];
			if ((Object)(object)val != (Object)null)
			{
				((Graphic)val).color = ((i == padOptionIndex) ? new Color(0.52f, 0.36f, 0.13f, 1f) : new Color(0.15f, 0.13f, 0.11f, 1f));
			}
		}
	}

	private static void LeavePadFilterFocus()
	{
		padFilterFocus = -1;
		padPopupOpen = false;
		padOptionIndex = 0;
		PaintPadFocus();
		ClosePopup();
	}

	internal static void ConsumeFilterCancelBeforeInventoryUpdate(InventoryGui current)
	{
		if (benchStartFilterPending)
		{
			BeginBenchFilterFocus(current);
		}
		if (padFilterFocus < 0)
		{
			return;
		}
		if ((Object)(object)current == (Object)null || !UiReady || !IsStationCrafting() || !InventoryGui.IsVisible() || !GamepadIsActive() || !CraftingGroupActive(current) || !OnCraftTab(current))
		{
			LeavePadFilterFocus();
			return;
		}
		GuardStyleButton(current);
		if (!PadDown("JoyButtonB"))
		{
			return;
		}
		LeavePadFilterFocus();
		try
		{
			if (zPadReset != null)
			{
				zPadReset.Invoke(null, new object[1] { "JoyButtonB" });
			}
		}
		catch
		{
		}
	}

	internal static bool HandleRecipeGamepadInput(InventoryGui current)
	{
		if (benchStartFilterPending)
		{
			BeginBenchFilterFocus(current);
		}
		if ((Object)(object)current == (Object)null || !UiReady || !IsStationCrafting() || !InventoryGui.IsVisible() || !GamepadIsActive() || !CraftingGroupActive(current) || !OnCraftTab(current))
		{
			if (padFilterFocus >= 0)
			{
				LeavePadFilterFocus();
			}
			return true;
		}
		if (padFilterFocus < 0)
		{
			if (!PadVerticalUp())
			{
				return true;
			}
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(InventoryGui), "GetSelectedRecipeIndex", new Type[1] { typeof(bool) }, (Type[])null);
				if (methodInfo == null || (int)methodInfo.Invoke(current, new object[1] { false }) != 0)
				{
					return true;
				}
			}
			catch
			{
				return true;
			}
			padFilterFocus = 0;
			PaintPadFocus();
			return false;
		}
		if (padPopupOpen)
		{
			if (PadVerticalUp() && padOptionChoices.Count > 0)
			{
				padOptionIndex = (padOptionIndex + padOptionChoices.Count - 1) % padOptionChoices.Count;
				PaintPadOptions();
			}
			else if (PadVerticalDown() && padOptionChoices.Count > 0)
			{
				padOptionIndex = (padOptionIndex + 1) % padOptionChoices.Count;
				PaintPadOptions();
			}
			else if (PadDown("JoyButtonA") && padOptionChoices.Count > 0)
			{
				string choice = padOptionChoices[padOptionIndex];
				if (padFilterFocus == 0)
				{
					ChooseType(choice);
				}
				else
				{
					ChooseSource(choice);
				}
				PaintPadFocus();
			}
			return false;
		}
		if (PadDown("JoyDPadLeft") || PadDown("JoyRStickLeft") || PadDown("JoyLStickLeft"))
		{
			padFilterFocus = 0;
			PaintPadFocus();
		}
		else if (PadDown("JoyDPadRight") || PadDown("JoyRStickRight") || PadDown("JoyLStickRight"))
		{
			padFilterFocus = 1;
			PaintPadFocus();
		}
		else if (PadVerticalDown())
		{
			LeavePadFilterFocus();
		}
		else if (PadDown("JoyButtonA"))
		{
			List<string> list = new List<string>((padFilterFocus == 0) ? AvailableTypes : AvailableSources);
			if (!list.Contains("All"))
			{
				list.Insert(0, "All");
			}
			string selected = ((padFilterFocus == 0) ? TypeSelection : Selection);
			padOptionIndex = Mathf.Max(0, list.FindIndex((string c) => c.Equals(selected, StringComparison.OrdinalIgnoreCase)));
			padPopupOpen = true;
			OpenPopup(padFilterFocus == 1);
			if ((Object)(object)overlayRoot == (Object)null || !overlayRoot.activeSelf)
			{
				padPopupOpen = false;
			}
			PaintPadOptions();
		}
		return false;
	}

	internal static void ResetUi()
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		benchStartFilterPending = false;
		RestoreStyleButton();
		ResetFilterSelections();
		UiReady = false;
		if ((Object)(object)adjustedViewport != (Object)null)
		{
			adjustedViewport.offsetMax = originalOffsetMax;
		}
		adjustedViewport = null;
		if ((Object)(object)sourceControl != (Object)null)
		{
			Object.Destroy((Object)(object)sourceControl);
		}
		if ((Object)(object)typeControl != (Object)null)
		{
			Object.Destroy((Object)(object)typeControl);
		}
		if ((Object)(object)overlayRoot != (Object)null)
		{
			Object.Destroy((Object)(object)overlayRoot);
		}
		sourceControl = null;
		typeControl = null;
		overlayRoot = null;
		sourceLabel = null;
		typeLabel = null;
		gui = null;
	}
}
internal sealed class RecipeRowNewMarker : MonoBehaviour
{
	private TMP_Text tmpName;

	private Text legacyName;

	private string unmarkedText;

	internal void Show(TMP_Text titleTmp, Text titleLegacy, string key, bool isNew, string originalText)
	{
		tmpName = titleTmp;
		legacyName = titleLegacy;
		unmarkedText = originalText;
		string text = (isNew ? ModOriginPlugin.WithNewPrefix(originalText, (Object)(object)titleTmp != (Object)null) : originalText);
		if ((Object)(object)tmpName != (Object)null && tmpName.text != text)
		{
			tmpName.text = text;
		}
		else if ((Object)(object)legacyName != (Object)null && legacyName.text != text)
		{
			legacyName.text = text;
		}
	}

	internal void RemoveStarFromText()
	{
		if ((Object)(object)tmpName != (Object)null && !string.IsNullOrEmpty(unmarkedText))
		{
			tmpName.text = unmarkedText;
		}
		else if ((Object)(object)legacyName != (Object)null && !string.IsNullOrEmpty(unmarkedText))
		{
			legacyName.text = unmarkedText;
		}
	}
}
[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
[HarmonyPriority(800)]
internal static class VanillaCatalogPatch
{
	private static void Prefix(ObjectDB other)
	{
		ModOriginPlugin.CaptureVanillaItems(other);
	}
}
[HarmonyPatch]
internal static class ItemTooltipPatch
{
	private static IEnumerable<MethodBase> TargetMethods()
	{
		MethodInfo[] methods = typeof(ItemData).GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (MethodInfo methodInfo in methods)
		{
			if (methodInfo.Name != "GetTooltip" || methodInfo.ReturnType != typeof(string))
			{
				continue;
			}
			ParameterInfo[] parameters = methodInfo.GetParameters();
			for (int j = 0; j < parameters.Length; j++)
			{
				if (parameters[j].ParameterType == typeof(ItemData))
				{
					yield return methodInfo;
					break;
				}
			}
		}
	}

	private static void Postfix(object[] __args, ref string __result)
	{
		if (__args == null || string.IsNullOrEmpty(__result) || __result.Contains("Source Mod:") || __result.Contains("Source:"))
		{
			return;
		}
		ItemData val = null;
		foreach (object obj in __args)
		{
			val = (ItemData)((obj is ItemData) ? obj : null);
			if (val != null)
			{
				break;
			}
		}
		if (val != null)
		{
			string text = ModOriginPlugin.SourceForItem(val);
			__result = __result + "\n<color=#A3CE3C>Source:</color> " + text;
		}
	}
}
[HarmonyPatch(typeof(InventoryGui), "Update")]
[HarmonyPriority(800)]
internal static class FilterGamepadCancelPatch
{
	private static void Prefix(InventoryGui __instance)
	{
		ModOriginPlugin.ConsumeFilterCancelBeforeInventoryUpdate(__instance);
	}
}
[HarmonyPatch(typeof(InventoryGui), "Show", new Type[]
{
	typeof(Container),
	typeof(int)
})]
internal static class NewStationGamepadFocusPatch
{
	private static void Postfix(InventoryGui __instance)
	{
		ModOriginPlugin.OnCraftingWindowShown(__instance);
	}
}
[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeGamepadInput")]
internal static class FilterGamepadNavigationPatch
{
	private static bool Prefix(InventoryGui __instance)
	{
		return ModOriginPlugin.HandleRecipeGamepadInput(__instance);
	}
}
[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
internal static class RecipeListPatch
{
	private static void Prefix(InventoryGui __instance, ref List<Recipe> recipes)
	{
		if (!ModOriginPlugin.IsStationCrafting())
		{
			if (ModOriginPlugin.UiReady)
			{
				ModOriginPlugin.ResetUi();
			}
		}
		else
		{
			ModOriginPlugin.EnsureUi(__instance);
			ModOriginPlugin.UpdateRecipes(ref recipes);
		}
	}

	private static void Postfix(InventoryGui __instance, List<Recipe> recipes)
	{
		ModOriginPlugin.SortActualRecipeRows(__instance);
		ModOriginPlugin.DecorateRecipeRows(__instance, recipes);
	}
}
[HarmonyPatch(typeof(InventoryGui), "SetRecipe", new Type[]
{
	typeof(int),
	typeof(bool)
})]
internal static class GameRecipeSelectionPatch
{
	private static void Postfix(InventoryGui __instance, int __0)
	{
		ModOriginPlugin.OnGameRecipeSelected(__instance, __0);
	}
}
[HarmonyPatch(typeof(InventoryGui), "Hide")]
internal static class InventoryHidePatch
{
	private static void Postfix()
	{
		ModOriginPlugin.EndCraftingMenuSession();
		ModOriginPlugin.ResetFilterSelections();
	}
}
[HarmonyPatch(typeof(Player), "UpdateKnownRecipesList")]
internal static class KnownRecipesChangedPatch
{
	private static void Prefix(Player __instance, out HashSet<string> __state)
	{
		__state = ModOriginPlugin.SnapshotKnownRecipes(__instance);
	}

	private static void Postfix(Player __instance, HashSet<string> __state)
	{
		ModOriginPlugin.TrackRecipeDiscovery(__instance, __state);
	}
}