Decompiled source of RestlessCook v0.5.5

RestlessCook.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using RestlessQoL.Api;
using RestlessQoL.Core;
using RestlessQoL.HudTweaks;
using RestlessQoL.Storage;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
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("RestlessCook")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.5.5.0")]
[assembly: AssemblyInformationalVersion("0.5.5+11d2e243c950fa4b191334e2cf91604fb183fa49")]
[assembly: AssemblyProduct("RestlessCook")]
[assembly: AssemblyTitle("RestlessCook")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.5.5.0")]
[module: UnverifiableCode]
[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 RestlessCook
{
	internal sealed class CookbookWindow : MonoBehaviour
	{
		[HarmonyPatch(typeof(Menu), "Update")]
		private static class MenuInput
		{
			private static bool Prefix()
			{
				if ((Object)(object)_current == (Object)null)
				{
					return Time.frameCount != _closedFrame;
				}
				return false;
			}
		}

		private sealed class Card
		{
			internal readonly GameObject Root;

			private readonly Button _button;

			private readonly Image _icon;

			private readonly Text _name;

			private readonly Text _state;

			private readonly Text _expand;

			private readonly UiKitProgress _progress;

			private readonly Image _statusDiamond;

			private Action? _clicked;

			internal Card(Transform parent)
			{
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0112: Unknown result type (might be due to invalid IL or missing references)
				//IL_0139: Unknown result type (might be due to invalid IL or missing references)
				//IL_0168: Unknown result type (might be due to invalid IL or missing references)
				//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f5: Expected O, but got Unknown
				Root = RestlessUi.Chip(parent, "recipe");
				RestlessUi.PaperControl(Root, (Color?)null);
				_button = Root.AddComponent<Button>();
				((Selectable)_button).targetGraphic = (Graphic)(object)Root.GetComponent<Image>();
				RestlessUi.PaperSelectable((Selectable)(object)_button);
				_icon = RestlessUi.Graphic(Root.transform, "icon", Color.white, false).GetComponent<Image>();
				_icon.preserveAspect = true;
				_name = Label(Root.transform, "", 18, 0f, 0f, 100f, 40f);
				_name.alignment = (TextAnchor)3;
				RestlessUi.BoundedLabel(_name, 18, 15);
				_expand = Label(Root.transform, "›", 24, 0f, 0f, 20f, 28f);
				((Graphic)_expand).color = RestlessUi.PaperMuted;
				((Graphic)_expand).raycastTarget = false;
				_statusDiamond = RestlessUi.Graphic(Root.transform, "status-diamond", Color.white, false).GetComponent<Image>();
				((Transform)((Graphic)_statusDiamond).rectTransform).localRotation = Quaternion.Euler(0f, 0f, 45f);
				_progress = UiKitApi.Progress(Root.transform, "preparation-track");
				_state = Label(Root.transform, "", 15, 0f, 0f, 100f, 30f);
				_state.alignment = (TextAnchor)3;
				RestlessUi.BoundedLabel(_state, 15, 13);
				((UnityEvent)_button.onClick).AddListener((UnityAction)delegate
				{
					_clicked?.Invoke();
				});
			}

			internal void Progress(KitchenStep step)
			{
				//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_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: 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_005f: Unknown result type (might be due to invalid IL or missing references)
				//IL_007f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
				Rect rect = ((RectTransform)Root.transform).rect;
				Vector2 size = ((Rect)(ref rect)).size;
				float num = ((step.State == KitchenStepState.Prepared) ? 1f : ((step.DurationSeconds > 0f) ? Mathf.Clamp01(step.ElapsedSeconds / step.DurationSeconds) : 0f));
				_progress.Set(new Rect(20f, size.y - (float)(((Component)_statusDiamond).gameObject.activeSelf ? 34 : 10), size.x - 40f, 4f), 0f, num, Tint(step.State), Tint(step.State), step.State == KitchenStepState.Cooking && step.DurationSeconds > 0f);
			}

			internal void Set(string name, string state, Sprite? icon, Color tint, Action action, bool selected = false, bool featured = false, bool listEntry = false, bool expandable = false)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: 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_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d7: 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_01b3: 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_0186: Unknown result type (might be due to invalid IL or missing references)
				//IL_0198: Unknown result type (might be due to invalid IL or missing references)
				//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
				//IL_0296: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
				//IL_0209: Unknown result type (might be due to invalid IL or missing references)
				//IL_0215: Unknown result type (might be due to invalid IL or missing references)
				//IL_0231: Unknown result type (might be due to invalid IL or missing references)
				//IL_0247: Unknown result type (might be due to invalid IL or missing references)
				//IL_0348: Unknown result type (might be due to invalid IL or missing references)
				//IL_0360: Unknown result type (might be due to invalid IL or missing references)
				//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
				//IL_02d3: 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_03bb: Unknown result type (might be due to invalid IL or missing references)
				_clicked = action;
				Rect rect = ((RectTransform)Root.transform).rect;
				Vector2 size = ((Rect)(ref rect)).size;
				((Component)_statusDiamond).gameObject.SetActive(featured);
				((Component)_state).gameObject.SetActive(!listEntry);
				((Component)_expand).gameObject.SetActive(expandable);
				Position(((Component)_expand).gameObject, size.x - 24f, 14f, 16f, 28f);
				if (featured)
				{
					Portrait(((Component)_icon).gameObject, 26f, (size.y - 96f) / 2f, 96f, 96f);
					Position(((Component)_name).gameObject, 136f, 26f, size.x - 242f, 50f);
					Portrait(((Component)_statusDiamond).gameObject, 138f, 93f, 7f, 7f);
					Position(((Component)_state).gameObject, 156f, 80f, size.x - 194f, 34f);
				}
				else if (listEntry)
				{
					Portrait(((Component)_icon).gameObject, 10f, (size.y - 44f) / 2f, 44f, 44f);
					Position(((Component)_name).gameObject, 64f, (size.y - 44f) / 2f, size.x - 76f, 44f);
				}
				else if (size.y <= 64f)
				{
					Portrait(((Component)_icon).gameObject, 6f, (size.y - 36f) / 2f, 36f, 36f);
					Position(((Component)_name).gameObject, 50f, 4f, size.x - 188f, size.y - 8f);
					Position(((Component)_state).gameObject, size.x - 132f, 4f, 124f, size.y - 8f);
				}
				else
				{
					Portrait(((Component)_icon).gameObject, 10f, 12f, 48f, 48f);
					Position(((Component)_name).gameObject, 68f, 6f, size.x - (float)(expandable ? 98 : 80), 50f);
					Position(((Component)_state).gameObject, 12f, 62f, size.x - 24f, size.y - 76f);
				}
				_name.alignment = (TextAnchor)3;
				_state.alignment = (TextAnchor)((size.y <= 64f) ? 5 : 3);
				_icon.sprite = icon;
				((Behaviour)_icon).enabled = (Object)(object)icon != (Object)null;
				_name.text = name;
				_state.text = state;
				((Graphic)_state).color = tint;
				_progress.Hide();
				((Graphic)_statusDiamond).color = tint;
				if (featured)
				{
					RestlessUi.CookHeroSurface(Root);
					return;
				}
				Transform val = Root.transform.Find("cookHeroFrame");
				if ((Object)(object)val != (Object)null)
				{
					((Component)val).gameObject.SetActive(false);
				}
				RestlessUi.PaperControl(Root, (Color?)(Color)(selected ? RestlessUi.Accent : new Color(0.37f, 0.33f, 0.27f)));
				Transform val2 = Root.transform.Find("paperAccent");
				if ((Object)(object)val2 != (Object)null)
				{
					((Component)val2).gameObject.SetActive(true);
				}
			}
		}

		private static CookbookWindow? _current;

		private static int _closedFrame = -1;

		private CraftingStation _table;

		private UiKitWindow _frame;

		private string _stationSelection = "";

		private RectTransform _sheet;

		private RestlessScrollRect _recipes;

		private RestlessScrollRect _tree;

		private RestlessScrollRect _details;

		private readonly List<Card> _recipeCards = new List<Card>();

		private readonly List<Card> _nodes = new List<Card>();

		private readonly List<UiKitMaterialCard> _requirementCards = new List<UiKitMaterialCard>();

		private readonly List<GameObject> _lines = new List<GameObject>();

		private readonly List<Button> _tabs = new List<Button>();

		private readonly Dictionary<string, Sprite?> _icons = new Dictionary<string, Sprite>();

		private readonly List<int> _trail = new List<int>();

		private IReadOnlyList<KitchenStep> _steps = Array.Empty<KitchenStep>();

		private IReadOnlyList<KitchenOrder> _orders = Array.Empty<KitchenOrder>();

		private string _recipe = "";

		private string _query = "";

		private string _stamp = "";

		private int _tab;

		private int _count = 1;

		private int _focus;

		private int _order;

		private int _detailFocus = -1;

		private bool _blocked;

		private bool _confirmCancel;

		private string _category = "Feasts";

		private readonly List<Button> _filters = new List<Button>();

		private readonly List<GameObject> _quantityControls = new List<GameObject>();

		private Text _detailTitle;

		private Image _dish;

		private GameObject _dishFrame;

		private Text _dishName;

		private Text _dishKind;

		private Text _station;

		private Text _requirementsLabel;

		private float _next;

		private float _messageUntil;

		private Text _heading;

		private Text _copy;

		private Text _status;

		private Text _quantity;

		private Text _actionText;

		private Text _actionHint;

		private Button _action;

		private Button _collect;

		private Button _back;

		private Vector2 _canvas;

		private string _pantrySelection = "";

		internal static void Open(CraftingStation table)
		{
			//IL_0072: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.CookbookEnabled.Value)
			{
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)2, "Enable Cookbook in Restless settings.", 0, (Sprite)null, false);
				}
			}
			else if (!((Object)(object)table == (Object)null) && !((Object)(object)GUIManager.CustomGUIFront == (Object)null) && !SettingsUi.IsOpen && !InventoryGui.IsVisible())
			{
				Close();
				GameObject obj = RestlessUi.Graphic(GUIManager.CustomGUIFront.transform, "RestlessCookbook", new Color(0f, 0f, 0f, 0.28f), true);
				RestlessUi.Stretch(obj, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
				CookbookWindow cookbookWindow = (_current = obj.AddComponent<CookbookWindow>());
				cookbookWindow._table = table;
				try
				{
					cookbookWindow.Build();
					LookHints.SetSuppressed((object)cookbookWindow, true);
					cookbookWindow._blocked = true;
					GUIManager.BlockInput(true);
					cookbookWindow.RecipeList();
					cookbookWindow.Refresh(force: true);
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
					Close();
				}
			}
		}

		internal static void Close()
		{
			if (!((Object)(object)_current == (Object)null))
			{
				CookbookWindow? current = _current;
				_current = null;
				_closedFrame = Time.frameCount;
				((Component)current).gameObject.SetActive(false);
				Object.Destroy((Object)(object)((Component)current).gameObject);
			}
		}

		private void OnDisable()
		{
			LookHints.SetSuppressed((object)this, false);
			if ((Object)(object)_current == (Object)(object)this)
			{
				_current = null;
			}
			if (_blocked && !SettingsUi.IsOpen)
			{
				GUIManager.BlockInput(false);
			}
			_blocked = false;
		}

		private void Update()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!Input.GetKeyDown((KeyCode)27) && Plugin.CookbookEnabled.Value && !((Object)(object)_table == (Object)null) && !((Object)(object)localPlayer == (Object)null) && !((Character)localPlayer).IsDead() && !SettingsUi.IsOpen && !InventoryGui.IsVisible())
			{
				Vector3 val = ((Component)_table).transform.position - ((Component)localPlayer).transform.position;
				if (!(((Vector3)(ref val)).sqrMagnitude > 25f))
				{
					Fit();
					if (Time.unscaledTime >= _next)
					{
						Refresh(force: false);
					}
					return;
				}
			}
			Close();
		}

		private void Refresh(bool force)
		{
			_next = Time.unscaledTime + 1f;
			try
			{
				_orders = Kitchen.Orders(_table);
				if (_order != 0 && !_orders.Any((KitchenOrder o) => o.Id == _order))
				{
					_order = 0;
					_trail.Clear();
					_focus = 0;
					_detailFocus = -1;
				}
				if (_tab == 2)
				{
					PaintStations(force);
					return;
				}
				if (_tab == 3)
				{
					PaintPantry(force);
					return;
				}
				IReadOnlyList<KitchenStep> steps;
				if (_order == 0)
				{
					if (_tab != 1)
					{
						steps = Kitchen.Plan(_table, _recipe, _count);
					}
					else
					{
						IReadOnlyList<KitchenStep> readOnlyList = Array.Empty<KitchenStep>();
						steps = readOnlyList;
					}
				}
				else
				{
					steps = Kitchen.Live(_table, _order);
				}
				_steps = steps;
				StringBuilder stringBuilder = new StringBuilder().Append(_tab).Append('|').Append(_order)
					.Append('|')
					.Append(_recipe)
					.Append('|')
					.Append(_count);
				foreach (KitchenStep step in _steps)
				{
					stringBuilder.Append('|').Append(step.Output).Append(':')
						.Append(step.Parent)
						.Append(':')
						.Append(step.Depth)
						.Append(':')
						.Append(step.Need)
						.Append(':')
						.Append(step.Have)
						.Append(':')
						.Append(step.Available)
						.Append(':')
						.Append(step.Cooking)
						.Append(':')
						.Append(step.State)
						.Append(':')
						.Append(step.Note)
						.Append(':')
						.Append(step.ElapsedSeconds)
						.Append(':')
						.Append(step.DurationSeconds);
				}
				foreach (KitchenOrder order in _orders)
				{
					stringBuilder.Append('|').Append(order.Id).Append(':')
						.Append(order.Ready)
						.Append(':')
						.Append(order.Count);
				}
				string text = stringBuilder.ToString();
				if (force || text != _stamp)
				{
					if (_detailFocus >= _steps.Count)
					{
						_detailFocus = -1;
					}
					_stamp = text;
					if (_tab == 1)
					{
						OrderList();
					}
					if (_focus >= _steps.Count)
					{
						_focus = 0;
						_trail.Clear();
					}
					if (_tab == 1)
					{
						PaintOrderSteps();
					}
					else
					{
						PaintTree();
					}
					PaintDetails();
				}
				if (Time.unscaledTime >= _messageUntil)
				{
					_status.text = ((_order == 0) ? "Queue an order · missing ingredients can be supplied while it waits" : OrderStatus());
				}
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
				_status.text = "Kitchen data unavailable. Close and try again.";
			}
		}

		private string OrderStatus()
		{
			KitchenStep kitchenStep = _steps.FirstOrDefault((KitchenStep s) => s.State == KitchenStepState.Cooking && !Covered(s));
			if (kitchenStep != null)
			{
				return "Preparing " + Local(kitchenStep.Name) + " · " + State(kitchenStep);
			}
			KitchenStep kitchenStep2 = _steps.FirstOrDefault((KitchenStep s) => s.State == KitchenStepState.Blocked && !Covered(s));
			if (kitchenStep2 != null)
			{
				return Local(kitchenStep2.Name) + " · " + kitchenStep2.Note;
			}
			KitchenStep kitchenStep3 = _steps.FirstOrDefault((KitchenStep s) => s.State == KitchenStepState.Missing && s.Uses.Count == 0 && !Covered(s));
			if (kitchenStep3 != null)
			{
				return "Waiting for " + Local(kitchenStep3.Name) + " · " + KitchenStock.Count(kitchenStep3.Available, kitchenStep3.Need) + " available";
			}
			return "Order queued · waiting for the next preparation step";
		}

		private void Tab(int tab)
		{
			//IL_011d: 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_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			_detailFocus = -1;
			_tab = tab;
			_stamp = "";
			_confirmCancel = false;
			for (int i = 0; i < _tabs.Count; i++)
			{
				UiKitApi.Tab(_tabs[i], i == tab);
			}
			foreach (Button filter in _filters)
			{
				((Component)filter).gameObject.SetActive(tab == 0);
			}
			foreach (GameObject quantityControl in _quantityControls)
			{
				quantityControl.SetActive(tab == 0);
			}
			_detailTitle.text = ((tab == 2) ? "STATION DETAILS" : "SELECTED STEP");
			if (tab == 0)
			{
				_order = 0;
				RecipeList();
			}
			if (tab == 1)
			{
				OrderList();
			}
			_trail.Clear();
			_focus = 0;
			Refresh(force: true);
			RestlessScrollRect tree = _tree;
			Rect rect = ((ScrollRect)_tree).content.rect;
			Size(tree, ((Rect)(ref rect)).height, reset: true);
			RestlessScrollRect details = _details;
			rect = ((ScrollRect)_details).content.rect;
			Size(details, ((Rect)(ref rect)).height, reset: true);
			RestlessScrollRect recipes = _recipes;
			rect = ((ScrollRect)_recipes).content.rect;
			Size(recipes, ((Rect)(ref rect)).height, reset: true);
		}

		private void RecipeList()
		{
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			List<CookRow> list = (from cookRow in Kitchen.Rows
				where Matches(cookRow) && (string.IsNullOrWhiteSpace(_query) || cookRow.Name.IndexOf(_query.Trim(), StringComparison.CurrentCultureIgnoreCase) >= 0)
				orderby TierOrder(cookRow.Tier), cookRow.Name
				select cookRow).ToList();
			if (!list.Any((CookRow cookRow) => cookRow.Id == _recipe))
			{
				_recipe = ((list.Count > 0) ? list[0].Id : "");
				_detailFocus = -1;
				_focus = 0;
				_trail.Clear();
			}
			for (int num = 0; num < list.Count; num++)
			{
				CookRow r = list[num];
				Card card = GetCard(_recipeCards, num, (Transform)(object)((ScrollRect)_recipes).content);
				Position(card.Root, 0f, num * 80, 228f, 72f);
				card.Set(r.Name, TierName(r.Tier) + " · " + r.Kind, Icon(Output(r)), (r.Id == _recipe) ? RestlessUi.Accent : RestlessUi.PaperMuted, delegate
				{
					//IL_0088: Unknown result type (might be due to invalid IL or missing references)
					//IL_008d: Unknown result type (might be due to invalid IL or missing references)
					//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
					//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
					_detailFocus = -1;
					_recipe = r.Id;
					_order = 0;
					_focus = 0;
					_trail.Clear();
					_confirmCancel = false;
					RecipeList();
					Refresh(force: true);
					RestlessScrollRect tree = _tree;
					Rect rect = ((ScrollRect)_tree).content.rect;
					Size(tree, ((Rect)(ref rect)).height, reset: true);
					RestlessScrollRect details = _details;
					rect = ((ScrollRect)_details).content.rect;
					Size(details, ((Rect)(ref rect)).height, reset: true);
				}, r.Id == _recipe, featured: false, listEntry: true);
			}
			HideAfter(_recipeCards, list.Count);
			Size(_recipes, list.Count * 80, reset: false);
			if (list.Count == 0)
			{
				Message("No matching recipes.");
			}
		}

		private void OrderList()
		{
			//IL_00d0: 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)
			for (int i = 0; i < _orders.Count; i++)
			{
				KitchenOrder o = _orders[i];
				Card card = GetCard(_recipeCards, i, (Transform)(object)((ScrollRect)_recipes).content);
				Position(card.Root, 0f, i * 96, 228f, 90f);
				card.Set(o.Name, o.Collected + o.Ready + " / " + o.Count + " finished", Icon(o.Feast), (o.Id == _order) ? RestlessUi.Accent : RestlessUi.PaperMuted, delegate
				{
					_detailFocus = -1;
					_order = o.Id;
					_focus = 0;
					_trail.Clear();
					_confirmCancel = false;
					Refresh(force: true);
				}, o.Id == _order);
			}
			HideAfter(_recipeCards, _orders.Count);
			Size(_recipes, _orders.Count * 96, reset: false);
		}

		private List<int> Children(int index)
		{
			List<int> list = new List<int>();
			for (int i = index + 1; i < _steps.Count && _steps[i].Depth > _steps[index].Depth; i++)
			{
				if (_steps[i].Depth == _steps[index].Depth + 1)
				{
					list.Add(i);
				}
			}
			return list;
		}

		private void Focus(int index)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			_detailFocus = -1;
			_trail.Add(_focus);
			_focus = index;
			if (_tab == 1)
			{
				PaintOrderSteps();
			}
			else
			{
				PaintTree();
			}
			PaintDetails();
			RestlessScrollRect tree = _tree;
			Rect rect = ((ScrollRect)_tree).content.rect;
			Size(tree, ((Rect)(ref rect)).height, reset: true);
			RestlessScrollRect details = _details;
			rect = ((ScrollRect)_details).content.rect;
			Size(details, ((Rect)(ref rect)).height, reset: true);
		}

		private void Inspect(int index)
		{
			//IL_003f: 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)
			if (_steps[index].Uses.Count > 0)
			{
				Focus(index);
				return;
			}
			_detailFocus = index;
			PaintDetails();
			RestlessScrollRect details = _details;
			Rect rect = ((ScrollRect)_details).content.rect;
			Size(details, ((Rect)(ref rect)).height, reset: true);
		}

		private void PaintTree()
		{
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			foreach (GameObject line in _lines)
			{
				line.SetActive(false);
			}
			((Selectable)_back).interactable = _trail.Count > 0;
			if (_steps.Count == 0)
			{
				HideAfter(_nodes, 0);
				_heading.text = ((_tab != 1) ? "Choose a recipe" : ((_orders.Count == 0) ? "No kitchen orders" : "Choose an order"));
				return;
			}
			KitchenStep kitchenStep = _steps[_focus];
			_heading.text = ((_trail.Count == 0) ? "Preparation plan" : "Ingredient preparation");
			Card card = GetCard(_nodes, 0, (Transform)(object)((ScrollRect)_tree).content);
			Position(card.Root, 18f, 8f, 492f, 152f);
			card.Set(Local(kitchenStep.Name), State(kitchenStep), Icon(kitchenStep.Output), Tint(kitchenStep.State), delegate
			{
				_detailFocus = -1;
				PaintDetails();
			}, selected: true, featured: true);
			card.Progress(kitchenStep);
			List<int> list = Children(_focus);
			int num = 0;
			for (int num2 = 0; num2 < list.Count; num2++)
			{
				int index = list[num2];
				KitchenStep kitchenStep2 = _steps[index];
				float num3 = ((num2 == list.Count - 1 && list.Count % 2 == 1) ? 138 : (num2 % 2 * 276));
				float num4 = 192 + num2 / 2 * 144;
				Line(num++, 264f, 142f, 2f, num4 - 158f);
				Line(num++, Math.Min(264f, num3 + 126f), num4 - 16f, Math.Abs(264f - (num3 + 126f)), 2f);
				Line(num++, num3 + 126f, num4 - 16f, 2f, 16f);
				Card card2 = GetCard(_nodes, num2 + 1, (Transform)(object)((ScrollRect)_tree).content);
				Position(card2.Root, num3, num4, 252f, 116f);
				card2.Set(Local(kitchenStep2.Name), State(kitchenStep2), Icon(kitchenStep2.Output), Tint(kitchenStep2.State), delegate
				{
					Inspect(index);
				}, selected: false, featured: false, listEntry: false, kitchenStep2.Uses.Count > 0);
				card2.Progress(kitchenStep2);
			}
			HideAfter(_nodes, list.Count + 1);
			Size(_tree, (list.Count == 0) ? 168 : (192 + (list.Count + 1) / 2 * 144), reset: false);
		}

		private void PaintDetails()
		{
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Expected O, but got Unknown
			ShowDish();
			int num = ((_detailFocus >= 0 && _detailFocus < _steps.Count) ? _detailFocus : _focus);
			KitchenStep kitchenStep = ((_steps.Count > num) ? _steps[num] : null);
			_dish.sprite = ((kitchenStep == null) ? null : Icon(kitchenStep.Output));
			((Behaviour)_dish).enabled = (Object)(object)_dish.sprite != (Object)null;
			_dishFrame.SetActive(kitchenStep != null);
			_dishName.text = ((kitchenStep == null) ? "Select a dish" : Local(kitchenStep.Name));
			_dishKind.text = ((kitchenStep == null) ? "" : State(kitchenStep));
			((Graphic)_dishKind).color = ((kitchenStep == null) ? RestlessUi.PaperMuted : Tint(kitchenStep.State));
			_station.text = ((kitchenStep == null) ? "" : ((kitchenStep.Station == KitchenStationKind.None) ? "Gather from the world" : (StationName(kitchenStep.Station) + ((kitchenStep.Station == KitchenStationKind.Cauldron || kitchenStep.Station == KitchenStationKind.PrepTable || kitchenStep.Station == KitchenStationKind.MeadKettle) ? ("\nRequired level " + kitchenStep.StationLevel) : ((kitchenStep.Station == KitchenStationKind.Fermenter) ? "\nUses native fermentation time" : "\nUses native cooking time")))));
			StringBuilder stringBuilder = new StringBuilder();
			int num2 = kitchenStep?.Uses.Count ?? 0;
			List<int> list = ((kitchenStep == null) ? new List<int>() : Children(num));
			for (int i = 0; i < num2; i++)
			{
				KitchenUse use = kitchenStep.Uses[i];
				int index = list.FindIndex((int n) => _steps[n].Output == use.Item);
				if (index >= 0)
				{
					index = list[index];
				}
				KitchenStep kitchenStep2 = ((index >= 0) ? _steps[index] : null);
				int num3 = kitchenStep2?.Available ?? use.Have;
				bool flag = kitchenStep2 != null && Covered(kitchenStep2);
				if (i == _requirementCards.Count)
				{
					_requirementCards.Add(new UiKitMaterialCard((Transform)(object)((ScrollRect)_details).content));
				}
				UiKitMaterialCard obj = _requirementCards[i];
				string text = KitchenStock.Count(num3, use.Amount);
				obj.Set(new Rect(0f, (float)(26 + i * 84), 280f, 76f), Local(use.Name), text, flag ? "Covered by another step" : ((num3 >= use.Amount) ? "Available / needed" : "Missing ingredients"), Icon(use.Item), !flag && num3 < use.Amount, (index >= 0) ? ((Action)delegate
				{
					Inspect(index);
				}) : null);
			}
			HideAfter(_requirementCards, num2);
			if (kitchenStep != null)
			{
				if ((_order != 0 || num != 0) && !string.IsNullOrWhiteSpace(kitchenStep.Note))
				{
					stringBuilder.AppendLine(kitchenStep.Note).AppendLine();
				}
				IReadOnlyList<CookRow> readOnlyList = Kitchen.OtherUses(kitchenStep.Output);
				if (readOnlyList.Count > 0)
				{
					stringBuilder.AppendLine("ALSO USED IN");
					foreach (CookRow item in readOnlyList)
					{
						stringBuilder.AppendLine(item.Name);
					}
				}
			}
			else
			{
				stringBuilder.Append((_tab == 1) ? "Select an order on the left to follow its progress." : "Select a recipe to explore its ingredients.");
			}
			_requirementsLabel.text = ((num2 > 0) ? "INGREDIENTS · STOCK / NEEDED" : "");
			_copy.text = stringBuilder.ToString();
			int num4 = ((num2 > 0) ? (34 + num2 * 84) : 0);
			Position(((Component)_copy).gameObject, 0f, num4, 280f, Mathf.Max(60f, _copy.preferredHeight));
			Size(_details, (float)num4 + _copy.preferredHeight + 16f, reset: false);
			KitchenOrder kitchenOrder = _orders.FirstOrDefault((KitchenOrder o) => o.Id == _order);
			((Component)_collect).gameObject.SetActive(kitchenOrder != null);
			((Selectable)_collect).interactable = kitchenOrder != null && kitchenOrder.Ready > 0;
			((Component)_action).gameObject.SetActive(_tab < 2);
			((Selectable)_action).interactable = kitchenOrder != null || (_tab == 0 && _steps.Count > 0 && _steps[0].Uses.Count > 0 && _orders.Count < 8);
			_actionText.text = ((kitchenOrder == null) ? ("Queue " + _count) : (_confirmCancel ? "Confirm cancellation" : "Cancel order"));
			((Component)_actionHint).gameObject.SetActive(_tab == 0);
			_actionHint.text = ((_steps.Count == 0) ? "Choose a recipe to queue." : QueueReason(_steps[0]));
			_quantity.text = _count.ToString();
		}

		private void Act()
		{
			if (_tab == 3)
			{
				TakePantry();
			}
			else
			{
				if (!((Selectable)_action).interactable)
				{
					return;
				}
				try
				{
					if (_order != 0)
					{
						if (!_confirmCancel)
						{
							_confirmCancel = true;
							PaintDetails();
							Message("Cancel this order? Prepared food remains in the kitchen pantry.");
							return;
						}
						Kitchen.Cancel(_table, _order);
						_order = 0;
						_confirmCancel = false;
						Message("Cancellation requested.");
					}
					else
					{
						HashSet<int> previous = new HashSet<int>(from o in Kitchen.Orders(_table)
							select o.Id);
						if (Kitchen.Place(_table, _recipe, _count))
						{
							_order = Kitchen.Orders(_table).FirstOrDefault((KitchenOrder o) => !previous.Contains(o.Id))?.Id ?? 0;
							Tab(1);
							Message("Order queued. Each step below shows what happens next.");
						}
						else
						{
							Message("Order could not be placed. Check ownership or queue capacity.");
						}
					}
					Refresh(force: true);
				}
				catch (Exception ex)
				{
					Debug.LogException(ex);
					Message("Action failed. Check Orders before trying again.");
				}
			}
		}

		private void Collect()
		{
			try
			{
				Message("Collected " + Kitchen.Collect(_table, _order) + ". Remaining food stays at the table.");
				Refresh(force: true);
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
				Message("Collection failed. Check your inventory.");
			}
		}

		private void PaintStations(bool force)
		{
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0419: Unknown result type (might be due to invalid IL or missing references)
			HideDish();
			_requirementsLabel.text = "";
			((Component)_actionHint).gameObject.SetActive(false);
			HideAfter(_requirementCards, 0);
			List<KitchenStationInfo> list = (from s in Kitchen.Stations(_table)
				where Local(s.Name).IndexOf(_query, StringComparison.OrdinalIgnoreCase) >= 0
				select s).ToList();
			if (!list.Any((KitchenStationInfo s) => s.Id == _stationSelection))
			{
				_stationSelection = list.FirstOrDefault()?.Id ?? "";
			}
			string text = "stations|" + _stationSelection + "|" + string.Join("|", list.Select((KitchenStationInfo s) => s.Id + ":" + s.Level + ":" + s.Free + ":" + s.Cooking + ":" + s.Ready + ":" + s.Fuel + ":" + s.Block));
			if (!force && text == _stamp)
			{
				return;
			}
			_stamp = text;
			foreach (GameObject line in _lines)
			{
				line.SetActive(false);
			}
			for (int num = 0; num < list.Count; num++)
			{
				KitchenStationInfo station = list[num];
				Card card = GetCard(_recipeCards, num, (Transform)(object)((ScrollRect)_recipes).content);
				Position(card.Root, 0f, num * 100, 228f, 92f);
				card.Set(Local(station.Name), UiKitApi.StationState(Local(station.Block)), null, string.IsNullOrEmpty(station.Block) ? RestlessUi.Accent : RestlessUi.HealthTint, delegate
				{
					//IL_003d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0042: Unknown result type (might be due to invalid IL or missing references)
					_stationSelection = station.Id;
					PaintStations(force: true);
					RestlessScrollRect details = _details;
					Rect rect = ((ScrollRect)_details).content.rect;
					Size(details, ((Rect)(ref rect)).height, reset: true);
				}, station.Id == _stationSelection);
			}
			HideAfter(_recipeCards, list.Count);
			Size(_recipes, list.Count * 100, reset: false);
			KitchenStationInfo kitchenStationInfo = list.FirstOrDefault((KitchenStationInfo s) => s.Id == _stationSelection);
			_heading.text = ((kitchenStationInfo == null) ? "No kitchen stations nearby" : Local(kitchenStationInfo.Name));
			Card card2 = GetCard(_nodes, 0, (Transform)(object)((ScrollRect)_tree).content);
			Position(card2.Root, 24f, 24f, 500f, 128f);
			card2.Set((kitchenStationInfo == null) ? "Your kitchen" : Local(kitchenStationInfo.Name), (kitchenStationInfo == null) ? "Build a cooking station within the table's reach." : UiKitApi.StationState(Local(kitchenStationInfo.Block)), null, RestlessUi.Accent, delegate
			{
			}, selected: false, featured: true);
			if (kitchenStationInfo != null)
			{
				string[] array = new string[3]
				{
					(kitchenStationInfo.Kind == KitchenStationKind.Cauldron || kitchenStationInfo.Kind == KitchenStationKind.MeadKettle) ? ("Station level " + kitchenStationInfo.Level) : (kitchenStationInfo.Free + " free slots · " + kitchenStationInfo.Cooking + " cooking · " + kitchenStationInfo.Ready + " ready"),
					(kitchenStationInfo.FuelMax > 0) ? ("Fuel " + kitchenStationInfo.Fuel + " / " + kitchenStationInfo.FuelMax) : "No fuel required",
					kitchenStationInfo.Distance.ToString("0.0") + " m from preparation table"
				};
				for (int num2 = 0; num2 < array.Length; num2++)
				{
					Card card3 = GetCard(_nodes, num2 + 1, (Transform)(object)((ScrollRect)_tree).content);
					Position(card3.Root, 24f, 176 + num2 * 96, 500f, 84f);
					card3.Set(array[num2], "", null, RestlessUi.PaperMuted, delegate
					{
					});
				}
				HideAfter(_nodes, 4);
				Size(_tree, 480f, reset: false);
			}
			else
			{
				HideAfter(_nodes, 1);
				Size(_tree, 170f, reset: false);
			}
			_copy.text = ((kitchenStationInfo == null) ? "No cooking stations found nearby." : (Local(kitchenStationInfo.Name) + "\n\n" + UiKitApi.StationState(Local(kitchenStationInfo.Block)) + "\n\n" + ((!kitchenStationInfo.NeedsFire) ? "No external fire required." : (kitchenStationInfo.FireLit ? "Required fire is lit." : "A nearby fire is required.")) + "\n\nKitchen orders use existing station reservations and native cooking times."));
			Position(((Component)_copy).gameObject, 0f, 0f, 280f, Mathf.Max(60f, _copy.preferredHeight));
			Size(_details, _copy.preferredHeight + 16f, reset: false);
			((Component)_action).gameObject.SetActive(false);
			((Component)_collect).gameObject.SetActive(false);
			((Selectable)_back).interactable = false;
		}

		private void Message(string message)
		{
			_status.text = message;
			_messageUntil = Time.unscaledTime + 5f;
		}

		private static string Local(string text)
		{
			if (Localization.instance != null)
			{
				return Localization.instance.Localize(text);
			}
			return text;
		}

		private static string Output(CookRow r)
		{
			if (!r.IsFeast || !r.IsAdd || r.Prefab.EndsWith("_Material"))
			{
				return r.Prefab;
			}
			return r.Prefab + "_Material";
		}

		private Sprite? Icon(string prefab)
		{
			if (_icons.TryGetValue(prefab, out Sprite value))
			{
				return value;
			}
			ObjectDB instance = ObjectDB.instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				GameObject itemPrefab = instance.GetItemPrefab(prefab);
				obj = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			}
			Sprite[] array = ((ItemDrop)(obj?)).m_itemData?.m_shared?.m_icons;
			value = ((array != null && array.Length != 0) ? array[0] : null);
			_icons[prefab] = value;
			return value;
		}

		private bool Covered(KitchenStep step)
		{
			int parentIndex = step.ParentIndex;
			int num = 0;
			while (parentIndex >= 0 && parentIndex < _steps.Count && num < _steps.Count)
			{
				KitchenStep kitchenStep = _steps[parentIndex];
				if (kitchenStep.Need > 0 && kitchenStep.Have + kitchenStep.Cooking >= kitchenStep.Need)
				{
					return true;
				}
				parentIndex = kitchenStep.ParentIndex;
				num++;
			}
			return false;
		}

		private string State(KitchenStep s)
		{
			string text = KitchenStock.Count(s.Available, s.Need);
			if (Covered(s))
			{
				return "Covered by another step";
			}
			if (s.State == KitchenStepState.Blocked)
			{
				return Local(s.Note) + " · " + text;
			}
			if (s.Cooking > 0)
			{
				string text2 = ((s.DurationSeconds > 0f) ? (" · " + Mathf.CeilToInt(Mathf.Max(0f, s.DurationSeconds - s.ElapsedSeconds)) + "s") : "");
				return s.Cooking + " cooking" + text2 + (string.IsNullOrEmpty(s.ActiveStation) ? "" : (" · " + Local(s.ActiveStation)));
			}
			if (s.Uses.Count == 0)
			{
				return ((s.Available >= s.Need) ? "Available · " : "Missing · ") + text;
			}
			if (s.Available >= s.Need)
			{
				return "Prepared · " + text;
			}
			return s.Available + " prepared · " + Math.Max(0, s.Need - s.Available) + " to make";
		}

		private static string QueueReason(KitchenStep root)
		{
			return root.State switch
			{
				KitchenStepState.Ready => "Ingredients available · ready to prepare", 
				KitchenStepState.Queued => "Ingredients available · waiting for a station", 
				KitchenStepState.Prepared => "Preparation complete", 
				_ => string.IsNullOrWhiteSpace(root.Note) ? "Queue this dish for preparation" : Local(root.Note), 
			};
		}

		private static Color Tint(KitchenStepState s)
		{
			//IL_0022: 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_0007: Unknown result type (might be due to invalid IL or missing references)
			return (Color)(s switch
			{
				KitchenStepState.Blocked => RestlessUi.HealthTint, 
				KitchenStepState.Prepared => new Color(0.58f, 0.76f, 0.56f), 
				_ => RestlessUi.Accent, 
			});
		}

		private static string TierName(string tier)
		{
			string text = tier.ToLowerInvariant();
			switch (text)
			{
			default:
				if (text.Length != 0)
				{
					break;
				}
				return "Kitchen";
			case "blackforest":
				return "Black Forest";
			case "deepnorth":
				return "Deep North";
			case null:
				break;
			}
			return char.ToUpperInvariant(tier[0]) + tier.Substring(1);
		}

		private static int TierOrder(string tier)
		{
			return tier.ToLowerInvariant() switch
			{
				"meadows" => 0, 
				"blackforest" => 1, 
				"swamp" => 2, 
				"mountains" => 3, 
				"plains" => 4, 
				"mistlands" => 5, 
				"ashlands" => 6, 
				"deepnorth" => 7, 
				_ => 8, 
			};
		}

		private static string StationName(KitchenStationKind s)
		{
			return s switch
			{
				KitchenStationKind.Rack => "Cooking rack", 
				KitchenStationKind.PrepTable => "Preparation table", 
				KitchenStationKind.MeadKettle => "Mead kettle", 
				_ => s.ToString(), 
			};
		}

		private void Build()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_0476: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			_frame = new UiKitWindow(((Component)this).transform, "Cookbook", new Vector2(1240f, 800f), (Action)Close);
			_sheet = _frame.Sheet;
			_frame.Subtitle.text = "Cook the haul. Prepare meals. Share a feast.";
			string[] array = new string[4] { "Recipes", "Orders", "Kitchen", "Pantry" };
			for (int i = 0; i < array.Length; i++)
			{
				int tab = i;
				_tabs.Add(Button((Transform)(object)_sheet, array[i], 570 + i * 124, 34f, 114f, 38f, delegate
				{
					Tab(tab);
				}));
			}
			((UnityEvent<string>)(object)Field((Transform)(object)_sheet, 28f, 132f, 252f, 40f).onValueChanged).AddListener((UnityAction<string>)delegate(string value)
			{
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Unknown result type (might be due to invalid IL or missing references)
				_query = value;
				if (_tab == 0)
				{
					RecipeList();
				}
				else if (_tab == 1)
				{
					OrderList();
				}
				Refresh(force: true);
				RestlessScrollRect recipes = _recipes;
				Rect rect = ((ScrollRect)_recipes).content.rect;
				Size(recipes, ((Rect)(ref rect)).height, reset: true);
			});
			string[] categories = new string[6] { "All", "Feasts", "Meals", "Prep", "Bait", "Meads" };
			for (int num = 0; num < categories.Length; num++)
			{
				string category = categories[num];
				Button val = Button((Transform)(object)_sheet, category, 28 + num % 3 * 84, 182 + num / 3 * 36, 80f, 30f, delegate
				{
					//IL_005a: Unknown result type (might be due to invalid IL or missing references)
					//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
					//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
					_category = category;
					for (int j = 0; j < _filters.Count; j++)
					{
						RestlessUi.PaperControl(((Component)_filters[j]).gameObject, (categories[j] == category) ? new Color?(RestlessUi.Accent) : ((Color?)null));
					}
					if (_tab == 0)
					{
						RecipeList();
						Refresh(force: true);
						RestlessScrollRect recipes = _recipes;
						Rect rect = ((ScrollRect)_recipes).content.rect;
						Size(recipes, ((Rect)(ref rect)).height, reset: true);
					}
				});
				_filters.Add(val);
				if (category == _category)
				{
					RestlessUi.PaperControl(((Component)val).gameObject, (Color?)RestlessUi.Accent);
				}
			}
			_recipes = Reader((Transform)(object)_sheet, "recipes", 28f, 260f, 252f, 422f, 80f);
			_quantityControls.Add(((Component)Label((Transform)(object)_sheet, "Order quantity", 18, 28f, 696f, 252f, 26f)).gameObject);
			_quantityControls.Add(((Component)Button((Transform)(object)_sheet, "−", 28f, 726f, 52f, 36f, delegate
			{
				Quantity(-1);
			})).gameObject);
			_quantity = Label((Transform)(object)_sheet, "1", 22, 88f, 726f, 132f, 36f);
			_quantity.alignment = (TextAnchor)4;
			_quantityControls.Add(((Component)_quantity).gameObject);
			_quantityControls.Add(((Component)Button((Transform)(object)_sheet, "+", 228f, 726f, 52f, 36f, delegate
			{
				Quantity(1);
			})).gameObject);
			Rule((Transform)(object)_sheet, 296f, 132f, 1f, 630f);
			_back = Button((Transform)(object)_sheet, "‹ Back", 316f, 132f, 100f, 34f, delegate
			{
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
				if (_trail.Count != 0)
				{
					_detailFocus = -1;
					_focus = _trail[_trail.Count - 1];
					_trail.RemoveAt(_trail.Count - 1);
					PaintTree();
					PaintDetails();
					RestlessScrollRect tree = _tree;
					Rect rect = ((ScrollRect)_tree).content.rect;
					Size(tree, ((Rect)(ref rect)).height, reset: true);
					RestlessScrollRect details = _details;
					rect = ((ScrollRect)_details).content.rect;
					Size(details, ((Rect)(ref rect)).height, reset: true);
				}
			});
			_heading = Label((Transform)(object)_sheet, "Choose a recipe", 24, 428f, 130f, 424f, 62f);
			RestlessUi.BoundedLabel(_heading, 24, 19);
			_tree = Reader((Transform)(object)_sheet, "recipe-tree", 316f, 206f, 552f, 552f, 112f);
			Rule((Transform)(object)_sheet, 884f, 132f, 1f, 630f);
			_detailTitle = Label((Transform)(object)_sheet, "SELECTED STEP", 18, 904f, 136f, 300f, 30f);
			_dish = RestlessUi.Graphic((Transform)(object)_sheet, "featured-dish", Color.white, false).GetComponent<Image>();
			_dish.preserveAspect = true;
			Portrait(((Component)_dish).gameObject, 916f, 194f, 68f, 52f);
			_dishFrame = RestlessUi.Picture((Transform)(object)_sheet, "dish-frame", "cook-portrait", false);
			Portrait(_dishFrame, 904f, 186f, 96f, 64f);
			_dishName = Label((Transform)(object)_sheet, "", 22, 1012f, 180f, 192f, 78f);
			RestlessUi.BoundedLabel(_dishName, 22, 18);
			GameObject val2 = RestlessUi.Node((Transform)(object)_sheet, "dish-state");
			Position(val2, 904f, 264f, 304f, 30f);
			_dishKind = Label(val2.transform, "", 17, 0f, 0f, 304f, 36f);
			RestlessUi.BoundedLabel(_dishKind, 17, 14);
			_station = Label((Transform)(object)_sheet, "", 18, 904f, 302f, 300f, 48f);
			Rule((Transform)(object)_sheet, 904f, 352f, 300f, 1f);
			_details = Reader((Transform)(object)_sheet, "details", 904f, 358f, 304f, 262f, 64f);
			_requirementsLabel = Label((Transform)(object)((ScrollRect)_details).content, "", 15, 0f, 0f, 280f, 24f);
			_copy = Label((Transform)(object)((ScrollRect)_details).content, "", 17, 0f, 0f, 280f, 100f);
			_copy.alignment = (TextAnchor)0;
			_copy.verticalOverflow = (VerticalWrapMode)1;
			_collect = Button((Transform)(object)_sheet, "Collect ready food", 904f, 636f, 304f, 42f, Collect);
			_actionHint = Label((Transform)(object)_sheet, "", 17, 904f, 630f, 304f, 58f);
			RestlessUi.BoundedLabel(_actionHint, 17, 14);
			_action = Button((Transform)(object)_sheet, "Queue 1", 904f, 694f, 304f, 52f, Act);
			RestlessUi.ForgedSurface(((Component)_action).gameObject, true, true);
			_actionText = ((Component)_action).GetComponentInChildren<Text>();
			_status = Label((Transform)(object)_sheet, "", 16, 316f, 766f, 888f, 26f);
			RestlessUi.BoundedLabel(_status, 16, 13);
			UiKitApi.Tab(_tabs[0], true);
			Fit();
		}

		private void Quantity(int delta)
		{
			if (_tab == 0)
			{
				_count = Mathf.Clamp(_count + delta, 1, 100);
				Refresh(force: true);
			}
		}

		private void Fit()
		{
			_frame.Fit();
		}

		private void Line(int index, float x, float y, float width, float height)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (index == _lines.Count)
			{
				GameObject val = RestlessUi.Graphic((Transform)(object)((ScrollRect)_tree).content, "branch", new Color(0.64f, 0.52f, 0.32f, 0.85f), false);
				val.transform.SetAsFirstSibling();
				_lines.Add(val);
			}
			GameObject obj = _lines[index];
			obj.SetActive(true);
			Position(obj, x, y, Mathf.Max(1f, width), height);
		}

		private static void Position(GameObject go, float x, float y, float w, float h)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			RestlessUi.Pin(go, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(x, 0f - y), new Vector2(w, h));
		}

		private static void Portrait(GameObject go, float x, float y, float w, float h)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			RestlessUi.Pin(go, new Vector2(0f, 1f), new Vector2(0.5f, 0.5f), new Vector2(x + w / 2f, 0f - y - h / 2f), new Vector2(w, h));
		}

		private static Text Label(Transform parent, string text, int size, float x, float y, float w, float h)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			Text obj = RestlessUi.Label(parent, text, size, RestlessUi.Text, (TextAnchor)3);
			Position(((Component)obj).gameObject, x, y, w, h);
			obj.horizontalOverflow = (HorizontalWrapMode)0;
			return obj;
		}

		private static Button Button(Transform parent, string text, float x, float y, float w, float h, Action action)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return UiKitApi.Button(parent, text, new Rect(x, y, w, h), action);
		}

		private static InputField Field(Transform parent, float x, float y, float w, float h)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			return UiKitApi.Field(parent, "Search recipes…", new Rect(x, y, w, h), false, 128);
		}

		private static void Rule(Transform parent, float x, float y, float w, float h)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			Position(RestlessUi.Graphic(parent, "rule", new Color(0.5f, 0.43f, 0.32f, 0.5f), false), x, y, w, h);
		}

		private static RestlessScrollRect Reader(Transform parent, string name, float x, float y, float w, float h, float row)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return UiKitApi.Reader(parent, name, new Rect(x, y, w, h), row, 2f, (Scrollbar)null);
		}

		private static void Size(RestlessScrollRect scroll, float height, bool reset)
		{
			UiKitApi.SizeReader(scroll, height, reset);
		}

		private static Card GetCard(List<Card> cards, int i, Transform parent)
		{
			if (i == cards.Count)
			{
				cards.Add(new Card(parent));
			}
			cards[i].Root.SetActive(true);
			return cards[i];
		}

		private static void HideAfter(List<Card> cards, int count)
		{
			for (int i = count; i < cards.Count; i++)
			{
				cards[i].Root.SetActive(false);
			}
		}

		private static void HideAfter(List<UiKitMaterialCard> cards, int count)
		{
			for (int i = count; i < cards.Count; i++)
			{
				cards[i].Root.SetActive(false);
			}
		}

		private bool Matches(CookRow row)
		{
			bool flag = row.Prefab.StartsWith("Mead", StringComparison.OrdinalIgnoreCase) || row.Kind.Equals("mead", StringComparison.OrdinalIgnoreCase);
			return _category switch
			{
				"Feasts" => row.IsFeast, 
				"Meals" => row.IsMeal && !flag, 
				"Prep" => row.Kind == "ingredient" || row.IsSideboard, 
				"Bait" => row.Kind == "bait", 
				"Meads" => flag, 
				_ => row.IsFeast || row.IsMeal || row.IsSideboard || flag || row.Kind == "ingredient" || row.Kind == "bait", 
			};
		}

		private void HideDish()
		{
			((Component)_actionHint).gameObject.SetActive(false);
			_station.text = "";
			_requirementsLabel.text = "";
			HideAfter(_requirementCards, 0);
			((Behaviour)_dish).enabled = false;
			_dishFrame.SetActive(false);
			_dishName.text = "";
			_dishKind.text = "";
			((Component)((Component)_dishKind).transform.parent).gameObject.SetActive(false);
			Position(((Component)_details).gameObject, 904f, 184f, 304f, 436f);
			((ScrollRect)_details).viewport.SetSizeWithCurrentAnchors((Axis)1, 436f);
			if ((Object)(object)((ScrollRect)_details).verticalScrollbar != (Object)null)
			{
				Position(((Component)((ScrollRect)_details).verticalScrollbar).gameObject, 298f, 0f, 6f, 436f);
			}
		}

		private void ShowDish()
		{
			((Component)((Component)_dishKind).transform.parent).gameObject.SetActive(true);
			Position(((Component)_details).gameObject, 904f, 358f, 304f, 262f);
			((ScrollRect)_details).viewport.SetSizeWithCurrentAnchors((Axis)1, 262f);
			if ((Object)(object)((ScrollRect)_details).verticalScrollbar != (Object)null)
			{
				Position(((Component)((ScrollRect)_details).verticalScrollbar).gameObject, 298f, 0f, 6f, 262f);
			}
		}

		private void PaintOrderSteps()
		{
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			foreach (GameObject line in _lines)
			{
				line.SetActive(false);
			}
			((Selectable)_back).interactable = false;
			KitchenOrder kitchenOrder = _orders.FirstOrDefault((KitchenOrder o) => o.Id == _order);
			_heading.text = ((kitchenOrder == null) ? "Select an order" : kitchenOrder.Name);
			for (int num = 0; num < _steps.Count; num++)
			{
				int index = num;
				KitchenStep kitchenStep = _steps[num];
				Card card = GetCard(_nodes, num, (Transform)(object)((ScrollRect)_tree).content);
				int num2 = Mathf.Min(kitchenStep.Depth, 4) * 12;
				Position(card.Root, num2, num * 114, 528 - num2, 104f);
				card.Set(Local(kitchenStep.Name), State(kitchenStep), Icon(kitchenStep.Output), Tint(kitchenStep.State), delegate
				{
					//IL_004e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0053: Unknown result type (might be due to invalid IL or missing references)
					_detailFocus = -1;
					_focus = index;
					PaintOrderSteps();
					PaintDetails();
					RestlessScrollRect details = _details;
					Rect rect = ((ScrollRect)_details).content.rect;
					Size(details, ((Rect)(ref rect)).height, reset: true);
				}, num == _focus);
				card.Progress(kitchenStep);
			}
			HideAfter(_nodes, _steps.Count);
			Size(_tree, _steps.Count * 114, reset: false);
		}

		private void PaintPantry(bool force)
		{
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			((Component)_actionHint).gameObject.SetActive(false);
			IReadOnlyList<KitchenPantryItem> readOnlyList = Kitchen.Pantry(_table);
			string text = "pantry|" + string.Join("|", readOnlyList.Select((KitchenPantryItem p) => p.Prefab + ":" + p.Count + ":" + p.Reserved));
			if (!force && _stamp == text)
			{
				return;
			}
			_stamp = text;
			_heading.text = "Kitchen pantry";
			((Selectable)_back).interactable = false;
			foreach (GameObject line in _lines)
			{
				line.SetActive(false);
			}
			HideAfter(_recipeCards, 0);
			if (!readOnlyList.Any((KitchenPantryItem p) => p.Prefab == _pantrySelection))
			{
				_pantrySelection = readOnlyList.FirstOrDefault()?.Prefab ?? "";
			}
			for (int num = 0; num < readOnlyList.Count; num++)
			{
				KitchenPantryItem item = readOnlyList[num];
				Card card = GetCard(_nodes, num, (Transform)(object)((ScrollRect)_tree).content);
				Position(card.Root, num % 2 * 276, num / 2 * 128, 252f, 116f);
				int num2 = Math.Max(0, item.Count - item.Reserved);
				card.Set(Local(item.Name), num2 + " available · " + item.Reserved + " reserved", Icon(item.Prefab), RestlessUi.Accent, delegate
				{
					_pantrySelection = item.Prefab;
					PaintPantry(force: true);
				}, item.Prefab == _pantrySelection);
			}
			HideAfter(_nodes, readOnlyList.Count);
			Size(_tree, (readOnlyList.Count + 1) / 2 * 128, reset: false);
			KitchenPantryItem kitchenPantryItem = readOnlyList.FirstOrDefault((KitchenPantryItem p) => p.Prefab == _pantrySelection);
			HideAfter(_requirementCards, 0);
			_requirementsLabel.text = "";
			_station.text = "";
			ShowDish();
			_dish.sprite = ((kitchenPantryItem == null) ? null : Icon(kitchenPantryItem.Prefab));
			((Behaviour)_dish).enabled = (Object)(object)_dish.sprite != (Object)null;
			_dishFrame.SetActive(kitchenPantryItem != null);
			_dishName.text = ((kitchenPantryItem == null) ? "Pantry is empty" : Local(kitchenPantryItem.Name));
			_dishKind.text = "Stored preparation";
			((Graphic)_dishKind).color = RestlessUi.PaperMuted;
			_copy.text = "Unreserved food can be collected here. Ready food reserved for active orders stays with its order.";
			Position(((Component)_copy).gameObject, 0f, 0f, 280f, Mathf.Max(60f, _copy.preferredHeight));
			Size(_details, _copy.preferredHeight + 16f, reset: false);
			((Component)_collect).gameObject.SetActive(false);
			((Component)_action).gameObject.SetActive(true);
			((Selectable)_action).interactable = kitchenPantryItem != null && kitchenPantryItem.Count > kitchenPantryItem.Reserved;
			_actionText.text = "Take a stack";
			if (Time.unscaledTime >= _messageUntil)
			{
				_status.text = "Prepared food and returned ingredients · order reservations are protected";
			}
		}

		private void TakePantry()
		{
			KitchenPantryItem kitchenPantryItem = Kitchen.Pantry(_table).FirstOrDefault((KitchenPantryItem p) => p.Prefab == _pantrySelection);
			if (kitchenPantryItem == null)
			{
				return;
			}
			ObjectDB instance = ObjectDB.instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				GameObject itemPrefab = instance.GetItemPrefab(kitchenPantryItem.Prefab);
				obj = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			}
			int val = ((ItemDrop)(obj?)).m_itemData?.m_shared?.m_maxStackSize ?? 1;
			try
			{
				Message("Collected " + Kitchen.Take(_table, kitchenPantryItem.Prefab, Math.Min(val, Math.Max(0, kitchenPantryItem.Count - kitchenPantryItem.Reserved))) + ".");
				PaintPantry(force: true);
			}
			catch (Exception ex)
			{
				Debug.LogException(ex);
				Message("Could not collect. Check your inventory before retrying.");
			}
		}
	}
	internal static class CookIcons
	{
		private static readonly Dictionary<string, Sprite> Cache = new Dictionary<string, Sprite>();

		private static MethodInfo? _loadImage;

		private static bool _searched;

		public static Sprite? Sprite(string id)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			string text = id.Replace('_', '-');
			if (Cache.TryGetValue(text, out Sprite value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			Texture2D val = Texture(text);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			value = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
			((Object)value).name = text;
			Cache[text] = value;
			return value;
		}

		private static Texture2D? Texture(string key)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			Stream manifestResourceStream = typeof(CookIcons).Assembly.GetManifestResourceStream("RestlessCook.Assets." + key + ".png");
			if (manifestResourceStream == null)
			{
				Plugin.Log.LogWarning((object)("cook icon missing " + key));
				return null;
			}
			using (manifestResourceStream)
			{
				byte[] array = new byte[manifestResourceStream.Length];
				int num;
				for (int i = 0; i < array.Length; i += num)
				{
					num = manifestResourceStream.Read(array, i, array.Length - i);
					if (num <= 0)
					{
						break;
					}
				}
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				MethodInfo methodInfo = LoadImage();
				if (methodInfo == null || !(bool)methodInfo.Invoke(null, new object[2] { val, array }))
				{
					Object.Destroy((Object)(object)val);
					Plugin.Log.LogWarning((object)("cook icon decode failed " + key));
					return null;
				}
				((Object)val).name = key;
				((Texture)val).wrapMode = (TextureWrapMode)1;
				((Texture)val).filterMode = (FilterMode)1;
				return val;
			}
		}

		private static MethodInfo? LoadImage()
		{
			if (_searched)
			{
				return _loadImage;
			}
			_searched = true;
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type type = assemblies[i].GetType("UnityEngine.ImageConversion");
				if (!(type == null))
				{
					_loadImage = type.GetMethod("LoadImage", new Type[2]
					{
						typeof(Texture2D),
						typeof(byte[])
					});
					if (_loadImage != null)
					{
						return _loadImage;
					}
				}
			}
			return null;
		}
	}
	internal static class CookMesh
	{
		private static readonly Dictionary<string, Mesh> Meshes = new Dictionary<string, Mesh>();

		private static readonly Dictionary<string, Texture2D> Albedos = new Dictionary<string, Texture2D>();

		private static string? _folder;

		private static MethodInfo? _loadImage;

		private static bool _searched;

		public static string Folder()
		{
			if (_folder != null)
			{
				return _folder;
			}
			string[] array = PluginRoots();
			string[] array2 = array;
			foreach (string text in array2)
			{
				string dir = Path.Combine(text, "mesh");
				if (HasRcm(dir))
				{
					return Remember(dir);
				}
				if (HasRcm(text))
				{
					return Remember(text);
				}
			}
			_folder = Path.Combine((array.Length != 0) ? array[0] : ".", "mesh");
			Plugin.Log.LogWarning((object)("cook mesh folder missing, looking in " + _folder));
			return _folder;
		}

		private static string[] PluginRoots()
		{
			List<string> list = new List<string>();
			Plugin instance = Plugin.Instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				PluginInfo info = ((BaseUnityPlugin)instance).Info;
				obj = ((info != null) ? info.Location : null);
			}
			string text = (string)obj;
			if (!string.IsNullOrEmpty(text))
			{
				AddRoot(list, Path.GetDirectoryName(text));
			}
			string location = typeof(CookMesh).Assembly.Location;
			if (!string.IsNullOrEmpty(location))
			{
				AddRoot(list, Path.GetDirectoryName(location));
			}
			return list.ToArray();
		}

		private static void AddRoot(List<string> roots, string? root)
		{
			if (string.IsNullOrEmpty(root))
			{
				return;
			}
			foreach (string root2 in roots)
			{
				if (string.Equals(root2, root, StringComparison.OrdinalIgnoreCase))
				{
					return;
				}
			}
			roots.Add(root);
		}

		private static string Remember(string dir)
		{
			_folder = dir;
			Plugin.Log.LogInfo((object)("cook mesh folder " + dir));
			return dir;
		}

		private static bool HasRcm(string dir)
		{
			if (Directory.Exists(dir))
			{
				return Directory.GetFiles(dir, "*.rcm").Length != 0;
			}
			return false;
		}

		public static Mesh? Mesh(string id)
		{
			string text = id.Replace('_', '-');
			if (Meshes.TryGetValue(text, out Mesh value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			string path = Path.Combine(Folder(), text + ".rcm");
			if (!File.Exists(path))
			{
				Plugin.Log.LogWarning((object)("cook mesh missing " + text));
				return null;
			}
			value = ReadRcm(File.ReadAllBytes(path), text);
			if ((Object)(object)value != (Object)null)
			{
				Meshes[text] = value;
			}
			return value;
		}

		public static Texture2D? Albedo(string id)
		{
			string text = id.Replace('_', '-');
			if (Albedos.TryGetValue(text, out Texture2D value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			string path = Path.Combine(Folder(), text + ".png");
			if (!File.Exists(path))
			{
				Plugin.Log.LogWarning((object)("cook albedo missing " + text));
				return null;
			}
			value = DecodePng(File.ReadAllBytes(path), text);
			if ((Object)(object)value != (Object)null)
			{
				Albedos[text] = value;
			}
			return value;
		}

		private static Mesh? ReadRcm(byte[] data, string name)
		{
			//IL_00ce: 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_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: 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)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: 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_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Expected O, but got Unknown
			if (data.Length < 12 || data[0] != 82 || data[1] != 67 || data[2] != 77 || (data[3] != 49 && data[3] != 50))
			{
				Plugin.Log.LogWarning((object)("cook mesh bad header " + name));
				return null;
			}
			bool flag = data[3] == 49;
			int num = 4;
			int num2 = BitConverter.ToInt32(data, num);
			num += 4;
			int num3 = BitConverter.ToInt32(data, num);
			num += 4;
			if (num2 <= 0 || num3 <= 0 || num + num2 * 32 + num3 * 4 > data.Length)
			{
				Plugin.Log.LogWarning((object)("cook mesh truncated " + name));
				return null;
			}
			Vector3[] array = (Vector3[])(object)new Vector3[num2];
			Vector3[] array2 = (Vector3[])(object)new Vector3[num2];
			Vector2[] array3 = (Vector2[])(object)new Vector2[num2];
			for (int i = 0; i < num2; i++)
			{
				array[i] = new Vector3(BitConverter.ToSingle(data, num), BitConverter.ToSingle(data, num + 4), BitConverter.ToSingle(data, num + 8));
				array2[i] = new Vector3(BitConverter.ToSingle(data, num + 12), BitConverter.ToSingle(data, num + 16), BitConverter.ToSingle(data, num + 20));
				float num4 = BitConverter.ToSingle(data, num + 28);
				array3[i] = new Vector2(BitConverter.ToSingle(data, num + 24), flag ? (1f - num4) : num4);
				num += 32;
			}
			int[] array4 = new int[num3];
			for (int j = 0; j < num3; j++)
			{
				array4[j] = BitConverter.ToInt32(data, num);
				num += 4;
			}
			Mesh val = new Mesh
			{
				name = name,
				indexFormat = (IndexFormat)(num2 > 65000)
			};
			val.SetVertices(array);
			val.SetNormals(array2);
			val.SetUVs(0, array3);
			val.SetTriangles(array4, 0);
			val.RecalculateBounds();
			return val;
		}

		private static Texture2D? DecodePng(byte[] bytes, string name)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true);
			MethodInfo methodInfo = LoadImage();
			if (methodInfo == null || !(bool)methodInfo.Invoke(null, new object[2] { val, bytes }))
			{
				Object.Destroy((Object)(object)val);
				Plugin.Log.LogWarning((object)("cook albedo decode failed " + name));
				return null;
			}
			((Object)val).name = name;
			((Texture)val).wrapMode = (TextureWrapMode)1;
			((Texture)val).filterMode = (FilterMode)1;
			((Texture)val).anisoLevel = 4;
			val.Apply(true, false);
			return val;
		}

		private static MethodInfo? LoadImage()
		{
			if (_searched)
			{
				return _loadImage;
			}
			_searched = true;
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				Type type = assemblies[i].GetType("UnityEngine.ImageConversion");
				if (!(type == null))
				{
					_loadImage = type.GetMethod("LoadImage", new Type[2]
					{
						typeof(Texture2D),
						typeof(byte[])
					});
					if (_loadImage != null)
					{
						return _loadImage;
					}
				}
			}
			return null;
		}
	}
	public sealed class CookUse
	{
		public string Item { get; set; } = "";

		public int Amount { get; set; }
	}
	public sealed class CookRow
	{
		public string Id { get; set; } = "";

		public string Name { get; set; } = "";

		public string Kind { get; set; } = "";

		public string Source { get; set; } = "";

		public string Operation { get; set; } = "";

		public string Tier { get; set; } = "";

		public string Prefab { get; set; } = "";

		public string RecipeId { get; set; } = "";

		public string CloneFrom { get; set; } = "";

		public int Food { get; set; }

		public int FoodStamina { get; set; }

		public int FoodEitr { get; set; }

		public float FoodRegen { get; set; }

		public int FoodMinutes { get; set; }

		public List<string> Feeds { get; } = new List<string>();

		public List<CookUse> Uses { get; } = new List<CookUse>();

		public int OutputAmount { get; set; } = 1;

		public bool AnyOne { get; set; }

		public string Station { get; set; } = "";

		public int StationLevel { get; set; } = 1;

		public float PreparationSeconds { get; set; }

		public bool IsAdd => Operation == "add";

		public bool IsRewrite => Operation == "rewrite";

		public bool IsReference => Operation == "reference";

		public bool IsMeal => Kind == "meal";

		public bool IsFeast => Kind == "feast";

		public bool IsSideboard => Kind == "sideboard";

		public bool IsStation => Kind == "station";

		public bool IsTool => Kind == "tool";
	}
	public sealed class CookBook
	{
		public List<CookRow> Items { get; } = new List<CookRow>();

		public List<CookRow> Kit { get; } = new List<CookRow>();
	}
	internal static class CookVisual
	{
		private const string ChildName = "RestlessCookMesh";

		private const float FeastMeshScale = 3f;

		private static readonly Vector3 ModelScale = Vector3.one * 2.5f;

		public static void Apply(CustomItem item, CookRow row)
		{
			if ((Object)(object)((item != null) ? item.ItemPrefab : null) != (Object)null)
			{
				Apply(item.ItemPrefab, row);
			}
		}

		public static void Apply(GameObject prefab, CookRow row)
		{
			if (!((Object)(object)prefab == (Object)null))
			{
				Mesh val = CookMesh.Mesh(row.Id);
				Texture2D albedo = CookMesh.Albedo(row.Id);
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogWarning((object)("RestlessCook: no custom model for '" + row.Id + "', using vanilla appearance."));
					return;
				}
				GameObject val2 = FindOrCreate(prefab);
				(val2.GetComponent<MeshFilter>() ?? val2.AddComponent<MeshFilter>()).sharedMesh = val;
				MeshRenderer obj = val2.GetComponent<MeshRenderer>() ?? val2.AddComponent<MeshRenderer>();
				((Renderer)obj).enabled = true;
				Paint((Renderer)(object)obj, albedo, prefab);
				KeepPlate(prefab);
			}
		}

		public static void KeepPlate(GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				return;
			}
			Transform obj = prefab.transform.Find("RestlessCookMesh");
			Renderer val = ((obj != null) ? ((Component)obj).GetComponent<Renderer>() : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			val.enabled = true;
			((Component)val).gameObject.SetActive(true);
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)val) && (val2 is MeshRenderer || val2 is SkinnedMeshRenderer))
				{
					val2.enabled = false;
				}
			}
			EnsureHit(prefab);
		}

		public static void EnsureHit(GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				return;
			}
			Transform val = prefab.transform.Find("RestlessCookMesh");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if ((Object)(object)prefab.GetComponent<Feast>() == (Object)null)
			{
				Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(true);
				foreach (Collider obj in componentsInChildren)
				{
					MeshCollider val2 = (MeshCollider)(object)((obj is MeshCollider) ? obj : null);
					if (val2 != null)
					{
						Object.DestroyImmediate((Object)(object)val2);
					}
				}
				if ((Object)(object)prefab.GetComponentInChildren<Collider>(true) == (Object)null)
				{
					SitOnGround(val);
				}
			}
			else
			{
				DressFeast(prefab, val);
			}
		}

		private static void DressFeast(GameObject prefab, Transform keep)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			keep.localScale = Vector3.one * 3f;
			keep.localPosition = new Vector3(0f, 0.02f, 0f);
			FeastColliderState feastColliderState = prefab.GetComponent<FeastColliderState>() ?? prefab.AddComponent<FeastColliderState>();
			if (feastColliderState.Colliders == null)
			{
				List<Collider> list = new List<Collider>();
				Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(true);
				foreach (Collider val in componentsInChildren)
				{
					if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).transform != (Object)(object)keep && !((Component)val).transform.IsChildOf(keep))
					{
						list.Add(val);
					}
				}
				feastColliderState.Colliders = list.ToArray();
				feastColliderState.Enabled = Array.ConvertAll(feastColliderState.Colliders, (Collider col) => col.enabled);
			}
			Piece component = prefab.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null)
			{
				component.m_clipGround = true;
				component.m_noInWater = true;
				component.m_cultivatedGroundOnly = false;
				component.m_groundOnly = false;
			}
			MeshFilter component2 = ((Component)keep).GetComponent<MeshFilter>();
			if (!((Object)(object)((component2 != null) ? component2.sharedMesh : null) == (Object)null))
			{
				MeshCollider val2 = ((Component)keep).GetComponent<MeshCollider>() ?? ((Component)keep).gameObject.AddComponent<MeshCollider>();
				val2.sharedMesh = component2.sharedMesh;
				val2.convex = true;
				ZNetView component3 = prefab.GetComponent<ZNetView>();
				FeastColliderState.Apply(feastColliderState.Colliders, feastColliderState.Enabled, (Collider?)(object)val2, (Object)(object)component3 != (Object)null && component3.IsValid());
			}
		}

		public static void RestoreSupport(GameObject placed)
		{
			if (!((Object)(object)placed == (Object)null))
			{
				FeastColliderState component = placed.GetComponent<FeastColliderState>();
				if (component?.Colliders != null)
				{
					Transform obj = placed.transform.Find("RestlessCookMesh");
					MeshCollider plate = ((obj != null) ? ((Component)obj).GetComponent<MeshCollider>() : null);
					FeastColliderState.Apply(component.Colliders, component.Enabled, (Collider?)(object)plate, placed: true);
				}
			}
		}

		private static void SitOnGround(Transform keep)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			MeshFilter component = ((Component)keep).GetComponent<MeshFilter>();
			if (!((Object)(object)((component != null) ? component.sharedMesh : null) == (Object)null))
			{
				BoxCollider obj = ((Component)keep).GetComponent<BoxCollider>() ?? ((Component)keep).gameObject.AddComponent<BoxCollider>();
				Bounds bounds = component.sharedMesh.bounds;
				obj.center = ((Bounds)(ref bounds)).center;
				obj.size = Vector3.Max(((Bounds)(ref bounds)).size, new Vector3(0.08f, 0.04f, 0.08f));
				((Collider)obj).enabled = true;
			}
		}

		private static GameObject FindOrCreate(GameObject prefab)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Expected O, but got Unknown
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			Transform val = prefab.transform.Find("RestlessCookMesh");
			if ((Object)(object)val != (Object)null)
			{
				val.SetParent(prefab.transform, false);
				val.localPosition = Vector3.zero;
				val.localRotation = Quaternion.identity;
				val.localScale = ModelScale;
				((Component)val).gameObject.layer = prefab.layer;
				((Component)val).gameObject.SetActive(true);
				return ((Component)val).gameObject;
			}
			GameObject val2 = new GameObject("RestlessCookMesh")
			{
				layer = prefab.layer
			};
			val2.transform.SetParent(prefab.transform, false);
			val2.transform.localPosition = Vector3.zero;
			val2.transform.localRotation = Quaternion.identity;
			val2.transform.localScale = ModelScale;
			return val2;
		}

		private static void Paint(Renderer renderer, Texture2D? albedo, GameObject prefab)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			Material val = CopyLit(prefab);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			val.color = Color.white;
			SetColor(val, "_Color", Color.white);
			SetColor(val, "_BaseColor", Color.white);
			SetColor(val, "_Tint", Color.white);
			SetFloat(val, "_Metallic", 0f);
			SetFloat(val, "_Glossiness", 0.12f);
			SetFloat(val, "_Smoothness", 0.12f);
			SetFloat(val, "_GlossMapScale", 0.12f);
			MuteGlow(val);
			if ((Object)(object)albedo != (Object)null)
			{
				if (val.HasProperty("_MainTex"))
				{
					val.SetTexture("_MainTex", (Texture)(object)albedo);
				}
				if (val.HasProperty("_BaseMap"))
				{
					val.SetTexture("_BaseMap", (Texture)(object)albedo);
				}
				if (val.HasProperty("_Diffuse"))
				{
					val.SetTexture("_Diffuse", (Texture)(object)albedo);
				}
			}
			renderer.sharedMaterial = val;
		}

		private static Material? CopyLit(GameObject prefab)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			Material val = QuietMat(prefab) ?? QuietFeast();
			if ((Object)(object)val != (Object)null)
			{
				return new Material(val);
			}
			Shader val2 = Shader.Find("Standard") ?? Shader.Find("Diffuse") ?? Shader.Find("Legacy Shaders/Diffuse");
			if (!((Object)(object)val2 != (Object)null))
			{
				return null;
			}
			return new Material(val2);
		}

		private static Material? QuietFeast()
		{
			string[] array = new string[2] { "FeastMeadows", "FeastBlackforest" };
			foreach (string text in array)
			{
				PrefabManager instance = PrefabManager.Instance;
				Material val = QuietMat((instance != null) ? instance.GetPrefab(text) : null);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private static Material? QuietMat(GameObject? prefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				return null;
			}
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !(((Object)((Component)val).transform).name == "RestlessCookMesh") && val is MeshRenderer && !Garnish(((Component)val).transform))
				{
					Material sharedMaterial = val.sharedMaterial;
					if (!((Object)(object)((sharedMaterial != null) ? sharedMaterial.shader : null) == (Object)null) && !Glows(sharedMaterial))
					{
						return sharedMaterial;
					}
				}
			}
			return null;
		}

		private static bool Garnish(Transform node)
		{
			Transform val = node;
			while ((Object)(object)val != (Object)null)
			{
				string name = ((Object)val).name;
				if (Has(name, "thistle") || Has(name, "spice") || Has(name, "eitr") || Has(name, "glow") || Has(name, "garnish") || Has(name, "magecap") || Has(name, "jotun") || Has(name, "wisp") || Has(name, "mist"))
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private static bool Glows(Material mat)
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			string text = ((Object)mat).name + " " + ((Object)mat.shader).name;
			if (Has(text, "thistle") || Has(text, "spice") || Has(text, "eitr") || Has(text, "glow"))
			{
				return true;
			}
			if (mat.IsKeywordEnabled("_EMISSION") || mat.IsKeywordEnabled("EMISSION"))
			{
				return true;
			}
			if (mat.HasProperty("_EmissionMap") && (Object)(object)mat.GetTexture("_EmissionMap") != (Object)null)
			{
				return true;
			}
			if (mat.HasProperty("_EmissionColorMap") && (Object)(object)mat.GetTexture("_EmissionColorMap") != (Object)null)
			{
				return true;
			}
			Color color;
			if (mat.HasProperty("_EmissionColor"))
			{
				color = mat.GetColor("_EmissionColor");
				if (((Color)(ref color)).maxColorComponent > 0.02f)
				{
					return true;
				}
			}
			if (mat.HasProperty("_EmissiveColor"))
			{
				color = mat.GetColor("_EmissiveColor");
				if (((Color)(ref color)).maxColorComponent > 0.02f)
				{
					return true;
				}
			}
			if (mat.HasProperty("_EnableEmission") && mat.GetFloat("_EnableEmission") > 0.5f)
			{
				return true;
			}
			return false;
		}

		private static void MuteGlow(Material mat)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			SetColor(mat, "_EmissionColor", Color.black);
			SetColor(mat, "_EmissiveColor", Color.black);
			SetColor(mat, "_GlowColor", Color.black);
			SetFloat(mat, "_EnableEmission", 0f);
			SetFloat(mat, "_EmissionIntensity", 0f);
			if (mat.HasProperty("_EmissionMap"))
			{
				mat.SetTexture("_EmissionMap", (Texture)null);
			}
			if (mat.HasProperty("_EmissionColorMap"))
			{
				mat.SetTexture("_EmissionColorMap", (Texture)null);
			}
			mat.DisableKeyword("_EMISSION");
			mat.DisableKeyword("EMISSION");
		}

		private static bool Has(string text, string token)
		{
			return text.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static void SetColor(Material mat, string prop, Color color)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (mat.HasProperty(prop))
			{
				mat.SetColor(prop, color);
			}
		}

		private static void SetFloat(Material mat, string prop, float value)
		{
			if (mat.HasProperty(prop))
			{
				mat.SetFloat(prop, value);
			}
		}
	}
	public static class CookYaml
	{
		public static CookBook LoadEmbedded()
		{
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("RestlessCook.cook.yaml") ?? throw new InvalidOperationException("Missing embedded cook.yaml");
			using StreamReader streamReader = new StreamReader(stream);
			return Parse(streamReader.ReadToEnd());
		}

		public static CookBook Parse(string text)
		{
			CookBook book = new CookBook();
			CookRow cur = null;
			CookUse cookUse = null;
			string text2 = null;
			string section = null;
			string[] array = text.Split(new string[2] { "\r\n", "\n" }, StringSplitOptions.None);
			for (int i = 0; i < array.Length; i++)
			{
				string text3 = array[i].TrimEnd(Array.Empty<char>());
				if (text3 == "kit:" || text3 == "items:")
				{
					Flush();
					section = text3.TrimEnd(new char[1] { ':' });
					cookUse = null;
					text2 = null;
				}
				else
				{
					if (section == null)
					{
						continue;
					}
					if (text3.StartsWith("  - id:", StringComparison.Ordinal))
					{
						Flush();
						cur = new CookRow
						{
							Id = Value(text3)
						};
						cookUse = null;
						text2 = null;
					}
					else
					{
						if (cur == null)
						{
							continue;
						}
						if (text3.StartsWith("    feeds:", StringComparison.Ordinal))
						{
							text2 = "feeds";
							if (text3.Contains("[]"))
							{
								text2 = null;
							}
						}
						else if (text3.StartsWith("    uses:", StringComparison.Ordinal))
						{
							text2 = "uses";
						}
						else if (text2 == "feeds" && text3.StartsWith("      - ", StringComparison.Ordinal))
						{
							cur.Feeds.Add(text3.Substring(text3.IndexOf('-') + 1).Trim());
						}
						else if (text2 == "uses" && text3.StartsWith("      - item:", StringComparison.Ordinal))
						{
							cookUse = new CookUse
							{
								Item = Value(text3)
							};
							cur.Uses.Add(cookUse);
						}
						else if (text2 == "uses" && cookUse != null && text3.StartsWith("        amount:", StringComparison.Ordinal))
						{
							cookUse.Amount = int.Parse(Value(text3));
						}
						else if (text3.StartsWith("    ", StringComparison.Ordinal) && text3.Contains(":") && !text3.StartsWith("      ", StringComparison.Ordinal))
						{
							text2 = null;
							int num = text3.IndexOf(':');
							string text4 = text3.Substring(0, num).Trim();
							string text5 = Unquote(text3.Substring(num + 1).Trim());
							switch (text4)
							{
							case "name":
								cur.Name = text5;
								break;
							case "kind":
								cur.Kind = text5;
								break;
							case "source":
								cur.Source = text5;
								break;
							case "operation":
								cur.Operation = text5;
								break;
							case "tier":
								cur.Tier = text5;
								break;
							case "prefab":
								cur.Prefab = text5;
								break;
							case "recipe_id":
								cur.RecipeId = text5;
								break;
							case "clone_from":
								cur.CloneFrom = text5;
								break;
							case "food":
								cur.Food = int.Parse(text5);
								break;
							case "food_stamina":
								cur.FoodStamina = int.Parse(text5);
								break;
							case "food_eitr":
								cur.FoodEitr = int.Parse(text5);
								break;
							case "food_regen":
								cur.FoodRegen = float.Parse(text5, CultureInfo.InvariantCulture);
								break;
							case "food_minutes":
								cur.FoodMinutes = int.Parse(text5);
								break;
							case "output_amount":
								cur.OutputAmount = int.Parse(text5);
								break;
							case "station":
								cur.Station = text5;
								break;
							case "station_level":
								cur.StationLevel = int.Parse(text5);
								break;
							case "preparation_seconds":
								cur.PreparationSeconds = float.Parse(text5, CultureInfo.InvariantCulture);
								break;
							}
						}
					}
				}
			}
			Flush();
			Validate(book.Items);
			ValidateKit(book.Kit);
			return book;
			void Flush()
			{
				if (cur != null)
				{
					if (section == "kit")
					{
						book.Kit.Add(cur);
					}
					else if (section == "items")
					{
						book.Items.Add(cur);
					}
					cur = null;
				}
			}
		}

		public static void Validate(IReadOnlyList<CookRow> items)
		{
			if (items.Count != 81)
			{
				throw new InvalidOperationException($"cook.yaml must have 81 rows, got {items.Count}");
			}
			HashSet<string> hashSet = new HashSet<string>(items.Select((CookRow i) => i.Id), StringComparer.Ordinal);
			if (hashSet.Count != 81)
			{
				throw new InvalidOperationException("cook.yaml has duplicate ids");
			}
			foreach (CookRow item in items)
			{
				if (item.PreparationSeconds < 0f || float.IsNaN(item.PreparationSeconds) || float.IsInfinity(item.PreparationSeconds))
				{
					throw new InvalidOperationException(item.Id + ": invalid preparation_seconds");
				}
				if (item.Uses.Count == 0)
				{
					throw new InvalidOperationException(item.Id + ": empty uses[]");
				}
				foreach (string feed in item.Feeds)
				{
					if (!hashSet.Contains(feed))
					{
						throw new InvalidOperationException(item.Id + ": feeds unknown id " + feed);
					}
				}
			}
			Require(Count((CookRow i) => i.IsAdd) == 35, "35 add rows");
			Require(Count((CookRow i) => i.IsRewrite) == 16, "16 rewrite rows");
			Require(Count((CookRow i) => i.IsReference) == 30, "30 reference rows");
			Require(Count((CookRow i) => i.IsAdd || i.IsRewrite) == 51, "51 recipe operations");
			Require(Count((CookRow i) => i.IsMeal && i.Source == "custom" && i.IsAdd) == 17, "17 custom meals");
			Require(Count((CookRow i) => i.IsFeast && i.Source == "custom" && i.IsAdd) == 16, "16 custom feasts");
			Require(Count((CookRow i) => i.IsSideboard && i.IsAdd) == 2, "2 sideboards");
			Require(Count((CookRow i) => i.IsMeal && i.IsRewrite) == 14, "14 cooked-first rewrites");
			Require(Count((CookRow i) => i.IsFeast && i.IsRewrite) == 2, "2 feast reroutes");
			Require(Count((CookRow i) => i.IsMeal && i.IsReference) == 24, "24 meal references");
			Require(Count((CookRow i) => i.IsFeast && i.IsReference) == 6, "6 feast references");
			foreach (CookRow item2 in items.Where((CookRow i) => i.IsAdd))
			{
				if (string.IsNullOrEmpty(item2.CloneFrom))
				{
					throw new InvalidOperationException(item2.Id + ": add requires clone_from");
				}
				if (string.IsNullOrEmpty(item2.Prefab))
				{
					throw new InvalidOperationException(item2.Id + ": add requires prefab");
				}
			}
			foreach (CookRow item3 in items.Where((CookRow i) => i.IsAdd && (i.IsMeal || i.IsFeast)))
			{
				if (item3.Food == 0 && item3.FoodStamina == 0 && item3.FoodEitr == 0)
				{
					throw new InvalidOperationException(item3.Id + ": custom meal/feast needs food stats");
				}
				if (item3.FoodMinutes <= 0)
				{
					throw new InvalidOperationException(item3.Id + ": custom meal/feast needs food_minutes");
				}
				if (item3.FoodRegen <= 0f)
				{
					throw new InvalidOperationException(item3.Id + ": custom meal/feast needs food_regen");
				}
			}
			foreach (CookRow item4 in items.Where((CookRow i) => i.IsSideboard))
			{
				if (item4.Food != 0 || item4.FoodStamina != 0 || item4.FoodEitr != 0 || item4.FoodMinutes != 0)
				{
					throw new InvalidOperationException(item4.Id + ": sideboard is not edible");
				}
			}
			foreach (CookRow item5 in items.Where((CookRow i) => i.IsRewrite))
			{
				if (string.IsNullOrEmpty(item5.RecipeId))
				{
					throw new InvalidOperationException(item5.Id + ": rewrite requires recipe_id");
				}
			}
			Dictionary<string, CookRow> byId = items.ToDictionary<CookRow, string>((CookRow i) => i.Id, StringComparer.Ordinal);
			foreach (CookRow item6 in items.Where((CookRow i) => i.IsMeal))
			{
				if (!ReachesFeast(item6, byId))
				{
					throw new InvalidOperationException(item6.Id + ": meal has no path to a feast");
				}
			}
			foreach (CookRow item7 in items.Where((CookRow i) => i.IsFeast && i.Source == "custom" && i.IsAdd && (i.Tier == "meadows" || i.Tier == "blackforest")))
			{
				if (item7.Uses.Any((CookUse u) => u.Item == "SpiceForests"))
				{
					throw new InvalidOperationException(item7.Id + ": early custom feast cannot require Bog Witch spices");
				}
			}
			int Count(Func<CookRow, bool> pred)
			{
				return items.Count(pred);
			}
		}

		private static void ValidateKit(IReadOnlyList<CookRow> kit)
		{
			if (kit.Count != 2)
			{
				throw new InvalidOperationException($"cook.yaml kit must have 2 rows, got {kit.Count}");
			}
			CookRow cookRow = kit.FirstOrDefault((CookRow i) => i.Id == "food_preparation_table");
			CookRow cookRow2 = kit.FirstOrDefault((CookRow i) => i.Id == "serving_tray");
			if (cookRow == null || !cookRow.IsStation || !cookRow.IsRewrite || cookRow.Prefab != "piece_preptable" || cookRow.Uses.Count == 0)
			{
				throw new InvalidOperationException("kit: food_preparation_table must rewrite piece_preptable");
			}
			if (cookRow2 == null || !cookRow2.IsTool || !cookRow2.IsAdd || cookRow2.Prefab != "Feaster" || cookRow2.Uses.Count == 0)
			{
				throw new InvalidOperationException("kit: serving_tray must add a Feaster recipe");
			}
		}

		private static bool ReachesFeast(CookRow start, IReadOnlyDictionary<string, CookRow> byId)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			Stack<string> stack = new Stack<string>();
			stack.Push(start.Id);
			while (stack.Count > 0)
			{
				string text = stack.Pop();
				if (!hashSet.Add(text) || !byId.TryGetValue(text, out CookRow value))
				{
					continue;
				}
				if (value.IsFeast && text != start.Id)
				{
					return true;
				}
				foreach (string feed in value.Feeds)
				{
					stack.Push(feed);
				}
			}
			return start.IsFeast;
		}

		private static void Require(bool ok, string label)
		{
			if (!ok)
			{
				throw new InvalidOperationException("cook.yaml failed check: " + label);
			}
		}

		private static string Value(string line)
		{
			int num = line.IndexOf(':');
			return Unquote(line.Substring(num + 1).Trim());
		}

		private static string Unquote(string val)
		{
			if (val.Length >= 2 && ((val[0] == '"' && val[val.Length - 1] == '"') || (val[0] == '\'' && val[val.Length - 1] == '\'')))
			{
				return val.Substring(1, val.Length - 2);
			}
			return val;
		}
	}
	internal sealed class FeastColliderState : MonoBehaviour
	{
		public Collider[]? Colliders;

		public bool[] Enabled = Array.Empty<bool>();

		internal static void Apply(Collider[] colliders, bool[] enabled, Collider? plate, bool placed)
		{
			for (int i = 0; i < colliders.Length; i++)
			{
				if ((Object)(object)colliders[i] != (Object)null)
				{
					colliders[i].enabled = placed && i < enabled.Length && enabled[i];
				}
			}
			if ((Object)(object)plate != (Object)null)
			{
				plate.enabled = !placed;
			}
		}
	}
	public static class Kitchen
	{
		public static IReadOnlyList<CookRow> Rows => KitchenRun.Rows;

		public static event Action<CraftingStation>? Opened;

		public static void Load(CookBook book)
		{
			KitchenRun.Load(book);
		}

		public static CookRow? Find(string idOrPrefab)
		{
			return KitchenRun.Find(idOrPrefab);
		}

		public static IReadOnlyList<CookRow> OtherUses(string prefab)
		{
			return KitchenRun.OtherUses(prefab);
		}

		public static IReadOnlyList<KitchenStep> Plan(CraftingStation table, string idOrPrefab, int count)
		{
			return KitchenRun.Plan(table, idOrPrefab, count);
		}

		public static IReadOnlyList<KitchenOrder> Orders(CraftingStation table)
		{
			return KitchenRun.ReadOrders(table);
		}

		public static IReadOnlyList<KitchenStationInfo> Stations(CraftingStation table)
		{
			return KitchenRun.Describe(table);
		}

		public static IReadOnlyList<KitchenStep> Live(CraftingStation table, int orderId)
		{
			return KitchenRun.Live(table, orderId);
		}

		public static bool Place(CraftingStation table, string idOrPrefab, int count)
		{
			return KitchenRun.Place(table, idOrPrefab, count);
		}

		public static void Cancel(CraftingStation table, int orderId)
		{
			KitchenRun.Cancel(table, orderId);
		}

		public static int Collect(CraftingStation table, int orderId)
		{
			return KitchenRun.Collect(table, orderId);
		}

		public static IReadOnlyList<KitchenPantryItem> Pantry(CraftingStation table)
		{
			return KitchenRun.Pantry(table);
		}

		public static int Take(CraftingStation table, string prefab, int count)
		{
			return KitchenRun.Take(table, prefab, count);
		}

		internal static void Raise(CraftingStation table)
		{
			if (Kitchen.Opened != null)
			{
				Kitchen.Opened(table);
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, "Kitchen board is not in yet.", 0, (Sprite)null, false);
			}
		}
	}
	public enum KitchenStationKind
	{
		None,
		Cauldron,
		PrepTable,
		Rack,
		Oven,
		MeadKettle,
		Fermenter
	}
	public enum KitchenStepState
	{
		Prepared,
		Ready,
		Queued,
		Cooking,
		Missing,
		Blocked
	}
	public sealed class KitchenUse
	{
		public string Item = "";

		public string Name = "";

		public int Amount;

		public int Have;

		internal int UnitAmount;
	}
	public sealed class KitchenStep
	{
		public string Id = "";

		public string Name = "";

		public string Output = "";

		public string Parent = "";

		public int Depth;

		public int Need;

		public int Have;

		public int Available;

		public int Cooking;

		internal bool CoveredByParent;

		public KitchenStepState State;

		public KitchenStationKind Station;

		public string StationPrefab = "";

		public int StationLevel = 1;

		public string Note = "";

		public int ParentIndex = -1;

		public float ElapsedSeconds;

		public float DurationSeconds;

		public string ActiveStation = "";

		public readonly List<KitchenUse> Uses = new List<KitchenUse>();
	}
	public sealed class KitchenOrder
	{
		public int Id;

		public string Feast = "";

		public string Name = "";

		public int Count;

		public long PlayerId;

		public int Ready;

		public int Collected;
	}
	public sealed class KitchenPantryItem
	{
		public string Prefab = "";

		public string Name = "";

		public int Count;

		public int Reserved;
	}
	public sealed class KitchenStationInfo
	{
		public string Id = "";

		public float Distance;

		public string Name = "";

		public KitchenStationKind Kind;

		public int Free;

		public int Cooking;

		public int Ready;

		public int Fuel;

		public int FuelMax;

		public bool NeedsFire;

		public bool FireLit = true;

		public int Level;

		public string Block = "";
	}
	internal static class KitchenRun
	{
		private sealed class Conversion
		{
			public string From = "";

			public KitchenStationKind Kind;

			public int Amount = 1;
		}

		private sealed class Ledger
		{
			public int NextOrder;

			public readonly Dictionary<string, int> Pantry = new Dictionary<string, int>(StringComparer.Ordinal);

			public readonly List<KitchenOrder> Orders = new List<KitchenOrder>();

			public readonly List<Work> Work = new List<Work>();

			public readonl