Decompiled source of ExtendedCraftingCategories v1.0.0

ExtendedCraftingCategories.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ExtendedCraftingCategories")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+cf109efb2feabf1b08edb3810e40e13258f8fe8c")]
[assembly: AssemblyProduct("ExtendedCraftingCategories")]
[assembly: AssemblyTitle("ExtendedCraftingCategories")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ExtendedCraftingCategoriesMod;

[BepInPlugin("com.iancula.extendedcraftingcategories", "Extended crafting categories", "1.0.0")]
public class ExtendedCraftingCategoriesPlugin : BaseUnityPlugin
{
	public const string GUID = "com.iancula.extendedcraftingcategories";

	public const string NAME = "Extended crafting categories";

	public const string VERSION = "1.0.0";

	internal static ManualLogSource Log;

	private void Awake()
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		Log = ((BaseUnityPlugin)this).Logger;
		if (!CraftingMenu_RefreshAutoRecipe_Patch.ValidateReflection())
		{
			Log.LogError((object)"Reflection validation failed – patch will NOT be applied. Check the errors above.");
			return;
		}
		new Harmony("com.iancula.extendedcraftingcategories").PatchAll();
		Log.LogInfo((object)"Extended crafting categories loaded successfully.");
	}
}
[HarmonyPatch(typeof(CraftingMenu), "RefreshAutoRecipe")]
public static class CraftingMenu_RefreshAutoRecipe_Patch
{
	private struct SectionTitles
	{
		public RectTransform T1;

		public RectTransform T2;

		public RectTransform T3;
	}

	private static FieldInfo _f_refreshComplexRequired;

	private static FieldInfo _f_simpleMode;

	private static FieldInfo _f_allRecipes;

	private static FieldInfo _f_complexRecipes;

	private static FieldInfo _f_displayTemplate;

	private static FieldInfo _f_recipeDisplays;

	private static FieldInfo _f_recipeSeparator;

	private static FieldInfo _f_lastCraftedRecipeIndex;

	private static FieldInfo _f_lastPouchVersion;

	private static FieldInfo _f_lastBagVersion;

	private static FieldInfo _f_lblStationName;

	private static PropertyInfo _p_localCharacter;

	private static MethodInfo _m_refreshAvailableIngredients;

	private static MethodInfo _m_refreshAutoIngredients;

	private static readonly Dictionary<CraftingMenu, SectionTitles> _titleCache = new Dictionary<CraftingMenu, SectionTitles>();

	public static bool ValidateReflection()
	{
		return true & ResolveField(typeof(CraftingMenu), "m_refreshComplexeRecipeRequired", out _f_refreshComplexRequired) & ResolveField(typeof(CraftingMenu), "m_simpleMode", out _f_simpleMode) & ResolveField(typeof(CraftingMenu), "m_allRecipes", out _f_allRecipes) & ResolveField(typeof(CraftingMenu), "m_complexeRecipes", out _f_complexRecipes) & ResolveField(typeof(CraftingMenu), "m_recipeDisplayTemplate", out _f_displayTemplate) & ResolveField(typeof(CraftingMenu), "m_recipeDisplays", out _f_recipeDisplays) & ResolveField(typeof(CraftingMenu), "m_recipeSeparator", out _f_recipeSeparator) & ResolveField(typeof(CraftingMenu), "m_lastCraftedRecipeIndex", out _f_lastCraftedRecipeIndex) & ResolveField(typeof(CraftingMenu), "m_lastPouchVersion", out _f_lastPouchVersion) & ResolveField(typeof(CraftingMenu), "m_lastBagVersion", out _f_lastBagVersion) & ResolveField(typeof(CraftingMenu), "m_lblStationName", out _f_lblStationName) & ResolvePropertyInHierarchy(typeof(CraftingMenu), "LocalCharacter", out _p_localCharacter) & ResolveMethod(typeof(CraftingMenu), "RefreshAvailableIngredients", out _m_refreshAvailableIngredients) & ResolveMethod(typeof(CraftingMenu), "RefreshAutoIngredients", out _m_refreshAutoIngredients);
	}

	private static bool Prefix(CraftingMenu __instance)
	{
		try
		{
			return RunReplacement(__instance);
		}
		catch (Exception ex)
		{
			ExtendedCraftingCategoriesPlugin.Log.LogError((object)ex);
			return true;
		}
	}

