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;
}
}