Decompiled source of VanillaCraftingFilter v0.1.0

VanillaCraftingFilter.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Logging;
using GUIFramework;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Vanilla Crafting Filter")]
[assembly: AssemblyDescription("Adds the build menu's filter box to the crafting panel of every crafting station.")]
[assembly: AssemblyCompany("falconnn")]
[assembly: AssemblyProduct("Vanilla Crafting Filter")]
[assembly: AssemblyCopyright("Made by falconnn")]
[assembly: AssemblyFileVersion("0.1.0")]
[assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially or fully created with the assistance of Generative AI (Claude Code, Anthropic's AI coding agent).")]
[assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic")]
[assembly: AssemblyVersion("0.1.0.0")]
namespace VanillaCraftingFilter;

[HarmonyPatch]
internal static class CraftingFilter
{
	private const float Gap = 10f;

	private const float FallbackHeight = 36f;

	private static readonly Predicate<Recipe> DoesNotMatch = (Recipe recipe) => !Matches(recipe);

	private static FieldRef<BuildUi, GuiInputField> s_searchFieldRef;

	private static FieldRef<UIInputHint, UIGroupHandler> s_hintAlternativeGroupRef;

	private static Action<InventoryGui, bool> s_updateCraftingPanel;

	private static GuiInputField s_field;

	private static InventoryGui s_failedFor;

	private static string s_query = "";

	private static int s_focusedFrame = -1;

	private static bool IsTyping
	{
		get
		{
			if ((Object)(object)s_field != (Object)null)
			{
				if (!((TMP_InputField)s_field).isFocused)
				{
					return s_focusedFrame >= Time.frameCount - 1;
				}
				return true;
			}
			return false;
		}
	}

	[HarmonyPatch(typeof(Chat), "HasFocus")]
	[HarmonyPostfix]
	private static void TypingCountsAsChatFocus(ref bool __result)
	{
		if (IsTyping)
		{
			__result = true;
		}
	}

	[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
	[HarmonyPrefix]
	private static void RemoveNonMatching(List<Recipe> recipes)
	{
		if (s_query.Length > 0)
		{
			recipes.RemoveAll(DoesNotMatch);
		}
	}

	[HarmonyPatch(typeof(InventoryGui), "Update")]
	[HarmonyPostfix]
	private static void UpdateBox(InventoryGui __instance)
	{
		if ((Object)(object)s_field == (Object)null)
		{
			if ((Object)(object)s_failedFor != (Object)(object)__instance)
			{
				TryCreate(__instance);
			}
		}
		else if (((TMP_InputField)s_field).isFocused)
		{
			s_focusedFrame = Time.frameCount;
		}
		else if (InventoryGui.IsVisible() && ((Component)s_field).gameObject.activeInHierarchy && !OtherTextInputActive() && ZInput.GetKeyDown((KeyCode)102, true))
		{
			s_field.ActivateInputField();
		}
	}

	[HarmonyPatch(typeof(InventoryGui), "Hide")]
	[HarmonyPostfix]
	private static void ClearOnClose()
	{
		if (!((Object)(object)s_field == (Object)null) && ((TMP_InputField)s_field).text.Length != 0)
		{
			((TMP_InputField)s_field).SetTextWithoutNotify("");
			s_query = "";
		}
	}

	private static void TryCreate(InventoryGui gui)
	{
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_016d: Expected O, but got Unknown
		//IL_016d: Expected O, but got Unknown
		try
		{
			if ((Object)(object)Hud.instance == (Object)null || (Object)(object)Hud.instance.m_buildUi == (Object)null || (Object)(object)gui.m_recipeListRoot == (Object)null)
			{
				return;
			}
			if (s_searchFieldRef == null)
			{
				s_searchFieldRef = AccessTools.FieldRefAccess<BuildUi, GuiInputField>("m_searchField");
				s_hintAlternativeGroupRef = AccessTools.FieldRefAccess<UIInputHint, UIGroupHandler>("alternativeGroupHandler");
				s_updateCraftingPanel = AccessTools.MethodDelegate<Action<InventoryGui, bool>>(AccessTools.Method(typeof(InventoryGui), "UpdateCraftingPanel", (Type[])null, (Type[])null), (object)null, true);
			}
			GuiInputField val = s_searchFieldRef.Invoke(Hud.instance.m_buildUi);
			ScrollRect componentInParent = ((Component)gui.m_recipeListRoot).GetComponentInParent<ScrollRect>(true);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)componentInParent == (Object)null))
			{
				GameObject obj = CopyWithoutCaret(((Component)val).gameObject, ((Component)componentInParent).transform.parent);
				UIInputHint componentInChildren = obj.GetComponentInChildren<UIInputHint>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					s_hintAlternativeGroupRef.Invoke(componentInChildren) = gui.m_playerGrid.m_uiGroup;
				}
				GuiInputField component = obj.GetComponent<GuiInputField>();
				MuteCopiedListeners(component);
				((TMP_InputField)component).SetTextWithoutNotify("");
				((UnityEvent<string>)(object)((TMP_InputField)component).onValueChanged).AddListener((UnityAction<string>)OnTextChanged);
				Rect rect = ((RectTransform)((Component)val).transform).rect;
				float height = ((Rect)(ref rect)).height;
				PlaceAbove((RectTransform)obj.transform, (RectTransform)((Component)componentInParent).transform, gui.m_recipeListScroll, (height > 1f) ? height : 36f);
				s_field = component;
			}
		}
		catch (Exception arg)
		{
			s_failedFor = gui;
			Plugin.Log.LogError((object)$"Couldn't add the filter box to the crafting panel: {arg}");
		}
	}

	private static GameObject CopyWithoutCaret(GameObject source, Transform parent)
	{
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Expected O, but got Unknown
		GameObject val = new GameObject("VanillaCraftingFilterHolder");
		val.SetActive(false);
		GameObject val2 = Object.Instantiate<GameObject>(source, val.transform, false);
		((Object)val2).name = "VanillaCraftingFilter";
		TMP_SelectionCaret[] componentsInChildren = val2.GetComponentsInChildren<TMP_SelectionCaret>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Object.DestroyImmediate((Object)(object)((Component)componentsInChildren[i]).gameObject);
		}
		val2.transform.SetParent(parent, false);
		Object.Destroy((Object)(object)val);
		val2.SetActive(true);
		return val2;
	}

	private static void MuteCopiedListeners(GuiInputField field)
	{
		UnityEventBase[] array = (UnityEventBase[])(object)new UnityEventBase[5]
		{
			(UnityEventBase)((TMP_InputField)field).onValueChanged,
			(UnityEventBase)((TMP_InputField)field).onEndEdit,
			(UnityEventBase)((TMP_InputField)field).onSubmit,
			(UnityEventBase)((TMP_InputField)field).onSelect,
			(UnityEventBase)((TMP_InputField)field).onDeselect
		};
		foreach (UnityEventBase val in array)
		{
			for (int j = 0; j < val.GetPersistentEventCount(); j++)
			{
				val.SetPersistentListenerState(j, (UnityEventCallState)0);
			}
		}
	}

	private static void PlaceAbove(RectTransform box, RectTransform list, Scrollbar scrollbar, float height)
	{
		//IL_0002: 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: Unknown result type (might be due to invalid IL or missing references)
		//IL_0023: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: 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_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		box.anchorMin = new Vector2(list.anchorMin.x, list.anchorMax.y);
		box.anchorMax = list.anchorMax;
		box.pivot = new Vector2(0.5f, 1f);
		box.offsetMin = new Vector2(list.offsetMin.x, list.offsetMax.y - height);
		box.offsetMax = list.offsetMax;
		Vector2 val = default(Vector2);
		((Vector2)(ref val))..ctor(0f, height + 10f);
		list.offsetMax -= val;
		if ((Object)(object)scrollbar != (Object)null && (Object)(object)((Component)scrollbar).transform.parent == (Object)(object)((Transform)list).parent)
		{
			RectTransform val2 = (RectTransform)((Component)scrollbar).transform;
			val2.offsetMax -= val;
		}
	}

	private static void OnTextChanged(string text)
	{
		s_query = Normalize(text);
		InventoryGui instance = InventoryGui.instance;
		if ((Object)(object)instance != (Object)null && InventoryGui.IsVisible())
		{
			s_updateCraftingPanel(instance, arg2: false);
		}
	}

	private static bool OtherTextInputActive()
	{
		if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible())
		{
			return TextInput.IsVisible();
		}
		return true;
	}

	private static bool Matches(Recipe recipe)
	{
		if ((Object)(object)recipe.m_item != (Object)null && NameMatches(recipe.m_item))
		{
			return true;
		}
		if (recipe.m_resources == null)
		{
			return false;
		}
		Requirement[] resources = recipe.m_resources;
		foreach (Requirement val in resources)
		{
			if ((Object)(object)val.m_resItem != (Object)null && NameMatches(val.m_resItem))
			{
				return true;
			}
		}
		return false;
	}

	private static bool NameMatches(ItemDrop item)
	{
		return Normalize(Localization.instance.Localize(item.m_itemData.m_shared.m_name)).Contains(s_query);
	}

	private static string Normalize(string text)
	{
		return text.Replace(" ", "").ToLowerInvariant();
	}
}
[BepInPlugin("falconnn.VanillaCraftingFilter", "Vanilla Crafting Filter", "0.1.0")]
public class Plugin : BaseUnityPlugin
{
	public const string Guid = "falconnn.VanillaCraftingFilter";

	public const string Name = "Vanilla Crafting Filter";

	public const string Version = "0.1.0";

	internal static ManualLogSource Log;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		Log = ((BaseUnityPlugin)this).Logger;
		_harmony = new Harmony("falconnn.VanillaCraftingFilter");
		_harmony.PatchAll(typeof(Plugin).Assembly);
	}

	private void OnDestroy()
	{
		Harmony harmony = _harmony;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
	}
}