	private static bool RunReplacement(CraftingMenu instance)
	{
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007b: Expected O, but got Unknown
		//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Expected O, but got Unknown
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Expected O, but got Unknown
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_043c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0446: Expected O, but got Unknown
		bool num = (bool)_f_refreshComplexRequired.GetValue(instance);
		bool flag = (bool)_f_simpleMode.GetValue(instance);
		List<Recipe> list = (List<Recipe>)_f_allRecipes.GetValue(instance);
		List<KeyValuePair<int, Recipe>> list2 = (List<KeyValuePair<int, Recipe>>)_f_complexRecipes.GetValue(instance);
		RecipeDisplay val = (RecipeDisplay)_f_displayTemplate.GetValue(instance);
		List<RecipeDisplay> recipeDisplays = (List<RecipeDisplay>)_f_recipeDisplays.GetValue(instance);
		RectTransform val2 = (RectTransform)_f_recipeSeparator.GetValue(instance);
		int lastCraftedIdx = (int)_f_lastCraftedRecipeIndex.GetValue(instance);
		Character val3 = (Character)_p_localCharacter.GetValue(instance, null);
		if ((Object)(object)val2 != (Object)null)
		{
			((Component)val2).gameObject.SetActive(false);
		}
		_m_refreshAvailableIngredients.Invoke(instance, null);
		if (num)
		{
			list2.Clear();
			if (!flag)
			{
				for (int i = 0; i < list.Count; i++)
				{
					Recipe val4 = list[i];
					if (val4.IngredientCount > 1 && val3.Inventory.RecipeKnowledge.IsRecipeLearned(UID.op_Implicit(val4.UID)))
					{
						list2.Add(new KeyValuePair<int, Recipe>(i, val4));
					}
				}
			}
			_f_refreshComplexRequired.SetValue(instance, false);
		}
		list2.Sort((Comparison<KeyValuePair<int, Recipe>>)Recipe.SortByName);
		if ((Object)(object)val == (Object)null)
		{
			Debug.LogError((object)"No RecipeDisplay template.");
			return false;
		}
		_f_lastPouchVersion.SetValue(instance, val3.Inventory.Pouch.Version);
		_f_lastBagVersion.SetValue(instance, val3.Inventory.HasABag ? ((ItemContainer)val3.Inventory.EquippedBag.Container).Version : (-1));
		Transform parent = ((Component)val).transform.parent;
		EnsureTitles(instance, parent);
		SectionTitles sectionTitles = _titleCache[instance];
		foreach (RecipeDisplay item in recipeDisplays)
		{
			((Component)item).transform.SetSiblingIndex(int.MaxValue);
		}
		((Transform)sectionTitles.T1).SetSiblingIndex(int.MaxValue);
		((Transform)sectionTitles.T2).SetSiblingIndex(int.MaxValue);
		((Transform)sectionTitles.T3).SetSiblingIndex(int.MaxValue);
		List<int> list3 = new List<int>();
		List<int> list4 = new List<int>();
		List<int> list5 = new List<int>();
		int num2 = -1;
		for (int j = 0; j < list2.Count; j++)
		{
			if (j >= recipeDisplays.Count)
			{
				RecipeDisplay val5 = Object.Instantiate<RecipeDisplay>(val);
				((Component)val5).transform.SetParent(parent);
				UnityEngineExtensions.ResetLocal(((Component)val5).transform, true);
				((UIElement)val5).Show();
				recipeDisplays.Add(val5);
			}
			object[] array = new object[3]
			{
				list2[j].Value,
				null,
				null
			};
			bool flag2 = (bool)_m_refreshAutoIngredients.Invoke(instance, array);
			IList<int>[] array2 = (IList<int>[])array[1];
			IList<int> list6 = (IList<int>)array[2];
			int num3 = Categorize(flag2, array2);
			switch (num3)
			{
			case 0:
				list3.Add(j);
				break;
			case 1:
				list4.Add(j);
				break;
			default:
				list5.Add(j);
				break;
			}
			((UIElement)recipeDisplays[j]).Show();
			recipeDisplays[j].SetReferencedRecipe(list2[j].Value, flag2, array2, list6);
			int captured = j;
			((UnityEventBase)recipeDisplays[j].onClick).RemoveAllListeners();
			((UnityEvent)recipeDisplays[j].onClick).AddListener((UnityAction)delegate
			{
				instance.OnRecipeSelected(captured, false);
			});
			if (j == lastCraftedIdx)
			{
				num2 = num3;
			}
		}
		if (lastCraftedIdx != -1 && num2 != 0)
		{
			list4.Remove(lastCraftedIdx);
			list5.Remove(lastCraftedIdx);
			list3.Add(lastCraftedIdx);
		}
		List<object> list7 = new List<object>();
		bool flag3 = list5.Count > 0;
		bool flag4 = list4.Count > 0;
		bool flag5 = list3.Count > 0 && (flag4 || flag3);
		if (flag5)
		{
			list7.Add(sectionTitles.T1);
		}
		foreach (int item2 in list3)
		{
			list7.Add(recipeDisplays[item2]);
		}
		if (flag4)
		{
			list7.Add(sectionTitles.T2);
		}
		foreach (int item3 in list4)
		{
			list7.Add(recipeDisplays[item3]);
		}
		if (flag3)
		{
			list7.Add(sectionTitles.T3);
		}
		foreach (int item4 in list5)
		{
			list7.Add(recipeDisplays[item4]);
		}
		int num4 = 1;
		foreach (object item5 in list7)
		{
			RectTransform val6 = (RectTransform)((item5 is RectTransform) ? item5 : null);
			if (val6 != null)
			{
				((Component)val6).gameObject.SetActive(true);
				((Transform)val6).SetSiblingIndex(num4++);
				continue;
			}
			RecipeDisplay val7 = (RecipeDisplay)((item5 is RecipeDisplay) ? item5 : null);
			if (val7 != null)
			{
				((Component)val7).transform.SetSiblingIndex(num4++);
				val7.RealSiblingIndex = -1;
			}
		}
		((Component)sectionTitles.T1).gameObject.SetActive(flag5);
		((Component)sectionTitles.T2).gameObject.SetActive(flag4);
		((Component)sectionTitles.T3).gameObject.SetActive(flag3);
		if (lastCraftedIdx != -1)
		{
			int num5 = list7.FindIndex(delegate(object o)
			{
				RecipeDisplay val8 = (RecipeDisplay)((o is RecipeDisplay) ? o : null);
				return val8 != null && (Object)(object)val8 == (Object)(object)recipeDisplays[lastCraftedIdx];
			});
			if (num5 != -1)
			{
				recipeDisplays[lastCraftedIdx].RealSiblingIndex = num5 + 1;
			}
		}
		for (int k = list2.Count; k < recipeDisplays.Count; k++)
		{
			((UIElement)recipeDisplays[k]).Hide();
			((Component)recipeDisplays[k]).transform.SetSiblingIndex(int.MaxValue);
		}
		LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)(object)((parent is RectTransform) ? parent : null));
		return false;
	}

	private static int Categorize(bool canCraftFully, IList<int>[] allMatches)
	{
		if (canCraftFully)
		{
			return 0;
		}
		if (allMatches != null)
		{
			foreach (IList<int> list in allMatches)
			{
				if (list != null && list.Count > 0)
				{
					return 1;
				}
			}
		}
		return 2;
	}

	private static void EnsureTitles(CraftingMenu instance, Transform parent)
	{
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Expected O, but got Unknown
		//IL_00b9: 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_0107: Unknown result type (might be due to invalid IL or missing references)
		Font font = Resources.GetBuiltinResource<Font>("Arial.ttf");
		if (_f_lblStationName != null)
		{
			object? value = _f_lblStationName.GetValue(instance);
			Text val = (Text)((value is Text) ? value : null);
			if ((Object)(object)val != (Object)null && (Object)(object)val.font != (Object)null)
			{
				font = val.font;
			}
		}
		foreach (Transform item in parent)
		{
			Transform val2 = item;
			if (((Object)val2).name.StartsWith("_SectionTitle_"))
			{
				Object.Destroy((Object)(object)((Component)val2).gameObject);
			}
		}
		SectionTitles sectionTitles = default(SectionTitles);
		sectionTitles.T1 = CreateTitle("- Craftable -", parent, new Color(0.4f, 0.9f, 0.4f), font);
		sectionTitles.T2 = CreateTitle("- Partially missing -", parent, new Color(1f, 0.85f, 0.3f), font);
		sectionTitles.T3 = CreateTitle("- Fully missing -", parent, new Color(0.9f, 0.3f, 0.3f), font);
		SectionTitles value2 = sectionTitles;
		_titleCache[instance] = value2;
	}

	private static RectTransform CreateTitle(string label, Transform parent, Color color, Font font)
	{
		//IL_000b: 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)
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject("_SectionTitle_" + label);
		val.transform.SetParent(parent, false);
		RectTransform result = val.AddComponent<RectTransform>();
		val.AddComponent<LayoutElement>().preferredHeight = 40f;
		Text obj = val.AddComponent<Text>();
		((Graphic)obj).color = color;
		obj.text = label;
		obj.font = font;
		obj.alignment = (TextAnchor)4;
		obj.fontStyle = (FontStyle)2;
		obj.fontSize = 22;
		obj.fontStyle = (FontStyle)3;
		obj.alignment = (TextAnchor)4;
		((Graphic)obj).raycastTarget = false;
		return result;
	}

	private static bool ResolveField(Type type, string name, out FieldInfo result)
	{
		result = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (result != null)
		{
			return true;
		}
		ExtendedCraftingCategoriesPlugin.Log.LogError((object)("Missing field: " + name));
		return false;
	}

	private static bool ResolveMethod(Type type, string name, out MethodInfo result)
	{
		result = type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (result != null)
		{
			return true;
		}
		ExtendedCraftingCategoriesPlugin.Log.LogError((object)("Missing method: " + name));
		return false;
	}

	private static bool ResolvePropertyInHierarchy(Type type, string name, out PropertyInfo result)
	{
		while (type != null)
		{
			result = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
			if (result != null)
			{
				return true;
			}
			type = type.BaseType;
		}
		result = null;
		return false;
	}
}