Decompiled source of RestlessCore v0.3.2

RestlessCore.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.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GUIFramework;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using RestlessQoL.Api;
using RestlessQoL.Building;
using RestlessQoL.Core;
using RestlessQoL.HudTweaks;
using RestlessQoL.PlayerTweaks;
using RestlessQoL.Production;
using RestlessQoL.Storage;
using RestlessQoL.Ui;
using RestlessQoL.World;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("RestlessCore")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.2.0")]
[assembly: AssemblyInformationalVersion("0.3.2+3c3a455f9531bd9dc73b5fcaf8deb3470ee9edc9")]
[assembly: AssemblyProduct("RestlessCore")]
[assembly: AssemblyTitle("RestlessCore")]
[assembly: InternalsVisibleTo("RestlessPiles")]
[assembly: InternalsVisibleTo("RestlessStorage")]
[assembly: InternalsVisibleTo("RestlessCook")]
[assembly: InternalsVisibleTo("RestlessWorks")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.3.2.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 RestlessQoL
{
	[BepInPlugin("restless.core", "RestlessCore", "0.3.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "restless.core";

		public const string PluginName = "RestlessCore";

		public const string PluginVersion = "0.3.2";

		private readonly FeatureModule[] _modules = new FeatureModule[44]
		{
			new StorageSync(),
			new InventoryRecovery(),
			new CraftFromStorage(),
			new BuildFromStorage(),
			new QuickStack(),
			new Restock(),
			new PetPantry(),
			new GroundVacuum(),
			new StationPull(),
			new AreaRepair(),
			new AreaSeal(),
			new WorkbenchTweaks(),
			new DeathPins(),
			new SwimWield(),
			new CrossbowState(),
			new FriendlyFire(),
			new AxeCombo(),
			new AutoRepair(),
			new StackSizes(),
			new HonestItems(),
			new EternalFire(),
			new DigDeeper(),
			new NetworkUncap(),
			new FloatingItems(),
			new Ledger(),
			new SettingsUi(),
			new MenuScreen(),
			new BuffList(),
			new MapChrome(),
			new MapScreen(),
			new MapDots(),
			new Notices(),
			new Hotbar(),
			new InventoryScreen(),
			new CraftingInterface(),
			new StatSheet(),
			new ItemTooltip(),
			new ExtraSlots(),
			new SlotLock(),
			new Vitals(),
			new EquipHint(),
			new BuildMenu(),
			new ActionHints(),
			new LookHints()
		};

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			if (CoreFeatures.OptionalEnabled)
			{
				Kit.Warm();
			}
			FeatureModule[] modules = _modules;
			for (int i = 0; i < modules.Length; i++)
			{
				modules[i].TryLoad();
			}
			Log.LogInfo((object)string.Format("{0} {1} loaded ({2} modules registered).", "RestlessCore", "0.3.2", _modules.Length));
		}

		private void Update()
		{
			if (Console.IsVisible())
			{
				return;
			}
			if (SettingsUi.IsOpen)
			{
				FeatureModule[] modules = _modules;
				foreach (FeatureModule featureModule in modules)
				{
					if (featureModule is SettingsUi)
					{
						featureModule.TickConfigured();
					}
				}
			}
			else
			{
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					return;
				}
				bool flag = InventoryGui.IsVisible();
				FeatureModule[] modules = _modules;
				foreach (FeatureModule featureModule2 in modules)
				{
					if (!flag || featureModule2.TickInMenus)
					{
						featureModule2.TickConfigured();
					}
				}
			}
		}
	}
}
namespace RestlessQoL.World
{
	public sealed class DigDeeper : FeatureModule
	{
		[HarmonyPatch]
		private static class Patches
		{
			private const float CapEpsilon = 0.05f;

			private static float VanillaCap()
			{
				return 8f;
			}

			private static float MaxDelta()
			{
				if (!ModConfig.DigDeeperEnabled.Value)
				{
					return VanillaCap();
				}
				return ModConfig.DigMaxDelta.Value;
			}

			private static float MinDelta()
			{
				return 0f - MaxDelta();
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(Heightmap), "AtMaxWorldLevelDepth")]
			private static bool AtMaxWorldLevelDepth(Heightmap __instance, Vector3 worldPos, ref bool __result)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				if (!ModConfig.DigDeeperEnabled.Value)
				{
					return true;
				}
				float num = default(float);
				__instance.GetWorldHeight(worldPos, ref num);
				float num2 = default(float);
				__instance.GetWorldBaseHeight(worldPos, ref num2);
				__result = Mathf.Max(num2 - num, 0f) >= MaxDelta() - 0.05f;
				return false;
			}

			[HarmonyTranspiler]
			[HarmonyPatch(typeof(TerrainComp), "RaiseTerrain")]
			private static IEnumerable<CodeInstruction> RaiseTerrain(IEnumerable<CodeInstruction> instructions)
			{
				return ReplaceLevelClamp(instructions, "RaiseTerrain");
			}

			[HarmonyTranspiler]
			[HarmonyPatch(typeof(TerrainComp), "LevelTerrain")]
			private static IEnumerable<CodeInstruction> LevelTerrain(IEnumerable<CodeInstruction> instructions)
			{
				return ReplaceLevelClamp(instructions, "LevelTerrain");
			}

			[HarmonyTranspiler]
			[HarmonyPatch(typeof(TerrainComp), "ApplyToHeightmap")]
			private static IEnumerable<CodeInstruction> ApplyToHeightmap(IEnumerable<CodeInstruction> instructions)
			{
				return ReplaceLevelClamp(instructions, "ApplyToHeightmap");
			}

			private static IEnumerable<CodeInstruction> ReplaceLevelClamp(IEnumerable<CodeInstruction> instructions, string method)
			{
				float vanilla = VanillaCap();
				int replaced = 0;
				foreach (CodeInstruction instruction in instructions)
				{
					if (instruction.opcode == OpCodes.Ldc_R4 && instruction.operand is float num)
					{
						if (Math.Abs(num - vanilla) < 0.001f)
						{
							replaced++;
							yield return Retarget(instruction, "MaxDelta");
							continue;
						}
						if (Math.Abs(num + vanilla) < 0.001f)
						{
							replaced++;
							yield return Retarget(instruction, "MinDelta");
							continue;
						}
					}
					yield return instruction;
				}
				if (replaced == 0)
				{
					Plugin.Log.LogWarning((object)$"world.digdeeper: {method} has no ±{vanilla} clamps — 1.0 moved the cap, this feature is a no-op there.");
				}
			}

			private static CodeInstruction Retarget(CodeInstruction from, string method)
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Expected O, but got Unknown
				CodeInstruction val = new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Patches), method, (Type[])null, (Type[])null));
				val.labels.AddRange(from.labels);
				val.blocks.AddRange(from.blocks);
				return val;
			}
		}

		public override string Id => "world.digdeeper";

		public override bool Enabled => true;
	}
	public sealed class FloatingItems : FeatureModule
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyPostfix]
			[HarmonyPatch(typeof(ItemDrop), "Awake")]
			private static void Awake(ItemDrop __instance)
			{
				if (ModConfig.FloatingItemsEnabled.Value)
				{
					Apply(__instance);
				}
			}
		}

		private static HashSet<string>? _sink;

		private static HashSet<string>? _extra;

		private static Floating? _template;

		public override string Id => "world.floating";

		public override bool Enabled => true;

		private static HashSet<string> Sink => _sink ?? (_sink = Parse(ModConfig.FloatingSinkList.Value));

		private static HashSet<string> Extra => _extra ?? (_extra = Parse(ModConfig.FloatingExtraList.Value));

		protected override void OnLoaded()
		{
			ModConfig.FloatingSinkList.SettingChanged += Invalidate;
			ModConfig.FloatingExtraList.SettingChanged += Invalidate;
		}

		private static void Invalidate(object sender, EventArgs e)
		{
			_sink = null;
			_extra = null;
		}

		private static HashSet<string> Parse(string raw)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			if (string.IsNullOrWhiteSpace(raw))
			{
				return hashSet;
			}
			string[] array = raw.Split(new char[3] { ',', ';', '\n' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					hashSet.Add(text);
				}
			}
			return hashSet;
		}

		private static string PrefabName(ItemDrop drop)
		{
			string prefabName = Utils.GetPrefabName(((Component)drop).gameObject);
			if (!string.IsNullOrEmpty(prefabName))
			{
				return prefabName;
			}
			return ((Object)((Component)drop).gameObject).name;
		}

		private static bool ForceSink(string prefab)
		{
			return Sink.Contains(prefab);
		}

		private static bool ForceFloat(string prefab)
		{
			if (!ModConfig.FloatingEverything.Value)
			{
				return Extra.Contains(prefab);
			}
			return true;
		}

		private static Floating? Template()
		{
			if ((Object)(object)_template != (Object)null)
			{
				return _template;
			}
			ObjectDB instance = ObjectDB.instance;
			GameObject val = ((instance != null) ? instance.GetItemPrefab("Wood") : null);
			_template = (((Object)(object)val != (Object)null) ? val.GetComponent<Floating>() : null);
			return _template;
		}

		private static void Apply(ItemDrop drop)
		{
			if ((Object)(object)drop == (Object)null)
			{
				return;
			}
			string prefab = PrefabName(drop);
			if (ForceSink(prefab))
			{
				if (!((Object)(object)drop.m_floating == (Object)null))
				{
					Object.Destroy((Object)(object)drop.m_floating);
					drop.m_floating = null;
				}
			}
			else if (ForceFloat(prefab) && !((Object)(object)drop.m_floating != (Object)null))
			{
				Floating val = ((Component)drop).gameObject.AddComponent<Floating>();
				Floating val2 = Template();
				if ((Object)(object)val2 != (Object)null)
				{
					val.m_waterLevelOffset = val2.m_waterLevelOffset;
					val.m_forceDistance = val2.m_forceDistance;
					val.m_force = val2.m_force;
					val.m_balanceForceFraction = val2.m_balanceForceFraction;
					val.m_damping = val2.m_damping;
				}
				drop.m_floating = val;
			}
		}
	}
	public sealed class NetworkUncap : FeatureModule
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyTranspiler]
			[HarmonyPatch(typeof(ZDOMan), "SendZDOs")]
			private static IEnumerable<CodeInstruction> SendWindow(IEnumerable<CodeInstruction> instructions)
			{
				MethodInfo call = AccessTools.Method(typeof(NetworkUncap), "Window", (Type[])null, (Type[])null);
				int replaced = 0;
				foreach (CodeInstruction instruction in instructions)
				{
					if (instruction.opcode == OpCodes.Ldc_I4 && instruction.operand is int num && num == 10240)
					{
						replaced++;
						CodeInstruction val = new CodeInstruction(OpCodes.Call, (object)call);
						val.labels.AddRange(instruction.labels);
						val.blocks.AddRange(instruction.blocks);
						yield return val;
					}
					else
					{
						yield return instruction;
					}
				}
				if (replaced == 0)
				{
					Plugin.Log.LogWarning((object)"net.uncap: SendZDOs has no 10240 window — 1.0 moved the cap, this feature is a no-op there.");
				}
			}

			[HarmonyPostfix]
			[HarmonyPatch(typeof(ZSteamSocket), "RegisterGlobalCallbacks")]
			private static void AfterSteam()
			{
				ApplySteam();
			}
		}

		private const int VanillaWindow = 10240;

		private const int VanillaRate = 153600;

		public override string Id => "net.uncap";

		public override bool Enabled => true;

		protected override void OnLoaded()
		{
			ModConfig.NetworkUncapEnabled.SettingChanged += delegate
			{
				ApplySteam();
			};
		}

		private static int Window()
		{
			if (!ModConfig.NetworkUncapEnabled.Value)
			{
				return 10240;
			}
			return 32768;
		}

		private static int Rate()
		{
			if (!ModConfig.NetworkUncapEnabled.Value)
			{
				return 153600;
			}
			return 524288;
		}

		private static void ApplySteam()
		{
			GCHandle gCHandle = GCHandle.Alloc(Rate(), GCHandleType.Pinned);
			try
			{
				SteamNetworkingUtils.SetConfigValue((ESteamNetworkingConfigValue)11, (ESteamNetworkingConfigScope)1, IntPtr.Zero, (ESteamNetworkingConfigDataType)1, gCHandle.AddrOfPinnedObject());
			}
			catch (Exception ex)
			{
				if (ex.Message.IndexOf("not initialized", StringComparison.OrdinalIgnoreCase) < 0)
				{
					Plugin.Log.LogWarning((object)("net.uncap steam: " + ex.Message));
				}
			}
			finally
			{
				gCHandle.Free();
			}
		}
	}
}
namespace RestlessQoL.Ui
{
	internal sealed class CraftingBatch
	{
		internal const int Limit = 99;

