Decompiled source of CraftGuard v0.2.6

CraftGuard.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using InventoryUX.Core;
using InventoryUX.Runtime;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("CraftGuard")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.6.0")]
[assembly: AssemblyInformationalVersion("0.2.6+4807ce4e5136cb9a3af66b32700723df8c59a61d")]
[assembly: AssemblyProduct("CraftGuard")]
[assembly: AssemblyTitle("CraftGuard")]
[assembly: AssemblyVersion("0.2.6.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace InventoryUX
{
	[BepInPlugin("com.inventoryux.valheim", "CraftGuard", "0.2.6")]
	public sealed class Plugin : BaseUnityPlugin
	{
		internal const string PluginGuid = "com.inventoryux.valheim";

		internal const string PluginName = "CraftGuard";

		internal const string PluginVersion = "0.2.6";

		private Harmony? _harmony;

		internal static ManualLogSource LogInstance { get; private set; }

		internal static Plugin Instance { get; private set; }

		private void Awake()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			Instance = this;
			LogInstance = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony("com.inventoryux.valheim");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"CraftGuard 0.2.6 loaded. Undiscovered content is never rendered.");
		}

		private void OnDestroy()
		{
			Cleanup("Hammer UI", HammerGroupDecorations.Shutdown);
			Cleanup("Hammer sizing", HammerGridSizer.Restore);
			Cleanup("Hammer caches", HammerOrganizer.Reset);
			Cleanup("recipe UI", RecipeOrganizer.Shutdown);
			Cleanup("food cache", FoodStatsResolver.Reset);
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private static void Cleanup(string name, Action action)
		{
			try
			{
				action();
			}
			catch (Exception arg)
			{
				LogInstance.LogWarning((object)$"CraftGuard could not fully release {name} during shutdown: {arg}");
			}
		}
	}
}
namespace InventoryUX.Runtime
{
	internal enum CraftingSection
	{
		Workbench,
		Forge,
		Cooking,
		Advanced,
		Processing,
		Utility
	}
	internal readonly struct CraftingPieceLayout
	{
		internal CraftingSection Section { get; }

		internal int SortOrder { get; }

		internal int Subgroup { get; }

		internal bool IsPrimaryStation { get; }

		internal CraftingPieceLayout(CraftingSection section, int sortOrder, int subgroup, bool isPrimaryStation = false)
		{
			Section = section;
			SortOrder = sortOrder;
			Subgroup = subgroup;
			IsPrimaryStation = isPrimaryStation;
		}
	}
	internal static class CraftingLayoutMetadata
	{
		private readonly struct PieceRule
		{
			internal CraftingPieceLayout Layout { get; }

			private string[] Markers { get; }

			internal PieceRule(CraftingPieceLayout layout, string[] markers)
			{
				Layout = layout;
				Markers = markers;
			}

			internal bool Matches(string id)
			{
				for (int i = 0; i < Markers.Length; i++)
				{
					if (id.Contains(Markers[i]))
					{
						return true;
					}
				}
				return false;
			}
		}

		private static readonly PieceRule[] Rules = new PieceRule[46]
		{
			Rule(CraftingSection.Workbench, 110, 0, "choppingblock"),
			Rule(CraftingSection.Workbench, 120, 0, "tanningrack"),
			Rule(CraftingSection.Workbench, 130, 0, "adze"),
			Rule(CraftingSection.Workbench, 140, 0, "toolshelf"),
			Rule(CraftingSection.Workbench, 100, 0, true, "workbench"),
			Rule(CraftingSection.Forge, 210, 0, "forgebellows", "bellows"),
			Rule(CraftingSection.Forge, 220, 0, "anvils"),
			Rule(CraftingSection.Forge, 230, 0, "grindingwheel"),
			Rule(CraftingSection.Forge, 240, 0, "smithsanvil"),
			Rule(CraftingSection.Forge, 250, 0, "forgecooler"),
			Rule(CraftingSection.Forge, 260, 0, "forgetoolrack", "toolrack"),
			Rule(CraftingSection.Forge, 100, 0, true, "forge"),
			Rule(CraftingSection.Cooking, 110, 0, "spicerack"),
			Rule(CraftingSection.Cooking, 120, 0, "butcherstable", "butchertable"),
			Rule(CraftingSection.Cooking, 130, 0, "potsandpans"),
			Rule(CraftingSection.Cooking, 140, 0, "mortarandpestle", "mortar"),
			Rule(CraftingSection.Cooking, 150, 0, "rollingpin", "cuttingboard"),
			Rule(CraftingSection.Cooking, 400, 3, true, "meadketill", "meadkettle", "ketill", "kettle"),
			Rule(CraftingSection.Cooking, 410, 3, "fermenter", "fermentationbarrel"),
			Rule(CraftingSection.Cooking, 100, 0, true, "cauldron"),
			Rule(CraftingSection.Cooking, 210, 1, "ironcookingstation", "cookingstationiron"),
			Rule(CraftingSection.Cooking, 200, 1, true, "cookingstation"),
			Rule(CraftingSection.Cooking, 300, 2, true, "foodpreparation", "foodprep", "preptable"),
			Rule(CraftingSection.Cooking, 310, 2, "stoneoven", "oven"),
			Rule(CraftingSection.Advanced, 110, 0, "artisanpress"),
			Rule(CraftingSection.Advanced, 100, 0, true, "artisantable", "artisan"),
			Rule(CraftingSection.Advanced, 210, 1, "blackforgecooler"),
			Rule(CraftingSection.Advanced, 200, 1, true, "blackforge"),
			Rule(CraftingSection.Advanced, 300, 2, "gemcutter"),
			Rule(CraftingSection.Advanced, 310, 2, "metalcutter"),
			Rule(CraftingSection.Advanced, 320, 2, "vice", "vise"),
			Rule(CraftingSection.Advanced, 410, 3, "unfadingcandles"),
			Rule(CraftingSection.Advanced, 420, 3, "featherywreath", "wreath"),
			Rule(CraftingSection.Advanced, 430, 3, "runetable"),
			Rule(CraftingSection.Advanced, 400, 3, true, "galdrtable", "galdr"),
			Rule(CraftingSection.Processing, 100, 0, "charcoalkiln", "kiln"),
			Rule(CraftingSection.Processing, 110, 0, "smelter"),
			Rule(CraftingSection.Processing, 120, 0, "blastfurnace"),
			Rule(CraftingSection.Processing, 130, 0, "windmill"),
			Rule(CraftingSection.Processing, 140, 0, "spinningwheel"),
			Rule(CraftingSection.Processing, 150, 0, "sapextractor", "sapcollector"),
			Rule(CraftingSection.Processing, 160, 0, "obliterator", "incinerator"),
			Rule(CraftingSection.Processing, 170, 0, "eitrrefinery", "refineryeitr"),
			Rule(CraftingSection.Utility, 100, 0, "stonecutter"),
			Rule(CraftingSection.Utility, 110, 0, "beehive"),
			Rule(CraftingSection.Utility, 120, 0, "wispfountain")
		};

		internal static CraftingPieceLayout Resolve(Piece piece)
		{
			string text = Normalize(HammerOrganizer.GetLabel(piece, (PieceCategory)1));
			string text2 = ((Localization.instance != null) ? Localization.instance.Localize(piece.m_name) : piece.m_name);
			string text3 = Normalize(text + " " + ((Object)((Component)piece).gameObject).name + " " + piece.m_name + " " + text2);
			if (ContainsAny(text3, "eitrrefinery", "refineryeitr"))
			{
				return ResolveWithin(text3, CraftingSection.Processing, 170, 0);
			}
			if (text.Contains("workbench"))
			{
				return ResolveWithin(text3, CraftingSection.Workbench, 900, 1);
			}
			if (text.Contains("artisan"))
			{
				return ResolveWithin(text3, CraftingSection.Advanced, 900, 0);
			}
			if (text.Contains("blackforge"))
			{
				return ResolveWithin(text3, CraftingSection.Advanced, 900, 1);
			}
			if (text.Contains("galdr"))
			{
				return ResolveWithin(text3, CraftingSection.Advanced, 900, 3);
			}
			if (text.Contains("forge"))
			{
				return ResolveWithin(text3, CraftingSection.Forge, 900, 1);
			}
			if (ContainsAny(text, "cauldron", "foodpreparation", "foodprep", "preptable", "cooking"))
			{
				return ResolveWithin(text3, CraftingSection.Cooking, 900, 3);
			}
			if (ContainsAny(text, "mead", "ketill", "kettle", "brewing"))
			{
				return ResolveWithin(text3, CraftingSection.Cooking, 900, 3);
			}
			for (int i = 0; i < Rules.Length; i++)
			{
				if (Rules[i].Matches(text3))
				{
					return Rules[i].Layout;
				}
			}
			return new CraftingPieceLayout(CraftingSection.Utility, 900, 9);
		}

		internal static string Label(CraftingSection section)
		{
			return section switch
			{
				CraftingSection.Workbench => "WORKBENCH", 
				CraftingSection.Forge => "FORGE", 
				CraftingSection.Cooking => "COOKING", 
				CraftingSection.Advanced => "ADVANCED", 
				CraftingSection.Processing => "PROCESSING", 
				_ => "UTILITY", 
			};
		}

		internal static bool IsRepair(Piece piece)
		{
			if (piece.m_repairPiece)
			{
				return true;
			}
			string text = Normalize(((Object)((Component)piece).gameObject).name);
			string text2 = Normalize(piece.m_name);
			switch (text)
			{
			default:
				if (!(text2 == "repair"))
				{
					return text2 == "piecerepair";
				}
				break;
			case "repair":
			case "piecerepair":
			case "hammerrepair":
			case "repairpiece":
				break;
			}
			return true;
		}

		private static CraftingPieceLayout ResolveWithin(string id, CraftingSection section, int fallbackOrder, int fallbackSubgroup)
		{
			for (int i = 0; i < Rules.Length; i++)
			{
				PieceRule pieceRule = Rules[i];
				if (pieceRule.Layout.Section == section && pieceRule.Matches(id))
				{
					return pieceRule.Layout;
				}
			}
			return new CraftingPieceLayout(section, fallbackOrder, fallbackSubgroup);
		}

		private static PieceRule Rule(CraftingSection section, int order, int subgroup, params string[] markers)
		{
			return new PieceRule(new CraftingPieceLayout(section, order, subgroup), markers);
		}

		private static PieceRule Rule(CraftingSection section, int order, int subgroup, bool primary, params string[] markers)
		{
			return new PieceRule(new CraftingPieceLayout(section, order, subgroup, primary), markers);
		}

		private static bool ContainsAny(string value, params string[] markers)
		{
			for (int i = 0; i < markers.Length; i++)
			{
				if (value.Contains(markers[i]))
				{
					return true;
				}
			}
			return false;
		}

		private static string Normalize(string? value)
		{
			if (string.IsNullOrEmpty(value))
			{
				return string.Empty;
			}
			char[] array = new char[value.Length];
			int length = 0;
			foreach (char c in value)
			{
				if (char.IsLetterOrDigit(c))
				{
					array[length++] = char.ToLower(c, CultureInfo.InvariantCulture);
				}
			}
			return new string(array, 0, length);
		}
	}
	internal static class DataInventoryWriter
	{
		private static bool _written;

		internal static void TryWriteOnce()
		{
			if (_written || (Object)(object)ObjectDB.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			try
			{
				string text = Path.Combine(Paths.ConfigPath, "CraftGuard");
				Directory.CreateDirectory(text);
				string text2 = Path.Combine(text, "loaded-data-inventory.csv");
				File.WriteAllText(text2, BuildCsv(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: true));
				_written = true;
				Plugin.LogInstance.LogInfo((object)("Wrote the loaded piece/recipe inventory to " + text2));
			}
			catch (Exception arg)
			{
				_written = true;
				Plugin.LogInstance.LogError((object)$"Could not write the data inventory: {arg}");
			}
		}

		private static string BuildCsv()
		{
			StringBuilder stringBuilder = new StringBuilder();
			WriteRow(stringBuilder, "ContentType", "PrefabID", "DisplayName", "KnownUnlockMechanism", "HammerCategory", "PieceType", "CraftingStation", "StationExtensionParent", "StationLevelContribution", "ItemType", "WeaponFamily", "ArmorType", "Recipe", "Ingredients", "RequiredStation", "RequiredStationLevel", "FoodHP", "FoodStamina", "FoodEitr", "FoodDuration", "FoodRegen", "ProposedGroup", "ProposedBiome", "ProposedSortOrder");
			WritePieces(stringBuilder);
			WriteRecipes(stringBuilder);
			return stringBuilder.ToString();
		}

		private static void WritePieces(StringBuilder output)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			List<GameObject> prefabs = ZNetScene.instance.m_prefabs;
			for (int i = 0; i < prefabs.Count; i++)
			{
				GameObject val = prefabs[i];
				if (!((Object)(object)val == (Object)null))
				{
					Piece component = val.GetComponent<Piece>();
					if (!((Object)(object)component == (Object)null) && hashSet.Add(((Object)val).name))
					{
						CraftingStation component2 = val.GetComponent<CraftingStation>();
						StationExtension component3 = val.GetComponent<StationExtension>();
						PieceGroup pieceGroup = HammerOrganizer.Classify(component, component.m_category);
						string text = (((Object)(object)component2 != (Object)null) ? "Crafting station" : (((Object)(object)component3 != (Object)null) ? "Station extension" : "Build piece"));
						WriteRow(output, "Piece", ((Object)val).name, Localize(component.m_name), "Piece.m_name in Player.m_knownRecipes", ((object)Unsafe.As<PieceCategory, PieceCategory>(ref component.m_category)/*cast due to .constrained prefix*/).ToString(), text, ((Object)(object)component.m_craftingStation != (Object)null) ? Localize(component.m_craftingStation.m_name) : (((Object)(object)component2 != (Object)null) ? Localize(component2.m_name) : string.Empty), ((Object)(object)component3 != (Object)null && (Object)(object)component3.m_craftingStation != (Object)null) ? Localize(component3.m_craftingStation.m_name) : string.Empty, ((Object)(object)component3 != (Object)null) ? "Native unique attached extension (+1)" : string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, FormatPieceIngredients(component), string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, pieceGroup.Label, string.Empty, $"{pieceGroup.Order}:{pieceGroup.Suborder}");
					}
				}
			}
		}

		private static void WriteRecipes(StringBuilder output)
		{
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			List<Recipe> recipes = ObjectDB.instance.m_recipes;
			for (int i = 0; i < recipes.Count; i++)
			{
				Recipe val = recipes[i];
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.m_item == (Object)null))
				{
					SharedData shared = val.m_item.m_itemData.m_shared;
					RecipeFacts recipeFacts = ToFacts(val, i);
					RecipeGroup recipeGroup = (recipeFacts.IsFeast ? new RecipeGroup("Feasts", 4) : (recipeFacts.IsFood ? FoodClassifier.ToGroup(FoodClassifier.Classify(recipeFacts.Health, recipeFacts.Stamina, recipeFacts.Eitr)) : RecipeClassifier.GetTypeGroup(recipeFacts)));
					ProgressionBiome biome = BiomeClassifier.Classify(recipeFacts.Id, recipeFacts.IngredientIds);
					WriteRow(output, "Recipe", recipeFacts.Id, recipeFacts.DisplayName, "Player.GetAvailableRecipes / Player.IsRecipeKnown", string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, ((object)Unsafe.As<ItemType, ItemType>(ref shared.m_itemType)/*cast due to .constrained prefix*/).ToString(), ((object)Unsafe.As<SkillType, SkillType>(ref shared.m_skillType)/*cast due to .constrained prefix*/).ToString(), ArmorType(shared.m_itemType), ((Object)val).name, FormatRecipeIngredients(val), ((Object)(object)val.m_craftingStation != (Object)null) ? Localize(val.m_craftingStation.m_name) : string.Empty, val.m_minStationLevel.ToString(CultureInfo.InvariantCulture), shared.m_food.ToString(CultureInfo.InvariantCulture), shared.m_foodStamina.ToString(CultureInfo.InvariantCulture), shared.m_foodEitr.ToString(CultureInfo.InvariantCulture), shared.m_foodBurnTime.ToString(CultureInfo.InvariantCulture), shared.m_foodRegen.ToString(CultureInfo.InvariantCulture), recipeGroup.Label, biome.ToString(), $"{BiomeClassifier.ToGroup(biome).Order}:{recipeGroup.Order}");
				}
			}
		}

		private static RecipeFacts ToFacts(Recipe recipe, int originalIndex)
		{
			SharedData shared = recipe.m_item.m_itemData.m_shared;
			List<string> list = new List<string>();
			if (recipe.m_resources != null)
			{
				for (int i = 0; i < recipe.m_resources.Length; i++)
				{
					ItemDrop val = recipe.m_resources[i]?.m_resItem;
					if (!((Object)(object)val == (Object)null))
					{
						list.Add(((Object)((Component)val).gameObject).name);
						list.Add(val.m_itemData.m_shared.m_name);
					}
				}
			}
			ResolvedFoodStats resolvedFoodStats = FoodStatsResolver.Resolve(recipe.m_item);
			float health = (resolvedFoodStats.Resolved ? resolvedFoodStats.Health : shared.m_food);
			float stamina = (resolvedFoodStats.Resolved ? resolvedFoodStats.Stamina : shared.m_foodStamina);
			float eitr = (resolvedFoodStats.Resolved ? resolvedFoodStats.Eitr : shared.m_foodEitr);
			return new RecipeFacts(((Object)((Component)recipe.m_item).gameObject).name, Localize(shared.m_name), ((object)Unsafe.As<ItemType, ItemType>(ref shared.m_itemType)/*cast due to .constrained prefix*/).ToString(), ((object)Unsafe.As<SkillType, SkillType>(ref shared.m_skillType)/*cast due to .constrained prefix*/).ToString(), list, health, stamina, eitr, originalIndex, resolvedFoodStats.IsFeast);
		}

		private static string FormatPieceIngredients(Piece piece)
		{
			if (piece.m_resources == null)
			{
				return string.Empty;
			}
			List<string> list = new List<string>();
			for (int i = 0; i < piece.m_resources.Length; i++)
			{
				Requirement val = piece.m_resources[i];
				if ((Object)(object)val?.m_resItem != (Object)null)
				{
					list.Add($"{Localize(val.m_resItem.m_itemData.m_shared.m_name)} x{val.m_amount}");
				}
			}
			return string.Join("; ", list);
		}

		private static string FormatRecipeIngredients(Recipe recipe)
		{
			if (recipe.m_resources == null)
			{
				return string.Empty;
			}
			List<string> list = new List<string>();
			for (int i = 0; i < recipe.m_resources.Length; i++)
			{
				Requirement val = recipe.m_resources[i];
				if ((Object)(object)val?.m_resItem != (Object)null)
				{
					list.Add($"{Localize(val.m_resItem.m_itemData.m_shared.m_name)} x{val.m_amount}");
				}
			}
			return string.Join("; ", list);
		}

		private static string ArmorType(ItemType itemType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected I4, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Invalid comparison between Unknown and I4
			switch (itemType - 6)
			{
			default:
				if ((int)itemType != 17)
				{
					break;
				}
				return "Shoulder";
			case 0:
				return "Helmet";
			case 1:
				return "Chest";
			case 5:
				return "Legs";
			case 6:
				return "Hands";
			case 2:
			case 3:
			case 4:
				break;
			}
			return string.Empty;
		}

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

		private static void WriteRow(StringBuilder output, params string[] values)
		{
			for (int i = 0; i < values.Length; i++)
			{
				if (i > 0)
				{
					output.Append(',');
				}
				output.Append(Escape(values[i]));
			}
			output.AppendLine();
		}

		private static string Escape(string? value)
		{
			value = value ?? string.Empty;
			if (value.IndexOfAny(new char[4] { ',', '"', '\r', '\n' }) < 0)
			{
				return value;
			}
			return "\"" + value.Replace("\"", "\"\"") + "\"";
		}
	}
	internal sealed class FailureCircuitBreaker
	{
		private readonly string _operation;

		private readonly float _retryDelaySeconds;

		private readonly float _logIntervalSeconds;

		private float _retryAfter;

		private float _nextLogAt;

		private int _suppressedFailures;

		internal bool IsOpen => Time.realtimeSinceStartup < _retryAfter;

		internal FailureCircuitBreaker(string operation, float retryDelaySeconds = 10f, float logIntervalSeconds = 60f)
		{
			_operation = operation;
			_retryDelaySeconds = retryDelaySeconds;
			_logIntervalSeconds = logIntervalSeconds;
		}

		internal void Reset()
		{
			_retryAfter = 0f;
		}

		internal void Trip(Exception exception)
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			_retryAfter = realtimeSinceStartup + _retryDelaySeconds;
			if (realtimeSinceStartup < _nextLogAt)
			{
				_suppressedFailures++;
				return;
			}
			string text = ((_suppressedFailures > 0) ? $" ({_suppressedFailures} repeated failures suppressed)" : string.Empty);
			_suppressedFailures = 0;
			_nextLogAt = realtimeSinceStartup + _logIntervalSeconds;
			Plugin.LogInstance.LogWarning((object)$"{_operation} paused for {_retryDelaySeconds:0} seconds after an error{text}: {exception}");
		}
	}
	internal static class FoodStatsResolver
	{
		private readonly struct FoodResolutionCacheEntry
		{
			internal ItemDrop Output { get; }

			internal ResolvedFoodStats Stats { get; }

			internal FoodResolutionCacheEntry(ItemDrop output, ResolvedFoodStats stats)
			{
				Output = output;
				Stats = stats;
			}
		}

		private static readonly Dictionary<string, ItemDrop> CookedByInput = new Dictionary<string, ItemDrop>(StringComparer.Ordinal);

		private static readonly Dictionary<string, ItemDrop> FeastFoodByInput = new Dictionary<string, ItemDrop>(StringComparer.Ordinal);

		private static readonly Dictionary<int, FoodResolutionCacheEntry> ResolutionByOutput = new Dictionary<int, FoodResolutionCacheEntry>();

		private static int _sceneInstanceId = int.MinValue;

		private static int _scenePrefabCount = -1;

		internal static void Reset()
		{
			CookedByInput.Clear();
			FeastFoodByInput.Clear();
			ResolutionByOutput.Clear();
			_sceneInstanceId = int.MinValue;
			_scenePrefabCount = -1;
		}

		internal static ResolvedFoodStats Resolve(ItemDrop output)
		{
			if (output == null || (Object)(object)output == (Object)null)
			{
				return default(ResolvedFoodStats);
			}
			bool flag = EnsureIndex();
			int instanceID = ((Object)output).GetInstanceID();
			if (ResolutionByOutput.TryGetValue(instanceID, out var value) && value.Output == output)
			{
				return value.Stats;
			}
			Feast val = ((Component)output).GetComponent<Feast>() ?? ((Component)output).GetComponentInChildren<Feast>(true);
			ItemDrop val2 = (((Object)(object)val != (Object)null) ? GetFeastFood(val) : null);
			if ((Object)(object)val2 != (Object)null)
			{
				ResolvedFoodStats resolvedFoodStats = FromItem(val2, resolved: true, isFeast: true);
				if (flag)
				{
					ResolutionByOutput[instanceID] = new FoodResolutionCacheEntry(output, resolvedFoodStats);
				}
				return resolvedFoodStats;
			}
			string name = ((Object)((Component)output).gameObject).name;
			if (FeastFoodByInput.TryGetValue(name, out ItemDrop value2) && (Object)(object)value2 != (Object)null)
			{
				ResolvedFoodStats resolvedFoodStats2 = FromItem(value2, resolved: true, isFeast: true);
				if (flag)
				{
					ResolutionByOutput[instanceID] = new FoodResolutionCacheEntry(output, resolvedFoodStats2);
				}
				return resolvedFoodStats2;
			}
			ItemDrop val3 = output;
			bool resolved = false;
			string b = null;
			string b2 = null;
			string b3 = null;
			string b4 = null;
			for (int i = 0; i < 4; i++)
			{
				string name2 = ((Object)((Component)val3).gameObject).name;
				if (string.Equals(name2, b, StringComparison.Ordinal) || string.Equals(name2, b2, StringComparison.Ordinal) || string.Equals(name2, b3, StringComparison.Ordinal) || string.Equals(name2, b4, StringComparison.Ordinal) || !CookedByInput.TryGetValue(name2, out ItemDrop value3) || (Object)(object)value3 == (Object)null)
				{
					break;
				}
				switch (i)
				{
				case 0:
					b = name2;
					break;
				case 1:
					b2 = name2;
					break;
				case 2:
					b3 = name2;
					break;
				default:
					b4 = name2;
					break;
				}
				val3 = value3;
				resolved = true;
			}
			ResolvedFoodStats resolvedFoodStats3 = FromItem(val3, resolved, isFeast: false);
			if (flag)
			{
				ResolutionByOutput[instanceID] = new FoodResolutionCacheEntry(output, resolvedFoodStats3);
			}
			return resolvedFoodStats3;
		}

		private static bool EnsureIndex()
		{
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Invalid comparison between Unknown and I4
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null || instance.m_prefabs == null)
			{
				return false;
			}
			int instanceID = ((Object)instance).GetInstanceID();
			int count = instance.m_prefabs.Count;
			if (_sceneInstanceId == instanceID && _scenePrefabCount == count)
			{
				return true;
			}
			Reset();
			_sceneInstanceId = instanceID;
			_scenePrefabCount = count;
			for (int i = 0; i < instance.m_prefabs.Count; i++)
			{
				GameObject val = instance.m_prefabs[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				CookingStation[] componentsInChildren = val.GetComponentsInChildren<CookingStation>(true);
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					List<ItemConversion> conversion = componentsInChildren[j].m_conversion;
					if (conversion == null)
					{
						continue;
					}
					for (int k = 0; k < conversion.Count; k++)
					{
						ItemConversion val2 = conversion[k];
						if (!((Object)(object)val2?.m_from == (Object)null) && !((Object)(object)val2.m_to == (Object)null))
						{
							string name = ((Object)((Component)val2.m_from).gameObject).name;
							if (!CookedByInput.ContainsKey(name))
							{
								CookedByInput.Add(name, val2.m_to);
							}
						}
					}
				}
				Feast[] componentsInChildren2 = val.GetComponentsInChildren<Feast>(true);
				foreach (Feast val3 in componentsInChildren2)
				{
					Piece val4 = ((Component)val3).GetComponent<Piece>() ?? ((Component)val3).GetComponentInParent<Piece>();
					ItemDrop feastFood = GetFeastFood(val3);
					if ((Object)(object)feastFood == (Object)null)
					{
						continue;
					}
					ItemDrop val5 = ((Component)val3).GetComponent<ItemDrop>() ?? ((Component)val3).GetComponentInParent<ItemDrop>();
					if ((Object)(object)val5 != (Object)null)
					{
						AddFeastMapping(((Object)((Component)val5).gameObject).name, feastFood);
					}
					ItemDrop component = val.GetComponent<ItemDrop>();
					if ((Object)(object)component != (Object)null)
					{
						AddFeastMapping(((Object)((Component)component).gameObject).name, feastFood);
					}
					if ((Object)(object)val4 == (Object)null || (int)val4.m_category != 5 || val4.m_resources == null)
					{
						continue;
					}
					for (int m = 0; m < val4.m_resources.Length; m++)
					{
						ItemDrop val6 = val4.m_resources[m]?.m_resItem;
						if (!((Object)(object)val6 == (Object)null))
						{
							AddFeastMapping(((Object)((Component)val6).gameObject).name, feastFood);
						}
					}
				}
			}
			return true;
		}

		private static ItemDrop? GetFeastFood(Feast feast)
		{
			if ((Object)(object)feast.m_foodItem != (Object)null)
			{
				return feast.m_foodItem;
			}
			return ((Component)feast).GetComponent<ItemDrop>() ?? ((Component)feast).GetComponentInParent<ItemDrop>();
		}

		private static void AddFeastMapping(string inputId, ItemDrop feastFood)
		{
			if (!string.IsNullOrEmpty(inputId) && !FeastFoodByInput.ContainsKey(inputId))
			{
				FeastFoodByInput.Add(inputId, feastFood);
			}
		}

		private static ResolvedFoodStats FromItem(ItemDrop item, bool resolved, bool isFeast)
		{
			SharedData shared = item.m_itemData.m_shared;
			return new ResolvedFoodStats(shared.m_food, shared.m_foodStamina, shared.m_foodEitr, resolved, isFeast);
		}
	}
	internal readonly struct ResolvedFoodStats
	{
		internal float Health { get; }

		internal float Stamina { get; }

		internal float Eitr { get; }

		internal bool Resolved { get; }

		internal bool IsFeast { get; }

		internal ResolvedFoodStats(float health, float stamina, float eitr, bool resolved, bool isFeast)
		{
			Health = health;
			Stamina = stamina;
			Eitr = eitr;
			Resolved = resolved;
			IsFeast = isFeast;
		}
	}
	internal static class HammerGridDimensions
	{
		internal const int NativeWidth = 15;

		internal const int NativeHeight = 6;

		internal const int ExpandedWidth = 15;

		internal const int ExpandedHeight = 6;

		internal const float ReferenceCraftingRowScale = 1.1666666f;

		internal static int Width
		{
			get
			{
				if (!ModConfig.Enabled.Value)
				{
					return 15;
				}
				return 15;
			}
		}

		internal static int Height
		{
			get
			{
				if (!ModConfig.Enabled.Value)
				{
					return 6;
				}
				return 6;
			}
		}

		internal static int MaxX => Width - 1;

		internal static int MaxY => Height - 1;

		internal static float CraftingRowPitch(Hud hud)
		{
			return hud.m_pieceIconSpacing * 1.1666666f;
		}
	}
	internal static class HammerGridSizer
	{
		private sealed class RectState
		{
			private readonly RectTransform _rect;

			private readonly Vector2 _sizeDelta;

			private readonly Vector2 _anchoredPosition;

			internal RectState(RectTransform rect)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				_rect = rect;
				_sizeDelta = rect.sizeDelta;
				_anchoredPosition = rect.anchoredPosition;
			}

			internal void Restore()
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)_rect == (Object)null))
				{
					_rect.sizeDelta = _sizeDelta;
					_rect.anchoredPosition = _anchoredPosition;
				}
			}
		}

		private sealed class ReparentedRectState
		{
			private readonly RectTransform _rect;

			private readonly Transform _parent;

			private readonly int _siblingIndex;

			private readonly Vector2 _anchorMin;

			private readonly Vector2 _anchorMax;

			private readonly Vector2 _pivot;

			private readonly Vector2 _sizeDelta;

			private readonly Vector2 _anchoredPosition;

			internal ReparentedRectState(RectTransform rect)
			{
				//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)
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				_rect = rect;
				_parent = ((Transform)rect).parent;
				_siblingIndex = ((Transform)rect).GetSiblingIndex();
				_anchorMin = rect.anchorMin;
				_anchorMax = rect.anchorMax;
				_pivot = rect.pivot;
				_sizeDelta = rect.sizeDelta;
				_anchoredPosition = rect.anchoredPosition;
			}

			internal void Restore()
			{
				//IL_0059: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				//IL_007b: Unknown result type (might be due to invalid IL or missing references)
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				//IL_009d: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)_rect == (Object)null) && !((Object)(object)_parent == (Object)null))
				{
					((Transform)_rect).SetParent(_parent, false);
					((Transform)_rect).SetSiblingIndex(Mathf.Min(_siblingIndex, _parent.childCount - 1));
					_rect.anchorMin = _anchorMin;
					_rect.anchorMax = _anchorMax;
					_rect.pivot = _pivot;
					_rect.sizeDelta = _sizeDelta;
					_rect.anchoredPosition = _anchoredPosition;
				}
			}
		}

		private static int _hudInstanceId = int.MinValue;

		private static RectState? _windowState;

		private static RectState? _maskState;

		private static RectState? _categoryState;

		private static ReparentedRectState? _previousCategoryControlState;

		internal static float RepairRailWidth { get; private set; }

		internal static void Apply(Hud hud)
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			int instanceID = ((Object)hud).GetInstanceID();
			if (_hudInstanceId != instanceID)
			{
				Restore();
				float pieceIconSpacing = hud.m_pieceIconSpacing;
				float num = 0f * pieceIconSpacing;
				float num2 = Mathf.Max(0f, 1f * pieceIconSpacing);
				RepairRailWidth = pieceIconSpacing + 28f;
				RectTransform val = (((Object)(object)hud.m_pieceSelectionWindow != (Object)null) ? hud.m_pieceSelectionWindow.GetComponent<RectTransform>() : null);
				if ((Object)(object)val != (Object)null)
				{
					_windowState = new RectState(val);
					ExpandCentered(val, num + RepairRailWidth, num2);
				}
				RectTransform pieceListMask = hud.m_pieceListMask;
				if ((Object)(object)pieceListMask != (Object)null)
				{
					_maskState = new RectState(pieceListMask);
					float widthDelta = (Mathf.Approximately(pieceListMask.anchorMin.x, pieceListMask.anchorMax.x) ? num : 0f);
					float heightDelta = (Mathf.Approximately(pieceListMask.anchorMin.y, pieceListMask.anchorMax.y) ? num2 : 0f);
					ExpandKeepingTopLeft(pieceListMask, widthDelta, heightDelta);
					pieceListMask.anchoredPosition += new Vector2(RepairRailWidth, 0f);
				}
				RectTransform val2 = (((Object)(object)hud.m_pieceCategoryRoot != (Object)null) ? hud.m_pieceCategoryRoot.GetComponent<RectTransform>() : null);
				if ((Object)(object)val2 != (Object)null)
				{
					_categoryState = new RectState(val2);
					val2.sizeDelta -= new Vector2(RepairRailWidth, 0f);
					val2.anchoredPosition += new Vector2(RepairRailWidth * (1f - val2.pivot.x), 0f);
					MovePreviousCategoryControl(val2, val, RepairRailWidth);
				}
				_hudInstanceId = instanceID;
			}
		}

		internal static void Restore()
		{
			_windowState?.Restore();
			_maskState?.Restore();
			_categoryState?.Restore();
			_previousCategoryControlState?.Restore();
			_windowState = null;
			_maskState = null;
			_categoryState = null;
			_previousCategoryControlState = null;
			_hudInstanceId = int.MinValue;
			RepairRailWidth = 0f;
		}

		private static void MovePreviousCategoryControl(RectTransform categoryRoot, RectTransform? window, float repairRailWidth)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)window == (Object)null))
			{
				RectTransform val = FindInteractiveControl(categoryRoot, "Q") ?? FindInteractiveControl(window, "Q");
				if (!((Object)(object)val == (Object)null))
				{
					_previousCategoryControlState = new ReparentedRectState(val);
					((Transform)val).SetParent((Transform)(object)window, false);
					((Transform)val).SetAsLastSibling();
					val.anchorMin = new Vector2(0f, 1f);
					val.anchorMax = new Vector2(0f, 1f);
					val.pivot = new Vector2(0f, 1f);
					val.anchoredPosition = new Vector2(repairRailWidth + 42f, -18f);
				}
			}
		}

		private static RectTransform? FindInteractiveControl(RectTransform root, string displayedText)
		{
			TextMeshProUGUI[] componentsInChildren = ((Component)root).GetComponentsInChildren<TextMeshProUGUI>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (string.Equals(((TMP_Text)componentsInChildren[i]).text?.Trim(), displayedText, StringComparison.OrdinalIgnoreCase))
				{
					return InteractiveAncestor(root, ((TMP_Text)componentsInChildren[i]).transform);
				}
			}
			Text[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<Text>(true);
			for (int j = 0; j < componentsInChildren2.Length; j++)
			{
				if (string.Equals(componentsInChildren2[j].text?.Trim(), displayedText, StringComparison.OrdinalIgnoreCase))
				{
					return InteractiveAncestor(root, ((Component)componentsInChildren2[j]).transform);
				}
			}
			return null;
		}

		private static RectTransform? InteractiveAncestor(RectTransform root, Transform child)
		{
			Transform val = child;
			while ((Object)(object)val != (Object)(object)root && (Object)(object)val.parent != (Object)null)
			{
				if ((Object)(object)((Component)val).GetComponent<UIInputHandler>() != (Object)null || (Object)(object)((Component)val).GetComponent<Button>() != (Object)null)
				{
					return (RectTransform?)(object)((val is RectTransform) ? val : null);
				}
				val = val.parent;
			}
			return TopLevelChild(root, child);
		}

		private static RectTransform? TopLevelChild(RectTransform root, Transform child)
		{
			Transform val = child;
			while ((Object)(object)val.parent != (Object)null && (Object)(object)val.parent != (Object)(object)root)
			{
				val = val.parent;
			}
			if (!((Object)(object)val.parent == (Object)(object)root))
			{
				return null;
			}
			return (RectTransform?)(object)((val is RectTransform) ? val : null);
		}

		private static void ExpandCentered(RectTransform rect, float widthDelta, float heightDelta)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			rect.sizeDelta += new Vector2(widthDelta, heightDelta);
		}

		private static void ExpandKeepingTopLeft(RectTransform rect, float widthDelta, float heightDelta)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			rect.sizeDelta += new Vector2(widthDelta, heightDelta);
			rect.anchoredPosition += new Vector2(widthDelta * rect.pivot.x, (0f - heightDelta) * (1f - rect.pivot.y));
		}
	}
	internal static class HammerGroupDecorations
	{
		private readonly struct CraftingEntry
		{
			internal int PieceIndex { get; }

			internal CraftingPieceLayout Metadata { get; }

			internal string Name { get; }

			internal CraftingEntry(int pieceIndex, CraftingPieceLayout metadata, string name)
			{
				PieceIndex = pieceIndex;
				Metadata = metadata;
				Name = name;
			}
		}

		private sealed class CraftingLayoutResult
		{
			internal int[] Slots { get; }

			internal float[] XOffsets { get; }

			internal int RepairIndex { get; }

			internal CraftingSection?[] RowSections { get; }

			internal int[] Representatives { get; }

			internal List<SubgroupDivider> SubgroupBreaks { get; }

			internal int VisibleRows { get; }

			internal CraftingLayoutResult(int[] slots, float[] xOffsets, int repairIndex, CraftingSection?[] rowSections, int[] representatives, List<SubgroupDivider> subgroupBreaks, int visibleRows)
			{
				Slots = slots;
				XOffsets = xOffsets;
				RepairIndex = repairIndex;
				RowSections = rowSections;
				Representatives = representatives;
				SubgroupBreaks = subgroupBreaks;
				VisibleRows = visibleRows;
			}
		}

		private readonly struct SubgroupDivider
		{
			internal int Row { get; }

			internal int Column { get; }

			internal int GapCount { get; }

			internal SubgroupDivider(int row, int column, int gapCount)
			{
				Row = row;
				Column = column;
				GapCount = gapCount;
			}
		}

		private sealed class ShelfLayoutResult
		{
			internal int[] Slots { get; }

			internal float[] XPositions { get; }

			internal List<ShelfCard> Cards { get; }

			internal List<ShelfDivider> Dividers { get; }

			internal int VisibleRows { get; }

			internal float RowPitch { get; }

			internal int RepairIndex { get; }

			internal ShelfLayoutResult(int[] slots, float[] xPositions, List<ShelfCard> cards, List<ShelfDivider> dividers, int visibleRows, float rowPitch, int repairIndex)
			{
				Slots = slots;
				XPositions = xPositions;
				Cards = cards;
				Dividers = dividers;
				VisibleRows = visibleRows;
				RowPitch = rowPitch;
				RepairIndex = repairIndex;
			}
		}

		private readonly struct ShelfCard
		{
			internal int StartRow { get; }

			internal int RowSpan { get; }

			internal string Label { get; }

			internal int Representative { get; }

			internal ShelfCard(int startRow, int rowSpan, string label, int representative)
			{
				StartRow = startRow;
				RowSpan = rowSpan;
				Label = label;
				Representative = representative;
			}
		}

		private readonly struct ShelfDivider
		{
			internal int Row { get; }

			internal float X { get; }

			internal ShelfDivider(int row, float x)
			{
				Row = row;
				X = x;
			}
		}

		private readonly struct NativeBackgroundState
		{
			private Image Image { get; }

			private Color Color { get; }

			private bool RaycastTarget { get; }

			private RectTransform Rect { get; }

			private Vector2 SizeDelta { get; }

			private UIInputHandler? Input { get; }

			private bool InputEnabled { get; }

			internal NativeBackgroundState(Image image, Color color, bool raycastTarget, RectTransform rect, Vector2 sizeDelta, UIInputHandler? input, bool inputEnabled)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: 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)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				Image = image;
				Color = color;
				RaycastTarget = raycastTarget;
				Rect = rect;
				SizeDelta = sizeDelta;
				Input = input;
				InputEnabled = inputEnabled;
			}

			internal void SetHovered(bool hovered)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)Image == (Object)null))
				{
					Color color = Color;
					color.a = (hovered ? Mathf.Max(Color.a, 0.62f) : 0f);
					((Graphic)Image).color = color;
				}
			}

			internal void Restore()
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)Image != (Object)null)
				{
					((Graphic)Image).color = Color;
					((Graphic)Image).raycastTarget = RaycastTarget;
				}
				if ((Object)(object)Rect != (Object)null)
				{
					Rect.sizeDelta = SizeDelta;
				}
				if ((Object)(object)Input != (Object)null)
				{
					((Behaviour)Input).enabled = InputEnabled;
				}
			}
		}

		private readonly struct GroupPalette
		{
			internal Color Text { get; }

			internal Color Background { get; }

			internal GroupPalette(Color text, Color background)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				Text = text;
				Background = background;
			}
		}

		private sealed class CategoryCardView
		{
			internal GameObject Root { get; }

			internal RectTransform Rect { get; }

			internal Image Background { get; }

			internal RectTransform IconRect { get; }

			internal Image Icon { get; }

			internal RectTransform LabelRect { get; }

			internal TextMeshProUGUI Label { get; }

			internal CategoryCardView(GameObject root, RectTransform rect, Image background, RectTransform iconRect, Image icon, RectTransform labelRect, TextMeshProUGUI label)
			{
				Root = root;
				Rect = rect;
				Background = background;
				IconRect = iconRect;
				Icon = icon;
				LabelRect = labelRect;
				Label = label;
			}
		}

		private const string Prefix = "InventoryUX_";

		private const int GridWidth = 15;

		private const int GridHeight = 6;

		private const int CategoryColumns = 3;

		private const int ShelfColumns = 15;

		private const int ShelfRows = 7;

		private const float CraftingColumnPitchScale = 0.95f;

		private const float ShelfColumnPitchScale = 0.93f;

		private const float CategoryRailScale = 0.9f;

		private const float CategoryToItemsGap = 14f;

		private const float SubgroupSpacing = 26.4f;

		private const float SubgroupLineInset = 19.8f;

		private const float TileInset = 3f;

		private const float LabelHeight = 14f;

		private const float ViewControlsHeight = 76f;

		private const float ViewButtonGap = 6f;

		private static readonly FieldInfo PieceIconsField = AccessTools.Field(typeof(Hud), "m_pieceIcons");

		private static readonly FieldInfo PlayerBuildPiecesField = AccessTools.Field(typeof(Player), "m_buildPieces");

		private static readonly MethodInfo UpdateAvailablePiecesMethod = AccessTools.Method(typeof(Player), "UpdateAvailablePiecesList", (Type[])null, (Type[])null);

		private static readonly MethodInfo HudUpdatePieceListMethod = AccessTools.Method(typeof(Hud), "UpdatePieceList", new Type[4]
		{
			typeof(Player),
			typeof(Vector2Int),
			typeof(PieceCategory),
			typeof(bool)
		}, (Type[])null);

		private static readonly Dictionary<int, NativeBackgroundState> NativeBackgrounds = new Dictionary<int, NativeBackgroundState>();

		private static readonly Dictionary<int, UIInputHandler> HoverInputs = new Dictionary<int, UIInputHandler>();

		private static readonly List<CategoryCardView> CategoryCardPool = new List<CategoryCardView>();

		private static readonly List<Image> DecorationLinePool = new List<Image>();

		private static readonly List<GameObject> IconDecorationPool = new List<GameObject>();

		private static readonly HashSet<int> IconDecorationIds = new HashSet<int>();

		private static int _decorationPoolHudId = int.MinValue;

		private static int _usedCategoryCards;

		private static int _usedDecorationLines;

		private static Image? _categoryHeaderBackgroundForPass;

		private static Type? _iconType;

		private static FieldInfo? _iconGoField;

		private static int[] _visualSlots = Array.Empty<int>();

		private static int _visualWidth = 15;

		private static int _visualHeight = 6;

		private static bool _stateValid;

		private static int _appliedHudId = int.MinValue;

		private static readonly int[] PieceGenerations = new int[9];

		private static int _appliedPiecesGeneration = -1;

		private static int _appliedPieceCount = -1;

		private static bool _appliedShowSeparators;

		private static bool _appliedShowPieceNames;

		private static PieceCategory _appliedCategory = (PieceCategory)8;

		private static int _repairLogicalIndex = -1;

		private static Piece? _repairPiece;

		private static GameObject? _persistentRepair;

		private static GameObject? _hiddenRepairRoot;

		private static int _repairHudId = int.MinValue;

		private static GameObject? _persistentViewControls;

		private static Image? _defaultViewBackground;

		private static Image? _modViewBackground;

		private static int _viewControlsHudId = int.MinValue;

		private static int _cleanedGeneratedBackgroundHudId = int.MinValue;

		private static readonly GroupPalette[] FallbackPalettes = new GroupPalette[8]
		{
			Palette(0.88f, 0.69f, 0.39f, 0.5f, 0.34f, 0.14f),
			Palette(0.84f, 0.52f, 0.4f, 0.46f, 0.25f, 0.2f),
			Palette(0.62f, 0.76f, 0.53f, 0.28f, 0.42f, 0.24f),
			Palette(0.59f, 0.72f, 0.82f, 0.25f, 0.37f, 0.48f),
			Palette(0.71f, 0.63f, 0.81f, 0.35f, 0.29f, 0.44f),
			Palette(0.49f, 0.76f, 0.73f, 0.2f, 0.4f, 0.38f),
			Palette(0.82f, 0.68f, 0.48f, 0.45f, 0.34f, 0.21f),
			Palette(0.77f, 0.6f, 0.68f, 0.42f, 0.27f, 0.35f)
		};

		internal static bool UseModView { get; private set; } = true;

		internal static bool ShouldUseModView(PieceTable table)
		{
			if ((Object)(object)table != (Object)null && (Object)(object)((Component)table).gameObject != (Object)null)
			{
				return ModConfig.GetToolModView(((Object)((Component)table).gameObject).name);
			}
			return false;
		}

		internal static void NotifyPiecesChanged(PieceCategory category)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Expected I4, but got Unknown
			int num = (int)category;
			if (num >= 0 && num < PieceGenerations.Length)
			{
				PieceGenerations[num]++;
			}
		}

		private static int GetPiecesGeneration(PieceCategory category)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Expected I4, but got Unknown
			int num = (int)category;
			if (num < 0 || num >= PieceGenerations.Length)
			{
				return 0;
			}
			return PieceGenerations[num];
		}

		internal static void Apply(Hud hud, IReadOnlyList<Piece> pieces, PieceCategory category)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Invalid comparison between Unknown and I4
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Invalid comparison between Unknown and I4
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Invalid comparison between Unknown and I4
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			int instanceID = ((Object)hud).GetInstanceID();
			RemoveStaleRepairForDifferentHud(instanceID);
			Player localPlayer = Player.m_localPlayer;
			PieceTable val = (PieceTable)(((Object)(object)localPlayer == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
			if ((Object)(object)val != (Object)null)
			{
				UseModView = ShouldUseModView(val);
			}
			EnsurePersistentViewControls(hud, instanceID);
			if (_cleanedGeneratedBackgroundHudId != instanceID)
			{
				RemoveGeneratedWarmBackgrounds(hud);
				_cleanedGeneratedBackgroundHudId = instanceID;
			}
			if (!IsEnabled(category))
			{
				Clear(hud, (int)category == 1);
				return;
			}
			bool value = ModConfig.ShowSeparators.Value;
			bool value2 = ModConfig.ShowHammerPieceNames.Value;
			if (_stateValid && _appliedHudId == instanceID && _appliedCategory == category && _appliedPiecesGeneration == GetPiecesGeneration(category) && _appliedPieceCount == pieces.Count && _appliedShowSeparators == value && _appliedShowPieceNames == value2)
			{
				return;
			}
			IList list = (IList)PieceIconsField.GetValue(hud);
			int num = Math.Min(pieces.Count, list.Count);
			Clear(hud);
			_categoryHeaderBackgroundForPass = FindVanillaCategoryHeaderBackground(hud);
			try
			{
				if ((int)category == 1 && CanUseReferenceCraftingLayout(pieces, num))
				{
					CraftingLayoutResult craftingLayoutResult = BuildCraftingLayout(pieces, num);
					_visualSlots = craftingLayoutResult.Slots;
					_repairLogicalIndex = craftingLayoutResult.RepairIndex;
					EnsurePersistentRepair(hud, pieces, list, craftingLayoutResult.RepairIndex);
					ApplyGridPermutation(hud, list, craftingLayoutResult, num);
					ConfigureNativePieceCells(list, num, craftingLayoutResult.Slots, craftingLayoutResult.RepairIndex);
					AddReferenceCraftingRows(hud, pieces, list, num, craftingLayoutResult);
					_visualWidth = 15;
					_visualHeight = 6;
					RememberState(instanceID, category, pieces.Count, value, value2);
					return;
				}
				if ((int)category != 1 && CanUseShelfLayout(pieces, num))
				{
					ShelfLayoutResult shelfLayoutResult = BuildShelfLayout(hud, pieces, num, category);
					_visualSlots = shelfLayoutResult.Slots;
					_visualWidth = 15;
					_visualHeight = shelfLayoutResult.VisibleRows;
					_repairLogicalIndex = shelfLayoutResult.RepairIndex;
					if (shelfLayoutResult.RepairIndex >= 0)
					{
						EnsurePersistentRepair(hud, pieces, list, shelfLayoutResult.RepairIndex);
					}
					ConfigureNativePieceCells(list, num, shelfLayoutResult.Slots, shelfLayoutResult.RepairIndex);
					ApplyShelfPositions(hud, list, shelfLayoutResult, num);
					AddShelfRows(hud, pieces, list, num, shelfLayoutResult);
					RememberState(instanceID, category, pieces.Count, value, value2);
					return;
				}
				string a = null;
				for (int i = 0; i < num; i++)
				{
					string text = HammerOrganizer.GetLabel(pieces[i], category) ?? "Other";
					GroupPalette palette = GetPalette(category, text);
					bool flag = !string.Equals(a, text, StringComparison.Ordinal);
					GameObject iconGameObject = GetIconGameObject(list[i]);
					AddTileTint(iconGameObject, palette, flag);
					if (flag && !IsStandaloneAction(category, text))
					{
						AddLabel(hud, iconGameObject, CompactLabel(text), palette);
					}
					a = text;
				}
				RememberState(instanceID, category, pieces.Count, value, value2);
			}
			catch
			{
				RemoveDecorations(hud, list);
				ResetState();
				throw;
			}
		}

		private static void RememberState(int hudInstanceId, PieceCategory category, int pieceCount, bool showSeparators, bool showPieceNames)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			_appliedHudId = hudInstanceId;
			_appliedCategory = category;
			_appliedPiecesGeneration = GetPiecesGeneration(category);
			_appliedPieceCount = pieceCount;
			_appliedShowSeparators = showSeparators;
			_appliedShowPieceNames = showPieceNames;
			_stateValid = true;
		}

		private static void ResetState()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			_stateValid = false;
			_appliedHudId = int.MinValue;
			_appliedPiecesGeneration = -1;
			_appliedPieceCount = -1;
			_appliedCategory = (PieceCategory)8;
			_visualSlots = Array.Empty<int>();
			_visualWidth = 15;
			_visualHeight = 6;
			_repairLogicalIndex = -1;
			_categoryHeaderBackgroundForPass = null;
		}

		internal static bool TryNavigate(PieceTable table, int horizontal, int vertical)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_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 (_visualSlots.Length < 2 || table.GetSelectedCategory() != _appliedCategory)
			{
				return false;
			}
			Vector2Int selectedIndex = table.GetSelectedIndex();
			int num = ((Vector2Int)(ref selectedIndex)).y * 15 + ((Vector2Int)(ref selectedIndex)).x;
			if (num < 0 || num >= _visualSlots.Length)
			{
				return false;
			}
			int num2 = _visualSlots[num];
			if (num2 < 0)
			{
				int num3 = ((horizontal < 0 || vertical < 0) ? FindLastVisualPiece() : FindFirstVisualPiece());
				if (num3 >= 0)
				{
					SelectLogicalIndex(table, num3);
				}
				return true;
			}
			int num4 = num2 % _visualWidth;
			int num5 = num2 / _visualWidth;
			int num6 = -1;
			if (horizontal != 0)
			{
				int num7 = int.MaxValue;
				for (int i = 0; i < _visualSlots.Length; i++)
				{
					int num8 = _visualSlots[i];
					if (num8 < 0 || num8 / _visualWidth != num5)
					{
						continue;
					}
					int num9 = num8 % _visualWidth - num4;
					if ((horizontal >= 0 || num9 < 0) && (horizontal <= 0 || num9 > 0))
					{
						int num10 = Math.Abs(num9);
						if (num10 < num7)
						{
							num7 = num10;
							num6 = i;
						}
					}
				}
				if (num6 < 0 && horizontal < 0 && _repairLogicalIndex >= 0)
				{
					num6 = _repairLogicalIndex;
				}
				else if (num6 < 0)
				{
					int num11 = ((horizontal < 0) ? int.MinValue : int.MaxValue);
					for (int j = 0; j < _visualSlots.Length; j++)
					{
						int num12 = _visualSlots[j];
						if (num12 >= 0 && num12 / _visualWidth == num5)
						{
							int num13 = num12 % _visualWidth;
							if ((horizontal < 0 && num13 > num11) || (horizontal > 0 && num13 < num11))
							{
								num11 = num13;
								num6 = j;
							}
						}
					}
				}
			}
			else if (vertical != 0)
			{
				for (int k = 1; k < _visualHeight; k++)
				{
					if (num6 >= 0)
					{
						break;
					}
					int num14 = (num5 + vertical * k + _visualHeight * 2) % _visualHeight;
					int num15 = int.MaxValue;
					for (int l = 0; l < _visualSlots.Length; l++)
					{
						int num16 = _visualSlots[l];
						if (num16 >= 0 && num16 / _visualWidth == num14)
						{
							int num17 = Math.Abs(num16 % _visualWidth - num4);
							if (num17 < num15)
							{
								num15 = num17;
								num6 = l;
							}
						}
					}
				}
			}
			if (num6 >= 0 && num6 != num)
			{
				SelectLogicalIndex(table, num6);
			}
			return true;
		}

		private static void SelectLogicalIndex(PieceTable table, int logicalIndex)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			table.SetSelected(new Vector2Int(logicalIndex % 15, logicalIndex / 15));
		}

		private static int FindFirstVisualPiece()
		{
			int result = -1;
			int num = int.MaxValue;
			for (int i = 0; i < _visualSlots.Length; i++)
			{
				int num2 = _visualSlots[i];
				if (num2 >= 0 && num2 < num)
				{
					num = num2;
					result = i;
				}
			}
			return result;
		}

		private static int FindLastVisualPiece()
		{
			int result = -1;
			int num = int.MinValue;
			for (int i = 0; i < _visualSlots.Length; i++)
			{
				int num2 = _visualSlots[i];
				if (num2 > num)
				{
					num = num2;
					result = i;
				}
			}
			return result;
		}

		private static CraftingLayoutResult BuildCraftingLayout(IReadOnlyList<Piece> pieces, int count)
		{
			List<CraftingEntry>[] array = new List<CraftingEntry>[6];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = new List<CraftingEntry>();
			}
			int repairIndex = -1;
			for (int j = 0; j < count; j++)
			{
				Piece val = pieces[j];
				if (CraftingLayoutMetadata.IsRepair(val))
				{
					repairIndex = j;
					continue;
				}
				CraftingPieceLayout metadata = CraftingLayoutMetadata.Resolve(val);
				array[(int)metadata.Section].Add(new CraftingEntry(j, metadata, Localize(val.m_name)));
			}
			for (int k = 0; k < array.Length; k++)
			{
				array[k].Sort(delegate(CraftingEntry left, CraftingEntry right)
				{
					int num11 = left.Metadata.SortOrder.CompareTo(right.Metadata.SortOrder);
					if (num11 != 0)
					{
						return num11;
					}
					num11 = string.Compare(left.Name, right.Name, StringComparison.CurrentCultureIgnoreCase);
					return (num11 == 0) ? left.PieceIndex.CompareTo(right.PieceIndex) : num11;
				});
			}
			int[] array2 = new int[count];
			for (int num = 0; num < array2.Length; num++)
			{
				array2[num] = -1;
			}
			float[] array3 = new float[count];
			bool[] array4 = new bool[90];
			CraftingSection?[] array5 = new CraftingSection?[6];
			int[] array6 = new int[6];
			for (int num2 = 0; num2 < array6.Length; num2++)
			{
				array6[num2] = -1;
			}
			List<SubgroupDivider> list = new List<SubgroupDivider>();
			List<int> list2 = new List<int>();
			int num3 = 0;
			for (int num4 = 0; num4 < array.Length; num4++)
			{
				if (num3 >= 6)
				{
					break;
				}
				List<CraftingEntry> list3 = array[num4];
				if (list3.Count == 0)
				{
					continue;
				}
				array5[num3] = (CraftingSection)num4;
				array6[num3] = FindCategoryRepresentative(list3, (CraftingSection)num4);
				int num5 = 3;
				int subgroup = list3[0].Metadata.Subgroup;
				int num6 = 0;
				for (int num7 = 0; num7 < list3.Count; num7++)
				{
					CraftingEntry craftingEntry = list3[num7];
					if (num7 > 0 && craftingEntry.Metadata.Subgroup != subgroup)
					{
						num6++;
						list.Add(new SubgroupDivider(num3, num5, num6));
					}
					if (num5 >= 15)
					{
						list2.Add(craftingEntry.PieceIndex);
					}
					else
					{
						int num8 = num3 * 15 + num5;
						array2[craftingEntry.PieceIndex] = num8;
						array3[craftingEntry.PieceIndex] = (float)num6 * 26.4f;
						array4[num8] = true;
						num5++;
					}
					subgroup = craftingEntry.Metadata.Subgroup;
				}
				num3++;
			}
			for (int num9 = 0; num9 < list2.Count; num9++)
			{
				int num10 = FirstFreePieceSlot(array4);
				if (num10 < 0)
				{
					break;
				}
				array2[list2[num9]] = num10;
				array4[num10] = true;
			}
			return new CraftingLayoutResult(array2, array3, repairIndex, array5, array6, list, num3);
		}

		private static bool CanUseShelfLayout(IReadOnlyList<Piece> pieces, int count)
		{
			int num = 0;
			for (int i = 0; i < count; i++)
			{
				if (!CraftingLayoutMetadata.IsRepair(pieces[i]))
				{
					num++;
				}
			}
			if (num > 0)
			{
				return num <= 105;
			}
			return false;
		}

		private static ShelfLayoutResult BuildShelfLayout(Hud hud, IReadOnlyList<Piece> pieces, int count, PieceCategory category)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Invalid comparison between Unknown and I4
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			List<int> list = new List<int>(count);
			int repairIndex = -1;
			for (int i = 0; i < count; i++)
			{
				if (CraftingLayoutMetadata.IsRepair(pieces[i]))
				{
					repairIndex = i;
				}
				else
				{
					list.Add(i);
				}
			}
			string[] array = new string[list.Count];
			int[] array2 = new int[list.Count];
			int num = 0;
			int num2 = 0;
			string a = null;
			for (int j = 0; j < list.Count; j++)
			{
				Piece piece = pieces[list[j]];
				PieceGroup pieceGroup = HammerOrganizer.Classify(piece, category);
				string text = (array[j] = HammerOrganizer.GetLabel(piece, category) ?? pieceGroup.Label);
				array2[j] = pieceGroup.Suborder;
				if (j == 0 || string.Equals(a, text, StringComparison.Ordinal))
				{
					num2++;
				}
				else
				{
					num += Mathf.CeilToInt((float)num2 / 15f);
					num2 = 1;
				}
				a = text;
			}
			if (num2 > 0)
			{
				num += Mathf.CeilToInt((float)num2 / 15f);
			}
			int num3 = Mathf.Clamp(Mathf.Max(Mathf.CeilToInt((float)list.Count / 15f), num), 1, 7);
			List<int> list2 = (((int)category == 2) ? BuildMaterialRowSizes(array) : null);
			if (list2 != null)
			{
				num3 = list2.Count;
			}
			float pieceIconSpacing = hud.m_pieceIconSpacing;
			float rowPitch = ShelfRowPitch(hud, num3);
			float num4 = CategoryRailWidth(pieceIconSpacing) + 14f;
			float num5 = 14f * pieceIconSpacing;
			int[] array3 = new int[count];
			for (int k = 0; k < array3.Length; k++)
			{
				array3[k] = -1;
			}
			float[] array4 = new float[count];
			string[] array5 = new string[num3];
			int[] array6 = new int[num3];
			List<ShelfDivider> list3 = new List<ShelfDivider>();
			int num6 = 0;
			for (int l = 0; l < num3; l++)
			{
				int num7 = list2?[l] ?? ShelfRowPlanner.ChooseGroupRowSize(array, num6, 15, num3 - l);
				array5[l] = array[num6];
				array6[l] = list[num6];
				int num8 = 0;
				for (int m = 1; m < num7; m++)
				{
					if (IsShelfBreak(array, array2, num6 + m, category))
					{
						num8++;
					}
				}
				float num9 = pieceIconSpacing * 0.93f;
				if (num7 > 1)
				{
					float num10 = (num5 - num4 - (float)num8 * 26.4f) / (float)(num7 - 1);
					num9 = Mathf.Min(num9, num10);
				}
				int num11 = 0;
				for (int n = 0; n < num7; n++)
				{
					int index = num6 + n;
					int num12 = list[index];
					if (n > 0 && IsShelfBreak(array, array2, index, category))
					{
						num11++;
					}
					float num13 = num4 + (float)n * num9 + (float)num11 * 26.4f;
					if (n > 0 && IsShelfBreak(array, array2, index, category))
					{
						list3.Add(new ShelfDivider(l, num13 - 19.8f));
					}
					array3[num12] = l * 15 + n;
					array4[num12] = num13;
				}
				num6 += num7;
			}
			List<ShelfCard> cards = BuildShelfCards(pieces, list, array, array5, array6, category);
			return new ShelfLayoutResult(array3, array4, cards, list3, num3, rowPitch, repairIndex);
		}

		private static bool IsShelfBreak(string[] labels, int[] subgroups, int index, PieceCategory category)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			if (index <= 0 || index >= labels.Length)
			{
				return false;
			}
			if (!string.Equals(labels[index - 1], labels[index], StringComparison.Ordinal))
			{
				return true;
			}
			if ((int)category == 2 && string.Equals(Normalize(labels[index]), "corewood", StringComparison.Ordinal))
			{
				return false;
			}
			if ((int)category == 2)
			{
				return subgroups[index - 1] != subgroups[index];
			}
			return false;
		}

		private static List<int> BuildMaterialRowSizes(string[] labels)
		{
			List<int> list = new List<int>();
			int num = 0;
			while (num < labels.Length)
			{
				int i;
				for (i = num + 1; i < labels.Length && string.Equals(labels[num], labels[i], StringComparison.Ordinal); i++)
				{
				}
				int num2 = i - num;
				int num3 = Mathf.CeilToInt((float)num2 / 15f);
				for (int j = 0; j < num3; j++)
				{
					int num4 = Mathf.CeilToInt((float)num2 / (float)(num3 - j));
					list.Add(num4);
					num2 -= num4;
				}
				num = i;
			}
			return list;
		}

		private static List<ShelfCard> BuildShelfCards(IReadOnlyList<Piece> pieces, List<int> sourceIndices, string[] labels, string[] rowLabels, int[] representatives, PieceCategory category)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Invalid comparison between Unknown and I4
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			List<ShelfCard> list = new List<ShelfCard>();
			for (int i = 0; i < rowLabels.Length; i++)
			{
				string text = rowLabels[i];
				if (list.Count > 0 && string.Equals(list[list.Count - 1].Label, text, StringComparison.Ordinal))
				{
					ShelfCard shelfCard = list[list.Count - 1];
					list[list.Count - 1] = new ShelfCard(shelfCard.StartRow, shelfCard.RowSpan + 1, shelfCard.Label, shelfCard.Representative);
					continue;
				}
				int num = representatives[i];
				if ((int)category == 2)
				{
					num = FindBuildingBeamRepresentative(pieces, sourceIndices, labels, text, num);
				}
				else if ((int)category == 0 && string.Equals(Normalize(text), "utility", StringComparison.Ordinal))
				{
					num = FindCartographyRepresentative(pieces, sourceIndices, labels, text, num);
				}
				list.Add(new ShelfCard(i, 1, text, num));
			}
			return list;
		}

		private static int FindBuildingBeamRepresentative(IReadOnlyList<Piece> pieces, List<int> sourceIndices, string[] labels, string label, int fallback)
		{
			string text = Normalize(label);
			for (int i = 0; i < sourceIndices.Count; i++)
			{
				if (string.Equals(labels[i], label, StringComparison.Ordinal))
				{
					Piece val = pieces[sourceIndices[i]];
					string text2 = Normalize(((Object)((Component)val).gameObject).name + " " + val.m_name);
					if (text2.Contains("beam") && (!(text == "darkwood") || text2.Contains("darkwood")) && (!(text == "ashwood") || text2.Contains("grausten") || text2.Contains("ashwood") || text2.Contains("blackwood")) && (!(text == "corewood") || text2.Contains("corewood") || text2.Contains("log")) && (!(text == "wood") || (!text2.Contains("darkwood") && !text2.Contains("grausten") && !text2.Contains("ashwood") && !text2.Contains("corewood") && !text2.Contains("log"))))
					{
						return sourceIndices[i];
					}
				}
			}
			return fallback;
		}

		private static int FindCartographyRepresentative(IReadOnlyList<Piece> pieces, List<int> sourceIndices, string[] labels, string label, int fallback)
		{
			for (int i = 0; i < sourceIndices.Count; i++)
			{
				if (string.Equals(labels[i], label, StringComparison.Ordinal))
				{
					Piece val = pieces[sourceIndices[i]];
					string text = Normalize(((Object)((Component)val).gameObject).name + " " + val.m_name);
					if (text.Contains("cartography") || text.Contains("maptable"))
					{
						return sourceIndices[i];
					}
				}
			}
			return fallback;
		}

		private static float CategoryRailWidth(float spacing)
		{
			return (3f * spacing - 28f) * 0.9f;
		}

		private static float CraftingContentShift(float spacing)
		{
			return CategoryRailWidth(spacing) + 14f - 3f * spacing * 0.95f;
		}

		private static float ShelfRowPitch(Hud hud, int visibleRows)
		{
			if (visibleRows <= 6)
			{
				return hud.m_pieceIconSpacing * 1.1666666f;
			}
			return hud.m_pieceIconSpacing * 7f / (float)visibleRows;
		}

		private static int FindCategoryRepresentative(List<CraftingEntry> entries, CraftingSection section)
		{
			int num = 100;
			for (int i = 0; i < entries.Count; i++)
			{
				if (entries[i].Metadata.SortOrder == num)
				{
					return entries[i].PieceIndex;
				}
			}
			return entries[0].PieceIndex;
		}

		private static bool CanUseReferenceCraftingLayout(IReadOnlyList<Piece> pieces, int count)
		{
			int num = 0;
			for (int i = 0; i < count; i++)
			{
				if (!CraftingLayoutMetadata.IsRepair(pieces[i]))
				{
					num++;
				}
			}
			if (num > 0)
			{
				return num <= 72;
			}
			return false;
		}

		private static int FirstFreePieceSlot(bool[] used)
		{
			for (int i = 0; i < 6; i++)
			{
				for (int j = 3; j < 15; j++)
				{
					int num = i * 15 + j;
					if (!used[num])
					{
						return num;
					}
				}
			}
			return -1;
		}

		private static void AddReferenceCraftingRows(Hud hud, IReadOnlyList<Piece> pieces, IList icons, int count, CraftingLayoutResult layout)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			RectTransform templateRect = (RectTransform)GetIconGameObject(icons[0]).transform;
			for (int i = 0; i < count; i++)
			{
				if (i != layout.RepairIndex && layout.Slots[i] >= 0 && ModConfig.ShowHammerPieceNames.Value)
				{
					AddReferenceTile(hud, GetIconGameObject(icons[i]), pieces[i]);
				}
			}
			for (int j = 0; j < layout.VisibleRows; j++)
			{
				if (j < layout.VisibleRows - 1 && ModConfig.ShowSeparators.Value)
				{
					AddRowSeparator(hud, templateRect, j);
				}
				CraftingSection? craftingSection = layout.RowSections[j];
				int num = layout.Representatives[j];
				if (craftingSection.HasValue && num >= 0)
				{
					AddCategoryCard(hud, templateRect, j, craftingSection.Value, pieces[num]);
				}
			}
			if (ModConfig.ShowSeparators.Value)
			{
				for (int k = 0; k < layout.SubgroupBreaks.Count; k++)
				{
					AddSubgroupSeparator(hud, templateRect, layout.SubgroupBreaks[k]);
				}
			}
		}

		private static void AddShelfRows(Hud hud, IReadOnlyList<Piece> pieces, IList icons, int count, ShelfLayoutResult layout)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			RectTransform templateRect = (RectTransform)GetIconGameObject(icons[0]).transform;
			for (int i = 0; i < count; i++)
			{
				if (layout.Slots[i] >= 0 && ModConfig.ShowHammerPieceNames.Value)
				{
					AddReferenceTile(hud, GetIconGameObject(icons[i]), pieces[i]);
				}
			}
			for (int j = 0; j < layout.VisibleRows; j++)
			{
				if (j >= layout.VisibleRows - 1 || !ModConfig.ShowSeparators.Value)
				{
					continue;
				}
				bool flag = false;
				for (int k = 0; k < layout.Cards.Count; k++)
				{
					if (layout.Cards[k].StartRow == j + 1)
					{
						flag = true;
						break;
					}
				}
				if (flag)
				{
					AddRowSeparator(hud, templateRect, j, layout.RowPitch, 0f);
				}
			}
			for (int l = 0; l < layout.Cards.Count; l++)
			{
				ShelfCard shelfCard = layout.Cards[l];
				AddCategoryCard(hud, templateRect, shelfCard.StartRow, layout.RowPitch, shelfCard.Label, pieces[shelfCard.Representative], shelfCard.RowSpan);
			}
			if (ModConfig.ShowSeparators.Value)
			{
				for (int m = 0; m < layout.Dividers.Count; m++)
				{
					AddShelfDivider(hud, templateRect, layout.Dividers[m], layout.RowPitch);
				}
			}
		}

		private static void AddReferenceTile(Hud hud, GameObject iconRoot, Piece piece)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: 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_01a6: Unknown result type (might be due to invalid IL or missing references)
			Transform val = iconRoot.transform.Find("InventoryUX_CraftingPieceName");
			GameObject val2;
			if ((Object)(object)val != (Object)null)
			{
				val2 = ((Component)val).gameObject;
				val2.SetActive(true);
			}
			else
			{
				val2 = new GameObject("InventoryUX_CraftingPieceName", new Type[2]
				{
					typeof(RectTransform),
					typeof(TextMeshProUGUI)
				});
				val2.transform.SetParent(iconRoot.transform, false);
			}
			TrackIconDecoration(val2);
			val2.transform.SetAsLastSibling();
			RectTransform val3 = (RectTransform)val2.transform;
			val3.anchorMin = new Vector2(0f, 0f);
			val3.anchorMax = new Vector2(1f, 0f);
			val3.pivot = new Vector2(0.5f, 0f);
			val3.anchoredPosition = new Vector2(0f, 3f);
			val3.sizeDelta = new Vector2(-8f, 27f);
			TextMeshProUGUI component = val2.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component).text = Localize(piece.m_name);
			((TMP_Text)component).font = (((Object)(object)hud.m_pieceDescription != (Object)null) ? hud.m_pieceDescription.font : null);
			((TMP_Text)component).fontSize = 10.6f;
			((TMP_Text)component).fontSizeMin = 8.6f;
			((TMP_Text)component).fontSizeMax = 10.6f;
			((TMP_Text)component).enableAutoSizing = true;
			((TMP_Text)component).fontStyle = (FontStyles)1;
			((Graphic)component).color = new Color(0.96f, 0.88f, 0.72f, 1f);
			((TMP_Text)component).alignment = (TextAlignmentOptions)1026;
			((TMP_Text)component).textWrappingMode = (TextWrappingModes)1;
			((TMP_Text)component).overflowMode = (TextOverflowModes)1;
			((TMP_Text)component).maxVisibleLines = 2;
			((TMP_Text)component).outlineWidth = 0.22f;
			((TMP_Text)component).outlineColor = new Color32((byte)0, (byte)0, (byte)0, byte.MaxValue);
			((Graphic)component).raycastTarget = false;
		}

		private static void AddCategoryCard(Hud hud, RectTransform templateRect, int row, CraftingSection section, Piece representative)
		{
			AddCategoryCard(hud, templateRect, row, HammerGridDimensions.CraftingRowPitch(hud), CraftingLayoutMetadata.Label(section), representative);
		}

		private static void AddCategoryCard(Hud hud, RectTransform templateRect, int row, float rowPitch, string text, Piece representative, int rowSpan = 1)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: 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_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			float pieceIconSpacing = hud.m_pieceIconSpacing;
			CategoryCardView categoryCardView = AcquireCategoryCard(hud);
			GameObject root = categoryCardView.Root;
			((Object)root).name = "InventoryUX_CraftingCategory_" + row;
			root.transform.SetAsLastSibling();
			RectTransform rect = categoryCardView.Rect;
			rect.anchorMin = templateRect.anchorMin;
			rect.anchorMax = templateRect.anchorMax;
			rect.pivot = templateRect.pivot;
			rect.anchoredPosition = new Vector2(0f, (float)(-row) * rowPitch);
			rect.sizeDelta = new Vector2(CategoryRailWidth(pieceIconSpacing), rowPitch * (float)rowSpan - 7f);
			Image background = categoryCardView.Background;
			Image categoryHeaderBackgroundForPass = _categoryHeaderBackgroundForPass;
			if ((Object)(object)categoryHeaderBackgroundForPass != (Object)null)
			{
				background.sprite = categoryHeaderBackgroundForPass.sprite;
				background.overrideSprite = categoryHeaderBackgroundForPass.overrideSprite;
				((Graphic)background).material = ((Graphic)categoryHeaderBackgroundForPass).material;
				background.type = categoryHeaderBackgroundForPass.type;
				background.preserveAspect = categoryHeaderBackgroundForPass.preserveAspect;
				background.fillCenter = categoryHeaderBackgroundForPass.fillCenter;
				background.pixelsPerUnitMultiplier = categoryHeaderBackgroundForPass.pixelsPerUnitMultiplier;
				((Graphic)background).color = ((Graphic)categoryHeaderBackgroundForPass).canvasRenderer.GetColor();
			}
			else
			{
				background.sprite = null;
				background.overrideSprite = null;
				((Graphic)background).material = null;
				background.type = (Type)0;
				((Graphic)background).color = new Color(0.2f, 0.2f, 0.2f, 0.7f);
			}
			((Graphic)background).raycastTarget = false;
			RectTransform iconRect = categoryCardView.IconRect;
			iconRect.anchorMin = new Vector2(0f, 0.5f);
			iconRect.anchorMax = new Vector2(0f, 0.5f);
			iconRect.pivot = new Vector2(0f, 0.5f);
			iconRect.anchoredPosition = new Vector2(8f, 0f);
			iconRect.sizeDelta = new Vector2(56f, 56f);
			Image icon = categoryCardView.Icon;
			icon.sprite = representative.m_icon;
			icon.preserveAspect = true;
			((Graphic)icon).color = Color.white;
			((Graphic)icon).raycastTarget = false;
			RectTransform labelRect = categoryCardView.LabelRect;
			labelRect.anchorMin = Vector2.zero;
			labelRect.anchorMax = Vector2.one;
			labelRect.offsetMin = new Vector2(66f, 6f);
			labelRect.offsetMax = new Vector2(-7f, -6f);
			TextMeshProUGUI label = categoryCardView.Label;
			((TMP_Text)label).text = text.ToUpperInvariant();
			((TMP_Text)label).font = (((Object)(object)hud.m_pieceDescription != (Object)null) ? hud.m_pieceDescription.font : null);
			((TMP_Text)label).fontSize = 12.8f;
			((TMP_Text)label).fontSizeMin = 9.5f;
			((TMP_Text)label).fontSizeMax = 12.8f;
			((TMP_Text)label).enableAutoSizing = true;
			((TMP_Text)label).fontStyle = (FontStyles)1;
			((Graphic)label).color = new Color(0.84f, 0.69f, 0.43f, 1f);
			((TMP_Text)label).alignment = (TextAlignmentOptions)4097;
			((TMP_Text)label).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)label).overflowMode = (TextOverflowModes)1;
			((TMP_Text)label).outlineWidth = 0.12f;
			((TMP_Text)label).outlineColor = new Color32((byte)18, (byte)12, (byte)8, (byte)245);
			((Graphic)label).raycastTarget = false;
		}

		private static CategoryCardView AcquireCategoryCard(Hud hud)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Expected O, but got Unknown
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Expected O, but got Unknown
			EnsureDecorationPoolOwner(hud);
			CategoryCardView categoryCardView = ((_usedCategoryCards < CategoryCardPool.Count) ? CategoryCardPool[_usedCategoryCards] : null);
			if (categoryCardView == null || (Object)(object)categoryCardView.Root == (Object)null)
			{
				GameObject val = new GameObject("InventoryUX_CraftingCategoryPool", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				val.transform.SetParent((Transform)(object)hud.m_pieceListRoot, false);
				RectTransform val2 = (RectTransform)val.transform;
				Image component = val.GetComponent<Image>();
				AddRectBorder(val2, new Color(0.68f, 0.5f, 0.25f, 0.68f));
				GameObject val3 = new GameObject("InventoryUX_CraftingCategoryIcon", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				val3.transform.SetParent((Transform)(object)val2, false);
				RectTransform iconRect = (RectTransform)val3.transform;
				Image component2 = val3.GetComponent<Image>();
				GameObject val4 = new GameObject("InventoryUX_CraftingCategoryLabel", new Type[2]
				{
					typeof(RectTransform),
					typeof(TextMeshProUGUI)
				});
				val4.transform.SetParent((Transform)(object)val2, false);
				RectTransform labelRect = (RectTransform)val4.transform;
				TextMeshProUGUI component3 = val4.GetComponent<TextMeshProUGUI>();
				categoryCardView = new CategoryCardView(val, val2, component, iconRect, component2, labelRect, component3);
				if (_usedCategoryCards < CategoryCardPool.Count)
				{
					CategoryCardPool[_usedCategoryCards] = categoryCardView;
				}
				else
				{
					CategoryCardPool.Add(categoryCardView);
				}
			}
			categoryCardView.Root.SetActive(true);
			_usedCategoryCards++;
			return categoryCardView;
		}

		private static Image? FindVanillaCategoryHeaderBackground(Hud hud)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			Image result = null;
			float num = float.MaxValue;
			GameObject[] pieceCategoryTabs = hud.m_pieceCategoryTabs;
			foreach (GameObject val in pieceCategoryTabs)
			{
				if ((Object)(object)val == (Object)null || !val.activeInHierarchy)
				{
					continue;
				}
				Image val2 = val.GetComponent<Image>() ?? val.GetComponentInChildren<Image>(true);
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				Color color = ((Graphic)val2).canvasRenderer.GetColor();
				if (!(color.a <= 0.05f))
				{
					float num2 = color.r * 0.2126f + color.g * 0.7152f + color.b * 0.0722f;
					if (num2 < num)
					{
						result = val2;
						num = num2;
					}
				}
			}
			return result;
		}

		private static void AddRowSeparator(Hud hud, RectTransform templateRect, int row)
		{
			AddRowSeparator(hud, templateRect, row, HammerGridDimensions.CraftingRowPitch(hud));
		}

		private static void AddRowSeparator(Hud hud, RectTransform templateRect, int row, float rowPitch)
		{
			AddRowSeparator(hud, templateRect, row, rowPitch, 0f);
		}

		private static void AddRowSeparator(Hud hud, RectTransform templateRect, int row, float rowPitch, float startX)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			float pieceIconSpacing = hud.m_pieceIconSpacing;
			Image obj = AcquireDecorationLine(hud, "InventoryUX_CraftingRowSeparator_" + row);
			((Component)obj).transform.SetAsLastSibling();
			RectTransform val = (RectTransform)((Component)obj).transform;
			val.anchorMin = templateRect.anchorMin;
			val.anchorMax = templateRect.anchorMax;
			val.pivot = new Vector2(0f, 0.5f);
			val.anchoredPosition = new Vector2(startX, (0f - ((float)row + 1f)) * rowPitch + 3.5f);
			val.sizeDelta = new Vector2(15f * pieceIconSpacing - 9f - startX, 1f);
			((Graphic)obj).color = new Color(0.57f, 0.4f, 0.19f, 0.34f);
			((Graphic)obj).raycastTarget = false;
		}

		private static void AddSubgroupSeparator(Hud hud, RectTransform templateRect, SubgroupDivider divider)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			float pieceIconSpacing = hud.m_pieceIconSpacing;
			float num = pieceIconSpacing * 0.95f;
			float num2 = HammerGridDimensions.CraftingRowPitch(hud);
			float num3 = (float)divider.Column * num + CraftingContentShift(pieceIconSpacing) + (float)divider.GapCount * 26.4f;
			Image obj = AcquireDecorationLine(hud, "InventoryUX_CraftingSubgroupSeparator_" + divider.Row + "_" + divider.Column);
			((Component)obj).transform.SetAsLastSibling();
			RectTransform val = (RectTransform)((Component)obj).transform;
			val.anchorMin = templateRect.anchorMin;
			val.anchorMax = templateRect.anchorMax;
			val.pivot = new Vector2(0.5f, 0.5f);
			val.anchoredPosition = new Vector2(num3 - 19.8f, (float)(-divider.Row) * num2 - num2 * 0.5f);
			val.sizeDelta = new Vector2(1f, num2 - 20f);
			((Graphic)obj).color = new Color(0.62f, 0.47f, 0.25f, 0.42f);
			((Graphic)obj).raycastTarget = false;
		}

		private static void AddShelfDivider(Hud hud, RectTransform templateRect, ShelfDivider divider, float rowPitch)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
			Image obj = AcquireDecorationLine(hud, "InventoryUX_CraftingShelfDivider_" + divider.Row + "_" + divider.X);
			((Component)obj).transform.SetAsLastSibling();
			RectTransform val = (RectTransform)((Component)obj).transform;
			val.anchorMin = templateRect.anchorMin;
			val.anchorMax = templateRect.anchorMax;
			val.pivot = new Vector2(0.5f, 0.5f);
			val.anchoredPosition = new Vector2(divider.X, (float)(-divider.Row) * rowPitch - rowPitch * 0.5f);
			val.sizeDelta = new Vector2(1f, rowPitch - 20f);
			((Graphic)obj).color = new Color(0.62f, 0.47f, 0.25f, 0.42f);
			((Graphic)obj).raycastTarget = false;
		}

		private static Image AcquireDecorationLine(Hud hud, string name)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			EnsureDecorationPoolOwner(hud);
			Image val = ((_usedDecorationLines < DecorationLinePool.Count) ? DecorationLinePool[_usedDecorationLines] : null);
			if ((Object)(object)val == (Object)null)
			{
				GameObject val2 = new GameObject(name, new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				val2.transform.SetParent((Transform)(object)hud.m_pieceListRoot, false);
				val = val2.GetComponent<Image>();
				if (_usedDecorationLines < DecorationLinePool.Count)
				{
					DecorationLinePool[_usedDecorationLines] = val;
				}
				else
				{
					DecorationLinePool.Add(val);
				}
			}
			((Object)((Component)val).gameObject).name = name;
			((Component)val).gameObject.SetActive(true);
			_usedDecorationLines++;
			return val;
		}

		private static void EnsureDecorationPoolOwner(Hud hud)
		{
			int instanceID = ((Object)hud).GetInstanceID();
			if (_decorationPoolHudId != instanceID)
			{
				DestroyDecorationPool();
				_decorationPoolHudId = instanceID;
			}
		}

		private static void DeactivateDecorationPool()
		{
			for (int i = 0; i < CategoryCardPool.Count; i++)
			{
				CategoryCardView categoryCardView = CategoryCardPool[i];
				if (categoryCardView != null && (Object)(object)categoryCardView.Root != (Object)null)
				{
					categoryCardView.Root.SetActive(false);
				}
			}
			for (int j = 0; j < DecorationLinePool.Count; j++)
			{
				if ((Object)(object)DecorationLinePool[j] != (Object)null)
				{
					((Component)DecorationLinePool[j]).gameObject.SetActive(false);
				}
			}
			_usedCategoryCards = 0;
			_usedDecorationLines = 0;
		}

		private static void DestroyDecorationPool()
		{
			for (int i = 0; i < CategoryCardPool.Count; i++)
			{
				CategoryCardView categoryCardView = CategoryCardPool[i];
				if (categoryCardView != null && (Object)(object)categoryCardView.Root != (Object)null)
				{
					Object.Destroy((Object)(object)categoryCardView.Root);
				}
			}
			for (int j = 0; j < DecorationLinePool.Count; j++)
			{
				if ((Object)(object)DecorationLinePool[j] != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)DecorationLinePool[j]).gameObject);
				}
			}
			CategoryCardPool.Clear();
			DecorationLinePool.Clear();
			_usedCategoryCards = 0;
			_usedDecorationLines = 0;
			_decorationPoolHudId = int.MinValue;
		}

		private static void ConfigureNativePieceCells(IList icons, int occupiedCount, int[] slots, int repairIndex)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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_008b: Expected O, but got Unknown
			for (int i = 0; i < icons.Count; i++)
			{
				GameObject iconGameObject = GetIconGameObject(icons[i]);
				Image component = iconGameObject.GetComponent<Image>();
				if ((Object)(object)component == (Object)null)
				{
					continue;
				}
				UIInputHandler component2 = iconGameObject.GetComponent<UIInputHandler>();
				int instanceID = ((Object)component).GetInstanceID();
				if (!NativeBackgrounds.ContainsKey(instanceID))
				{
					NativeBackgrounds[instanceID] = new NativeBackgroundState(component, ((Graphic)component).color, ((Graphic)component).raycastTarget, (RectTransform)iconGameObject.transform, ((RectTransform)iconGameObject.transform).sizeDelta, component2, (Object)(object)component2 != (Object)null && ((Behaviour)component2).enabled);
				}
				bool flag = i < occupiedCount && i < slots.Length && slots[i] >= 0 && i != repairIndex;
				Color color = ((Graphic)component).color;
				color.a = 0f;
				((Graphic)component).color = color;
				((Graphic)component).raycastTarget = flag;
				if ((Object)(object)component2 != (Object)null)
				{
					((Behaviour)component2).enabled = flag;
					if (flag && !HoverInputs.ContainsKey(((Object)component2).GetInstanceID()))
					{
						component2.m_onPointerEnter = (Action<UIInputHandler>)Delegate.Combine(component2.m_onPointerEnter, new Action<UIInputHandler>(OnPieceHoverEnter));
						component2.m_onPointerExit = (Action<UIInputHandler>)Delegate.Combine(component2.m_onPointerExit, new Action<UIInputHandler>(OnPieceHoverExit));
						HoverInputs[((Object)component2).GetInstanceID()] = component2;
					}
				}
			}
		}

		private static void OnPieceHoverEnter(UIInputHandler input)
		{
			Image val = (((Object)(object)input != (Object)null) ? ((Component)input).GetComponent<Image>() : null);
			if (!((Object)(object)val == (Object)null) && NativeBackgrounds.TryGetValue(((Object)val).GetInstanceID(), out var value))
			{
				value.SetHovered(hovered: true);
			}
		}

		private static void OnPieceHoverExit(UIInputHandler input)
		{
			Image val = (((Object)(object)input != (Object)null) ? ((Component)input).GetComponent<Image>() : null);
			if (!((Object)(object)val == (Object)null) && NativeBackgrounds.TryGetValue(((Object)val).GetInstanceID(), out var value))
			{
				value.SetHovered(hovered: false);
			}
		}

		private static void RestoreNativeCraftingCells()
		{
			foreach (KeyValuePair<int, UIInputHandler> hoverInput in HoverInputs)
			{
				UIInputHandler value = hoverInput.Value;
				if (!((Object)(object)value == (Object)null))
				{
					value.m_onPointerEnter = (Action<UIInputHandler>)Delegate.Remove(value.m_onPointerEnter, new Action<UIInputHandler>(OnPieceHoverEnter));
					value.m_onPointerExit = (Action<UIInputHandler>)Delegate.Remove(value.m_onPointerExit, new Action<UIInputHandler>(OnPieceHoverExit));
				}
			}
			HoverInputs.Clear();
			foreach (KeyValuePair<int, NativeBackgroundState> nativeBackground in NativeBackgrounds)
			{
				nativeBackground.Value.Restore();
			}
			NativeBackgrounds.Clear();
		}

		private static void EnsurePersistentRepair(Hud hud, IReadOnlyList<Piece> pieces, IList icons, int repairIndex)
		{
			if (repairIndex < 0 || repairIndex >= pieces.Count || repairIndex >= icons.Count)
			{
				DestroyPersistentRepair();
				return;
			}
			Piece val = pieces[repairIndex];
			if ((Object)(object)_persistentRepair == (Object)null || _repairHudId != ((Object)hud).GetInstanceID() || (Object)(object)_repairPiece == (Object)null || ((Object)_repairPiece).GetInstanceID() !=