Decompiled source of FoodCategories v0.1.35

FoodCategories.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
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.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("FoodCategories")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.35.0")]
[assembly: AssemblyInformationalVersion("0.1.35")]
[assembly: AssemblyProduct("FoodCategories")]
[assembly: AssemblyTitle("FoodCategories")]
[assembly: AssemblyVersion("0.1.35.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FoodCategories
{
	[BepInPlugin("branchofyore.foodcategories", "Food Categories", "0.1.35")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private enum FoodFilter
		{
			All,
			Health,
			Stamina,
			Eitr,
			Balanced,
			Feast
		}

		private sealed class FilterBar
		{
			public FoodFilter Current;

			public RectTransform Root;

			public bool PreparationStation;

			public readonly Dictionary<FoodFilter, Button> Buttons = new Dictionary<FoodFilter, Button>();

			public Sprite? TabSprite;

			public Image? CraftTabTemplate;

			public Image? UpgradeTabTemplate;
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
		private static class RecipeListPatch
		{
			private static void Postfix(InventoryGui __instance)
			{
				try
				{
					Apply(__instance, resetScroll: true);
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)("Food Categories: " + ex.Message));
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Update")]
		private static class CraftWindowRefreshPatch
		{
			private static void Postfix(InventoryGui __instance)
			{
				if (Environment.GetEnvironmentVariable("FOOD_CATEGORIES_MANUAL_TEST") == "1" && KeepManualCraftMenuOpen)
				{
					if (Input.GetKeyDown((KeyCode)27))
					{
						KeepManualCraftMenuOpen = false;
					}
					else
					{
						if (Object.op_Implicit((Object)(object)__instance.m_inventoryRoot) && !((Component)__instance.m_inventoryRoot).gameObject.activeSelf)
						{
							((Component)__instance.m_inventoryRoot).gameObject.SetActive(true);
						}
						if (Object.op_Implicit((Object)(object)__instance.m_inventoryGroup) && !__instance.m_inventoryGroup.IsActive)
						{
							__instance.m_inventoryGroup.SetActive(true);
						}
						if (Object.op_Implicit((Object)(object)__instance.m_crafting) && !((Component)__instance.m_crafting).gameObject.activeSelf)
						{
							((Component)__instance.m_crafting).gameObject.SetActive(true);
						}
						if (Object.op_Implicit((Object)(object)__instance.m_recipeListRoot) && !((Component)__instance.m_recipeListRoot).gameObject.activeSelf)
						{
							((Component)__instance.m_recipeListRoot).gameObject.SetActive(true);
						}
						if (Object.op_Implicit((Object)(object)__instance.m_inventoryRoot))
						{
							foreach (CanvasGroup item in ((Component)__instance.m_inventoryRoot).GetComponentsInParent<CanvasGroup>(true).Concat(((Component)__instance.m_inventoryRoot).GetComponentsInChildren<CanvasGroup>(true)).Distinct())
							{
								item.alpha = 1f;
								item.interactable = true;
								item.blocksRaycasts = true;
							}
						}
						if (!__instance.InCraftTab())
						{
							AccessTools.Method(typeof(InventoryGui), "OnTabCraftPressed", (Type[])null, (Type[])null)?.Invoke(__instance, null);
						}
					}
				}
				if (!Object.op_Implicit((Object)(object)__instance))
				{
					return;
				}
				Transform inventoryRoot = __instance.m_inventoryRoot;
				if (!Object.op_Implicit((Object)(object)inventoryRoot) || !((Component)inventoryRoot).gameObject.activeInHierarchy || !Object.op_Implicit((Object)(object)__instance.m_inventoryGroup) || !__instance.m_inventoryGroup.IsActive || !__instance.InCraftTab())
				{
					HideBar(__instance);
					return;
				}
				float unscaledTime = Time.unscaledTime;
				if (NextCategoryRefresh.TryGetValue(__instance, out var value) && unscaledTime < value)
				{
					return;
				}
				NextCategoryRefresh[__instance] = unscaledTime + 0.2f;
				try
				{
					Apply(__instance);
				}
				catch (Exception ex)
				{
					Debug.LogWarning((object)("Food Categories refresh: " + ex.Message));
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		private static class HideCraftMenuPatch
		{
			private static void Postfix(InventoryGui __instance)
			{
				HideBar(__instance);
			}
		}

		[HarmonyPatch(typeof(UIGroupHandler), "SetActive")]
		private static class InventoryGroupVisibilityPatch
		{
			private static void Postfix(UIGroupHandler __instance, bool active)
			{
				if (active)
				{
					return;
				}
				InventoryGui[] array = Bars.Keys.ToArray();
				foreach (InventoryGui val in array)
				{
					if (Object.op_Implicit((Object)(object)val) && (Object)(object)val.m_inventoryGroup == (Object)(object)__instance)
					{
						HideBar(val);
					}
				}
			}
		}

		private sealed class Entry
		{
			public Recipe Recipe;

			public ItemData Item;

			public GameObject Element;
		}

		public const string Id = "branchofyore.foodcategories";

		private static readonly Harmony Harmony = new Harmony("branchofyore.foodcategories");

		private static readonly Dictionary<InventoryGui, FilterBar> Bars = new Dictionary<InventoryGui, FilterBar>();

		private static readonly Dictionary<InventoryGui, float> NextCategoryRefresh = new Dictionary<InventoryGui, float>();

		private static readonly HashSet<string> AuditedRows = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<RectTransform, Vector2> OriginalRowPositions = new Dictionary<RectTransform, Vector2>();

		private static readonly Dictionary<RectTransform, Vector2> OriginalRowSizes = new Dictionary<RectTransform, Vector2>();

		private static ManualLogSource? TestLog;

		private static bool KeepManualCraftMenuOpen;

		private void Awake()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			TestLog = ((BaseUnityPlugin)this).Logger;
			if (Environment.GetEnvironmentVariable("FOOD_CATEGORIES_MANUAL_TEST") == "1")
			{
				Application.runInBackground = true;
			}
			Harmony.PatchAll();
			if (Environment.GetEnvironmentVariable("FOOD_CATEGORIES_MANUAL_TEST") == "1")
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Player), "GetMaxCarryWeight", (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					Harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "TestCarryWeightPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Food Categories: crafting food filters enabled.");
			if (Environment.GetEnvironmentVariable("FOOD_CATEGORIES_MANUAL_TEST") == "1")
			{
				((MonoBehaviour)this).StartCoroutine(PrepareManualTest());
			}
		}

		private void OnDestroy()
		{
			Harmony.UnpatchSelf();
		}

		private static void TestCarryWeightPostfix(ref float __result)
		{
			if (Environment.GetEnvironmentVariable("FOOD_CATEGORIES_MANUAL_TEST") == "1")
			{
				__result = 100000f;
			}
		}

		private IEnumerator PrepareManualTest()
		{
			yield return (object)new WaitForSecondsRealtime(10f);
			Game.SetProfile("FoodCategories_Manual_" + DateTime.UtcNow.Ticks, (FileSource)2);
			ZNet.SetServer(true, false, false, "Food Categories test", "", World.GetCreateWorld("FoodCategories_Test", (FileSource)2));
			AccessTools.Method(typeof(FejdStartup), "LoadMainScene", (Type[])null, (Type[])null)?.Invoke(FejdStartup.instance, null);
			float deadline = Time.realtimeSinceStartup + 180f;
			while (!Object.op_Implicit((Object)(object)Player.m_localPlayer) && Time.realtimeSinceStartup < deadline)
			{
				yield return (object)new WaitForSecondsRealtime(1f);
			}
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)ObjectDB.instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				yield break;
			}
			yield return (object)new WaitForSecondsRealtime(4f);
			Valkyrie[] array = Object.FindObjectsByType<Valkyrie>((FindObjectsSortMode)0);
			foreach (Valkyrie val in array)
			{
				ZNetScene.instance.Destroy(((Component)val).gameObject);
			}
			Player player = Player.m_localPlayer;
			player.SetIntro(false);
			((Character)player).AttachStop();
			if (Object.op_Implicit((Object)(object)TextViewer.instance))
			{
				TextViewer.instance.HideIntro();
			}
			Vector3 val2 = default(Vector3);
			ZoneSystem.instance.GetLocationIcon("StartTemple", ref val2);
			val2.y = ZoneSystem.instance.GetGroundHeight(val2) + 0.2f;
			((Component)player).transform.position = val2;
			((Component)player).GetComponent<Rigidbody>().position = val2;
			((Component)player).GetComponent<Rigidbody>().linearVelocity = Vector3.zero;
			AccessTools.Field(typeof(Player), "m_noPlacementCost")?.SetValue(player, true);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Native food labels: " + Localization.instance.Localize("$item_food_health") + " | " + Localization.instance.Localize("$item_food_stamina") + " | " + Localization.instance.Localize("$item_food_eitr")));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("TEST station interaction APIs: " + string.Join(" | ", from method in typeof(CraftingStation).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
				where method.Name.IndexOf("interact", StringComparison.OrdinalIgnoreCase) >= 0 || method.Name.IndexOf("craft", StringComparison.OrdinalIgnoreCase) >= 0
				select method.Name + "(" + string.Join(",", from parameter in method.GetParameters()
					select parameter.ParameterType.Name) + ")")));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Native UI sprite candidates: " + string.Join(", ", (from sprite in Resources.FindObjectsOfTypeAll<Sprite>()
				where ((Object)sprite).name.IndexOf("food", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)sprite).name.IndexOf("health", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)sprite).name.IndexOf("stamina", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)sprite).name.IndexOf("eitr", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)sprite).name.IndexOf("fork", StringComparison.OrdinalIgnoreCase) >= 0
				select ((Object)sprite).name).Distinct().Take(80))));
			List<Recipe> testRecipes = ObjectDB.instance.m_recipes.Where((Recipe recipe) => Object.op_Implicit((Object)(object)recipe?.m_item) && (IsFood(recipe.m_item.m_itemData) || IsFeast(recipe.m_item.m_itemData) || IsMead(recipe.m_item.m_itemData))).ToList();
			foreach (Recipe item in testRecipes)
			{
				AccessTools.Method(typeof(Player), "AddKnownRecipe", new Type[1] { typeof(Recipe) }, (Type[])null)?.Invoke(player, new object[1] { item });
				player.AddKnownItem(item.m_item.m_itemData);
				Requirement[] resources = item.m_resources;
				foreach (Requirement val3 in resources)
				{
					if (Object.op_Implicit((Object)(object)val3?.m_resItem))
					{
						player.AddKnownItem(val3.m_resItem.m_itemData);
					}
				}
			}
			(string, int)[] array2 = new(string, int)[23]
			{
				("Hammer", 1),
				("Wood", 100),
				("Stone", 100),
				("Tin", 40),
				("RawMeat", 20),
				("DeerMeat", 20),
				("WolfMeat", 20),
				("LoxMeat", 20),
				("Raspberry", 20),
				("Blueberries", 20),
				("Cloudberry", 20),
				("Mushroom", 20),
				("Honey", 20),
				("Barley", 20),
				("BarleyFlour", 20),
				("FishRaw", 20),
				("Thistle", 20),
				("Dandelion", 20),
				("GreydwarfEye", 20),
				("Bloodbag", 20),
				("FreezeGland", 20),
				("Ooze", 20),
				("Entrails", 20)
			};
			for (int i = 0; i < array2.Length; i++)
			{
				(string, int) tuple = array2[i];
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(tuple.Item1);
				ItemDrop val4 = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if (Object.op_Implicit((Object)(object)val4))
				{
					ItemData val5 = val4.m_itemData.Clone();
					val5.m_dropPrefab = itemPrefab;
					val5.m_stack = tuple.Item2;
					((Humanoid)player).GetInventory().AddItem(val5);
				}
			}
			foreach (Requirement item2 in from @group in (from requirement in testRecipes.Where((Recipe recipe) => IsMead(recipe.m_item.m_itemData)).SelectMany((Recipe recipe) => recipe.m_resources)
					where Object.op_Implicit((Object)(object)requirement?.m_resItem)
					select requirement).GroupBy<Requirement, string>((Requirement requirement) => ((Object)requirement.m_resItem).name, StringComparer.OrdinalIgnoreCase)
				select @group.First())
			{
				GameObject gameObject = ((Component)item2.m_resItem).gameObject;
				ItemDrop component = gameObject.GetComponent<ItemDrop>();
				if (Object.op_Implicit((Object)(object)component))
				{
					ItemData val6 = component.m_itemData.Clone();
					val6.m_dropPrefab = gameObject;
					val6.m_stack = Math.Max(20, item2.m_amount);
					((Humanoid)player).GetInventory().AddItem(val6);
				}
			}
			Vector3 kitchen = val2 + ((Component)player).transform.forward * 6f;
			kitchen.y = ZoneSystem.instance.GetGroundHeight(kitchen);
			SpawnTestPiece("fire_pit", kitchen);
			SpawnTestPiece("piece_cauldron", kitchen + Vector3.up * 1.15f, 180f);
			SpawnTestPiece("piece_cauldron_ext1_spice", kitchen + new Vector3(-2.3f, 0f, 1.4f), 35f);
			SpawnTestPiece("piece_cauldron_ext3_butchertable", kitchen + new Vector3(2.3f, 0f, 1.4f), -35f);
			SpawnTestPiece("piece_cauldron_ext4_pans", kitchen + new Vector3(-2.3f, 0f, -1.4f), 145f);
			SpawnTestPiece("piece_cauldron_ext5_mortarandpestle", kitchen + new Vector3(2.3f, 0f, -1.4f), -145f);
			SpawnTestPiece("piece_cauldron_ext6_rollingpins", kitchen + new Vector3(0f, 0f, 2.8f));
			SpawnTestPiece("piece_cauldron_ext7_smoker", kitchen + new Vector3(0f, 0f, -2.8f), 180f);
			Vector3 meadKitchen = kitchen + ((Component)player).transform.right * 6f;
			meadKitchen.y = ZoneSystem.instance.GetGroundHeight(meadKitchen);
			GameObject val7 = SpawnTestPiece("fire_pit", meadKitchen);
			GameObject val8 = SpawnTestPiece("piece_meadcauldron", meadKitchen + Vector3.up * 1.15f, 180f);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Food Categories manual Mead setup: Mead Cauldron=" + (Object.op_Implicit((Object)(object)val8) ? ((Object)val8).name : "prefab not found") + ", fire pit beneath=" + (Object.op_Implicit((Object)(object)val7) ? ((Object)val7).name : "prefab not found")));
			Vector3 preparationTable = kitchen + ((Component)player).transform.right * 12f;
			preparationTable.y = ZoneSystem.instance.GetGroundHeight(preparationTable) + 0.05f;
			SpawnTestPiece("piece_preptable", preparationTable, 90f);
			SpawnTestPiece("wood_wall", preparationTable + new Vector3(-2f, 1.3f, 0f), 90f);
			SpawnTestPiece("wood_wall", preparationTable + new Vector3(2f, 1.3f, 0f), -90f);
			SpawnTestPiece("wood_wall", preparationTable + new Vector3(0f, 1.3f, 2f), 180f);
			SpawnTestPiece("wood_roof_45", preparationTable + new Vector3(-1f, 1.75f, 0f), 90f);
			SpawnTestPiece("wood_roof_45", preparationTable + new Vector3(1f, 1.75f, 0f), -90f);
			SpawnTestPiece("wood_floor_2x2", preparationTable + new Vector3(0f, 1.9f, 0f));
			AccessTools.Field(typeof(Player), "m_noPlacementCost")?.SetValue(player, false);
			AccessTools.Field(typeof(Player), "m_maxCarryWeight")?.SetValue(player, 100000f);
			Vector3 val9 = preparationTable + new Vector3(0f, 0f, 0.45f);
			val9.y = ZoneSystem.instance.GetGroundHeight(val9) + 0.2f;
			((Component)player).transform.position = val9;
			Transform transform = ((Component)player).transform;
			Vector3 val10 = preparationTable - val9;
			transform.rotation = Quaternion.LookRotation(((Vector3)(ref val10)).normalized, Vector3.up);
			((Component)player).GetComponent<Rigidbody>().position = val9;
			((Component)player).GetComponent<Rigidbody>().linearVelocity = Vector3.zero;
			yield return (object)new WaitForSecondsRealtime(1f);
			object obj = AccessTools.Method(typeof(Player), "IsUnderRoof", (Type[])null, (Type[])null)?.Invoke(player, null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Food Categories test shelter check: player under roof=" + (obj ?? "unavailable")?.ToString() + ", table distance=" + Vector3.Distance(((Component)player).transform.position, preparationTable)));
			IEnumerable<string> values = from @group in (from recipe in ObjectDB.instance.m_recipes
					select recipe?.m_item?.m_itemData into item
					where item != null
					select (item)).Where(IsFood).GroupBy(Classify)
				orderby @group.Key
				select @group.Key.ToString() + "=" + @group.Count();
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Food Categories recipe audit: " + string.Join(", ", values)));
			foreach (GameObject item3 in ObjectDB.instance.m_items)
			{
				ItemData val11 = ((!Object.op_Implicit((Object)(object)item3)) ? null : item3.GetComponent<ItemDrop>()?.m_itemData);
				if (val11 != null && IsFood(val11))
				{
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Food Categories catalog: " + val11.m_shared.m_name + "=" + Classify(val11).ToString() + " (HP=" + val11.m_shared.m_food + ", stamina=" + val11.m_shared.m_foodStamina + ", eitr=" + val11.m_shared.m_foodEitr + ")"));
				}
			}
			ItemData val12 = ObjectDB.instance.m_items.Select((GameObject prefab) => (!Object.op_Implicit((Object)(object)prefab)) ? null : prefab.GetComponent<ItemDrop>()?.m_itemData).FirstOrDefault((Func<ItemData, bool>)((ItemData item) => item?.m_shared.m_name.Equals("$item_bakedpoteitr_uncooked", StringComparison.OrdinalIgnoreCase) ?? false));
			string text = ((val12 == null) ? "not-found" : Classify(val12).ToString());
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Food Categories check: Unbaked Poteitr=" + text + " (HP=" + val12?.m_shared.m_food + ", stamina=" + val12?.m_shared.m_foodStamina + ", eitr=" + val12?.m_shared.m_foodEitr + "), Feast recipes=" + ObjectDB.instance.m_recipes.Count((Recipe recipe) => Object.op_Implicit((Object)(object)recipe?.m_item) && IsFeast(recipe.m_item.m_itemData))));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Food Categories station audit: Cauldron=" + ObjectDB.instance.m_recipes.Count((Recipe recipe) => Object.op_Implicit((Object)(object)recipe?.m_item) && IsFood(recipe.m_item.m_itemData) && BelongsToStation(recipe, preparationStation: false)) + ", Preparation=" + ObjectDB.instance.m_recipes.Count((Recipe recipe) => Object.op_Implicit((Object)(object)recipe?.m_item) && IsFood(recipe.m_item.m_itemData) && BelongsToStation(recipe, preparationStation: true))));
			foreach (Recipe item4 in ObjectDB.instance.m_recipes.Where((Recipe recipe) => Object.op_Implicit((Object)(object)recipe?.m_item) && recipe.m_item.m_itemData.m_shared.m_name.IndexOf("pancake", StringComparison.OrdinalIgnoreCase) >= 0))
			{
				ItemData itemData = item4.m_item.m_itemData;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Food Categories pancake check: " + itemData.m_shared.m_name + "=" + Classify(itemData).ToString() + " (HP=" + itemData.m_shared.m_food + ", stamina=" + itemData.m_shared.m_foodStamina + ", eitr=" + itemData.m_shared.m_foodEitr + ")"));
			}
			foreach (Recipe item5 in ObjectDB.instance.m_recipes.Where((Recipe recipe) => Object.op_Implicit((Object)(object)recipe?.m_item) && (recipe.m_item.m_itemData.m_shared.m_name.IndexOf("crust", StringComparison.OrdinalIgnoreCase) >= 0 || recipe.m_item.m_itemData.m_shared.m_name.IndexOf("sweetbread", StringComparison.OrdinalIgnoreCase) >= 0)))
			{
				ItemData itemData2 = item5.m_item.m_itemData;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Food Categories row audit: " + itemData2.m_shared.m_name + "=" + Classify(itemData2).ToString() + " (HP=" + itemData2.m_shared.m_food + ", stamina=" + itemData2.m_shared.m_foodStamina + ", eitr=" + itemData2.m_shared.m_foodEitr + ")"));
			}
			foreach (Recipe item6 in ObjectDB.instance.m_recipes.Where((Recipe recipe) => Object.op_Implicit((Object)(object)recipe?.m_item) && IsFood(recipe.m_item.m_itemData) && BelongsToStation(recipe, preparationStation: true)))
			{
				ItemData itemData3 = item6.m_item.m_itemData;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Food Categories preparation audit: " + itemData3.m_shared.m_name + "=" + Classify(itemData3).ToString() + " (HP=" + itemData3.m_shared.m_food + ", stamina=" + itemData3.m_shared.m_foodStamina + ", eitr=" + itemData3.m_shared.m_foodEitr + ")"));
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Food Categories manual test ready: fully upgraded cauldron and Food Preparation Table placed.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Food Categories manual test Mead recipes unlocked: " + string.Join(", ", from recipe in testRecipes
				where IsMead(recipe.m_item.m_itemData)
				select ((Object)recipe.m_item).name)));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Food Categories manual test Mead station requirements: " + string.Join(" | ", from recipe in testRecipes
				where IsMead(recipe.m_item.m_itemData)
				select ((Object)recipe.m_item).name + " station=" + RecipeStationName(recipe) + " level=" + AccessTools.Field(typeof(Recipe), "m_minStationLevel")?.GetValue(recipe))));
			CraftingStation[] source = Object.FindObjectsByType<CraftingStation>((FindObjectsSortMode)0);
			CraftingStation val13 = (from candidate in source
				where Object.op_Implicit((Object)(object)candidate) && ((Object)((Component)candidate).gameObject).name.IndexOf("meadcauldron", StringComparison.OrdinalIgnoreCase) >= 0
				orderby Vector3.Distance(((Component)candidate).transform.position, meadKitchen)
				select candidate).FirstOrDefault();
			CraftingStation val14 = (from candidate in source
				where Object.op_Implicit((Object)(object)candidate) && ((Object)((Component)candidate).gameObject).name.IndexOf("cauldron", StringComparison.OrdinalIgnoreCase) >= 0 && ((Object)((Component)candidate).gameObject).name.IndexOf("meadcauldron", StringComparison.OrdinalIgnoreCase) < 0
				orderby Vector3.Distance(((Component)candidate).transform.position, kitchen)
				select candidate).FirstOrDefault();
			(from candidate in source
				where Object.op_Implicit((Object)(object)candidate) && ((Object)((Component)candidate).gameObject).name.IndexOf("preptable", StringComparison.OrdinalIgnoreCase) >= 0
				orderby Vector3.Distance(((Component)candidate).transform.position, preparationTable)
				select candidate).FirstOrDefault();
			CraftingStation val15 = (Object.op_Implicit((Object)(object)val13) ? val13 : val14);
			if (Object.op_Implicit((Object)(object)val15))
			{
				Vector3 val16 = ((Component)val15).transform.position - ((Component)val15).transform.forward * 1.4f;
				val16.y = ZoneSystem.instance.GetGroundHeight(val16) + 0.2f;
				((Component)player).transform.position = val16;
				((Component)player).GetComponent<Rigidbody>().position = val16;
				((Component)player).GetComponent<Rigidbody>().linearVelocity = Vector3.zero;
				val10 = ((Component)val15).transform.position + Vector3.up * 0.35f - (val16 + Vector3.up * 1.5f);
				Vector3 normalized = ((Vector3)(ref val10)).normalized;
				((Component)player).transform.rotation = Quaternion.LookRotation(new Vector3(normalized.x, 0f, normalized.z), Vector3.up);
				player.SetCraftingStation(val15);
				MethodInfo methodInfo = AccessTools.Method(typeof(CraftingStation), "Interact", new Type[3]
				{
					typeof(Humanoid),
					typeof(bool),
					typeof(bool)
				}, (Type[])null);
				bool num = methodInfo != null && (bool)(methodInfo.Invoke(val15, new object[3] { player, false, false }) ?? ((object)false));
				InventoryGui instance = InventoryGui.instance;
				KeepManualCraftMenuOpen = true;
				if (!num)
				{
					AccessTools.Method(typeof(InventoryGui), "Show", new Type[2]
					{
						typeof(Container),
						typeof(int)
					}, (Type[])null)?.Invoke(instance, new object[2] { null, 0 });
					if (Object.op_Implicit((Object)(object)instance.m_inventoryRoot) && !((Component)instance.m_inventoryRoot).gameObject.activeSelf)
					{
						((Component)instance.m_inventoryRoot).gameObject.SetActive(true);
					}
					if (Object.op_Implicit((Object)(object)instance.m_inventoryGroup) && !instance.m_inventoryGroup.IsActive)
					{
						instance.m_inventoryGroup.SetActive(true);
					}
					AccessTools.Method(typeof(InventoryGui), "OnTabCraftPressed", (Type[])null, (Type[])null)?.Invoke(instance, null);
					AccessTools.Method(typeof(InventoryGui), "UpdateCraftingPanel", new Type[1] { typeof(bool) }, (Type[])null)?.Invoke(instance, new object[1] { true });
				}
				List<string> list = (from entry in Entries(instance)
					where IsMead(entry.Item)
					select (!Object.op_Implicit((Object)(object)entry.Item.m_dropPrefab)) ? entry.Item.m_shared.m_name : ((Object)entry.Item.m_dropPrefab).name).ToList();
				ManualLogSource? testLog = TestLog;
				if (testLog != null)
				{
					testLog.LogInfo((object)("TEST visible Mead rows=" + list.Count + ": " + string.Join(", ", list)));
				}
				ManualLogSource? testLog2 = TestLog;
				if (testLog2 != null)
				{
					testLog2.LogInfo((object)("TEST ready: " + (Object.op_Implicit((Object)(object)val13) ? "Mead Cauldron" : "Cauldron fallback") + " menu requested (visible=" + (Object.op_Implicit((Object)(object)instance.m_inventoryRoot) && ((Component)instance.m_inventoryRoot).gameObject.activeInHierarchy) + ", recipes=" + Entries(instance).Count() + "); player is " + Vector3.Distance(((Component)player).transform.position, ((Component)val15).transform.position) + "m from station; fire pit beneath Mead Cauldron and Food Preparation Table under a roof nearby."));
				}
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"TEST could not find a Cauldron or Mead Cauldron.");
			}
			yield return null;
		}

		private static GameObject? SpawnTestPiece(string prefabName, Vector3 position, float yaw = 0f)
		{
			//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)
			GameObject prefab = ZNetScene.instance.GetPrefab(prefabName);
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				return null;
			}
			GameObject obj = Object.Instantiate<GameObject>(prefab, position, Quaternion.Euler(0f, yaw, 0f));
			WearNTear component = obj.GetComponent<WearNTear>();
			FieldInfo fieldInfo = AccessTools.Field(typeof(WearNTear), "m_noSupportWear");
			if ((object)fieldInfo != null)
			{
				fieldInfo.SetValue(component, true);
				return obj;
			}
			return obj;
		}

		private static void Apply(InventoryGui gui, bool resetScroll = false)
		{
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)gui))
			{
				return;
			}
			List<Entry> list = Entries(gui).ToList();
			if (!gui.InCraftTab())
			{
				HideFoodEntries(list);
				HideBar(gui);
				return;
			}
			RectTransform recipeListRoot = gui.m_recipeListRoot;
			if (!Object.op_Implicit((Object)(object)recipeListRoot))
			{
				return;
			}
			if (!IsFoodStation(gui, list, out var preparationStation))
			{
				HideFoodEntries(list);
				HideBar(gui);
				return;
			}
			List<Entry> list2 = list.Where((Entry entry) => IsFood(entry.Item) && BelongsToStation(entry.Recipe, preparationStation)).ToList();
			if (list2.Count == 0)
			{
				HideBar(gui);
				return;
			}
			FilterBar bar = GetOrCreateBar(gui, recipeListRoot, preparationStation, list);
			if (list.Count == 0)
			{
				return;
			}
			List<Entry> list3 = (from entry in list2
				where bar.Current == FoodFilter.All || (!IsUnfilteredOnly(entry.Item) && Matches(entry.Item, bar.Current))
				orderby Score(entry.Item, bar.Current) descending
				select entry).Concat(list.Where((Entry entry) => bar.Current == FoodFilter.All && !IsFood(entry.Item))).ToList();
			foreach (Entry item in list)
			{
				item.Element.SetActive(list3.Contains(item));
			}
			for (int num = 0; num < list3.Count; num++)
			{
				RectTransform component = list3[num].Element.GetComponent<RectTransform>();
				if (!OriginalRowPositions.ContainsKey(component))
				{
					OriginalRowPositions[component] = component.anchoredPosition;
				}
				if (!OriginalRowSizes.ContainsKey(component))
				{
					OriginalRowSizes[component] = component.sizeDelta;
				}
				Vector2 val = OriginalRowPositions[component];
				Vector2 sizeDelta = OriginalRowSizes[component];
				component.anchoredPosition = new Vector2(val.x, (float)(-num) * gui.m_recipeListSpace);
				component.sizeDelta = sizeDelta;
			}
			recipeListRoot.SetSizeWithCurrentAnchors((Axis)1, Mathf.Max((float)list3.Count * gui.m_recipeListSpace, 30f));
			if (resetScroll)
			{
				gui.m_recipeListScroll.value = 1f;
			}
			SetButtonColors(bar);
			PositionBar(gui, bar, recipeListRoot);
		}

		private static void HideFoodEntries(IEnumerable<Entry> entries)
		{
			foreach (Entry entry in entries)
			{
				if (IsFood(entry.Item))
				{
					entry.Element.SetActive(false);
				}
			}
		}

		private unsafe static FilterBar GetOrCreateBar(InventoryGui gui, RectTransform list, bool preparationStation, IReadOnlyCollection<Entry> entries)
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Expected O, but got Unknown
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0463: Unknown result type (might be due to invalid IL or missing references)
			//IL_0465: Unknown result type (might be due to invalid IL or missing references)
			if (Bars.TryGetValue(gui, out FilterBar value) && Object.op_Implicit((Object)(object)value.Root) && value.PreparationStation == preparationStation)
			{
				((Component)value.Root).gameObject.SetActive(true);
				return value;
			}
			if (Object.op_Implicit((Object)(object)value?.Root))
			{
				Object.Destroy((Object)(object)((Component)value.Root).gameObject);
			}
			FilterBar filterBar = new FilterBar
			{
				PreparationStation = preparationStation
			};
			GameObject val = new GameObject("Food Category Filters", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			filterBar.Root = val.GetComponent<RectTransform>();
			filterBar.CraftTabTemplate = FindNativeTabImage(gui, "m_tabCraft");
			filterBar.UpgradeTabTemplate = FindNativeTabImage(gui, "m_tabUpgrade");
			if (!Object.op_Implicit((Object)(object)filterBar.CraftTabTemplate) || !Object.op_Implicit((Object)(object)filterBar.UpgradeTabTemplate))
			{
				FindNativeTabTemplates(gui, out filterBar.CraftTabTemplate, out filterBar.UpgradeTabTemplate);
			}
			Image? craftTabTemplate = filterBar.CraftTabTemplate;
			object obj = ((craftTabTemplate != null) ? craftTabTemplate.sprite : null);
			if (obj == null)
			{
				Image? upgradeTabTemplate = filterBar.UpgradeTabTemplate;
				obj = ((upgradeTabTemplate != null) ? upgradeTabTemplate.sprite : null) ?? FindNativeTabSprite(gui);
			}
			filterBar.TabSprite = (Sprite?)obj;
			filterBar.Root.anchorMin = new Vector2(0f, 1f);
			filterBar.Root.anchorMax = new Vector2(0f, 1f);
			filterBar.Root.pivot = new Vector2(0f, 1f);
			List<FoodFilter> list2 = new List<FoodFilter>
			{
				FoodFilter.Health,
				FoodFilter.Stamina,
				FoodFilter.Eitr,
				FoodFilter.Balanced
			};
			if (preparationStation)
			{
				list2.Add(FoodFilter.Feast);
			}
			filterBar.Root.sizeDelta = new Vector2(58f, 4f + (float)list2.Count * 24f + (float)(list2.Count - 1) * 1f);
			Canvas componentInParent = ((Component)gui).GetComponentInParent<Canvas>();
			RectTransform val2 = (RectTransform)(Object.op_Implicit((Object)(object)componentInParent) ? /*isinst with value type is only supported in some contexts*/: null);
			val.transform.SetParent((Transform)(Object.op_Implicit((Object)(object)val2) ? ((object)val2) : ((object)((Transform)list).parent)), false);
			Image component = val.GetComponent<Image>();
			Image? obj2 = filterBar.UpgradeTabTemplate ?? filterBar.CraftTabTemplate;
			CopyTabStyle(obj2, component);
			Image val3 = component;
			if (val3.sprite == null)
			{
				Sprite val4 = (val3.sprite = filterBar.TabSprite);
			}
			int num;
			if (Object.op_Implicit((Object)(object)component.sprite))
			{
				Vector4 border = component.sprite.border;
				if (((Vector4)(ref border)).sqrMagnitude > 0f)
				{
					num = 1;
					goto IL_0297;
				}
			}
			num = 0;
			goto IL_0297;
			IL_0297:
			component.type = (Type)num;
			if (!Object.op_Implicit((Object)(object)obj2))
			{
				((Graphic)component).color = new Color(0.5f, 0.36f, 0.22f, 1f);
			}
			((Graphic)component).raycastTarget = false;
			VerticalLayoutGroup obj3 = val.AddComponent<VerticalLayoutGroup>();
			((LayoutGroup)obj3).padding = new RectOffset(3, 3, 3, 3);
			((HorizontalOrVerticalLayoutGroup)obj3).spacing = 1f;
			((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)obj3).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj3).childControlHeight = true;
			Outline obj4 = val.AddComponent<Outline>();
			((Shadow)obj4).effectColor = new Color(0.76f, 0.4f, 0.1f, 0.9f);
			((Shadow)obj4).effectDistance = new Vector2(1f, -1f);
			foreach (FoodFilter item in list2)
			{
				filterBar.Buttons[item] = CreateButton(filterBar, item);
			}
			Bars[gui] = filterBar;
			PositionBar(gui, filterBar, list);
			gui.m_recipeListScroll.value = 1f;
			Vector2 val5 = RectTransformUtility.WorldToScreenPoint(Object.op_Implicit((Object)(object)componentInParent) ? componentInParent.worldCamera : null, ((Transform)filterBar.Root).position);
			ManualLogSource? testLog = TestLog;
			if (testLog != null)
			{
				string[] obj5 = new string[11]
				{
					"Food Categories: created ",
					filterBar.Buttons.Count.ToString(),
					" filters for ",
					preparationStation ? "Food Preparation Station" : "Cauldron",
					"; available rows=",
					Entries(gui).Count().ToString(),
					"; parent=",
					null,
					null,
					null,
					null
				};
				Transform parent = val.transform.parent;
				obj5[7] = ((parent != null) ? ((Object)parent).name : null);
				obj5[8] = "; screen position=";
				Vector2 val6 = val5;
				obj5[9] = ((object)(*(Vector2*)(&val6))/*cast due to .constrained prefix*/).ToString();
				obj5[10] = ".";
				testLog.LogInfo((object)string.Concat(obj5));
			}
			return filterBar;
		}

		private static void PositionBar(InventoryGui gui, FilterBar bar, RectTransform list)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//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_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			Canvas componentInParent = ((Component)gui).GetComponentInParent<Canvas>();
			Canvas val = (Object.op_Implicit((Object)(object)componentInParent) ? componentInParent.rootCanvas : null);
			RectTransform val2 = (RectTransform)(Object.op_Implicit((Object)(object)val) ? /*isinst with value type is only supported in some contexts*/: null);
			if (Object.op_Implicit((Object)(object)val2))
			{
				Camera val3 = (Object.op_Implicit((Object)(object)val) ? val.worldCamera : null);
				Transform parent = ((Transform)list).parent;
				RectTransform val4 = (RectTransform)(object)((parent is RectTransform) ? parent : null);
				if (!Object.op_Implicit((Object)(object)val4))
				{
					val4 = list;
				}
				Vector3[] array = (Vector3[])(object)new Vector3[4];
				val4.GetWorldCorners(array);
				Vector2 val5 = RectTransformUtility.WorldToScreenPoint(val3, array[1]);
				object obj = (Object.op_Implicit((Object)(object)gui.m_crafting) ? ((object)gui.m_crafting) : ((object)list));
				Vector3[] array2 = (Vector3[])(object)new Vector3[4];
				((RectTransform)obj).GetWorldCorners(array2);
				Vector2 val6 = RectTransformUtility.WorldToScreenPoint(val3, array2[1]);
				Rect rect = bar.Root.rect;
				float num = ((Rect)(ref rect)).width * val.scaleFactor;
				Vector2 val7 = default(Vector2);
				((Vector2)(ref val7))..ctor(val6.x - num - 2f, val5.y - 58f);
				RectTransform val8 = FindRepairRect(gui);
				if (Object.op_Implicit((Object)(object)val8))
				{
					Vector3[] array3 = (Vector3[])(object)new Vector3[4];
					val8.GetWorldCorners(array3);
					Vector2 val9 = RectTransformUtility.WorldToScreenPoint(val3, array3[0]);
					val7.y = val9.y - 8f;
				}
				float y = val7.y;
				rect = bar.Root.rect;
				val7.y = Mathf.Clamp(y, ((Rect)(ref rect)).height + 4f, (float)Screen.height - 6f);
				Vector3 position = default(Vector3);
				if (RectTransformUtility.ScreenPointToWorldPointInRectangle(val2, val7, val3, ref position))
				{
					((Transform)bar.Root).position = position;
				}
			}
		}

		private static Image? FindNativeTabImage(InventoryGui gui, string fieldName)
		{
			object obj = AccessTools.Field(typeof(InventoryGui), fieldName)?.GetValue(gui);
			if (obj == null)
			{
				return null;
			}
			Image val = (Image)((obj is Image) ? obj : null);
			if (val != null)
			{
				return val;
			}
			Button val2 = (Button)((obj is Button) ? obj : null);
			if (val2 != null)
			{
				Graphic targetGraphic = ((Selectable)val2).targetGraphic;
				return (Image?)(((object)((targetGraphic is Image) ? targetGraphic : null)) ?? ((object)((Component)val2).GetComponent<Image>()));
			}
			Component val3 = (Component)((obj is Component) ? obj : null);
			if (val3 != null)
			{
				Button componentInChildren = val3.GetComponentInChildren<Button>(true);
				if (Object.op_Implicit((Object)(object)componentInChildren))
				{
					Graphic targetGraphic2 = ((Selectable)componentInChildren).targetGraphic;
					Image val4 = (Image)(object)((targetGraphic2 is Image) ? targetGraphic2 : null);
					if (val4 != null)
					{
						return val4;
					}
				}
				return val3.GetComponentInChildren<Image>(true);
			}
			GameObject val5 = (GameObject)((obj is GameObject) ? obj : null);
			if (val5 != null)
			{
				Button componentInChildren2 = val5.GetComponentInChildren<Button>(true);
				if (Object.op_Implicit((Object)(object)componentInChildren2))
				{
					Graphic targetGraphic3 = ((Selectable)componentInChildren2).targetGraphic;
					Image val6 = (Image)(object)((targetGraphic3 is Image) ? targetGraphic3 : null);
					if (val6 != null)
					{
						return val6;
					}
				}
				return val5.GetComponentInChildren<Image>(true);
			}
			FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			for (int i = 0; i < fields.Length; i++)
			{
				object value = fields[i].GetValue(obj);
				Image val7 = (Image)((value is Image) ? value : null);
				if (val7 != null)
				{
					return val7;
				}
				Button val8 = (Button)((value is Button) ? value : null);
				if (val8 != null)
				{
					Graphic targetGraphic4 = ((Selectable)val8).targetGraphic;
					Image val9 = (Image)(object)((targetGraphic4 is Image) ? targetGraphic4 : null);
					if (val9 != null)
					{
						return val9;
					}
				}
				Component val10 = (Component)((value is Component) ? value : null);
				if (val10 != null)
				{
					Button componentInChildren3 = val10.GetComponentInChildren<Button>(true);
					if (Object.op_Implicit((Object)(object)componentInChildren3))
					{
						Graphic targetGraphic5 = ((Selectable)componentInChildren3).targetGraphic;
						Image val11 = (Image)(object)((targetGraphic5 is Image) ? targetGraphic5 : null);
						if (val11 != null)
						{
							return val11;
						}
					}
					Image componentInChildren4 = val10.GetComponentInChildren<Image>(true);
					if (Object.op_Implicit((Object)(object)componentInChildren4))
					{
						return componentInChildren4;
					}
				}
				GameObject val12 = (GameObject)((value is GameObject) ? value : null);
				if (val12 == null)
				{
					continue;
				}
				Button componentInChildren5 = val12.GetComponentInChildren<Button>(true);
				if (Object.op_Implicit((Object)(object)componentInChildren5))
				{
					Graphic targetGraphic6 = ((Selectable)componentInChildren5).targetGraphic;
					Image val13 = (Image)(object)((targetGraphic6 is Image) ? targetGraphic6 : null);
					if (val13 != null)
					{
						return val13;
					}
				}
				Image componentInChildren6 = val12.GetComponentInChildren<Image>(true);
				if (Object.op_Implicit((Object)(object)componentInChildren6))
				{
					return componentInChildren6;
				}
			}
			return null;
		}

		private static RectTransform? FindRepairRect(InventoryGui gui)
		{
			object obj = AccessTools.Field(typeof(InventoryGui), "m_repairButton")?.GetValue(gui);
			RectTransform val = (RectTransform)((obj is RectTransform) ? obj : null);
			if (val != null)
			{
				return val;
			}
			Component val2 = (Component)((obj is Component) ? obj : null);
			if (val2 != null)
			{
				Transform transform = val2.transform;
				RectTransform val3 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
				if (val3 != null)
				{
					return val3;
				}
			}
			GameObject val4 = (GameObject)((obj is GameObject) ? obj : null);
			if (val4 != null)
			{
				Transform transform2 = val4.transform;
				RectTransform val5 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null);
				if (val5 != null)
				{
					return val5;
				}
			}
			return ((IEnumerable<RectTransform>)((Component)gui).GetComponentsInChildren<RectTransform>(true)).FirstOrDefault((Func<RectTransform, bool>)((RectTransform candidate) => ((Component)candidate).gameObject.activeInHierarchy && ((Object)candidate).name.IndexOf("repair", StringComparison.OrdinalIgnoreCase) >= 0));
		}

		private static void FindNativeTabTemplates(InventoryGui gui, out Image? craft, out Image? upgrade)
		{
			craft = null;
			upgrade = null;
			Button[] componentsInChildren = ((Component)gui).GetComponentsInChildren<Button>(true);
			foreach (Button obj in componentsInChildren)
			{
				TMP_Text componentInChildren = ((Component)obj).GetComponentInChildren<TMP_Text>(true);
				Image component = ((Component)obj).GetComponent<Image>();
				if (Object.op_Implicit((Object)(object)componentInChildren) && Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.sprite))
				{
					if (componentInChildren.text.IndexOf("Craft", StringComparison.OrdinalIgnoreCase) >= 0 && craft == null)
					{
						craft = component;
					}
					if (componentInChildren.text.IndexOf("Upgrade", StringComparison.OrdinalIgnoreCase) >= 0 && upgrade == null)
					{
						upgrade = component;
					}
					if (Object.op_Implicit((Object)(object)craft) && Object.op_Implicit((Object)(object)upgrade))
					{
						break;
					}
				}
			}
		}

		private static Sprite? FindNativeTabSprite(InventoryGui gui)
		{
			return (from sprite in Resources.FindObjectsOfTypeAll<Sprite>()
				where Object.op_Implicit((Object)(object)sprite) && (((Object)sprite).name.IndexOf("tab", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)sprite).name.IndexOf("woodpanel", StringComparison.OrdinalIgnoreCase) >= 0)
				orderby (((Object)sprite).name.IndexOf("tab", StringComparison.OrdinalIgnoreCase) < 0) ? 1 : 0
				select sprite).FirstOrDefault();
		}

		private static void CopyTabStyle(Image? template, Image target)
		{
			//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)
			if (Object.op_Implicit((Object)(object)template))
			{
				target.sprite = template.sprite;
				target.type = template.type;
				((Graphic)target).color = ((Graphic)template).color;
				((Graphic)target).material = ((Graphic)template).material;
				target.preserveAspect = template.preserveAspect;
				target.fillCenter = template.fillCenter;
			}
		}

		private static Button CreateButton(FilterBar bar, FoodFilter filter)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Expected O, but got Unknown
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Food " + filter, new Type[5]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image),
				typeof(Button),
				typeof(LayoutElement)
			});
			val.transform.SetParent((Transform)(object)bar.Root, false);
			LayoutElement component = val.GetComponent<LayoutElement>();
			component.minWidth = 50f;
			component.preferredWidth = 50f;
			component.minHeight = 24f;
			component.preferredHeight = 24f;
			component.flexibleHeight = 0f;
			Image component2 = val.GetComponent<Image>();
			CopyTabStyle(bar.UpgradeTabTemplate ?? bar.CraftTabTemplate, component2);
			Image val2 = component2;
			if (val2.sprite == null)
			{
				Sprite val3 = (val2.sprite = bar.TabSprite);
			}
			if (!Object.op_Implicit((Object)(object)bar.UpgradeTabTemplate) && !Object.op_Implicit((Object)(object)bar.CraftTabTemplate))
			{
				((Graphic)component2).color = new Color(0.5f, 0.36f, 0.22f, 1f);
			}
			Button component3 = val.GetComponent<Button>();
			ColorBlock colors = ((Selectable)component3).colors;
			((ColorBlock)(ref colors)).normalColor = Color.white;
			((ColorBlock)(ref colors)).highlightedColor = new Color(1f, 1f, 1f, 0.9f);
			((ColorBlock)(ref colors)).pressedColor = new Color(0.72f, 0.72f, 0.72f, 1f);
			((Selectable)component3).colors = colors;
			CreateNativeFoodIcon(val.transform, filter);
			((UnityEvent)component3.onClick).AddListener((UnityAction)delegate
			{
				bar.Current = ((bar.Current != filter) ? filter : FoodFilter.All);
				Apply(Bars.First<KeyValuePair<InventoryGui, FilterBar>>((KeyValuePair<InventoryGui, FilterBar> pair) => pair.Value == bar).Key, resetScroll: true);
			});
			return component3;
		}

		private static void CreateNativeFoodIcon(Transform parent, FoodFilter filter)
		{
			//IL_0087: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			Sprite[] source = Resources.FindObjectsOfTypeAll<Sprite>();
			Sprite sprite = ((IEnumerable<Sprite>)source).FirstOrDefault((Func<Sprite, bool>)((Sprite candidate) => ((Object)candidate).name.Equals("food_icon", StringComparison.OrdinalIgnoreCase))) ?? ((IEnumerable<Sprite>)source).FirstOrDefault((Func<Sprite, bool>)((Sprite candidate) => ((Object)candidate).name.Equals("food_icon", StringComparison.OrdinalIgnoreCase)));
			GameObject val = new GameObject("Valheim Food Icon", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 0.5f);
			component.anchorMax = new Vector2(0.5f, 0.5f);
			component.sizeDelta = new Vector2(17f, 17f);
			Image component2 = val.GetComponent<Image>();
			component2.sprite = sprite;
			((Graphic)component2).color = FilterColor(filter);
			component2.preserveAspect = true;
			((Graphic)component2).raycastTarget = false;
		}

		private static void SetButtonColors(FilterBar bar)
		{
			//IL_008b: 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_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<FoodFilter, Button> button in bar.Buttons)
			{
				Image component = ((Component)button.Value).GetComponent<Image>();
				bool flag = button.Key == bar.Current;
				CopyTabStyle(flag ? bar.CraftTabTemplate : bar.UpgradeTabTemplate, component);
				if (!Object.op_Implicit((Object)(object)component.sprite))
				{
					component.sprite = bar.TabSprite;
				}
				if (flag && !Object.op_Implicit((Object)(object)bar.CraftTabTemplate))
				{
					((Graphic)component).color = new Color(1f, 0.58f, 0.12f, 1f);
				}
				if (!flag && !Object.op_Implicit((Object)(object)bar.UpgradeTabTemplate) && !Object.op_Implicit((Object)(object)bar.CraftTabTemplate))
				{
					((Graphic)component).color = new Color(0.5f, 0.36f, 0.22f, 1f);
				}
				Outline obj = ((Component)button.Value).GetComponent<Outline>() ?? ((Component)button.Value).gameObject.AddComponent<Outline>();
				((Behaviour)obj).enabled = flag;
				((Shadow)obj).effectColor = new Color(1f, 0.42f, 0.06f, 1f);
				((Shadow)obj).effectDistance = new Vector2(3f, -3f);
				Transform obj2 = ((Component)button.Value).transform.Find("Valheim Food Icon");
				Image val = ((obj2 != null) ? ((Component)obj2).GetComponent<Image>() : null);
				if (Object.op_Implicit((Object)(object)val))
				{
					((Graphic)val).rectTransform.sizeDelta = (flag ? new Vector2(21f, 21f) : new Vector2(17f, 17f));
				}
			}
		}

		private static IEnumerable<Entry> Entries(InventoryGui gui)
		{
			if (!(AccessTools.Field(typeof(InventoryGui), "m_availableRecipes")?.GetValue(gui) is IEnumerable enumerable))
			{
				yield break;
			}
			foreach (object item in enumerable)
			{
				if (item == null)
				{
					continue;
				}
				Type type = item.GetType();
				object? obj = AccessTools.Property(type, "Recipe")?.GetValue(item);
				Recipe val = (Recipe)((obj is Recipe) ? obj : null);
				object? obj2 = AccessTools.Property(type, "ItemData")?.GetValue(item);
				ItemData val2 = (ItemData)(((obj2 is ItemData) ? obj2 : null) ?? val?.m_item?.m_itemData);
				object? obj3 = AccessTools.Property(type, "InterfaceElement")?.GetValue(item);
				GameObject val3 = (GameObject)((obj3 is GameObject) ? obj3 : null);
				if (!((Object)(object)val != (Object)null) || val2 == null || !((Object)(object)val3 != (Object)null))
				{
					continue;
				}
				ItemData val4 = val.m_item?.m_itemData;
				if (Environment.GetEnvironmentVariable("FOOD_CATEGORIES_MANUAL_TEST") == "1" && val4 != null && IsFood(val2))
				{
					string name = val2.m_shared.m_name;
					if (!string.IsNullOrEmpty(name) && AuditedRows.Add(name))
					{
						Debug.Log((object)("Food Categories actual row: " + name + "=" + Classify(val2).ToString() + " HP=" + val2.m_shared.m_food + " stamina=" + val2.m_shared.m_foodStamina + " eitr=" + val2.m_shared.m_foodEitr + "; recipe data=" + val4.m_shared.m_food + "/" + val4.m_shared.m_foodStamina + "/" + val4.m_shared.m_foodEitr));
					}
				}
				yield return new Entry
				{
					Recipe = val,
					Item = val2,
					Element = val3
				};
			}
		}

		private static bool BelongsToStation(Recipe recipe, bool preparationStation)
		{
			string text = RecipeStationName(recipe);
			if (preparationStation)
			{
				if (!text.Contains("preparation"))
				{
					return text.Contains("preptable");
				}
				return true;
			}
			return text.Contains("cauldron");
		}

		private static string RecipeStationName(Recipe recipe)
		{
			return AccessTools.Field(typeof(Recipe), "m_craftingStation")?.GetValue(recipe)?.ToString()?.ToLowerInvariant() ?? string.Empty;
		}

		private static bool IsFood(ItemData item)
		{
			(item.m_shared.m_name + " " + (Object.op_Implicit((Object)(object)item.m_dropPrefab) ? ((Object)item.m_dropPrefab).name : string.Empty)).ToLowerInvariant();
			if (IsMead(item))
			{
				return false;
			}
			if (!IsFeast(item) && !(item.m_shared.m_food > 0f) && !(item.m_shared.m_foodStamina > 0f))
			{
				return item.m_shared.m_foodEitr > 0f;
			}
			return true;
		}

		private static bool IsMead(ItemData item)
		{
			if (!item.m_shared.m_name.StartsWith("$item_mead", StringComparison.OrdinalIgnoreCase))
			{
				if (Object.op_Implicit((Object)(object)item.m_dropPrefab))
				{
					return ((Object)item.m_dropPrefab).name.StartsWith("Mead", StringComparison.OrdinalIgnoreCase);
				}
				return false;
			}
			return true;
		}

		private static bool IsUnfilteredOnly(ItemData item)
		{
			if (!item.m_shared.m_name.Equals("$item_fish_raw", StringComparison.OrdinalIgnoreCase) && item.m_shared.m_name.IndexOf("bait", StringComparison.OrdinalIgnoreCase) < 0)
			{
				if (Object.op_Implicit((Object)(object)item.m_dropPrefab))
				{
					return ((Object)item.m_dropPrefab).name.IndexOf("bait", StringComparison.OrdinalIgnoreCase) >= 0;
				}
				return false;
			}
			return true;
		}

		private static bool IsFeast(ItemData item)
		{
			if (item.m_shared.m_name.Equals("$item_feaster", StringComparison.OrdinalIgnoreCase) || (Object.op_Implicit((Object)(object)item.m_dropPrefab) && ((Object)item.m_dropPrefab).name.Equals("Feaster", StringComparison.OrdinalIgnoreCase)))
			{
				return false;
			}
			if (item.m_shared.m_name.IndexOf("feast", StringComparison.OrdinalIgnoreCase) < 0)
			{
				if (Object.op_Implicit((Object)(object)item.m_dropPrefab))
				{
					return ((Object)item.m_dropPrefab).name.IndexOf("feast", StringComparison.OrdinalIgnoreCase) >= 0;
				}
				return false;
			}
			return true;
		}

		private static FoodFilter Classify(ItemData item)
		{
			if (IsFeast(item))
			{
				return FoodFilter.Feast;
			}
			string text = (item.m_shared.m_name + " " + (Object.op_Implicit((Object)(object)item.m_dropPrefab) ? ((Object)item.m_dropPrefab).name : string.Empty)).ToLowerInvariant();
			if (text.Contains("misthare"))
			{
				return FoodFilter.Health;
			}
			if (text.Contains("sweetbread") || text.Contains("vikingcupcake"))
			{
				return FoodFilter.Balanced;
			}
			if (text.Contains("bakedpoteitr_uncooked"))
			{
				return FoodFilter.Health;
			}
			if (text.Contains("ovenpancake_uncooked") || text.Contains("ovenpancakebatter"))
			{
				return FoodFilter.Health;
			}
			if (text.Contains("roastedcrustpie_uncooked"))
			{
				return FoodFilter.Stamina;
			}
			if (text.Contains("kalechips_uncooked"))
			{
				return FoodFilter.Health;
			}
			float food = item.m_shared.m_food;
			float foodStamina = item.m_shared.m_foodStamina;
			float foodEitr = item.m_shared.m_foodEitr;
			if (food <= 0f && foodStamina <= 0f && foodEitr > 0f)
			{
				return FoodFilter.Eitr;
			}
			if (food > 0f && foodStamina > 0f)
			{
				float num = Mathf.Max(food, foodStamina);
				if (Mathf.Abs(food - foodStamina) <= num * 0.2f)
				{
					return FoodFilter.Balanced;
				}
			}
			if (foodEitr > 0f)
			{
				return FoodFilter.Eitr;
			}
			if (!(food > foodStamina))
			{
				return FoodFilter.Stamina;
			}
			return FoodFilter.Health;
		}

		private static bool Matches(ItemData item, FoodFilter filter)
		{
			if (filter == FoodFilter.All)
			{
				return true;
			}
			return Classify(item) == filter;
		}

		private static float Score(ItemData item, FoodFilter filter)
		{
			return filter switch
			{
				FoodFilter.Health => item.m_shared.m_food, 
				FoodFilter.Stamina => item.m_shared.m_foodStamina, 
				FoodFilter.Eitr => item.m_shared.m_foodEitr, 
				FoodFilter.Balanced => item.m_shared.m_food + item.m_shared.m_foodStamina, 
				FoodFilter.Feast => 1f, 
				_ => 0f, 
			};
		}

		private static Color FilterColor(FoodFilter filter)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_0049: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			return (Color)(filter switch
			{
				FoodFilter.Health => new Color(0.82f, 0.16f, 0.12f), 
				FoodFilter.Stamina => new Color(0.95f, 0.72f, 0.12f), 
				FoodFilter.Eitr => new Color(0.18f, 0.53f, 0.95f), 
				FoodFilter.Feast => new Color(0.55f, 0.28f, 0.82f), 
				_ => new Color(0.58f, 0.58f, 0.58f), 
			});
		}

		private static bool IsFoodStation(InventoryGui gui, IReadOnlyCollection<Entry> entries, out bool preparationStation)
		{
			preparationStation = false;
			List<string> list = new List<string>();
			if (Object.op_Implicit((Object)(object)gui.m_craftingStationName))
			{
				list.Add(gui.m_craftingStationName.text);
			}
			CraftingStation val = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? Player.m_localPlayer.GetCurrentCraftingStation() : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				list.Add(((Object)((Component)val).gameObject).name);
				list.Add(val.m_name);
			}
			string text = string.Join(" ", list).ToLowerInvariant();
			if (text.Contains("preparation") || text.Contains("preptable"))
			{
				preparationStation = true;
				return true;
			}
			if (text.Contains("cauldron") || text.Contains("cooking"))
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)val) || list.Any((string candidate) => !string.IsNullOrWhiteSpace(candidate)))
			{
				return false;
			}
			bool flag = entries.Any((Entry entry) => IsFood(entry.Item) && BelongsToStation(entry.Recipe, preparationStation: true));
			bool flag2 = entries.Any((Entry entry) => IsFood(entry.Item) && BelongsToStation(entry.Recipe, preparationStation: false));
			if (flag || flag2)
			{
				preparationStation = flag && !flag2;
				return true;
			}
			return false;
		}

		private static void HideBar(InventoryGui gui)
		{
			if (Bars.TryGetValue(gui, out FilterBar value) && Object.op_Implicit((Object)(object)value.Root))
			{
				((Component)value.Root).gameObject.SetActive(false);
			}
		}
	}
}