		internal int Total { get; private set; }

		internal int Completed { get; private set; }

		internal bool Active { get; private set; }

		internal int Remaining
		{
			get
			{
				if (!Active)
				{
					return 0;
				}
				return Total - Completed;
			}
		}

		internal void Start(int count)
		{
			Total = Math.Max(1, Math.Min(99, count));
			Completed = 0;
			Active = true;
		}

		internal bool Complete(bool success)
		{
			if (!Active)
			{
				return false;
			}
			if (!success)
			{
				Active = false;
				return false;
			}
			Completed++;
			Active = Completed < Total;
			return Active;
		}

		internal void Cancel()
		{
			Active = false;
		}

		internal static int Maximum(Func<int, bool> allows)
		{
			int num = 0;
			int num2 = 99;
			while (num < num2)
			{
				int num3 = num + (num2 - num + 1) / 2;
				if (allows(num3))
				{
					num = num3;
				}
				else
				{
					num2 = num3 - 1;
				}
			}
			return num;
		}
	}
	internal static class CraftingBridge
	{
		internal sealed class Choice
		{
			internal Recipe Recipe;

			internal ItemData? Item;

			internal string Name = "";

			internal string Category = "";

			internal string State = "";

			internal Sprite? Icon;

			internal bool Available;
		}

		internal sealed class Material
		{
			internal string Name = "";

			internal string Counts = "";

			internal Sprite? Icon;

			internal bool Missing;
		}

		internal static List<Choice> Choices(InventoryGui gui)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			List<Choice> list = new List<Choice>();
			foreach (RecipeDataPair availableRecipe in gui.m_availableRecipes)
			{
				RecipeDataPair current = availableRecipe;
				ItemData val = ((RecipeDataPair)(ref current)).ItemData ?? ((RecipeDataPair)(ref current)).Recipe?.m_item?.m_itemData;
				if (!((Object)(object)((RecipeDataPair)(ref current)).Recipe == (Object)null) && val != null)
				{
					list.Add(new Choice
					{
						Recipe = ((RecipeDataPair)(ref current)).Recipe,
						Item = ((RecipeDataPair)(ref current)).ItemData,
						Name = Local(val.m_shared.m_name),
						Category = ((object)Unsafe.As<ItemType, ItemType>(ref val.m_shared.m_itemType)/*cast due to .constrained prefix*/).ToString(),
						Icon = val.GetIcon(),
						Available = ((RecipeDataPair)(ref current)).CanCraft,
						State = ((((RecipeDataPair)(ref current)).ItemData != null) ? ((((RecipeDataPair)(ref current)).CanCraft ? "Ready · " : "Requirements missing · ") + "Quality " + val.m_quality + (val.m_equipped ? " · Equipped" : "")) : (((RecipeDataPair)(ref current)).CanCraft ? "Ready to craft" : "Requirements missing"))
					});
				}
			}
			return list;
		}

		internal static string RowsStamp(IEnumerable<Choice> choices, Choice? selected, int tab, float width, bool running)
		{
			StringBuilder stringBuilder = new StringBuilder().Append(tab).Append('|').Append(width)
				.Append('|')
				.Append(running);
			foreach (Choice choice in choices)
			{
				StringBuilder stringBuilder2 = stringBuilder.Append('|').Append(((Object)choice.Recipe).GetInstanceID()).Append(':')
					.Append(((object)choice.Item)?.GetHashCode() ?? 0)
					.Append(':')
					.Append(choice.Name)
					.Append(':')
					.Append(choice.State)
					.Append(':');
				Sprite? icon = choice.Icon;
				stringBuilder2.Append((icon != null) ? ((Object)icon).GetInstanceID() : 0).Append(':').Append(selected != null && (Object)(object)choice.Recipe == (Object)(object)selected.Recipe && choice.Item == selected.Item);
			}
			return stringBuilder.ToString();
		}

		internal static bool Select(InventoryGui gui, Choice choice)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (gui.m_craftTimer >= 0f)
			{
				return false;
			}
			for (int i = 0; i < gui.m_availableRecipes.Count; i++)
			{
				RecipeDataPair val = gui.m_availableRecipes[i];
				if ((Object)(object)((RecipeDataPair)(ref val)).Recipe == (Object)(object)choice.Recipe && ((RecipeDataPair)(ref val)).ItemData == choice.Item)
				{
					gui.SetRecipe(i, true);
					gui.UpdateRecipe(Player.m_localPlayer, 0f);
					return true;
				}
			}
			return false;
		}

		internal static bool Selected(InventoryGui gui, Choice choice)
		{
			if ((Object)(object)((RecipeDataPair)(ref gui.m_selectedRecipe)).Recipe == (Object)(object)choice.Recipe)
			{
				return ((RecipeDataPair)(ref gui.m_selectedRecipe)).ItemData == choice.Item;
			}
			return false;
		}

		internal static List<Material> Materials(InventoryGui gui)
		{
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			List<Material> list = new List<Material>();
			GameObject[] recipeRequirementList = gui.m_recipeRequirementList;
			foreach (GameObject val in recipeRequirementList)
			{
				if ((Object)(object)val == (Object)null || !val.activeSelf)
				{
					continue;
				}
				TMP_Text val2 = RestlessUi.Deep<TMP_Text>(val.transform, "res_amount");
				Image val3 = RestlessUi.Deep<Image>(val.transform, "res_icon");
				if (!((Object)(object)val2 == (Object)null) && ((Component)val2).gameObject.activeSelf && !((Object)(object)val3 == (Object)null) && ((Component)val3).gameObject.activeSelf)
				{
					TMP_Text? obj = RestlessUi.Deep<TMP_Text>(val.transform, "res_name");
					string text = Local(((obj != null) ? obj.text : null) ?? "");
					if (text.Length == 0)
					{
						UITooltip val4 = ((Component)val3).GetComponent<UITooltip>() ?? val.GetComponent<UITooltip>();
						text = Local((!string.IsNullOrEmpty(val4?.m_topic)) ? val4.m_topic : (val4?.m_text ?? "Material"));
					}
					string text2 = val2.text;
					string[] array = CraftingDetails.Plain(text2).Split(new char[1] { '/' });
					int result;
					int result2;
					bool missing = ((array.Length == 2 && int.TryParse(array[0].Trim(), out result) && int.TryParse(array[1].Trim(), out result2)) ? (result < result2) : (((Graphic)val2).color.r > ((Graphic)val2).color.g * 1.4f));
					list.Add(new Material
					{
						Name = text,
						Counts = text2,
						Icon = val3.sprite,
						Missing = missing
					});
				}
			}
			return list;
		}

		internal static CraftingDetails.Details Details(Choice choice)
		{
			ItemData val = choice.Item ?? choice.Recipe.m_item.m_itemData;
			ItemData val2 = val.Clone();
			val2.m_quality = ((choice.Item == null) ? 1 : (val.m_quality + 1));
			if (choice.Item != null)
			{
				return CraftingDetails.Read(Local(val.GetTooltip(-1)), Local(val2.GetTooltip(-1)));
			}
			return CraftingDetails.Read(Local(val2.GetTooltip(-1)));
		}

		internal static string Requirements(InventoryGui gui)
		{
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = new List<string>();
			GameObject[] recipeRequirementList = gui.m_recipeRequirementList;
			foreach (GameObject val in recipeRequirementList)
			{
				if ((Object)(object)val == (Object)null || !val.activeSelf)
				{
					continue;
				}
				TMP_Text val2 = RestlessUi.Deep<TMP_Text>(val.transform, "res_name");
				TMP_Text val3 = RestlessUi.Deep<TMP_Text>(val.transform, "res_amount");
				Image val4 = RestlessUi.Deep<Image>(val.transform, "res_icon");
				if (!((Object)(object)val3 == (Object)null) && ((Component)val3).gameObject.activeSelf && !((Object)(object)val4 == (Object)null) && ((Component)val4).gameObject.activeSelf)
				{
					string text = Local(((val2 != null) ? val2.text : null) ?? "");
					if (text.Length == 0)
					{
						Image? obj = RestlessUi.Deep<Image>(val.transform, "res_icon");
						UITooltip val5 = ((obj != null) ? ((Component)obj).GetComponent<UITooltip>() : null) ?? val.GetComponent<UITooltip>();
						text = Local((!string.IsNullOrEmpty(val5?.m_topic)) ? val5.m_topic : (val5?.m_text ?? "Material"));
					}
					string text2 = ((val3 != null) ? val3.text : null) ?? "";
					if ((Object)(object)val3 != (Object)null && ((Graphic)val3).color.r > ((Graphic)val3).color.g * 1.4f)
					{
						text2 = "<color=#DB7770>" + text2 + "</color>";
					}
					list.Add(text + "  " + text2);
				}
			}
			if (list.Count != 0)
			{
				return string.Join("\n\n", list);
			}
			return "No materials required";
		}

		internal static string Preview(Choice choice)
		{
			ItemData val = choice.Item ?? choice.Recipe.m_item.m_itemData;
			ItemData val2 = val.Clone();
			val2.m_quality = ((choice.Item == null) ? 1 : (val.m_quality + 1));
			if (choice.Item == null)
			{
				return Local(val2.GetTooltip(-1));
			}
			return "CURRENT · QUALITY " + val.m_quality + "\n" + Local(val.GetTooltip(-1)) + "\n\nAFTER UPGRADE · QUALITY " + val2.m_quality + "\n" + Local(val2.GetTooltip(-1));
		}

		internal static bool Execute(InventoryGui gui, Choice choice)
		{
			if (!Select(gui, choice) || (Object)(object)Player.m_localPlayer == (Object)null || !((Selectable)gui.m_craftButton).interactable)
			{
				return false;
			}
			if (choice.Item != null && !((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems().Contains(choice.Item))
			{
				return false;
			}
			gui.OnCraftPressed();
			return gui.m_craftTimer >= 0f;
		}

		internal static int Output(Choice choice, int count)
		{
			int num = default(int);
			ItemData val = default(ItemData);
			return choice.Recipe.GetAmount(1, ref num, ref val, count);
		}

		internal static bool CanCraftCount(Choice choice, int count)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || choice.Item != null || count < 1 || count > 99)
			{
				return false;
			}
			CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation();
			if ((Object)(object)choice.Recipe.GetRequiredStation(1) != (Object)null && ((Object)(object)currentCraftingStation == (Object)null || !currentCraftingStation.CheckUsable(localPlayer, false)))
			{
				return false;
			}
			if (!localPlayer.HaveRequirements(choice.Recipe, false, 1, count) && !localPlayer.NoCostCheat())
			{
				ZoneSystem instance = ZoneSystem.instance;
				if (instance == null || !instance.GetGlobalKey((GlobalKeys)25))
				{
					return false;
				}
			}
			int num = Output(choice, count);
			if (num > 0)
			{
				return ((Humanoid)localPlayer).GetInventory().CanAddItem(((Component)choice.Recipe.m_item).gameObject, num);
			}
			return false;
		}

		internal static bool ExecuteSingle(InventoryGui gui, Choice choice)
		{
			int multiCraftAmount = gui.m_multiCraftAmount;
			bool touchMultiCrafting = gui.m_touchMultiCrafting;
			try
			{
				gui.m_multiCraftAmount = 1;
				gui.m_touchMultiCrafting = false;
				if (!Select(gui, choice) || !CanCraftCount(choice, 1) || !((Selectable)gui.m_craftButton).interactable)
				{
					return false;
				}
				gui.m_multiCraftAmount = 1;
				gui.m_touchMultiCrafting = false;
				gui.OnCraftPressed();
				gui.m_multiCrafting = false;
				return gui.m_craftTimer >= 0f;
			}
			finally
			{
				gui.m_multiCraftAmount = multiCraftAmount;
				gui.m_touchMultiCrafting = touchMultiCrafting;
			}
		}

		internal static string BlockedReason(InventoryGui gui, Choice choice)
		{
			string text = Local(((Component)gui.m_craftButton).GetComponent<UITooltip>()?.m_text ?? "");
			if (text.Length > 0 && text != Local("$msg_missingrequirement") && text != Local("$msg_missingstation"))
			{
				return text;
			}
			if (choice.Item == null && (Object)(object)Player.m_localPlayer != (Object)null && !((Humanoid)Player.m_localPlayer).GetInventory().CanAddItem(((Component)choice.Recipe.m_item).gameObject, Output(choice, Math.Max(1, gui.m_multiCraftAmount))))
			{
				return "Not enough inventory space for this output";
			}
			Player localPlayer = Player.m_localPlayer;
			CraftingStation val = ((localPlayer != null) ? localPlayer.GetCurrentCraftingStation() : null);
			int num = ((choice.Item == null) ? 1 : (choice.Item.m_quality + 1));
			int num2 = (((Object)(object)val != (Object)null && val.m_upgrader) ? 1 : choice.Recipe.GetRequiredStationLevel(num));
			if ((Object)(object)choice.Recipe.GetRequiredStation(num) != (Object)null && ((Object)(object)val == (Object)null || val.GetLevel(true) < num2))
			{
				return "Requires station level " + num2 + " · current " + ((val != null) ? val.GetLevel(true) : 0);
			}
			if (!choice.Recipe.m_requireOnlyOneIngredient)
			{
				List<string> list = (from m in Materials(gui)
					where m.Missing
					select m.Name).ToList();
				if (list.Count > 0)
				{
					return "Missing: " + string.Join(", ", list.Take(2)) + ((list.Count > 2) ? (" +" + (list.Count - 2)) : "");
				}
			}
			if (text.Length > 0)
			{
				return text;
			}
			return "Craft unavailable · check the station and recipe requirements";
		}

		internal static string ResultText(string name, bool upgrade, Dictionary<int, int> before, Dictionary<int, int> after)
		{
			int value;
			List<KeyValuePair<int, int>> list = after.Where((KeyValuePair<int, int> p) => p.Value - (before.TryGetValue(p.Key, out value) ? value : 0) > 0).ToList();
			int num = after.Values.Sum() - before.Values.Sum();
			if (!upgrade || list.Count <= 0)
			{
				if (upgrade || num <= 0)
				{
					return "Craft ended · no item gain";
				}
				return "Crafted " + Local(name) + " × " + num;
			}
			return "Result: " + Local(name) + " · quality " + list.Max((KeyValuePair<int, int> p) => p.Key);
		}

		internal static string Local(string text)
		{
			if (Localization.instance == null)
			{
				return text;
			}
			return Localization.instance.Localize(text);
		}
	}
	internal static class CraftingDetails
	{
		internal sealed class Attribute
		{
			internal string Name = "";

			internal string Current = "";

			internal string? Next;

			internal bool Changed
			{
				get
				{
					if (Next != null)
					{
						return Plain(Current) != Plain(Next);
					}
					return false;
				}
			}
		}

		internal sealed class Details
		{
			internal string Description = "";

			internal readonly List<Attribute> Attributes = new List<Attribute>();
		}

		internal static string Plain(string text)
		{
			return Regex.Replace(text ?? "", "<[^>]*>", "").Trim();
		}

		internal static Details Read(string current, string? next = null)
		{
			Details details = Parse(current);
			if (next == null)
			{
				return details;
			}
			Details after = Parse(next);
			HashSet<int> used = new HashSet<int>();
			if (Plain(details.Description) != Plain(after.Description) && after.Description.Length > 0)
			{
				details.Description = details.Description + "\n\nAFTER UPGRADE\n" + after.Description;
			}
			foreach (Attribute attribute in details.Attributes)
			{
				int num = after.Attributes.FindIndex((Attribute a) => a.Name == attribute.Name && !used.Contains(after.Attributes.IndexOf(a)));
				if (num < 0)
				{
					attribute.Next = "—";
					continue;
				}
				used.Add(num);
				attribute.Next = after.Attributes[num].Current;
			}
			for (int num2 = 0; num2 < after.Attributes.Count; num2++)
			{
				if (!used.Contains(num2))
				{
					details.Attributes.Add(new Attribute
					{
						Name = after.Attributes[num2].Name,
						Current = "—",
						Next = after.Attributes[num2].Current
					});
				}
			}
			return details;
		}

		private static Details Parse(string tooltip)
		{
			Details details = new Details();
			List<string> list = new List<string>();
			string[] array = tooltip.Replace("\r", "").Split(new char[1] { '\n' });
			foreach (string text in array)
			{
				int num = text.IndexOf(':');
				if (num > 0 && Plain(text.Substring(0, num)).Length > 0 && Plain(text.Substring(num + 1)).Length > 0)
				{
					details.Attributes.Add(new Attribute
					{
						Name = Plain(text.Substring(0, num)),
						Current = text.Substring(num + 1).Trim()
					});
				}
				else if (!string.IsNullOrWhiteSpace(text))
				{
					list.Add(text.Trim());
				}
			}
			details.Description = string.Join("\n", list);
			return details;
		}
	}
	public sealed class CraftingInterface : FeatureModule
	{
		[HarmonyPatch]
		private static class Patches
		{
			[HarmonyPostfix]
			[HarmonyPatch(typeof(InventoryGui), "Show")]
			private static void Show(InventoryGui __instance, Container container)
			{
				if (!ModConfig.CraftingWindowEnabled.Value)
				{
					return;
				}
				EnsureEntry(__instance);
				if ((Object)(object)container == (Object)null)
				{
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)((localPlayer != null) ? localPlayer.GetCurrentCraftingStation() : null) != (Object)null)
					{
						CraftingWindow.Open(__instance);
					}
				}
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(InventoryGui), "Hide")]
			private static void Hide()
			{
				CraftingWindow.Close(hideInventory: false);
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(InventoryGui), "UpdateGamepad")]
			private static bool Gamepad()
			{
				return !CraftingWindow.IsOpen;
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeGamepadInput")]
			private static bool RecipeGamepad()
			{
				return !CraftingWindow.IsOpen;
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")]
			private static void PreviewQuantity(InventoryGui __instance)
			{
				CraftingWindow.PreparePreview(__instance);
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
			private static void BeforeCraft(InventoryGui __instance, out CraftingWindow.CraftResult? __state)
			{
				__state = CraftingWindow.BeforeCraft(__instance);
			}

			[HarmonyPostfix]
			[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
			private static void AfterCraft(InventoryGui __instance, CraftingWindow.CraftResult? __state)
			{
				CraftingWindow.AfterCraft(__instance, __state);
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(Menu), "Update")]
			private static bool MenuInput()
			{
				return !CraftingWindow.BlocksMenu;
			}

			[HarmonyPrefix]
			[HarmonyPatch(typeof(SettingsUi), "Open")]
			private static void Settings()
			{
				CraftingWindow.Close(hideInventory: true);
			}
		}

		private static CanvasGroup? _craftGroup;

		private static bool _addedGroup;

		private static float _alpha;

		private static bool _interactable;

		private static bool _raycasts;

		private static GameObject? _entry;

		public override string Id => "ui.crafting_window";

		public override bool Enabled => true;

		public override bool TickInMenus => true;

		protected override void OnLoaded()
		{
			GUIManager.OnCustomGUIAvailable += Reset;
		}

		public override void Tick()
		{
			if (!ModConfig.CraftingWindowEnabled.Value)
			{
				CraftingWindow.Close(hideInventory: false);
				Restore();
				return;
			}
			InventoryGui instance = InventoryGui.instance;
			if (!((Object)(object)instance == (Object)null) && InventoryGui.IsVisible())
			{
				EnsureEntry(instance);
				if ((Object)(object)_entry != (Object)null)
				{
					_entry.SetActive(((Component)instance.m_crafting).gameObject.activeInHierarchy);
				}
			}
		}

		private static void EnsureEntry(InventoryGui gui)
		{
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: 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_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: 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_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Expected O, but got Unknown
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Expected O, but got Unknown
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Expected O, but got Unknown
			if (!((Object)(object)_entry != (Object)null) && !((Object)(object)gui.m_crafting == (Object)null))
			{
				_craftGroup = ((Component)gui.m_crafting).GetComponent<CanvasGroup>();
				_addedGroup = (Object)(object)_craftGroup == (Object)null;
				if ((Object)(object)_craftGroup == (Object)null)
				{
					_craftGroup = ((Component)gui.m_crafting).gameObject.AddComponent<CanvasGroup>();
				}
				_alpha = _craftGroup.alpha;
				_interactable = _craftGroup.interactable;
				_raycasts = _craftGroup.blocksRaycasts;
				_craftGroup.alpha = 0f;
				_craftGroup.interactable = false;
				_craftGroup.blocksRaycasts = false;
				_entry = RestlessUi.Tray(((Transform)gui.m_crafting).parent, "RestlessCraftingEntry");
				RestlessUi.PaperSurface(_entry);
				RectTransform val = (RectTransform)_entry.transform;
				val.anchorMin = gui.m_crafting.anchorMin;
				val.anchorMax = gui.m_crafting.anchorMax;
				val.pivot = gui.m_crafting.pivot;
				val.anchoredPosition = gui.m_crafting.anchoredPosition;
				val.sizeDelta = new Vector2(360f, 160f);
				UiKitWindow.Label((Transform)val, "Crafting", 26, new Rect(24f, 16f, 300f, 36f));
				UiKitWindow.Label((Transform)val, "Recipes, equipment upgrades and station extensions", 17, new Rect(24f, 54f, 310f, 44f), muted: true);
				UiKitApi.Button((Transform)val, "Open Crafting", new Rect(24f, 108f, 310f, 38f), delegate
				{
					CraftingWindow.Open(gui);
				});
			}
		}

		private static void Restore()
		{
			if ((Object)(object)_craftGroup != (Object)null)
			{
				if (_addedGroup)
				{
					Object.Destroy((Object)(object)_craftGroup);
				}
				else
				{
					_craftGroup.alpha = _alpha;
					_craftGroup.interactable = _interactable;
					_craftGroup.blocksRaycasts = _raycasts;
				}
			}
			_craftGroup = null;
			_addedGroup = false;
			if ((Object)(object)_entry != (Object)null)
			{
				_entry.SetActive(false);
				Object.Destroy((Object)(object)_entry);
			}
			_entry = null;
		}

		private static void Reset()
		{
			CraftingWindow.Reset();
			Restore();
		}
	}
	internal sealed class CraftingWindow : MonoBehaviour
	{
		internal sealed class CraftResult
		{
			internal string Name = "";

			internal bool Upgrade;

			internal Dictionary<int, int> Before = new Dictionary<int, int>();
		}

		private sealed class StationChoice
		{
			internal string Id = "";

			internal string Name = "";

			internal string State = "";

			internal Piece? Piece;

			internal StationExtension? Extension;

			internal bool Connected;
		}

		private readonly CraftingBatch _batch = new CraftingBatch();

		private CraftingBridge.Choice? _batchChoice;

		private Recipe? _quantityRecipe;

		private int _quantity = 1;

		private int _maximum;

		private bool _pendingCraft;

		private bool _ownsQuantity;

		private bool _executingSingle;

		private int _previousAmount;

		private bool _previousTouch;

		private float _nextMaximum;

		private Button _less;

		private Button _more;

		private Button _max;

		private InputField _amount;

		private Text _batchLabel;

		private static CraftingWindow? _current;

		private static CraftingWindow? _cached;

		private CanvasGroup _visibility;

		private bool _built;

		private string _rowStamp = "";

		private string _bagStamp = "";

		private string _paintedCategory = "";

		private int _paintedTab = -1;

		private CraftingBridge.Choice? _previewChoice;

		private float _nextPreview;

		private int _previewQuality;

		private int _previewVariant;

		private static int _closedFrame = -1;

		private InventoryGui _gui;

		private CraftingStation? _station;

		private UiKitWindow _frame;

		private RestlessScrollRect _browser;

		private RestlessScrollRect _detail;

		private RestlessScrollRect _requirements;

		private Text _heading;

		private Text _copy;

		private Text _needs;

		private Text _reason;

		private Text _bag;

		private Text _context;

		private Image _portrait;

		private GameObject _feature;

		private GameObject _portraitFrame;

		private Text _heroMeta;

		private Text _heroNote;

		private Text _statHeader;

		private readonly List<UiKitDetailRow> _attributes = new List<UiKitDetailRow>();

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

		private string _detailStamp = "";

		private string _materialStamp = "";

		private Button _sortButton;

		private Button _savedOnlyButton;

		private Button _saveButton;

		private int _sort;

		private bool _savedOnly;

		private readonly HashSet<string> _saved = new HashSet<string>(StringComparer.Ordinal);

		private Button _action;

		private Button _cancel;

		private Button _variant;

		private Button _repair;

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

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

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

		private InputField _search;

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

		private readonly List<Text> _rowNames = new List<Text>();

		private readonly List<Text> _rowStates = new List<Text>();

		private readonly List<Image> _rowIcons = new List<Image>();

		private CanvasGroup? _native;

		private bool _ownsNative;

		private bool _blocked;

		private float _nativeAlpha;

		private float _next;

		private bool _nativeInteractable;

		private bool _nativeRaycasts;

		private int _tab;

		private string _query = "";

		private string _category = "All";

		private CraftingBridge.Choice? _choice;

		private StationChoice? _extension;

		private GameObject? _previousFocus;

		private int _openedFrame;

		private string _message = "";

		private float _messageUntil;

		private Vector2 _canvas;

		private bool _compact;

		private readonly float[] _scrollPositions = new float[3];

		private UiKitProgress _progress;

		private float _nextStation;

		private List<StationChoice> _stationChoices = new List<StationChoice>();

		private ZNetScene? _scene;

		private readonly List<StationExtension> _extensionPrefabs = new List<StationExtension>();

		private bool Busy
		{
			get
			{
				if (!_batch.Active)
				{
					return _gui.m_craftTimer >= 0f;
				}
				return true;
			}
		}

		private int PreviewQuantity
		{
			get
			{
				if (_tab != 0)
				{
					return 1;
				}
				if (!_batch.Active)
				{
					return _quantity;
				}
				return _batch.Remaining;
			}
		}

		internal static bool IsOpen => (Object)(object)_current != (Object)null;

		internal static bool BlocksMenu
		{
			get
			{
				if (!IsOpen)
				{
					return Time.frameCount == _closedFrame;
				}
				return true;
			}
		}

		private void OwnQuantity()
		{
			_previousAmount = _gui.m_multiCraftAmount;
			_previousTouch = _gui.m_touchMultiCrafting;
			_ownsQuantity = true;
			_batch.Cancel();
			_pendingCraft = false;
			_batchChoice = null;
			_quantityRecipe = null;
			_quantity = 1;
			_nextMaximum = 0f;
		}

		internal static void PreparePreview(InventoryGui gui)
		{
			if (!((Object)(object)_current == (Object)null) && !((Object)(object)_current._gui != (Object)(object)gui) && _current._ownsQuantity && !_current._executingSingle)
			{
				gui.m_multiCraftAmount = _current.PreviewQuantity;
				gui.m_touchMultiCrafting = _current.PreviewQuantity > 1;
			}
		}

		private void ReleaseQuantity()
		{
			if (!_ownsQuantity)
			{
				return;
			}
			if (_batch.Active)
			{
				_batch.Cancel();
				_pendingCraft = false;
				if (_gui.m_craftTimer >= 0f)
				{
					_gui.OnCraftCancelPressed();
				}
			}
			_batchChoice = null;
			_gui.m_multiCraftAmount = _previousAmount;
			_gui.m_touchMultiCrafting = _previousTouch;
			_ownsQuantity = false;
		}

		private void Quantity(int count)
		{
			if (!Busy)
			{
				_quantity = Mathf.Clamp(count, 1, 99);
				_nextPreview = 0f;
				_nextMaximum = 0f;
				_messageUntil = 0f;
				PreparePreview(_gui);
				_gui.UpdateRecipe(Player.m_localPlayer, 0f);
				Refresh();
			}
		}

		private void PaintQuantity()
		{
			bool flag = _tab == 0 && _choice != null;
			((Component)_batchLabel).gameObject.SetActive(flag);
			Selectable[] array = (Selectable[])(object)new Selectable[4]
			{
				(Selectable)_less,
				(Selectable)_amount,
				(Selectable)_more,
				(Selectable)_max
			};
			for (int i = 0; i < array.Length; i++)
			{
				((Component)array[i]).gameObject.SetActive(flag);
			}
			if (!flag)
			{
				return;
			}
			if ((Object)(object)_quantityRecipe != (Object)(object)_choice.Recipe && !Busy)
			{
				_quantityRecipe = _choice.Recipe;
				_quantity = 1;
				_nextMaximum = 0f;
				PreparePreview(_gui);
				_gui.UpdateRecipe(Player.m_localPlayer, 0f);
			}
			if (!Busy && Time.unscaledTime >= _nextMaximum)
			{
				_nextMaximum = Time.unscaledTime + 1f;
				_maximum = CraftingBatch.Maximum((int count) => CraftingBridge.CanCraftCount(_choice, count));
			}
			if (!_amount.isFocused)
			{
				_amount.SetTextWithoutNotify((_batch.Active ? _batch.Remaining : _quantity).ToString());
			}
			((Selectable)_amount).interactable = !Busy;
			((Selectable)_less).interactable = !Busy && _quantity > 1;
			((Selectable)_more).interactable = !Busy && _quantity < 99;
			((Selectable)_max).interactable = !Busy && _maximum > 0;
			Caption(_max, "Max: " + _maximum);
			_context.text = "Materials for " + PreviewQuantity + " batch" + ((PreviewQuantity == 1) ? "" : "es");
			_heroNote.text = "Produces " + CraftingBridge.Output(_choice, PreviewQuantity) + " item" + ((CraftingBridge.Output(_choice, PreviewQuantity) == 1) ? "" : "s");
			Caption(_action, "Craft " + CraftingBridge.Output(_choice, PreviewQuantity));
		}

		private void StartBatch()
		{
			if (_choice != null && !Busy)
			{
				if (!CraftingBridge.CanCraftCount(_choice, _quantity))
				{
					Message("Batch unavailable · check materials, station and inventory space");
					return;
				}
				_batchChoice = _choice;
				_batch.Start(_quantity);
				_pendingCraft = true;
				_messageUntil = 0f;
				StartNextCraft();
			}
		}

		private void StartNextCraft()
		{
			if (_batch.Active && !_pendingCraft && _gui.m_craftTimer < 0f)
			{
				_batch.Cancel();
				_batchChoice = null;
				Message("Batch stopped · " + _batch.Completed + " / " + _batch.Total + " crafts completed");
				_nextMaximum = 0f;
			}
			else
			{
				if (!_batch.Active || !_pendingCraft || _gui.m_craftTimer >= 0f)
				{
					return;
				}
				_pendingCraft = false;
				_executingSingle = true;
				bool flag;
				try
				{
					flag = _batchChoice != null && CraftingBridge.ExecuteSingle(_gui, _batchChoice);
				}
				catch (Exception ex)
				{
					flag = false;
					Plugin.Log.LogError((object)("Queued craft failed; stopped remaining work: " + ex));
				}
				finally
				{
					_executingSingle = false;
				}
				if (!flag)
				{
					_batch.Complete(success: false);
					Message("Batch stopped · " + _batch.Completed + " / " + _batch.Total + " crafts completed. Check materials, station and space.");
					_batchChoice = null;
					_nextMaximum = 0f;
				}
			}
		}

		private void CancelCraft()
		{
			int completed = _batch.Completed;
			int total = _batch.Total;
			bool active = _batch.Active;
			_batch.Cancel();
			_pendingCraft = false;
			_batchChoice = null;
			if (_gui.m_craftTimer >= 0f)
			{
				_gui.OnCraftCancelPressed();
			}
			Message(active ? ("Batch cancelled · " + completed + " / " + total + " crafts completed") : "Craft cancelled");
			_nextMaximum = 0f;
			Refresh();
		}

		internal static void Open(InventoryGui gui)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.CraftingWindowEnabled.Value || (Object)(object)GUIManager.CustomGUIFront == (Object)null || SettingsUi.IsOpen || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)_current != (Object)null)
			{
				return;
			}
			CraftingWindow craftingWindow = _cached;
			if ((Object)(object)craftingWindow == (Object)null)
			{
				GameObject val = RestlessUi.Graphic(GUIManager.CustomGUIFront.transform, "RestlessCraftingWindow", new Color(0f, 0f, 0f, 0.45f));
				RestlessUi.Stretch(val, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
				craftingWindow = val.AddComponent<CraftingWindow>();
				craftingWindow._visibility = val.AddComponent<CanvasGroup>();
				_cached = craftingWindow;
			}
			craftingWindow._visibility.alpha = 0f;
			craftingWindow._visibility.interactable = false;
			craftingWindow._visibility.blocksRaycasts = false;
			_current = craftingWindow;
			craftingWindow._gui = gui;
			craftingWindow._openedFrame = Time.frameCount;
			CraftingWindow craftingWindow2 = craftingWindow;
			EventSystem current = EventSystem.current;
			craftingWindow2._previousFocus = ((current != null) ? current.currentSelectedGameObject : null);
			((Component)craftingWindow).gameObject.SetActive(true);
			try
			{
				craftingWindow._station = Player.m_localPlayer.GetCurrentCraftingStation();
				craftingWindow._tab = (gui.InUpradeTab() ? 1 : 0);
				craftingWindow.OwnQuantity();
				gui.UpdateCraftingPanel(false);
				craftingWindow._choice = null;
				craftingWindow._extension = null;
				craftingWindow._saved.Clear();
				string[] array = ModConfig.CraftingSavedRecipes.Value.Split(new char[1] { '|' });
				foreach (string text in array)
				{
					if (text.Length > 0)
					{
						craftingWindow._saved.Add(text);
					}
				}
				craftingWindow._rowStamp = "";
				craftingWindow._bagStamp = "";
				craftingWindow._paintedTab = -1;
				craftingWindow._previewChoice = null;
				craftingWindow._nextPreview = 0f;
				craftingWindow._nextStation = 0f;
				craftingWindow._messageUntil = 0f;
				craftingWindow._canvas = Vector2.zero;
				craftingWindow._detailStamp = "";
				craftingWindow._materialStamp = "";
				Canvas.ForceUpdateCanvases();
				if (!craftingWindow._built)
				{
					craftingWindow.Build();
					craftingWindow._built = true;
				}
				else
				{
					craftingWindow._search.SetTextWithoutNotify(craftingWindow._query);
					craftingWindow.Fit();
				}
				craftingWindow.HideNative();
				craftingWindow._blocked = true;
				GUIManager.BlockInput(true);
				LookHints.SetSuppressed(craftingWindow, suppressed: true);
				craftingWindow.Refresh();
				((ScrollRect)craftingWindow._browser).content.anchoredPosition = new Vector2(0f, craftingWindow._scrollPositions[craftingWindow._tab]);
				RestlessScrollRect browser = craftingWindow._browser;
				Rect rect = ((ScrollRect)craftingWindow._browser).content.rect;
				UiKitApi.SizeReader(browser, ((Rect)(ref rect)).height);
				RestlessScrollRect detail = craftingWindow._detail;
				rect = ((ScrollRect)craftingWindow._detail).content.rect;
				UiKitApi.SizeReader(detail, ((Rect)(ref rect)).height, reset: true);
				Canvas.ForceUpdateCanvases();
				craftingWindow._visibility.alpha = 1f;
				craftingWindow._visibility.interactable = true;
				craftingWindow._visibility.blocksRaycasts = true;
				EventSystem current2 = EventSystem.current;
				if (current2 != null)
				{
					current2.SetSelectedGameObject(((Component)craftingWindow._tabs[craftingWindow._tab]).gameObject);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Crafting window failed; restored inventory: " + ex));
				Reset();
			}
		}

		internal static void Close(bool hideInventory)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_current == (Object)null))
			{
				CraftingWindow current = _current;
				_current = null;
				_closedFrame = Time.frameCount;
				if ((Object)(object)current._browser != (Object)null)
				{
					current._scrollPositions[current._tab] = ((ScrollRect)current._browser).content.anchoredPosition.y;
				}
				((Component)current).gameObject.SetActive(false);
				if (hideInventory && (Object)(object)current._gui != (Object)null)
				{
					current._gui.Hide();
				}
			}
		}

		internal static void Reset()
		{
			Close(hideInventory: false);
			if ((Object)(object)_cached != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_cached).gameObject);
			}
			_cached = null;
		}

		private void HideNative()
		{
			_native = ((Component)_gui.m_inventoryRoot).GetComponent<CanvasGroup>();
			_ownsNative = (Object)(object)_native == (Object)null;
			if ((Object)(object)_native == (Object)null)
			{
				_native = ((Component)_gui.m_inventoryRoot).gameObject.AddComponent<CanvasGroup>();
			}
			_nativeAlpha = _native.alpha;
			_nativeInteractable = _native.interactable;
			_nativeRaycasts = _native.blocksRaycasts;
			_native.alpha = 0f;
			_native.interactable = false;
			_native.blocksRaycasts = false;
		}

		private void OnDisable()
		{
			ReleaseQuantity();
			LookHints.SetSuppressed(this, suppressed: false);
			if ((Object)(object)_native != (Object)null)
			{
				if (_ownsNative)
				{
					Object.Destroy((Object)(object)_native);
				}
				else
				{
					_native.alpha = _nativeAlpha;
					_native.interactable = _nativeInteractable;
					_native.blocksRaycasts = _nativeRaycasts;
				}
			}
			if (_blocked && !SettingsUi.IsOpen)
			{
				GUIManager.BlockInput(false);
			}
			_blocked = false;
			if ((Object)(object)_previousFocus != (Object)null && _previousFocus.activeInHierarchy)
			{
				EventSystem current = EventSystem.current;
				if (current != null)
				{
					current.SetSelectedGameObject(_previousFocus);
				}
			}
			if ((Object)(object)_current == (Object)(object)this)
			{
				_current = null;
			}
		}

		private void LateUpdate()
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (Time.frameCount - _openedFrame < 2)
			{
				return;
			}
			if (!ModConfig.CraftingWindowEnabled.Value || (Object)(object)_gui == (Object)null || !InventoryGui.IsVisible() || (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || SettingsUi.IsOpen || Menu.IsVisible())
			{
				Close(hideInventory: false);
				return;
			}
			if (Input.GetKeyDown((KeyCode)27) || ZInput.GetButtonDown("JoyButtonB"))
			{
				Close(hideInventory: true);
				return;
			}
			CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation();
			if ((Object)(object)_station != (Object)null && ((Object)(object)currentCraftingStation != (Object)(object)_station || !StorageAccess.Allows(((Component)_station).transform.position, localPlayer.GetPlayerID()) || Vector3.Distance(((Component)localPlayer).transform.position, ((Component)_station).transform.position) > _station.m_useDistance))
			{
				Close(hideInventory: true);
				return;
			}
			StartNextCraft();
			Fit();
			if (Time.unscaledTime >= _next)
			{
				try
				{
					Refresh();
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Crafting refresh failed; restoring inventory: " + ex));
					Close(hideInventory: false);
				}
			}
			PaintProgress();
			EnsureFocusedVisible();
		}

		private void SelectTab(int tab)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			if (!Busy)
			{
				_scrollPositions[_tab] = ((ScrollRect)_browser).content.anchoredPosition.y;
				_tab = tab;
				_choice = null;
				_extension = null;
				_rowStamp = "";
				_nextPreview = 0f;
				_detailStamp = "";
				switch (tab)
				{
				case 0:
					_gui.OnTabCraftPressed();
					break;
				case 1:
					_gui.OnTabUpgradePressed();
					break;
				}
				Refresh();
				((ScrollRect)_browser).content.anchoredPosition = new Vector2(0f, _scrollPositions[tab]);
				RestlessScrollRect browser = _browser;
				Rect rect = ((ScrollRect)_browser).content.rect;
				UiKitApi.SizeReader(browser, ((Rect)(ref rect)).height);
			}
		}

		private void Refresh()
		{
			_next = Time.unscaledTime + 0.3f;
			_frame.Subtitle.text = (((Object)(object)_station == (Object)null) ? "Hand crafting" : (CraftingBridge.Local(_station.m_name) + " · Level " + _station.GetLevel(true)));
			if (_paintedTab != _tab || _paintedCategory != _category)
			{
				for (int i = 0; i < _tabs.Count; i++)
				{
					UiKitApi.Tab(_tabs[i], i == _tab);
				}
				for (int j = 0; j < _filters.Count; j++)
				{
					((Component)_filters[j]).gameObject.SetActive(_tab != 2);
					UiKitApi.Tab(_filters[j], ((Component)_filters[j]).GetComponentInChildren<Text>().text == _category);
				}
				_paintedTab = _tab;
				_paintedCategory = _category;
			}
			((Component)_sortButton).gameObject.SetActive(_tab != 2);
			((Component)_savedOnlyButton).gameObject.SetActive(_tab != 2);
			Caption(_sortButton, (_sort == 0) ? "Sort: native" : ((_sort == 1) ? "Sort: available" : "Sort: name"));
			Caption(_savedOnlyButton, _savedOnly ? "Saved only" : "All recipes");
			for (int k = 0; k < _tabs.Count; k++)
			{
				((Selectable)_tabs[k]).interactable = !Busy;
			}
			((Selectable)_search).interactable = !Busy;
			((Selectable)_sortButton).interactable = !Busy;
			((Selectable)_savedOnlyButton).interactable = !Busy;
			((Selectable)_saveButton).interactable = !Busy;
			foreach (Button filter in _filters)
			{
				((Selectable)filter).interactable = !Busy;
			}
			if (_tab == 2)
			{
				PaintStations();
				PaintQuantity();
			}
			else
			{
				PaintRecipes();
			}
			PaintBag();
			((Component)_repair).gameObject.SetActive((Object)(object)_gui.m_repairButton != (Object)null && ((Component)_gui.m_repairButton).gameObject.activeSelf);
			((Selectable)_repair).interactable = !Busy && (Object)(object)_gui.m_repairButton != (Object)null && ((Selectable)_gui.m_repairButton).interactable;
			Caption(_repair, ((Selectable)_repair).interactable ? "Repair equipment" : "No repairable equipment");
			UpdateNavigation();
			if (Time.unscaledTime < _messageUntil)
			{
				_reason.text = _message;
			}
		}

		private void PaintRecipes()
		{
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Expected O, but got Unknown
			//IL_053b: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			_context.text = "Required materials";
			List<CraftingBridge.Choice> list = CraftingBridge.Choices(_gui);
			IEnumerable<CraftingBridge.Choice> enumerable = list.Where((CraftingBridge.Choice c) => c.Name.IndexOf(_query, StringComparison.OrdinalIgnoreCase) >= 0 && Category(c) && (!_savedOnly || _saved.Contains(((Object)c.Recipe).name)));
			IEnumerable<CraftingBridge.Choice> source;
			if (_sort != 1)
			{
				if (_sort != 2)
				{
					source = enumerable;
				}
				else
				{
					IEnumerable<CraftingBridge.Choice> enumerable2 = enumerable.OrderBy((CraftingBridge.Choice c) => c.Name);
					source = enumerable2;
				}
			}
			else
			{
				IEnumerable<CraftingBridge.Choice> enumerable2 = from c in enumerable
					orderby c.Available descending, c.Name
					select c;
				source = enumerable2;
			}
			List<CraftingBridge.Choice> list2 = source.ToList();
			CraftingBridge.Choice nativeChoice = list.FirstOrDefault((CraftingBridge.Choice c) => CraftingBridge.Selected(_gui, c));
			if (Busy)
			{
				_choice = _batchChoice ?? nativeChoice ?? _choice;
			}
			else
			{
				_choice = list2.FirstOrDefault((CraftingBridge.Choice c) => nativeChoice != null && (Object)(object)c.Recipe == (Object)(object)nativeChoice.Recipe && c.Item == nativeChoice.Item) ?? list2.FirstOrDefault((CraftingBridge.Choice c) => _choice != null && (Object)(object)c.Recipe == (Object)(object)_choice.Recipe && c.Item == _choice.Item) ?? list2.FirstOrDefault();
			}
			if (_choice != null && !CraftingBridge.Selected(_gui, _choice) && _gui.m_craftTimer < 0f)
			{
				CraftingBridge.Select(_gui, _choice);
			}
			CraftingBridge.Choice? choice = _choice;
			int tab = _tab;
			Rect rect = ((ScrollRect)_browser).content.rect;
			string text = CraftingBridge.RowsStamp(list2, choice, tab, ((Rect)(ref rect)).width, Busy);
			if (text != _rowStamp)
			{
				for (int num = 0; num < list2.Count; num++)
				{
					CraftingBridge.Choice choice2 = list2[num];
					Button obj = Row(num);
					_rowNames[num].text = choice2.Name;
					_rowStates[num].text = (_saved.Contains(((Object)choice2.Recipe).name) ? "Saved · " : "") + choice2.State;
					_rowIcons[num].sprite = choice2.Icon;
					((Behaviour)_rowIcons[num]).enabled = (Object)(object)choice2.Icon != (Object)null;
					((UnityEventBase)obj.onClick).RemoveAllListeners();
					((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
					{
						//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
						//IL_00af: Unknown result type (might be due to invalid IL or missing references)
						if (!Busy && CraftingBridge.Select(_gui, choice2))
						{
							_choice = choice2;
							_nextPreview = 0f;
							_messageUntil = 0f;
							Refresh();
							RestlessScrollRect detail = _detail;
							Rect rect2 = ((ScrollRect)_detail).content.rect;
							UiKitApi.SizeReader(detail, ((Rect)(ref rect2)).height, reset: true);
						}
					});
					((Selectable)obj).interactable = !Busy;
					RestlessUi.PaperControl(((Component)obj).gameObject, (_choice != null && (Object)(object)choice2.Recipe == (Object)(object)_choice.Recipe && choice2.Item == _choice.Item) ? new Color?(UiKitApi.Accent) : ((Color?)null));
				}
				FinishRows(list2.Count);
				_rowStamp = text;
			}
			((Component)_variant).gameObject.SetActive((Object)(object)_gui.m_variantButton != (Object)null && ((Component)_gui.m_variantButton).gameObject.activeSelf && _tab == 0);
			((Selectable)_variant).interactable = !Busy;
			((Component)_action).gameObject.SetActive(true);
			((Component)_cancel).gameObject.SetActive(true);
			if (_choice == null)
			{
				_heading.text = ((list2.Count == 0 && list.Count > 0) ? "No matching items" : "No available recipes");
				_copy.text = ((_tab == 1) ? "Your inventory has no equipment eligible for this station's upgrade tab." : "Known recipes appear here when the current station supports them.");
				PaintQuantity();
				_previewChoice = null;
				_nextPreview = 0f;
				((Component)_saveButton).gameObject.SetActive(false);
				((Behaviour)_portrait).enabled = false;
				_heroMeta.text = "Choose an item";
				_heroNote.text = "";
				HideDetailRows();
				PaintMaterials(new List<CraftingBridge.Material>());
				_needs.text = "";
				_reason.text = "Choose a recipe or item";
				((Selectable)_action).interactable = false;
				Caption(_action, "Craft");
				ResizeCopy();
				return;
			}
			PaintQuantity();
			_heading.text = _choice.Name;
			Image portrait = _portrait;
			object obj2;
			if (_tab != 0)
			{
				obj2 = null;
			}
			else
			{
				Image recipeIcon = _gui.m_recipeIcon;
				obj2 = ((recipeIcon != null) ? recipeIcon.sprite : null);
			}
			if (obj2 == null)
			{
				obj2 = _choice.Icon;
			}
			portrait.sprite = (Sprite)obj2;
			((Transform)((Graphic)_portrait).rectTransform).localScale = Vector3.one;
			((Behaviour)_portrait).enabled = (Object)(object)_portrait.sprite != (Object)null;
			if (_previewChoice == null || (Object)(object)_previewChoice.Recipe != (Object)(object)_choice.Recipe || _previewChoice.Item != _choice.Item || _previewQuality != (_choice.Item?.m_quality ?? 1) || _previewVariant != _gui.m_selectedVariant || Time.unscaledTime >= _nextPreview)
			{
				PaintDetails((_tab == 0) ? CraftingDetails.Read(CraftingBridge.Local(_gui.m_recipeDecription.text)) : CraftingBridge.Details(_choice));
				_previewChoice = _choice;
				_previewQuality = _choice.Item?.m_quality ?? 1;
				_previewVariant = _gui.m_selectedVariant;
				_nextPreview = Time.unscaledTime + 1f;
			}
			_heroMeta.text = Regex.Replace(_choice.Category, "([a-z])([A-Z])", "$1 $2");
			if (_tab != 0)
			{
				_heroNote.text = ((_tab == 1) ? ("Quality " + _choice.Item.m_quality + " → " + (_choice.Item.m_quality + 1)) : ("Makes " + _choice.Recipe.m_amount + " · Quality 1"));
			}
			Caption(_saveButton, _saved.Contains(((Object)_choice.Recipe).name) ? "Saved recipe" : "Save recipe");
			((Component)_saveButton).gameObject.SetActive(true);
			PaintMaterials(CraftingBridge.Materials(_gui));
			bool flag = CraftingBridge.Selected(_gui, _choice);
			((Selectable)_action).interactable = flag && ((Selectable)_gui.m_craftButton).interactable && !Busy && (_tab != 0 || _quantity <= _maximum);
			if (_tab != 0)
			{
				Caption(_action, (_tab == 1) ? ("Upgrade to quality " + ((_choice.Item?.m_quality ?? 0) + 1)) : ("Craft " + _choice.Recipe.m_amount));
			}
			string text2 = (((Object)(object)_gui.m_minStationLevelIcon != (Object)null && ((Component)_gui.m_minStationLevelIcon).gameObject.activeSelf && (Object)(object)_gui.m_minStationLevelText != (Object)null) ? CraftingBridge.Local(_gui.m_minStationLevelText.text) : "");
			if (int.TryParse(RestlessUi.Bare(text2), out var result))
			{
				text2 = "Requires " + (((Object)(object)_station != (Object)null) ? CraftingBridge.Local(_station.m_name) : "station") + " level " + result;
			}
			_reason.text = ((!Busy) ? ((!((Selectable)_action).interactable) ? CraftingBridge.BlockedReason(_gui, _choice) : ((text2.Length > 0) ? ("Ready · " + text2) : "Ready")) : (_batch.Active ? ("Batch · " + _batch.Completed + " / " + _batch.Total + " crafts completed") : "Crafting in progress"));
		}

		private bool Category(CraftingBridge.Choice choice)
		{
			if (!(_category == "All"))
			{
				if (!(_category == "Equipment"))
				{
					return choice.Recipe.m_item.m_itemData.m_shared.m_maxQuality <= 1;
				}
				return choice.Recipe.m_item.m_itemData.m_shared.m_maxQuality > 1;
			}
			return true;
		}

		private void Act()
		{
			if (_tab == 2)
			{
				SelectBuildPiece();
			}
			else
			{
				if (_choice == null)
				{
					return;
				}
				if (_tab == 0)
				{
					StartBatch();
					Refresh();
					return;
				}
				if (!CraftingBridge.Execute(_gui, _choice))
				{
					Message(CraftingBridge.BlockedReason(_gui, _choice));
				}
				Refresh();
			}
		}

		private void PaintProgress()
		{
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			bool busy = Busy;
			((Selectable)_cancel).interactable = true;
			Caption(_cancel, (!busy) ? "Your full inventory" : (_batch.Active ? "Cancel batch" : "Cancel craft"));
			if (busy)
			{
				float total = (((Object)(object)_gui.m_craftProgressBar != (Object)null) ? Mathf.Clamp01(_gui.m_craftProgressBar.m_value / Mathf.Max(0.001f, _gui.m_craftProgressBar.m_maxValue)) : 0f);
				_progress.Set(new Rect((float)(_compact ? 638 : 906), (float)(_compact ? 478 : 578), (float)(_compact ? 298 : 326), 8f), 0f, total, UiKitApi.Accent, UiKitApi.Accent);
			}
			else
			{
				_progress.Hide();
			}
		}

		private void PaintBag()
		{
			//IL_0400: Unknown result type (might be due to invalid IL or missing references)
			//IL_040a: Expected O, but got Unknown
			//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ef: Expected O, but got Unknown
			//IL_04fb: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			List<ItemData> list = inventory.GetAllItems();
			if (_tab == 1)
			{
				List<ItemData> eligible = (from c in CraftingBridge.Choices(_gui)
					where c.Item != null
					select c.Item).ToList();
				list = (from i in list
					where eligible.Contains(i)
					orderby i.m_equipped descending
					select i).ToList();
			}
			bool flag = false;
			if (_tab == 0 && _choice != null)
			{
				HashSet<string> names = new HashSet<string>(from r in _choice.Recipe.m_resources
					where (Object)(object)r.m_resItem != (Object)null
					select r.m_resItem.m_itemData.m_shared.m_name);
				List<ItemData> list2 = list.Where((ItemData i) => names.Contains(i.m_shared.m_name)).ToList();
				if (list2.Count > 0)
				{
					list = list2;
					flag = true;
				}
			}
			_bag.text = ((_tab == 1) ? "Upgradeable equipment · " : (flag ? "Recipe ingredients in your bag · " : "Your inventory · ")) + inventory.GetTotalWeight().ToString("0.0") + " / " + localPlayer.GetMaxCarryWeight().ToString("0") + " weight · " + inventory.GetEmptySlots() + " free slots";
			StringBuilder stringBuilder = new StringBuilder().Append(_tab);
			for (int num = 0; num < Math.Min(list.Count, _slots.Count); num++)
			{
				ItemData val = list[num];
				stringBuilder.Append('|').Append(((object)val).GetHashCode()).Append(':')
					.Append(val.m_stack)
					.Append(':')
					.Append(val.m_quality)
					.Append(':')
					.Append(_choice?.Item == val);
			}
			string text = stringBuilder.ToString();
			if (text == _bagStamp)
			{
				return;
			}
			_bagStamp = text;
			for (int num2 = 0; num2 < _slots.Count; num2++)
			{
				ItemData item = ((num2 < list.Count) ? list[num2] : null);
				_slots[num2].SetActive(item != null);
				if (item == null)
				{
					continue;
				}
				((Component)_slots[num2].transform.Find("icon")).GetComponent<Image>().sprite = item.GetIcon();
				_slots[num2].GetComponentInChildren<Text>().text = ((item.m_stack > 1) ? item.m_stack.ToString() : ("Q" + item.m_quality));
				Button component = _slots[num2].GetComponent<Button>();
				((UnityEventBase)component.onClick).RemoveAllListeners();
				if (_tab == 1)
				{
					((UnityEvent)component.onClick).AddListener((UnityAction)delegate
					{
						if (!Busy)
						{
							CraftingBridge.Choice choice = CraftingBridge.Choices(_gui).FirstOrDefault((CraftingBridge.Choice c) => c.Item == item);
							if (choice != null && CraftingBridge.Select(_gui, choice))
							{
								_choice = choice;
								Refresh();
							}
						}
					});
				}
				else
				{
					((UnityEvent)component.onClick).AddListener((UnityAction)delegate
					{
						//IL_0095: 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)
						if (!Busy)
						{
							if (_tab == 2)
							{
								Close(hideInventory: false);
							}
							else
							{
								PaintDetails(CraftingDetails.Read(CraftingBridge.Local(item.m_shared.m_name) + "\n" + CraftingBridge.Local(item.GetTooltip(-1))));
								_nextPreview = Time.unscaledTime + 6f;
								RestlessScrollRect detail = _detail;
								Rect rect = ((ScrollRect)_detail).content.rect;
								UiKitApi.SizeReader(detail, ((Rect)(ref rect)).height, reset: true);
								Message("Inspecting " + CraftingBridge.Local(item.m_shared.m_name) + " · recipe selection retained");
							}
						}
					});
				}
				_slots[num2].GetComponent<RestlessHint>().Copy = CraftingBridge.Local(item.m_shared.m_name) + " · " + ((item.m_stack > 1) ? (item.m_stack + " in this stack") : ("Quality " + item.m_quality)) + "\n" + ((_tab == 1) ? "Select to view this equipment's upgrade" : ((_tab == 2) ? "Select to open your full inventory" : "Select to inspect this item for six seconds"));
				RestlessUi.PaperControl(_slots[num2], (_choice?.Item == item) ? new Color?(UiKitApi.Accent) : ((Color?)null));
			}
		}

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

		internal static CraftResult? BeforeCraft(InventoryGui gui)
		{
			if ((Object)(object)_current == (Object)null || (Object)(object)_current._gui != (Object)(object)gui || (Object)(object)gui.m_craftRecipe == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return null;
			}
			string name = gui.m_craftRecipe.m_item.m_itemData.m_shared.m_name;
			return new CraftResult
			{
				Name = name,
				Upgrade = (gui.m_craftUpgradeItem != null),
				Before = OwnedQualities(name)
			};
		}

		private static Dictionary<int, int> OwnedQualities(string name)
		{
			return (from i in ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems()
				where i.m_shared.m_name == name
				group i by i.m_quality).ToDictionary((IGrouping<int, ItemData> g) => g.Key, (IGrouping<int, ItemData> g) => g.Sum((ItemData i) => i.m_stack));
		}

		internal static void AfterCraft(InventoryGui gui, CraftResult? result)
		{
			if (result == null || (Object)(object)_current == (Object)null || (Object)(object)_current._gui != (Object)(object)gui || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			Dictionary<int, int> dictionary = OwnedQualities(result.Name);
			string text = CraftingBridge.ResultText(result.Name, result.Upgrade, result.Before, dictionary);
			if (_current._batch.Active)
			{
				bool flag = dictionary.Values.Sum() > result.Before.Values.Sum();
				_current._pendingCraft = _current._batch.Complete(flag);
				text = (_current._batch.Active ? "Batch · " : (flag ? "Batch complete · " : "Batch stopped · ")) + _current._batch.Completed + " / " + _current._batch.Total + " crafts completed";
				_current._nextMaximum = 0f;
				if (!_current._batch.Active)
				{
					_current._batchChoice = null;
				}
			}
			_current.Message(text);
			_current._next = 0f;
			_current._nextPreview = 0f;
			_current._bagStamp = "";
		}

		private void Repair()
		{
			_gui.UpdateRepair();
			if (!Busy && ((Component)_gui.m_repairButton).gameObject.activeSelf && ((Selectable)_gui.m_repairButton).interactable)
			{
				_gui.OnRepairPressed();
				_bagStamp = "";
				_nextPreview = 0f;
				Refresh();
				EventSystem current = EventSystem.current;
				if (current != null)
				{
					current.SetSelectedGameObject(((Selectable)_repair).interactable ? ((Component)_repair).gameObject : ((Component)_tabs[_tab]).gameObject);
				}
			}
		}

		private void UpdateNavigation()
		{
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0342: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0399: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_043b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0537: Unknown result type (might be due to invalid IL or missing references)
			//IL_049d: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0559: Unknown result type (might be due to invalid IL or missing references)
			//IL_055e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0573: Unknown result type (might be due to invalid IL or missing references)
			//IL_0582: Unknown result type (might be due to invalid IL or missing references)
			//IL_05cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_05de: Unknown result type (might be due to invalid IL or missing references)
			//IL_061b: Unknown result type (might be due to invalid IL or missing references)
			//IL_062a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0677: Unknown result type (might be due to invalid IL or missing references)
			//IL_0686: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0761: Unknown result type (might be due to invalid IL or missing references)
			//IL_0770: Unknown result type (might be due to invalid IL or missing references)
			//IL_07c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_07de: Unknown result type (might be due to invalid IL or missing references)
			//IL_085f: Unknown result type (might be due to invalid IL or missing references)
			Button val = ((IEnumerable<Button>)_rows).FirstOrDefault((Func<Button, bool>)((Button r) => ((Component)r).gameObject.activeSelf && ((Selectable)r).interactable));
			List<Button> list = (from s in _slots
				where s.activeSelf
				select s.GetComponent<Button>()).ToList();
			Button val2 = list.FirstOrDefault();
			Button val3 = ((((Component)_action).gameObject.activeSelf && ((Selectable)_action).interactable) ? _action : _cancel);
			Navigation navigation;
			for (int num = 0; num < _tabs.Count; num++)
			{
				Button obj = _tabs[num];
				navigation = default(Navigation);
				((Navigation)(ref navigation)).mode = (Mode)4;
				((Navigation)(ref navigation)).selectOnLeft = (Selectable)(object)((num > 0) ? _tabs[num - 1] : null);
				((Navigation)(ref navigation)).selectOnRight = (Selectable)(object)((num + 1 < _tabs.Count) ? _tabs[num + 1] : null);
				((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)(val ?? val3);
				((Selectable)obj).navigation = navigation;
			}
			Navigation navigation2 = ((Selectable)_tabs[0]).navigation;
			((Navigation)(ref navigation2)).selectOnDown = (Selectable)(object)_search;
			((Selectable)_tabs[0]).navigation = navigation2;
			InputField search = _search;
			navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)4;
			((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)_tabs[_tab];
			((Navigation)(ref navigation)).selectOnDown = (Selectable)((_tab == 2) ? ((object)(val ?? val3)) : ((object)_filters[0]));
			((Navigation)(ref navigation)).selectOnRight = (Selectable)(((Component)_saveButton).gameObject.activeSelf ? ((object)_saveButton) : ((object)val3));
			((Selectable)search).navigation = navigation;
			for (int num2 = 0; num2 < _filters.Count; num2++)
			{
				Button obj2 = _filters[num2];
				navigation = default(Navigation);
				((Navigation)(ref navigation)).mode = (Mode)4;
				((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)_search;
				((Navigation)(ref navigation)).selectOnLeft = (Selectable)(object)((num2 > 0) ? _filters[num2 - 1] : null);
				((Navigation)(ref navigation)).selectOnRight = (Selectable)((num2 + 1 < _filters.Count) ? ((object)_filters[num2 + 1]) : ((object)val3));
				((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)_sortButton;
				((Selectable)obj2).navigation = navigation;
			}
			Button sortButton = _sortButton;
			navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)4;
			((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)_filters[0];
			((Navigation)(ref navigation)).selectOnRight = (Selectable)(object)_savedOnlyButton;
			((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)(val ?? val3);
			((Selectable)sortButton).navigation = navigation;
			Button savedOnlyButton = _savedOnlyButton;
			navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)4;
			((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)_filters[2];
			((Navigation)(ref navigation)).selectOnLeft = (Selectable)(object)_sortButton;
			((Navigation)(ref navigation)).selectOnRight = (Selectable)(object)val3;
			((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)(val ?? val3);
			((Selectable)savedOnlyButton).navigation = navigation;
			Button saveButton = _saveButton;
			navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)4;
			((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)_tabs[_tab];
			((Navigation)(ref navigation)).selectOnLeft = (Selectable)(((object)val) ?? ((object)_search));
			((Navigation)(ref navigation)).selectOnRight = (Selectable)(object)val3;
			((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)val3;
			((Selectable)saveButton).navigation = navigation;
			Button variant = _variant;
			navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)4;
			((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)(((Component)_saveButton).gameObject.activeSelf ? _saveButton : _tabs[_tab]);
			((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)val3;
			((Navigation)(ref navigation)).selectOnLeft = (Selectable)(((object)val) ?? ((object)_search));
			((Selectable)variant).navigation = navigation;
			List<Button> list2 = _rows.Where((Button r) => ((Component)r).gameObject.activeSelf && ((Selectable)r).interactable).ToList();
			for (int num3 = 0; num3 < list2.Count; num3++)
			{
				Button obj3 = list2[num3];
				navigation = default(Navigation);
				((Navigation)(ref navigation)).mode = (Mode)4;
				((Navigation)(ref navigation)).selectOnUp = (Selectable)((num3 > 0) ? ((object)list2[num3 - 1]) : ((object)_tabs[_tab]));
				((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)((num3 + 1 < list2.Count) ? list2[num3 + 1] : val3);
				((Navigation)(ref navigation)).selectOnRight = (Selectable)(object)val3;
				((Selectable)obj3).navigation = navigation;
			}
			Button action = _action;
			navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)4;
			((Navigation)(ref navigation)).selectOnLeft = (Selectable)(object)(val ?? _tabs[_tab]);
			((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)((((Component)_variant).gameObject.activeSelf && ((Selectable)_variant).interactable) ? _variant : _tabs[_tab]);
			((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)_cancel;
			((Selectable)action).navigation = navigation;
			if (((Component)_amount).gameObject.activeSelf)
			{
				Navigation navigation3 = ((Selectable)_action).navigation;
				((Navigation)(ref navigation3)).selectOnUp = (Selectable)(object)_amount;
				((Selectable)_action).navigation = navigation3;
				Button less = _less;
				navigation = default(Navigation);
				((Navigation)(ref navigation)).mode = (Mode)4;
				((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)_saveButton;
				((Navigation)(ref navigation)).selectOnRight = (Selectable)(object)_amount;
				((Navigation)(ref navigation)).selectOnLeft = (Selectable)(object)(val ?? _tabs[_tab]);
				((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)val3;
				((Selectable)less).navigation = navigation;
				InputField amount = _amount;
				navigation = default(Navigation);
				((Navigation)(ref navigation)).mode = (Mode)4;
				((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)_saveButton;
				((Navigation)(ref navigation)).selectOnLeft = (Selectable)(object)_less;
				((Navigation)(ref navigation)).selectOnRight = (Selectable)(object)_more;
				((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)val3;
				((Selectable)amount).navigation = navigation;
				Button more = _more;
				navigation = default(Navigation);
				((Navigation)(ref navigation)).mode = (Mode)4;
				((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)_saveButton;
				((Navigation)(ref navigation)).selectOnLeft = (Selectable)(object)_amount;
				((Navigation)(ref navigation)).selectOnRight = (Selectable)(((Selectable)_max).interactable ? ((object)_max) : ((object)val3));
				((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)val3;
				((Selectable)more).navigation = navigation;
				Button max = _max;
				navigation = default(Navigation);
				((Navigation)(ref navigation)).mode = (Mode)4;
				((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)_saveButton;
				((Navigation)(ref navigation)).selectOnLeft = (Selectable)(object)_more;
				((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)val3;
				((Selectable)max).navigation = navigation;
			}
			Button cancel = _cancel;
			navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)4;
			((Navigation)(ref navigation)).selectOnLeft = (Selectable)(object)(val ?? _tabs[_tab]);
			((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)(((Selectable)_action).interactable ? _action : _tabs[_tab]);
			((Navigation)(ref navigation)).selectOnDown = (Selectable)((((Component)_repair).gameObject.activeSelf && ((Selectable)_repair).interactable) ? ((object)_repair) : ((object)(val2 ?? _tabs[_tab])));
			((Selectable)cancel).navigation = navigation;
			Button repair = _repair;
			navigation = default(Navigation);
			((Navigation)(ref navigation)).mode = (Mode)4;
			((Navigation)(ref navigation)).selectOnLeft = (Selectable)(object)(val ?? _tabs[_tab]);
			((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)_cancel;
			((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)(val2 ?? _tabs[_tab]);
			((Selectable)repair).navigation = navigation;
			for (int num4 = 0; num4 < list.Count; num4++)
			{
				Button obj4 = list[num4];
				navigation = default(Navigation);
				((Navigation)(ref navigation)).mode = (Mode)4;
				((Navigation)(ref navigation)).selectOnUp = (Selectable)(object)_cancel;
				((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)_tabs[_tab];
				((Navigation)(ref navigation)).selectOnLeft = (Selectable)((num4 > 0) ? ((object)list[num4 - 1]) : ((object)_tabs[_tab]));
				((Navigation)(ref navigation)).selectOnRight = (Selectable)((num4 + 1 < list.Count) ? ((object)list[num4 + 1]) : ((object)_cancel));
				((Selectable)obj4).navigation = navigation;
			}
			EventSystem current = EventSystem.current;
			GameObject val4 = ((current != null) ? current.currentSelectedGameObject : null);
			if (!((Object)(object)val4 != (Object)null) || !val4.transform.IsChildOf(((Component)this).transform))
			{
				return;
			}
			if (val4.activeInHierarchy)
			{
				Selectable component = val4.GetComponent<Selectable>();
				if (component == null || component.interactable)
				{
					return;
				}
			}
			EventSystem current2 = EventSystem.current;
			if (current2 != null)
			{
				current2.SetSelectedGameObject(Busy ? ((Component)_cancel).gameObject : ((Component)_tabs[_tab]).gameObject);
			}
		}

		private void EnsureFocusedVisible()
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			EventSystem current = EventSystem.current;
			GameObject current2 = ((current != null) ? current.currentSelectedGameObject : null);
			if ((Object)(object)current2 == (Object)null)
			{
				return;
			}
			int num = _rows.FindIndex((Button b) => (Object)(object)((Component)b).gameObject == (Object)(object)current2);
			if (num < 0)
			{
				return;
			}
			if (!((Component)_rows[num]).gameObject.activeInHierarchy)
			{
				EventSystem current3 = EventSystem.current;
				if (current3 != null)
				{
					current3.SetSelectedGameObject(((Component)_tabs[_tab]).gameObject);
				}
				return;
			}
			float num2 = (float)num * 76f;
			float num3 = ((ScrollRect)_browser).content.anchoredPosition.y;
			if (num2 < num3)
			{
				num3 = num2;
			}
			else
			{
				float num4 = num2 + 72f;
				float num5 = num3;
				Rect rect = ((ScrollRect)_browser).viewport.rect;
				if (num4 > num5 + ((Rect)(ref rect)).height)
				{
					float num6 = num2 + 72f;
					rect = ((ScrollRect)_browser).viewport.rect;
					num3 = num6 - ((Rect)(ref rect)).height;
				}
			}
			if (!Mathf.Approximately(num3, ((ScrollRect)_browser).content.anchoredPosition.y))
			{
				_browser.CancelWheel();
				((ScrollRect)_browser).content.anchoredPosition = new Vector2(0f, num3);
			}
		}

		private static void Caption(Button button, string caption)
		{
			((Component)button).GetComponentInChildren<Text>().text = caption;
		}

		private void Build()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: 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_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: 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)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0320: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0377: Unknown result type (might be due to invalid IL or missing references)
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_042c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0475: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04af: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0525: Unknown result type (might be due to invalid IL or missing references)
			//IL_0580: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0604: Unknown result type (might be due to invalid IL or missing references)
			//IL_0654: Unknown result type (might be due to invalid IL or missing references)
			//IL_0682: Unknown result type (might be due to invalid IL or missing references)
			//IL_0688: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0737: Unknown result type (might be due to invalid IL or missing references)
			//IL_073d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0768: Unknown result type (might be due to invalid IL or missing references)
			//IL_076e: Unknown result type (might be due to invalid IL or missing references)
			//IL_079b: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0840: Unknown result type (might be due to invalid IL or missing references)
			//IL_0880: Unknown result type (might be due to invalid IL or missing references)
			//IL_08b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_08e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_090d: Unknown result type (might be due to invalid IL or missing references)
			_frame = new UiKitWindow(((Component)this).transform, "Crafting", new Vector2(1280f, 720f), delegate
			{
				Close(hideInventory: true);
			});
			string[] array = new string[3] { "Craft", "Upgrade", "Stations" };
			for (int num = 0; num < array.Length; num++)
			{
				int tab = num;
				_tabs.Add(_frame.Tab(array[num], new Rect((float)(650 + num * 144), 30f, 132f, 38f), delegate
				{
					SelectTab(tab);
				}));
			}
			_search = UiKitApi.Field((Transform)(object)_frame.Sheet, "Search…", new Rect(28f, 130f, 252f, 40f));
			((UnityEvent<string>)(object)_search.onValueChanged).AddListener((UnityAction<string>)delegate(string value)
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				_query = value;
				Refresh();
				RestlessScrollRect browser = _browser;
				Rect rect = ((ScrollRect)_browser).content.rect;
				UiKitApi.SizeReader(browser, ((Rect)(ref rect)).height, reset: true);
			});
			string[] array2 = new string[3] { "All", "Equipment", "Other" };
			for (int num2 = 0; num2 < array2.Length; num2++)
			{
				string filter = array2[num2];
				_filters.Add(UiKitApi.Button((Transform)(object)_frame.Sheet, filter, new Rect((float)(28 + num2 * 84), 178f, 80f, 32f), delegate
				{
					//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)
					_category = filter;
					Refresh();
					RestlessScrollRect browser = _browser;
					Rect rect = ((ScrollRect)_browser).content.rect;
					UiKitApi.SizeReader(browser, ((Rect)(ref rect)).height, reset: true);
				}));
			}
			_browser = UiKitApi.Reader((Transform)(object)_frame.Sheet, "craft-browser", new Rect(28f, 222f, 252f, 430f), 76f);
			_heading = UiKitWindow.Label((Transform)(object)_frame.Sheet, "", 27, new Rect(310f, 132f, 560f, 48f));
			RestlessUi.BoundedLabel(_heading, 27, 22);
			_feature = RestlessUi.Tray((Transform)(object)_frame.Sheet, "selected-item-feature");
			UiKitApi.Surface(_feature);
			_portraitFrame = RestlessUi.Graphic(_feature.transform, "portrait-frame", Color.white, raycast: false);
			UiKitAssets.Apply(_portraitFrame.GetComponent<Image>(), UiKitAsset.Portrait);
			_portrait = RestlessUi.Graphic(_feature.transform, "craft-portrait", Color.white, raycast: false).GetComponent<Image>();
			_portrait.preserveAspect = true;
			_heroMeta = UiKitWindow.Label(_feature.transform, "", 22, default(Rect));
			RestlessUi.BoundedLabel(_heroMeta, 22, 18);
			_heroNote = UiKitWindow.Label(_feature.transform, "", 18, default(Rect), muted: true);
			_saveButton = UiKitApi.Button(_feature.transform, "Save recipe", default(Rect), delegate
			{
				if (_choice != null)
				{
					string name = ((Object)_choice.Recipe).name;
					if (!_saved.Remove(name))
					{
						_saved.Add(name);
					}
					ModConfig.CraftingSavedRecipes.Value = string.Join("|", _saved.OrderBy((string n) => n));
					_rowStamp = "";
					Refresh();
				}
			});
			_sortButton = UiKitApi.Button((Transform)(object)_frame.Sheet, "Sort: native", default(Rect), delegate
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				_sort = (_sort + 1) % 3;
				Refresh();
				RestlessScrollRect browser = _browser;
				Rect rect = ((ScrollRect)_browser).content.rect;
				UiKitApi.SizeReader(browser, ((Rect)(ref rect)).height, reset: true);
			});
			_savedOnlyButton = UiKitApi.Button((Transform)(object)_frame.Sheet, "All recipes", default(Rect), delegate
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				_savedOnly = !_savedOnly;
				Refresh();
				RestlessScrollRect browser = _browser;
				Rect rect = ((ScrollRect)_browser).content.rect;
				UiKitApi.SizeReader(browser, ((Rect)(ref rect)).height, reset: true);
			});
			_detail = UiKitApi.Reader((Transform)(object)_frame.Sheet, "craft-details", new Rect(310f, 360f, 560f, 292f), 42f);
			_copy = UiKitWindow.Label((Transform)(object)((ScrollRect)_detail).content, "", 18, new Rect(0f, 0f, 530f, 100f));
			_copy.supportRichText = true;
			_copy.alignment = (TextAnchor)0;
			_copy.verticalOverflow = (VerticalWrapMode)1;
			_statHeader = UiKitWindow.Label((Transform)(object)((ScrollRect)_detail).content, "", 14, default(Rect), muted: true);
			_context = UiKitWindow.Label((Transform)(object)_frame.Sheet, "Required materials", 22, new Rect(906f, 132f, 326f, 36f));
			_requirements = UiKitApi.Reader((Transform)(object)_frame.Sheet, "craft-requirements", new Rect(906f, 180f, 326f, 268f), 50f);
			_needs = UiKitWindow.Label((Transform)(object)((ScrollRect)_requirements).content, "", 18, new Rect(0f, 0f, 302f, 100f));
			_needs.supportRichText = true;
			_needs.alignment = (TextAnchor)0;
			_needs.verticalOverflow = (VerticalWrapMode)1;
			_reason = UiKitWindow.Label((Transform)(object)_frame.Sheet, "", 18, new Rect(906f, 462f, 326f, 64f));
			RestlessUi.BoundedLabel(_reason, 18, 16);
			_variant = UiKitApi.Button((Transform)(object)_frame.Sheet, "Change style", new Rect(906f, 534f, 326f, 36f), delegate
			{
				int num4 = (_choice?.Recipe.m_item.m_itemData)?.m_shared.m_variants ?? 0;
				if (num4 > 0 && _gui.m_craftTimer < 0f)
				{
					_gui.OnVariantSelected((_gui.m_selectedVariant + 1) % num4);
					Refresh();
				}
			});
			_action = UiKitApi.Button((Transform)(object)_frame.Sheet, "Craft", new Rect(906f, 600f, 326f, 48f), Act);
			UiKitApi.ActionSurface(((Component)_action).gameObject);
			_cancel = UiKitApi.Button((Transform)(object)_frame.Sheet, "Your full inventory", new Rect(906f, 660f, 326f, 40f), delegate
			{
				if (Busy)
				{
					CancelCraft();
				}
				else
				{
					Close(hideInventory: false);
				}
			});
			_repair = UiKitApi.Button((Transform)(object)_frame.Sheet, "Repair equipment", default(Rect), Repair);
			_less = UiKitApi.Button((Transform)(object)_frame.Sheet, "−", default(Rect), delegate
			{
				Quantity(_quantity - 1);
			});
			_amount = UiKitApi.Field((Transform)(object)_frame.Sheet, "Crafts", default(Rect));
			_amount.contentType = (ContentType)2;
			((UnityEvent<string>)(object)_amount.onEndEdit).AddListener((UnityAction<string>)delegate(string value)
			{
				Quantity((!int.TryParse(value, out var result)) ? 1 : result);
				_amount.SetTextWithoutNotify(_quantity.ToString());
			});
			_more = UiKitApi.Button((Transform)(object)_frame.Sheet, "+", default(Rect), delegate
			{
				Quantity(_quantity + 1);
			});
			_max = UiKitApi.Button((Transform)(object)_frame.Sheet, "Max", default(Rect), delegate
			{
				Quantity(Math.Max(1, _maximum));
			});
			_batchLabel = UiKitWindow.Label((Transform)(object)_frame.Sheet, "Batches", 13, default(Rect), muted: true);
			((Component)_max).gameObject.AddComponent<RestlessHint>().Copy = "Up to 99 normal crafts, based on current materials and output space. Each craft rechecks requirements. Cancellation keeps completed items; closing stops the queue. Nearby storage follows your existing settings.";
			((Component)_amount).gameObject.AddComponent<RestlessHint>().Copy = "Number of crafts, not output items. Materials and output show the selected total. Equipment upgrades remain one at a time.";
			((Component)_variant).transform.SetParent(_feature.transform, false);
			_progress = UiKitApi.Progress((Transform)(object)_frame.Sheet);
			_bag = UiKitWindow.Label((Transform)(object)_frame.Sheet, "", 17, new Rect(28f, 670f, 842f, 34f), muted: true);
			for (int num3 = 0; num3 < 10; num3++)
			{
				Button val = UiKitApi.Button((Transform)(object)_frame.Sheet, "", new Rect((float)(28 + num3 * 82), 718f, 72f, 64f), delegate
				{
				});
				GameOb