Decompiled source of Sorted Menus Cooking Crafting and Skills Menu v1.3.3

SortedMenus.dll

Decompiled 7 months ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: Guid("7acf09e7-8d02-4271-b678-38bbe20bf668")]
[assembly: ComVisible(false)]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyProduct("SortedMenus")]
[assembly: AssemblyCompany("")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyTitle("SortedMenus")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyFileVersion("1.3.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.3.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<51526939-6502-4573-9d74-00bc13480f09>Embedded]
	internal sealed class <51526939-6502-4573-9d74-00bc13480f09>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[<51526939-6502-4573-9d74-00bc13480f09>Embedded]
	[CompilerGenerated]
	internal sealed class <0a872965-f197-45cf-844e-d0c84cc3bca8>IsReadOnlyAttribute : Attribute
	{
	}
}
namespace SortedMenus
{
	internal sealed class ConfigurationManagerAttributes
	{
		public bool? ShowRangeAsPercent;

		public Action<ConfigEntryBase> CustomDrawer;

		public bool? Browsable;

		public string Category;

		public object DefaultValue;

		public bool? HideDefaultButton;

		public bool? HideSettingName;

		public string Description;

		public string DispName;

		public int? Order;

		public bool? ReadOnly;

		public bool? IsAdvanced;

		public Func<object, string> ObjToStr;

		public Func<string, object> StrToObj;

		internal static ConfigDescription HiddenDisplay(Func<bool> condition, string description, AcceptableValueBase acceptableValues = null)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			if (condition())
			{
				return new ConfigDescription(description, acceptableValues, new object[1]
				{
					new ConfigurationManagerAttributes
					{
						Browsable = false,
						ReadOnly = true
					}
				});
			}
			return new ConfigDescription(description, acceptableValues, Array.Empty<object>());
		}

		internal static ConfigDescription CustomSeeOnlyDisplay(string description, AcceptableValueBase acceptableValues = null)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			if (SortedMenusPlugin.HasAugaInstalled())
			{
				return new ConfigDescription("Skills menu sorting from this mod is incompatible with AUGA", acceptableValues, new object[1]
				{
					new ConfigurationManagerAttributes
					{
						ReadOnly = true,
						CustomDrawer = delegate
						{
							CustomLabelDrawer("Disabled due to using AUGA");
						}
					}
				});
			}
			if (SortedMenusPlugin.HasCombinedSkillsModInstalled())
			{
				return new ConfigDescription("Skills menu sorting from this mod is disabled in favor of the skills menu sorting of the 'Combine Skills' mod.", acceptableValues, new object[1]
				{
					new ConfigurationManagerAttributes
					{
						ReadOnly = true,
						CustomDrawer = delegate
						{
							CustomLabelDrawer("Disabled in favor of 'Combine Skills' mod");
						}
					}
				});
			}
			return new ConfigDescription(description, acceptableValues, Array.Empty<object>());
		}

		internal static ConfigDescription SeeOnlyDisplay(Func<bool> condition, string description, string overwriteDescription, string overwriteLabel, AcceptableValueBase acceptableValues = null)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			if (condition())
			{
				return new ConfigDescription(overwriteDescription, acceptableValues, new object[1]
				{
					new ConfigurationManagerAttributes
					{
						ReadOnly = true,
						CustomDrawer = delegate
						{
							CustomLabelDrawer(overwriteLabel);
						}
					}
				});
			}
			return new ConfigDescription(description, acceptableValues, Array.Empty<object>());
		}

		private static void CustomLabelDrawer(string labelText)
		{
			GUILayout.Label(labelText, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		}
	}
	[HarmonyPatch]
	internal class InventoryGuiPatch
	{
		internal static Dictionary<string, string> craftingStationSortingOverwrites = new Dictionary<string, string>();

		[HarmonyPriority(500)]
		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
		[HarmonyPrefix]
		private static void UpdateRecipeList(InventoryGui __instance, ref List<Recipe> recipes)
		{
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				return;
			}
			CraftingStation currentCraftingStation = Player.m_localPlayer.GetCurrentCraftingStation();
			string text = (Object.op_Implicit((Object)(object)currentCraftingStation) ? Utils.GetPrefabName(((Component)currentCraftingStation).gameObject) : null);
			if (text != null && craftingStationSortingOverwrites.TryGetValue(text, out var value))
			{
				string text2 = value.ToLower();
				string text3 = text2;
				if (text3 == "ignored")
				{
					return;
				}
				if (text3 == "cooking")
				{
					CookingMenuSorting.UpdateRecipeList(ref recipes, text, __instance.InCraftTab());
					return;
				}
			}
			if (text == "piece_cauldron")
			{
				CookingMenuSorting.UpdateRecipeList(ref recipes, text, __instance.InCraftTab());
			}
			else
			{
				CraftingMenuSorting.UpdateRecipeList(ref recipes, text, !Object.op_Implicit((Object)(object)currentCraftingStation));
			}
		}
	}
	[HarmonyPatch]
	internal class OverwritePatches
	{
		internal static Dictionary<string, string> importedNameOverwrites = new Dictionary<string, string>();

		internal static Dictionary<string, string> importedSortOverwrites = new Dictionary<string, string>();

		internal static readonly Dictionary<string, string> baseGameArmorSortOverwrites = new Dictionary<string, string>();

		private static readonly string[] uniformVanillaArmorSets = new string[8] { "bronze", "carapace", "iron", "fenris", "leather", "mage", "trollleather", "root" };

		[HarmonyPostfix]
		[HarmonyPriority(1)]
		[HarmonyPatch(typeof(FejdStartup), "Start")]
		private static void FejdStartup_Start_Postfix()
		{
			OverwriteFileLoader.LoadOverwrites();
			LoadBaseGameArmorSortOverwrites();
		}

		[HarmonyPatch(typeof(Localization), "Translate")]
		[HarmonyPostfix]
		public static void Localization_Translate_Postfix(string word, ref string __result)
		{
			if (SortConfig.EnableCustomNameOverrides.Value && importedNameOverwrites.TryGetValue(word, out var value))
			{
				__result = value;
			}
		}

		private static void LoadBaseGameArmorSortOverwrites()
		{
			baseGameArmorSortOverwrites.Clear();
			string[] array = uniformVanillaArmorSets;
			foreach (string text in array)
			{
				string value = "$item_chest_" + text;
				baseGameArmorSortOverwrites["$item_legs_" + text] = value;
				baseGameArmorSortOverwrites["$item_helmet_" + text] = value;
			}
			baseGameArmorSortOverwrites["$item_legs_pgreaves"] = "$item_chest_pcuirass";
			baseGameArmorSortOverwrites["$item_helmet_padded"] = "$item_chest_pcuirass";
			baseGameArmorSortOverwrites["$item_legs_wolf"] = "$item_chest_wolf";
			baseGameArmorSortOverwrites["$item_helmet_drake"] = "$item_chest_wolf";
			baseGameArmorSortOverwrites["$item_legs_rags"] = "$item_chest_rags";
			baseGameArmorSortOverwrites["$item_cape_deerhide"] = "$item_chest_leather";
			baseGameArmorSortOverwrites["$item_cape_trollhide"] = "$item_chest_trollleather";
			baseGameArmorSortOverwrites["$item_cape_wolf"] = "$item_chest_wolf";
			baseGameArmorSortOverwrites["$item_cape_odin"] = "$item_helmet_odin";
		}
	}
	internal class CookingMenuSorting
	{
		internal static readonly Dictionary<string, ItemData> cookingStationAndOvenRecipes = new Dictionary<string, ItemData>();

		internal static void UpdateRecipeList(ref List<Recipe> recipes, string stationName, bool isInCraftTab)
		{
			if (SortConfig.CookingMenuSorting.Value == SortCookingMenu.Disabled || !isInCraftTab)
			{
				return;
			}
			Stopwatch stopwatch = new Stopwatch();
			stopwatch.Start();
			if (stationName != "piece_cauldron")
			{
				recipes.Sort((Recipe recipeA, Recipe recipeB) => recipeA.CompareRecipeTo(recipeB, CraftingStationType.CookingPot));
			}
			else if (!SortedRecipeCaches.TryReapplySorting(ref recipes, SortedRecipeCaches.cachedSortedCauldronRecipes))
			{
				UpdateCookingStationAndOvenRecipeList();
				recipes.Sort((Recipe recipeA, Recipe recipeB) => recipeA.CompareRecipeTo(recipeB, CraftingStationType.CookingPot));
				SortedRecipeCaches.UpdateSortCache(recipes, SortedRecipeCaches.cachedSortedCauldronRecipes);
			}
			stopwatch.Stop();
			Helper.Log($"Time to sort {recipes.Count} recipes: {stopwatch.Elapsed}");
		}

		internal static void UpdateCookingStationAndOvenRecipeList()
		{
			cookingStationAndOvenRecipes.Clear();
			if (SortConfig.CheckIfItemIsInputForOvenOrCookingStation.Value)
			{
				CookingStation component = ZNetScene.instance.GetPrefab("piece_oven").GetComponent<CookingStation>();
				CookingStation component2 = ZNetScene.instance.GetPrefab("piece_cookingstation").GetComponent<CookingStation>();
				CookingStation component3 = ZNetScene.instance.GetPrefab("piece_cookingstation_iron").GetComponent<CookingStation>();
				IterateOverCookingStation(component);
				IterateOverCookingStation(component2);
				IterateOverCookingStation(component3);
			}
		}

		private static void IterateOverCookingStation(CookingStation station)
		{
			foreach (ItemConversion item in station.m_conversion)
			{
				if (item != null && Object.op_Implicit((Object)(object)item.m_to) && Object.op_Implicit((Object)(object)item.m_from))
				{
					string name = item.m_from.m_itemData.m_shared.m_name;
					if (!cookingStationAndOvenRecipes.TryGetValue(name, out var value) || value.GetSimpleFoodTotal() < item.m_to.m_itemData.GetSimpleFoodTotal())
					{
						cookingStationAndOvenRecipes[name] = item.m_to.m_itemData;
					}
				}
			}
		}
	}
	internal class ItemSortOverrider
	{
		internal static readonly Dictionary<string, string> sortOverrides = new Dictionary<string, string>();

		internal static void UpdateSortOverrides(List<Recipe> recipes)
		{
			sortOverrides.Clear();
			if (SortConfig.KeepArmorSetsTogether.Value != 0)
			{
				AddBaseGameArmorSortOverwrites();
			}
			if (SortConfig.EnableCustomSortOverrides.Value)
			{
				AddCustomSortOverrides();
			}
			if (SortConfig.KeepArmorSetsTogether.Value == ArmorSetSorting.EnabledWithModSupport)
			{
				MaybeAddModdedArmorSortOverrides(recipes);
			}
		}

		private static void AddBaseGameArmorSortOverwrites()
		{
			foreach (KeyValuePair<string, string> baseGameArmorSortOverwrite in OverwritePatches.baseGameArmorSortOverwrites)
			{
				sortOverrides[baseGameArmorSortOverwrite.Key] = baseGameArmorSortOverwrite.Value;
			}
			if (SortConfig.KeepArmorSetsTogether.Value == ArmorSetSorting.EnabledWithModSupport && Chainloader.PluginInfos.ContainsKey("goldenrevolver.SimpleSetAndCapeBonuses"))
			{
				sortOverrides["$item_helmet_midsummercrown"] = "$item_chest_rags";
			}
		}

		private static void AddCustomSortOverrides()
		{
			foreach (KeyValuePair<string, string> importedSortOverwrite in OverwritePatches.importedSortOverwrites)
			{
				AddOverrideWithPrefix(importedSortOverwrite.Key, importedSortOverwrite.Value);
			}
		}

		private static void AddOverrideWithPrefix(string key, string prefix)
		{
			sortOverrides[key] = prefix + " " + key;
		}

		private static void MaybeAddModdedArmorSortOverrides(List<Recipe> recipes)
		{
			foreach (Recipe recipe in recipes)
			{
				if (!((Object)(object)recipe == (Object)null) && Object.op_Implicit((Object)(object)recipe.m_item) && recipe.m_item.m_itemData != null)
				{
					MaybeAddModdedOverride(recipe.m_item.m_itemData);
				}
			}
		}

		private static void MaybeAddModdedOverride(ItemData item)
		{
			if (item.IsOverridableArmor() && !sortOverrides.ContainsKey(item.m_shared.m_name) && TryGetModdedOverride(item, out var moddedOverrideName))
			{
				sortOverrides[item.m_shared.m_name] = moddedOverrideName;
			}
		}

		private static bool TryGetModdedOverride(ItemData item, out string moddedOverrideName)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Invalid comparison between Unknown and I4
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Invalid comparison between Unknown and I4
			moddedOverrideName = item.m_shared.m_name;
			if ((int)item.m_shared.m_itemType == 6)
			{
				if (TryReplaceWithChest(ref moddedOverrideName, "HelmetAlt", "Helmet", "HelmAlt", "Helm"))
				{
					return true;
				}
			}
			else if ((int)item.m_shared.m_itemType == 11)
			{
				if (TryReplaceWithChest(ref moddedOverrideName, "Legs", "Greaves", "Pants"))
				{
					return true;
				}
			}
			else if ((int)item.m_shared.m_itemType == 17 && TryReplaceWithChest(ref moddedOverrideName, "Cape"))
			{
				return true;
			}
			return false;
		}

		private static bool TryReplaceWithChest(ref string itemName, params string[] infixesToTest)
		{
			foreach (string infixToReplace in infixesToTest)
			{
				if (TryReplaceInfix(ref itemName, infixToReplace, "Chest"))
				{
					return true;
				}
			}
			return false;
		}

		private static bool TryReplaceInfix(ref string itemName, string infixToReplace, string infixToCheckFor)
		{
			bool flag = itemName.Contains(infixToReplace);
			bool flag2 = itemName.Contains(infixToReplace.ToLower());
			if (!flag && !flag2)
			{
				return false;
			}
			if (flag)
			{
				string text = itemName.Replace(infixToReplace, infixToCheckFor);
				if (CheckIfTranslatable(text))
				{
					itemName = text;
					return true;
				}
			}
			if (flag2)
			{
				string text2 = itemName.Replace(infixToReplace.ToLower(), infixToCheckFor.ToLower());
				if (CheckIfTranslatable(text2))
				{
					itemName = text2;
					return true;
				}
			}
			return false;
		}

		private static bool CheckIfTranslatable(string value)
		{
			if (value.IndexOf('$') != 0)
			{
				return false;
			}
			string text = Localization.instance.Translate(value.Substring(1));
			return text.IndexOf('[') != 0;
		}
	}
	internal class CraftingMenuSorting
	{
		internal static void UpdateRecipeList(ref List<Recipe> recipes, string stationName, bool isHandCrafting)
		{
			if (SortConfig.CraftingMenuSorting.Value == SortCraftingMenu.Disabled)
			{
				return;
			}
			List<Recipe> oldSortedList = null;
			CraftingStationType stationType = CraftingStationType.Other;
			if (isHandCrafting)
			{
				if (SortConfig.HandCraftingMenuSorting.Value == SortHandCraftingMenu.Disabled || (SortConfig.HandCraftingMenuSorting.Value == SortHandCraftingMenu.OnlyWhileUsingNoCostCheat && !Player.m_localPlayer.NoCostCheat()))
				{
					return;
				}
				oldSortedList = ((!Player.m_localPlayer.NoCostCheat()) ? SortedRecipeCaches.cachedSortedHandCraftingRecipes : SortedRecipeCaches.cachedSortedNoCostRecipes);
			}
			else if (stationName == "forge")
			{
				stationType = CraftingStationType.Forge;
				oldSortedList = ((!Player.m_localPlayer.NoCostCheat()) ? SortedRecipeCaches.cachedSortedForgeRecipes : SortedRecipeCaches.cachedSortedNoCostRecipes);
			}
			else if (stationName == "piece_workbench")
			{
				oldSortedList = ((!Player.m_localPlayer.NoCostCheat()) ? SortedRecipeCaches.cachedSortedWorkBenchRecipes : SortedRecipeCaches.cachedSortedNoCostRecipes);
			}
			Stopwatch stopwatch = new Stopwatch();
			stopwatch.Start();
			if (!SortedRecipeCaches.TryReapplySorting(ref recipes, oldSortedList))
			{
				ItemSortOverrider.UpdateSortOverrides(recipes);
				recipes.Sort((Recipe recipeA, Recipe recipeB) => recipeA.CompareRecipeTo(recipeB, stationType));
				SortedRecipeCaches.UpdateSortCache(recipes, oldSortedList);
			}
			stopwatch.Stop();
			Helper.Log($"Time to sort {recipes.Count} recipes: {stopwatch.Elapsed}");
		}
	}
	internal static class FoodItemExtension
	{
		[<0a872965-f197-45cf-844e-d0c84cc3bca8>IsReadOnly]
		internal struct StatsWhenEaten
		{
			internal readonly float health;

			internal readonly float stamina;

			internal readonly float eitr;

			internal readonly float total;

			public StatsWhenEaten(float health, float stamina, float eitr)
			{
				this.health = health;
				this.stamina = stamina;
				this.eitr = eitr;
				total = health + stamina + eitr;
			}
		}

		private static bool IsOrCanBeEdible(ref ItemData item)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Invalid comparison between Unknown and I4
			if (SortConfig.CheckIfItemIsInputForOvenOrCookingStation.Value && CookingMenuSorting.cookingStationAndOvenRecipes.TryGetValue(item.m_shared.m_name, out var value))
			{
				item = value;
			}
			return (int)item.m_shared.m_itemType == 2;
		}

		internal static float GetSimpleFoodTotal(this ItemData item)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			if ((int)item.m_shared.m_itemType != 2)
			{
				return 0f;
			}
			return item.m_shared.m_food + item.m_shared.m_foodStamina + item.m_shared.m_foodEitr;
		}

		internal static StatsWhenEaten GetStatsWhenEaten(this ItemData item)
		{
			if (!IsOrCanBeEdible(ref item))
			{
				return new StatsWhenEaten(0f, 0f, 0f);
			}
			return new StatsWhenEaten(item.m_shared.m_food, item.m_shared.m_foodStamina, item.m_shared.m_foodEitr);
		}

		internal static int CompareFoodByConfig(this ItemData thisItem, ItemData otherItem)
		{
			StatsWhenEaten statsWhenEaten = thisItem.GetStatsWhenEaten();
			StatsWhenEaten statsWhenEaten2 = otherItem.GetStatsWhenEaten();
			float total = statsWhenEaten.total;
			int num = total.CompareTo(statsWhenEaten2.total);
			if (SortConfig.SortInediblesToBottom.Value && (statsWhenEaten.total == 0f || statsWhenEaten2.total == 0f) && num != 0)
			{
				return -num;
			}
			if (statsWhenEaten.total == 0f && statsWhenEaten2.total == 0f)
			{
				int num2 = thisItem.IsAmmo().CompareTo(otherItem.IsAmmo());
				if (num2 != 0)
				{
					return num2;
				}
				return thisItem.CompareItemNameTo(otherItem);
			}
			total = statsWhenEaten.health;
			int num3 = total.CompareTo(statsWhenEaten2.health);
			total = statsWhenEaten.stamina;
			int num4 = total.CompareTo(statsWhenEaten2.stamina);
			total = statsWhenEaten.eitr;
			int num5 = total.CompareTo(statsWhenEaten2.eitr);
			if (!SortConfig.SortFoodInAscendingOrder.Value)
			{
				num *= -1;
				num3 *= -1;
				num4 *= -1;
				num5 *= -1;
			}
			switch (SortConfig.CookingMenuSorting.Value)
			{
			case SortCookingMenu.ByTotalThenHealth:
				if (num != 0)
				{
					return num;
				}
				if (num3 != 0)
				{
					return num3;
				}
				break;
			case SortCookingMenu.ByTotalThenStamina:
				if (num != 0)
				{
					return num;
				}
				if (num4 != 0)
				{
					return num4;
				}
				break;
			case SortCookingMenu.ByTotalThenEitr:
				if (num != 0)
				{
					return num;
				}
				if (num5 != 0)
				{
					return num5;
				}
				break;
			case SortCookingMenu.ByHealthThenTotal:
				if (num3 != 0)
				{
					return num3;
				}
				if (num != 0)
				{
					return num;
				}
				break;
			case SortCookingMenu.ByStaminaThenTotal:
				if (num4 != 0)
				{
					return num4;
				}
				if (num != 0)
				{
					return num;
				}
				break;
			case SortCookingMenu.ByEitrThenTotal:
				if (num5 != 0)
				{
					return num5;
				}
				if (num != 0)
				{
					return num;
				}
				break;
			}
			return thisItem.CompareItemNameTo(otherItem);
		}
	}
	internal static class CustomItemSortExtension
	{
		internal static string GetCompareName(this ItemData item)
		{
			string name = item.m_shared.m_name;
			if (ItemSortOverrider.sortOverrides.TryGetValue(name, out var value))
			{
				return value;
			}
			return name;
		}

		internal static int CompareItemWithArmorOverridesTo(this ItemData thisItem, ItemData otherItem)
		{
			string compareName = thisItem.GetCompareName();
			string compareName2 = otherItem.GetCompareName();
			int num = compareName.CompareItemNameTo(compareName2);
			if (num != 0)
			{
				return num;
			}
			return thisItem.GetArmorCompareType().CompareTo(otherItem.GetArmorCompareType());
		}

		internal static int GetArmorCompareType(this ItemData item)
		{
			//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)
			//IL_000d: 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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			ItemType itemType = item.m_shared.m_itemType;
			ItemType val = itemType;
			if ((int)val <= 7)
			{
				if ((int)val == 6)
				{
					return 0;
				}
				if ((int)val == 7)
				{
					return 1;
				}
			}
			else
			{
				if ((int)val == 11)
				{
					return 2;
				}
				if ((int)val == 17)
				{
					return 3;
				}
			}
			return 4;
		}

		internal static int CompareAmmoTo(this ItemData thisAmmo, ItemData otherAmmo, SortAmmo ammoPriority)
		{
			if (ammoPriority == SortAmmo.NoPriority)
			{
				return 0;
			}
			if (SortConfig.UseSmartAmmoSorting.Value)
			{
				return thisAmmo.GetAmmoCompareValue(ammoPriority).CompareTo(otherAmmo.GetAmmoCompareValue(ammoPriority));
			}
			int num = thisAmmo.IsAmmo().CompareTo(otherAmmo.IsAmmo());
			return (ammoPriority == SortAmmo.ToTheTop) ? (-num) : num;
		}

		internal static int GetAmmoCompareValue(this ItemData item, SortAmmo ammoPriority)
		{
			//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)
			//IL_000d: 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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			ItemType itemType = item.m_shared.m_itemType;
			ItemType val = itemType;
			if ((int)val != 9)
			{
				if ((int)val == 23)
				{
					return 1;
				}
				return (ammoPriority == SortAmmo.ToTheTop) ? 5 : (-5);
			}
			return item.m_shared.m_name.ToLower().Contains("fishingbait") ? 2 : 0;
		}

		internal static bool IsAmmo(this ItemData item)
		{
			//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)
			//IL_000d: 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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			ItemType itemType = item.m_shared.m_itemType;
			ItemType val = itemType;
			if ((int)val == 9 || (int)val == 23)
			{
				return true;
			}
			return false;
		}

		internal static bool IsOverridableArmor(this ItemData item)
		{
			//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)
			//IL_000d: 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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			ItemType itemType = item.m_shared.m_itemType;
			ItemType val = itemType;
			if ((int)val == 6 || (int)val == 11 || (int)val == 17)
			{
				return true;
			}
			return false;
		}
	}
	internal static class GenericItemExtension
	{
		internal static string GetItemTranslation(this string itemName)
		{
			return Localization.instance.Localize(itemName);
		}

		internal static int CompareItemNameTo(this string thisItemName, string otherItemName)
		{
			return thisItemName.GetItemTranslation().CompareTo(otherItemName.GetItemTranslation());
		}

		internal static int CompareItemNameTo(this ItemData thisItem, ItemData otherItem)
		{
			return thisItem.m_shared.m_name.CompareItemNameTo(otherItem.m_shared.m_name);
		}

		internal static int CompareRecipeTo(this Recipe thisRecipe, Recipe otherRecipe, CraftingStationType stationType)
		{
			bool flag = (Object)(object)thisRecipe == (Object)null || !Object.op_Implicit((Object)(object)thisRecipe.m_item) || thisRecipe.m_item.m_itemData == null;
			bool flag2 = (Object)(object)otherRecipe == (Object)null || !Object.op_Implicit((Object)(object)otherRecipe.m_item) || otherRecipe.m_item.m_itemData == null;
			if (flag || flag2)
			{
				return (!flag).CompareTo(!flag2);
			}
			ItemData itemData = thisRecipe.m_item.m_itemData;
			ItemData itemData2 = otherRecipe.m_item.m_itemData;
			SortAmmo value;
			switch (stationType)
			{
			case CraftingStationType.CookingPot:
				return itemData.CompareFoodByConfig(itemData2);
			default:
				value = SortConfig.SortAmmo.Value;
				break;
			case CraftingStationType.Forge:
				value = SortConfig.SortAmmoAtForge.Value;
				break;
			}
			SortAmmo ammoPriority = value;
			int num = itemData.CompareAmmoTo(itemData2, ammoPriority);
			if (num != 0)
			{
				return num;
			}
			if (SortConfig.KeepArmorSetsTogether.Value != 0)
			{
				return itemData.CompareItemWithArmorOverridesTo(itemData2);
			}
			return itemData.CompareItemNameTo(itemData2);
		}
	}
	internal class OverwriteFileLoader
	{
		public static string[] supportedEmbeddedLanguages = new string[1] { "English" };

		private const string embeddedPathFormat = "SortedMenus.Overwrites.{0}.{1}.json";

		private const string nameOverwriteInfix = "SortedMenus.NameOverwrites";

		private const string sortOverwriteInfix = "SortedMenus.SortOverwrites";

		private const string loadingLog = "Loading {0} overwrite file '{1}' for language '{2}'";

		private const string failedLoadLog = "Failed loading {0} overwrite file '{1}' for language '{2}'";

		private const string external = "external";

		private const string embedded = "embedded";

		private const string embeddedPathFormatNoLanguage = "SortedMenus.Overwrites.";

		private const string craftingStationSortingOverwriteSuffix = "SortedMenus.CraftingStationSortingOverwrites.json";

		private const string loadingStationLog = "Loading {0} crafting station sort overwrite file";

		private const string failedStationLoadLog = "Failed loading {0} crafting station sort overwrite file";

		internal static void LoadOverwrites()
		{
			Dictionary<string, string> dictionary = LoadOverwriteFiles("SortedMenus.NameOverwrites");
			if (dictionary != null)
			{
				ValidateNameOverwrites(dictionary);
				OverwritePatches.importedNameOverwrites = dictionary;
			}
			Dictionary<string, string> dictionary2 = LoadOverwriteFiles("SortedMenus.SortOverwrites");
			if (dictionary2 != null)
			{
				OverwritePatches.importedSortOverwrites = dictionary2;
			}
			Dictionary<string, string> dictionary3 = LoadStationSortOverwriteFile();
			if (dictionary3 != null)
			{
				InventoryGuiPatch.craftingStationSortingOverwrites = dictionary3;
			}
		}

		internal static Dictionary<string, string> LoadStationSortOverwriteFile()
		{
			string[] files = Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), "SortedMenus.CraftingStationSortingOverwrites.json", SearchOption.AllDirectories);
			string[] array = files;
			foreach (string path in array)
			{
				Helper.Log(string.Format("Loading {0} crafting station sort overwrite file", "external"));
				Dictionary<string, string> dictionary = LoadExternalOverwriteFile(path);
				if (dictionary != null)
				{
					return dictionary;
				}
				Helper.LogWarning(string.Format("Failed loading {0} crafting station sort overwrite file", "external"));
			}
			Helper.Log(string.Format("Loading {0} crafting station sort overwrite file", "embedded"));
			string path2 = "SortedMenus.Overwrites.SortedMenus.CraftingStationSortingOverwrites.json";
			Dictionary<string, string> dictionary2 = LoadEmbeddedOverwriteFile(path2);
			if (dictionary2 != null)
			{
				return dictionary2;
			}
			Helper.LogWarning(string.Format("Failed loading {0} crafting station sort overwrite file", "embedded"));
			return null;
		}

		internal static Dictionary<string, string> LoadOverwriteFiles(string infix)
		{
			string selectedLanguage = Localization.instance.GetSelectedLanguage();
			string[] files = Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), infix + ".*.json", SearchOption.AllDirectories);
			string[] array = files;
			foreach (string path in array)
			{
				string text = Path.GetFileNameWithoutExtension(path).Split(new char[1] { '.' })[2];
				if (text == selectedLanguage)
				{
					Helper.Log(string.Format("Loading {0} overwrite file '{1}' for language '{2}'", "external", infix, selectedLanguage));
					Dictionary<string, string> dictionary = LoadExternalOverwriteFile(path);
					if (dictionary != null)
					{
						return dictionary;
					}
					Helper.LogWarning(string.Format("Failed loading {0} overwrite file '{1}' for language '{2}'", "external", infix, selectedLanguage));
					break;
				}
			}
			if (supportedEmbeddedLanguages.Contains(selectedLanguage))
			{
				Helper.Log(string.Format("Loading {0} overwrite file '{1}' for language '{2}'", "embedded", infix, selectedLanguage));
				string path2 = $"SortedMenus.Overwrites.{infix}.{selectedLanguage}.json";
				Dictionary<string, string> dictionary2 = LoadEmbeddedOverwriteFile(path2);
				if (dictionary2 != null)
				{
					return dictionary2;
				}
				Helper.LogWarning(string.Format("Failed loading {0} overwrite file '{1}' for language '{2}'", "embedded", infix, selectedLanguage));
			}
			return null;
		}

		internal static void ValidateNameOverwrites(Dictionary<string, string> dict)
		{
			List<KeyValuePair<string, string>> list = dict.ToList();
			foreach (KeyValuePair<string, string> item in list)
			{
				dict.Remove(item.Key);
				if (item.Key.IndexOf('$') == 0)
				{
					string key = item.Key.Substring(1);
					dict[key] = item.Value;
					if (!Localization.instance.m_translations.ContainsKey(key))
					{
						Helper.Log(item.Key + " may not be a valid translation key to overwrite (no matching translation found during late check)");
					}
				}
				else
				{
					Helper.Log(item.Key + " is not a valid translation key to overwrite (must start with $)");
				}
			}
		}

		internal static Dictionary<string, string> LoadExternalOverwriteFile(string path)
		{
			string text = File.ReadAllText(path);
			if (text == null)
			{
				return null;
			}
			return ParseStringToDictionary(text);
		}

		internal static Dictionary<string, string> LoadEmbeddedOverwriteFile(string path)
		{
			string text = ReadEmbeddedTextFile(path);
			if (text == null)
			{
				return null;
			}
			return ParseStringToDictionary(text);
		}

		internal static Dictionary<string, string> ParseStringToDictionary(string translationAsString)
		{
			Dictionary<string, string> dictionary = new DeserializerBuilder().IgnoreFields().Build().Deserialize<Dictionary<string, string>>(translationAsString);
			if (dictionary == null || dictionary.Count == 0)
			{
				return null;
			}
			return dictionary;
		}

		public static string ReadEmbeddedTextFile(string path)
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			Stream manifestResourceStream = executingAssembly.GetManifestResourceStream(path);
			if (manifestResourceStream == null)
			{
				return null;
			}
			using MemoryStream memoryStream = new MemoryStream();
			manifestResourceStream.CopyTo(memoryStream);
			byte[] array = ((memoryStream.Length > 0) ? memoryStream.ToArray() : null);
			return (array != null) ? Encoding.UTF8.GetString(array) : null;
		}
	}
	public static class Helper
	{
		internal static void Log(object s)
		{
			if (SortConfig.EnableDebugLogs.Value)
			{
				string text = "Sorted Cooking, Crafting and Skills Menu 1.3.3: " + ((s != null) ? s.ToString() : "null");
				Debug.Log((object)text);
			}
		}

		internal static void LogWarning(object s)
		{
			string text = "Sorted Cooking, Crafting and Skills Menu 1.3.3: " + ((s != null) ? s.ToString() : "null");
			Debug.LogWarning((object)text);
		}
	}
	internal static class SkillExtension
	{
		internal static int CompareSkillsByConfigSetting(this Skill thisSkill, Skill otherSkill)
		{
			if (SortConfig.SkillsMenuSorting.Value == SortSkillsMenu.ByLevel)
			{
				int num = -thisSkill.CompareSkillLevel(otherSkill);
				if (num != 0)
				{
					return num;
				}
			}
			return thisSkill.GetSkillTranslation().CompareTo(otherSkill.GetSkillTranslation());
		}

		internal static int CompareSkillLevel(this Skill thisSkill, Skill otherSkill)
		{
			int num = Mathf.FloorToInt(thisSkill.m_level).CompareTo(Mathf.FloorToInt(otherSkill.m_level));
			if (num != 0)
			{
				return num;
			}
			return thisSkill.m_accumulator.CompareTo(otherSkill.m_accumulator);
		}

		internal static string GetSkillTranslation(this Skill skill)
		{
			return Localization.instance.Localize("$skill_" + ((object)(SkillType)(ref skill.m_info.m_skill)).ToString().ToLower());
		}
	}
	[HarmonyPatch]
	internal class SkillsMenuPatches
	{
		private static bool safeToCallSetup;

		[HarmonyPostfix]
		[HarmonyPriority(100)]
		[HarmonyPatch(typeof(Skills), "GetSkillList")]
		private static void GetUISkillListPatch(ref List<Skill> __result)
		{
			if (!SortedMenusPlugin.HasSkillsMenuIncompatibleModInstalled() && SortConfig.SkillsMenuSorting.Value != 0)
			{
				__result.Sort((Skill a, Skill b) => a.CompareSkillsByConfigSetting(b));
			}
		}

		[HarmonyPriority(100)]
		[HarmonyPatch(typeof(Skills), "RaiseSkill")]
		[HarmonyPostfix]
		private static void RaiseSkillPatch(Skills __instance, SkillType skillType)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			if (!((Object)(object)__instance.m_player != (Object)(object)Player.m_localPlayer) && (SortConfig.UpdateSkillsMenuOnChange.Value != SortedMenus.UpdateSkillsMenu.EnabledExceptRunSkill || (int)skillType != 102))
			{
				UpdateSkillsMenu(__instance.m_player);
			}
		}

		[HarmonyPriority(300)]
		[HarmonyPatch(typeof(Humanoid), "EquipItem")]
		private static void Postfix(Humanoid __instance, bool __result)
		{
			if (__result && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				UpdateSkillsMenu(Player.m_localPlayer);
			}
		}

		[HarmonyPatch(typeof(Humanoid), "UnequipItem")]
		private static void Postfix(Humanoid __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				UpdateSkillsMenu(Player.m_localPlayer);
			}
		}

		[HarmonyPatch(typeof(SkillsDialog), "Setup")]
		[HarmonyPostfix]
		private static void AfterFirstSkillsDialogSetup()
		{
			safeToCallSetup = true;
		}

		[HarmonyPatch(typeof(Game), "Logout")]
		[HarmonyPrefix]
		internal static void ResetOnLogout()
		{
			safeToCallSetup = false;
		}

		internal static void UpdateSkillsMenu(Player player)
		{
			if (safeToCallSetup && !SortedMenusPlugin.HasSkillsMenuIncompatibleModInstalled() && SortConfig.UpdateSkillsMenuOnChange.Value != 0 && Object.op_Implicit((Object)(object)InventoryGui.instance) && Object.op_Implicit((Object)(object)InventoryGui.instance.m_skillsDialog) && Object.op_Implicit((Object)(object)((Component)InventoryGui.instance.m_skillsDialog).gameObject) && ((Component)InventoryGui.instance.m_skillsDialog).gameObject.activeSelf && Object.op_Implicit((Object)(object)Player.m_localPlayer) && !((Object)(object)player != (Object)(object)Player.m_localPlayer))
			{
				InventoryGui.instance.m_skillsDialog.Setup(player);
			}
		}
	}
	internal class SortConfig
	{
		internal static ConfigEntry<bool> CheckIfItemIsInputForOvenOrCookingStation;

		internal static ConfigEntry<SortCookingMenu> CookingMenuSorting;

		internal static ConfigEntry<bool> SortFoodInAscendingOrder;

		internal static ConfigEntry<bool> SortInediblesToBottom;

		internal static ConfigEntry<SortCraftingMenu> CraftingMenuSorting;

		internal static ConfigEntry<SortHandCraftingMenu> HandCraftingMenuSorting;

		internal static ConfigEntry<ArmorSetSorting> KeepArmorSetsTogether;

		internal static ConfigEntry<SortAmmo> SortAmmo;

		internal static ConfigEntry<SortAmmo> SortAmmoAtForge;

		internal static ConfigEntry<bool> UseSmartAmmoSorting;

		internal static ConfigEntry<bool> EnableCustomSortOverrides;

		internal static ConfigEntry<bool> EnableCustomNameOverrides;

		internal static ConfigEntry<SortSkillsMenu> SkillsMenuSorting;

		internal static ConfigEntry<UpdateSkillsMenu> UpdateSkillsMenuOnChange;

		internal static ConfigEntry<bool> EnableDebugLogs;

		internal static ConfigEntry<bool> EnablePerformanceMode;

		private static ConfigFile config;

		internal static void LoadConfig(BaseUnityPlugin plugin)
		{
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Expected O, but got Unknown
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Expected O, but got Unknown
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Expected O, but got Unknown
			config = plugin.Config;
			string text = "0 - Cooking Menu";
			CheckIfItemIsInputForOvenOrCookingStation = config.Bind<bool>(text, "CheckIfItemIsInputForOvenOrCookingStation", true, "If this is enabled, then items like bread dough will use the food values of the baked bread for the sorting, rather than being viewed as inedible.");
			CookingMenuSorting = config.Bind<SortCookingMenu>(text, "CookingMenuSorting", SortCookingMenu.ByTotalThenHealth, "'Total' means 'health + stamina' to make sorting consistent with progression.");
			SortFoodInAscendingOrder = config.Bind<bool>(text, "SortFoodInAscendingOrder", true, "This only applies to the food centric parameters, not the name.");
			SortInediblesToBottom = config.Bind<bool>(text, "SortInediblesToBottom", true, "Includes items like mead bases and fishing bait.");
			text = "1 - Crafting Menus";
			CraftingMenuSorting = config.Bind<SortCraftingMenu>(text, "CraftingMenuSorting", SortCraftingMenu.ByName, string.Empty);
			HandCraftingMenuSorting = config.Bind<SortHandCraftingMenu>(text, "HandCraftingMenuSorting", SortHandCraftingMenu.OnlyWhileUsingNoCostCheat, "Whether to sort the 'by hand' crafting menu that is directly in your inventory. Since without mods it only has 4 recipes and has to get sorted every time you open your inventory, by default it's only done when using the 'no cost' cheat.");
			KeepArmorSetsTogether = config.Bind<ArmorSetSorting>(text, "KeepArmorSetsTogether", ArmorSetSorting.EnabledWithModSupport, "If enabled, then armor set sorting is determined by the name of the chest piece, and the headpiece and legpiece are added around it. If applicable, the (thematic) cape is also added.");
			SortAmmo = config.Bind<SortAmmo>(text, "SortAmmo", SortedMenus.SortAmmo.ToTheTop, string.Empty);
			SortAmmoAtForge = config.Bind<SortAmmo>(text, "SortAmmoAtForge", SortedMenus.SortAmmo.ToTheBottom, "For people who don't use metal arrows.");
			UseSmartAmmoSorting = config.Bind<bool>(text, "UseSmartAmmoSorting", true, "Smart sort differentiates between normal ammo, fishing bait and unequippable ammo.");
			text = "1.1 - Custom Name or Sort Overwrites";
			EnableCustomNameOverrides = config.Bind<bool>(text, "EnableCustomNameOverrides", true, "Whether to load a custom file to override the item name of some items like the 'Battleaxe' to 'Iron battleaxe' or uniforming all the 'black metal' and 'blackmetal' items to 'black metal'. Only works if the file exists for your current language.");
			EnableCustomSortOverrides = config.Bind<bool>(text, "EnableCustomSortOverrides", true, "Whether to load a custom file to override the sorting behavior of items like 'Frostner' to be sorted to silver gear, or the 'Porcupine' to black metal gear, or to put all mistlands weapons close to each other. Only works if the file exists for your current language.");
			text = "2 - Skills Menu";
			SkillsMenuSorting = config.Bind<SortSkillsMenu>(text, "SkillsMenuSorting", SortSkillsMenu.ByLevel, ConfigurationManagerAttributes.CustomSeeOnlyDisplay(string.Empty));
			SkillsMenuSorting.SettingChanged += SkillsMenuSettingChanged;
			UpdateSkillsMenuOnChange = config.Bind<UpdateSkillsMenu>(text, "UpdateSkillsMenuOnChange", UpdateSkillsMenu.EnabledExceptRunSkill, ConfigurationManagerAttributes.HiddenDisplay(SortedMenusPlugin.HasSkillsMenuIncompatibleModInstalled, "Skills menu updates when changing gear or leveling up instead of requiring to be closed and reopened."));
			UpdateSkillsMenuOnChange.SettingChanged += SkillsMenuSettingChanged;
			bool oldValue = false;
			if (TryGetOldConfigValue(new ConfigDefinition("0 - Cooking Menu", "CheckIfItemIsProduceInOvenOrCookingStation"), ref oldValue))
			{
				CheckIfItemIsInputForOvenOrCookingStation.Value = oldValue;
			}
			if (TryGetOldConfigValue(new ConfigDefinition("0 - Cooking Menu", "SortPotionsAndOtherInediblesToBottom"), ref oldValue))
			{
				SortInediblesToBottom.Value = oldValue;
			}
			if (TryGetOldConfigValue(new ConfigDefinition("1 - Crafting Menus", "UseCustomSortOverrides"), ref oldValue) && !oldValue)
			{
				EnableCustomSortOverrides.Value = false;
				EnableCustomNameOverrides.Value = false;
			}
			text = "9 - Other";
			EnableDebugLogs = config.Bind<bool>(text, "EnableDebugLogs", false, "Mostly shows loading logs for custom name and sorting overwrite files.");
			EnablePerformanceMode = config.Bind<bool>(text, "EnablePerformanceMode", true, "This speeds up the sorting by saving (caching) the result of the last sorting for the base game crafting stations.");
			config.SettingChanged += Config_SettingChanged;
		}

		private static void Config_SettingChanged(object sender, SettingChangedEventArgs e)
		{
			SortedRecipeCaches.InvalidateCaches();
		}

		private static void SkillsMenuSettingChanged(object sender, EventArgs e)
		{
			SkillsMenuPatches.UpdateSkillsMenu(Player.m_localPlayer);
		}

		public static bool TryGetOldConfigValue<T>(ConfigDefinition configDefinition, ref T oldValue, bool removeIfFound = true)
		{
			if (!TomlTypeConverter.CanConvert(typeof(T)))
			{
				throw new ArgumentException(string.Format("Type {0} is not supported by the config system. Supported types: {1}", typeof(T), string.Join(", ", (from x in TomlTypeConverter.GetSupportedTypes()
					select x.Name).ToArray())));
			}
			try
			{
				object obj = AccessTools.FieldRefAccess<ConfigFile, object>("_ioLock").Invoke(config);
				Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)AccessTools.PropertyGetter(typeof(ConfigFile), "OrphanedEntries").Invoke(config, new object[0]);
				lock (obj)
				{
					if (dictionary.TryGetValue(configDefinition, out var value))
					{
						oldValue = (T)TomlTypeConverter.ConvertToValue(value, typeof(T));
						if (removeIfFound)
						{
							dictionary.Remove(configDefinition);
						}
						return true;
					}
				}
			}
			catch (Exception ex)
			{
				Helper.LogWarning("Error getting orphaned entry: " + ex.StackTrace);
			}
			return false;
		}
	}
	public enum UpdateSkillsMenu
	{
		Disabled,
		Enabled,
		EnabledExceptRunSkill
	}
	public enum ArmorSetSorting
	{
		Disabled,
		Enabled,
		EnabledWithModSupport
	}
	public enum SortHandCraftingMenu
	{
		Disabled,
		OnlyWhileUsingNoCostCheat,
		Enabled
	}
	public enum SortCraftingMenu
	{
		Disabled,
		ByName
	}
	public enum SortAmmo
	{
		NoPriority,
		ToTheTop,
		ToTheBottom
	}
	public enum SortSkillsMenu
	{
		Disabled,
		ByName,
		ByLevel
	}
	public enum SortCookingMenu
	{
		Disabled = 0,
		ByName = 1,
		ByTotalThenHealth = 10,
		ByTotalThenStamina = 11,
		ByTotalThenEitr = 12,
		ByHealthThenTotal = 20,
		ByStaminaThenTotal = 21,
		ByEitrThenTotal = 22
	}
	[BepInPlugin("goldenrevolver.SortedMenus", "Sorted Cooking, Crafting and Skills Menu", "1.3.3")]
	public class SortedMenusPlugin : BaseUnityPlugin
	{
		public const string GUID = "goldenrevolver.SortedMenus";

		public const string NAME = "Sorted Cooking, Crafting and Skills Menu";

		public const string VERSION = "1.3.3";

		private const string combineSkillsMod = "goldenrevolver.CombineSpearAndPolearmSkills";

		private const string augaMod = "randyknapp.mods.auga";

		protected void Start()
		{
			SortConfig.LoadConfig((BaseUnityPlugin)(object)this);
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
		}

		internal static bool HasSkillsMenuIncompatibleModInstalled()
		{
			return HasCombinedSkillsModInstalled() || HasAugaInstalled();
		}

		internal static bool HasCombinedSkillsModInstalled()
		{
			return Chainloader.PluginInfos.ContainsKey("goldenrevolver.CombineSpearAndPolearmSkills");
		}

		internal static bool HasAugaInstalled()
		{
			return Chainloader.PluginInfos.ContainsKey("randyknapp.mods.auga");
		}
	}
	internal enum CraftingStationType
	{
		CookingPot,
		Forge,
		Other
	}
	[HarmonyPatch]
	internal class SortedRecipeCaches
	{
		internal static readonly List<Recipe> cachedSortedCauldronRecipes = new List<Recipe>();

		internal static readonly List<Recipe> cachedSortedWorkBenchRecipes = new List<Recipe>();

		internal static readonly List<Recipe> cachedSortedForgeRecipes = new List<Recipe>();

		internal static readonly List<Recipe> cachedSortedNoCostRecipes = new List<Recipe>();

		internal static readonly List<Recipe> cachedSortedHandCraftingRecipes = new List<Recipe>();

		[HarmonyPatch(typeof(Game), "Logout")]
		[HarmonyPrefix]
		internal static void ResetOnLogout()
		{
			InvalidateCaches();
		}

		[HarmonyPatch(typeof(Player), "AddKnownRecipe")]
		[HarmonyPrefix]
		internal static void ResetOnAddNewRecipe(Player __instance, Recipe recipe)
		{
			if (Object.op_Implicit((Object)(object)__instance) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !__instance.m_knownRecipes.Contains(recipe.m_item.m_itemData.m_shared.m_name))
			{
				InvalidateCaches();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "AddKnownPiece")]
		internal static void ResetOnAddNewPiece(Player __instance, Piece piece)
		{
			if (Object.op_Implicit((Object)(object)__instance) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !__instance.m_knownRecipes.Contains(piece.m_name))
			{
				InvalidateCaches();
			}
		}

		internal static void InvalidateCaches()
		{
			cachedSortedCauldronRecipes.Clear();
			cachedSortedWorkBenchRecipes.Clear();
			cachedSortedForgeRecipes.Clear();
			cachedSortedNoCostRecipes.Clear();
			cachedSortedHandCraftingRecipes.Clear();
		}

		internal static void UpdateSortCache(List<Recipe> newSortedList, List<Recipe> oldSortedList)
		{
			if (oldSortedList != null)
			{
				oldSortedList.Clear();
				oldSortedList.AddRange(newSortedList);
			}
		}

		internal static bool TryReapplySorting(ref List<Recipe> newSortedList, List<Recipe> oldSortedList)
		{
			if (oldSortedList == null || !SortConfig.EnablePerformanceMode.Value)
			{
				return false;
			}
			if (newSortedList.Count != oldSortedList.Count)
			{
				return false;
			}
			newSortedList = (from i in oldSortedList
				join j in newSortedList on i equals j
				select j).ToList();
			return true;
		}
	}
}
namespace Microsoft.CodeAnalysis
{
	[Microsoft.CodeAnalysis.Embedded]
	[CompilerGenerated]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[Microsoft.CodeAnalysis.Embedded]
	[CompilerGenerated]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[Microsoft.CodeAnalysis.Embedded]
	[CompilerGenerated]
	[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;
		}
	}
	[Microsoft.CodeAnalysis.Embedded]
	[CompilerGenerated]
	[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;
		}
	}
}
namespace YamlDotNet
{
	internal sealed class CultureInfoAdapter : CultureInfo
	{
		private readonly IFormatProvider provider;

		public CultureInfoAdapter(CultureInfo baseCulture, IFormatProvider provider)
			: base(baseCulture.LCID)
		{
			this.provider = provider;
		}

		public override object? GetFormat(Type? formatType)
		{
			return provider.GetFormat(formatType);
		}
	}
	internal static class ReflectionExtensions
	{
		private static readonly FieldInfo? RemoteStackTraceField = typeof(Exception).GetField("_remoteStackTraceString", BindingFlags.Instance | BindingFlags.NonPublic);

		public static Type? BaseType(this Type type)
		{
			return type.BaseType;
		}

		public static bool IsValueType(this Type type)
		{
			return type.IsValueType;
		}

		public static bool IsGenericType(this Type type)
		{
			return type.IsGenericType;
		}

		public static bool IsGenericTypeDefinition(this Type type)
		{
			return type.IsGenericTypeDefinition;
		}

		public static bool IsInterface(this Type type)
		{
			return type.IsInterface;
		}

		public static bool IsEnum(this Type type)
		{
			return type.IsEnum;
		}

		public static bool IsDbNull(this object value)
		{
			return value is DBNull;
		}

		public static bool HasDefaultConstructor(this Type type, bool allowPrivateConstructors)
		{
			BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public;
			if (allowPrivateConstructors)
			{
				bindingFlags |= BindingFlags.NonPublic;
			}
			if (!type.IsValueType)
			{
				return type.GetConstructor(bindingFlags, null, Type.EmptyTypes, null) != null;
			}
			return true;
		}

		public static TypeCode GetTypeCode(this Type type)
		{
			return Type.GetTypeCode(type);
		}

		public static PropertyInfo? GetPublicProperty(this Type type, string name)
		{
			return type.GetProperty(name);
		}

		public static FieldInfo? GetPublicStaticField(this Type type, string name)
		{
			return type.GetField(name, BindingFlags.Static | BindingFlags.Public);
		}

		public static IEnumerable<PropertyInfo> GetProperties(this Type type, bool includeNonPublic)
		{
			BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public;
			if (includeNonPublic)
			{
				bindingFlags |= BindingFlags.NonPublic;
			}
			if (!type.IsInterface)
			{
				return type.GetProperties(bindingFlags);
			}
			return new Type[1] { type }.Concat(type.GetInterfaces()).SelectMany((Type i) => i.GetProperties(bindingFlags));
		}

		public static IEnumerable<PropertyInfo> GetPublicProperties(this Type type)
		{
			return type.GetProperties(includeNonPublic: false);
		}

		public static IEnumerable<FieldInfo> GetPublicFields(this Type type)
		{
			return type.GetFields(BindingFlags.Instance | BindingFlags.Public);
		}

		public static IEnumerable<MethodInfo> GetPublicStaticMethods(this Type type)
		{
			return type.GetMethods(BindingFlags.Static | BindingFlags.Public);
		}

		public static MethodInfo GetPrivateStaticMethod(this Type type, string name)
		{
			return type.GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic) ?? throw new MissingMethodException("Expected to find a method named '" + name + "' in '" + type.FullName + "'.");
		}

		public static MethodInfo? GetPublicStaticMethod(this Type type, string name, params Type[] parameterTypes)
		{
			return type.GetMethod(name, BindingFlags.Static | BindingFlags.Public, null, parameterTypes, null);
		}

		public static MethodInfo? GetPublicInstanceMethod(this Type type, string name)
		{
			return type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public);
		}

		public static Exception Unwrap(this TargetInvocationException ex)
		{
			Exception innerException = ex.InnerException;
			if (innerException == null)
			{
				return ex;
			}
			if (RemoteStackTraceField != null)
			{
				RemoteStackTraceField.SetValue(innerException, innerException.StackTrace + "\r\n");
			}
			return innerException;
		}

		public static bool IsInstanceOf(this Type type, object o)
		{
			return type.IsInstanceOfType(o);
		}

		public static Attribute[] GetAllCustomAttributes<TAttribute>(this PropertyInfo property)
		{
			return Attribute.GetCustomAttributes(property, typeof(TAttribute), inherit: true);
		}
	}
	internal static class PropertyInfoExtensions
	{
		public static object? ReadValue(this PropertyInfo property, object target)
		{
			return property.GetValue(target, null);
		}
	}
	internal static class StandardRegexOptions
	{
		public const RegexOptions Compiled = RegexOptions.Compiled;
	}
}
namespace YamlDotNet.Serialization
{
	internal abstract class BuilderSkeleton<TBuilder> where TBuilder : BuilderSkeleton<TBuilder>
	{
		internal INamingConvention namingConvention = NullNamingConvention.Instance;

		internal ITypeResolver typeResolver;

		internal readonly YamlAttributeOverrides overrides;

		internal readonly LazyComponentRegistrationList<Nothing, IYamlTypeConverter> typeConverterFactories;

		internal readonly LazyComponentRegistrationList<ITypeInspector, ITypeInspector> typeInspectorFactories;

		internal bool ignoreFields;

		internal bool includeNonPublicProperties;

		internal Settings settings;

		protected abstract TBuilder Self { get; }

		internal BuilderSkeleton(ITypeResolver typeResolver)
		{
			overrides = new YamlAttributeOverrides();
			typeConverterFactories = new LazyComponentRegistrationList<Nothing, IYamlTypeConverter>
			{
				{
					typeof(YamlDotNet.Serialization.Converters.GuidConverter),
					(Nothing _) => new YamlDotNet.Serialization.Converters.GuidConverter(jsonCompatible: false)
				},
				{
					typeof(SystemTypeConverter),
					(Nothing _) => new SystemTypeConverter()
				}
			};
			typeInspectorFactories = new LazyComponentRegistrationList<ITypeInspector, ITypeInspector>();
			this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver");
			settings = new Settings();
		}

		public TBuilder IgnoreFields()
		{
			ignoreFields = true;
			return Self;
		}

		public TBuilder IncludeNonPublicProperties()
		{
			includeNonPublicProperties = true;
			return Self;
		}

		public TBuilder EnablePrivateConstructors()
		{
			settings.AllowPrivateConstructors = true;
			return Self;
		}

		public TBuilder WithNamingConvention(INamingConvention namingConvention)
		{
			this.namingConvention = namingConvention ?? throw new ArgumentNullException("namingConvention");
			return Self;
		}

		public TBuilder WithTypeResolver(ITypeResolver typeResolver)
		{
			this.typeResolver = typeResolver ?? throw new ArgumentNullException("typeResolver");
			return Self;
		}

		public abstract TBuilder WithTagMapping(TagName tag, Type type);

		public TBuilder WithAttributeOverride<TClass>(Expression<Func<TClass, object>> propertyAccessor, Attribute attribute)
		{
			overrides.Add(propertyAccessor, attribute);
			return Self;
		}

		public TBuilder WithAttributeOverride(Type type, string member, Attribute attribute)
		{
			overrides.Add(type, member, attribute);
			return Self;
		}

		public TBuilder WithTypeConverter(IYamlTypeConverter typeConverter)
		{
			return WithTypeConverter(typeConverter, delegate(IRegistrationLocationSelectionSyntax<IYamlTypeConverter> w)
			{
				w.OnTop();
			});
		}

		public TBuilder WithTypeConverter(IYamlTypeConverter typeConverter, Action<IRegistrationLocationSelectionSyntax<IYamlTypeConverter>> where)
		{
			IYamlTypeConverter typeConverter2 = typeConverter;
			if (typeConverter2 == null)
			{
				throw new ArgumentNullException("typeConverter");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(typeConverterFactories.CreateRegistrationLocationSelector(typeConverter2.GetType(), (Nothing _) => typeConverter2));
			return Self;
		}

		public TBuilder WithTypeConverter<TYamlTypeConverter>(WrapperFactory<IYamlTypeConverter, IYamlTypeConverter> typeConverterFactory, Action<ITrackingRegistrationLocationSelectionSyntax<IYamlTypeConverter>> where) where TYamlTypeConverter : IYamlTypeConverter
		{
			WrapperFactory<IYamlTypeConverter, IYamlTypeConverter> typeConverterFactory2 = typeConverterFactory;
			if (typeConverterFactory2 == null)
			{
				throw new ArgumentNullException("typeConverterFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(typeConverterFactories.CreateTrackingRegistrationLocationSelector(typeof(TYamlTypeConverter), (IYamlTypeConverter wrapped, Nothing _) => typeConverterFactory2(wrapped)));
			return Self;
		}

		public TBuilder WithoutTypeConverter<TYamlTypeConverter>() where TYamlTypeConverter : IYamlTypeConverter
		{
			return WithoutTypeConverter(typeof(TYamlTypeConverter));
		}

		public TBuilder WithoutTypeConverter(Type converterType)
		{
			if (converterType == null)
			{
				throw new ArgumentNullException("converterType");
			}
			typeConverterFactories.Remove(converterType);
			return Self;
		}

		public TBuilder WithTypeInspector<TTypeInspector>(Func<ITypeInspector, TTypeInspector> typeInspectorFactory) where TTypeInspector : ITypeInspector
		{
			return WithTypeInspector(typeInspectorFactory, delegate(IRegistrationLocationSelectionSyntax<ITypeInspector> w)
			{
				w.OnTop();
			});
		}

		public TBuilder WithTypeInspector<TTypeInspector>(Func<ITypeInspector, TTypeInspector> typeInspectorFactory, Action<IRegistrationLocationSelectionSyntax<ITypeInspector>> where) where TTypeInspector : ITypeInspector
		{
			Func<ITypeInspector, TTypeInspector> typeInspectorFactory2 = typeInspectorFactory;
			if (typeInspectorFactory2 == null)
			{
				throw new ArgumentNullException("typeInspectorFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(typeInspectorFactories.CreateRegistrationLocationSelector(typeof(TTypeInspector), (ITypeInspector inner) => typeInspectorFactory2(inner)));
			return Self;
		}

		public TBuilder WithTypeInspector<TTypeInspector>(WrapperFactory<ITypeInspector, ITypeInspector, TTypeInspector> typeInspectorFactory, Action<ITrackingRegistrationLocationSelectionSyntax<ITypeInspector>> where) where TTypeInspector : ITypeInspector
		{
			WrapperFactory<ITypeInspector, ITypeInspector, TTypeInspector> typeInspectorFactory2 = typeInspectorFactory;
			if (typeInspectorFactory2 == null)
			{
				throw new ArgumentNullException("typeInspectorFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(typeInspectorFactories.CreateTrackingRegistrationLocationSelector(typeof(TTypeInspector), (ITypeInspector wrapped, ITypeInspector inner) => typeInspectorFactory2(wrapped, inner)));
			return Self;
		}

		public TBuilder WithoutTypeInspector<TTypeInspector>() where TTypeInspector : ITypeInspector
		{
			return WithoutTypeInspector(typeof(TTypeInspector));
		}

		public TBuilder WithoutTypeInspector(Type inspectorType)
		{
			if (inspectorType == null)
			{
				throw new ArgumentNullException("inspectorType");
			}
			typeInspectorFactories.Remove(inspectorType);
			return Self;
		}

		protected IEnumerable<IYamlTypeConverter> BuildTypeConverters()
		{
			return typeConverterFactories.BuildComponentList();
		}
	}
	internal delegate TComponent WrapperFactory<TComponentBase, TComponent>(TComponentBase wrapped) where TComponent : TComponentBase;
	internal delegate TComponent WrapperFactory<TArgument, TComponentBase, TComponent>(TComponentBase wrapped, TArgument argument) where TComponent : TComponentBase;
	[Flags]
	internal enum DefaultValuesHandling
	{
		Preserve = 0,
		OmitNull = 1,
		OmitDefaults = 2,
		OmitEmptyCollections = 4
	}
	internal sealed class Deserializer : IDeserializer
	{
		private readonly IValueDeserializer valueDeserializer;

		public Deserializer()
			: this(new DeserializerBuilder().BuildValueDeserializer())
		{
		}

		private Deserializer(IValueDeserializer valueDeserializer)
		{
			this.valueDeserializer = valueDeserializer ?? throw new ArgumentNullException("valueDeserializer");
		}

		public static Deserializer FromValueDeserializer(IValueDeserializer valueDeserializer)
		{
			return new Deserializer(valueDeserializer);
		}

		public T Deserialize<T>(string input)
		{
			using StringReader input2 = new StringReader(input);
			return Deserialize<T>(input2);
		}

		public T Deserialize<T>(TextReader input)
		{
			return Deserialize<T>(new Parser(input));
		}

		public object? Deserialize(TextReader input)
		{
			return Deserialize(input, typeof(object));
		}

		public object? Deserialize(string input, Type type)
		{
			using StringReader input2 = new StringReader(input);
			return Deserialize(input2, type);
		}

		public object? Deserialize(TextReader input, Type type)
		{
			return Deserialize(new Parser(input), type);
		}

		public T Deserialize<T>(IParser parser)
		{
			return (T)Deserialize(parser, typeof(T));
		}

		public object? Deserialize(IParser parser)
		{
			return Deserialize(parser, typeof(object));
		}

		public object? Deserialize(IParser parser, Type type)
		{
			if (parser == null)
			{
				throw new ArgumentNullException("parser");
			}
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			YamlDotNet.Core.Events.StreamStart @event;
			bool flag = parser.TryConsume<YamlDotNet.Core.Events.StreamStart>(out @event);
			YamlDotNet.Core.Events.DocumentStart event2;
			bool flag2 = parser.TryConsume<YamlDotNet.Core.Events.DocumentStart>(out event2);
			object result = null;
			if (!parser.Accept<YamlDotNet.Core.Events.DocumentEnd>(out var _) && !parser.Accept<YamlDotNet.Core.Events.StreamEnd>(out var _))
			{
				using SerializerState serializerState = new SerializerState();
				result = valueDeserializer.DeserializeValue(parser, type, serializerState, valueDeserializer);
				serializerState.OnDeserialization();
			}
			if (flag2)
			{
				parser.Consume<YamlDotNet.Core.Events.DocumentEnd>();
			}
			if (flag)
			{
				parser.Consume<YamlDotNet.Core.Events.StreamEnd>();
			}
			return result;
		}
	}
	internal sealed class DeserializerBuilder : BuilderSkeleton<DeserializerBuilder>
	{
		private Lazy<IObjectFactory> objectFactory;

		private readonly LazyComponentRegistrationList<Nothing, INodeDeserializer> nodeDeserializerFactories;

		private readonly LazyComponentRegistrationList<Nothing, INodeTypeResolver> nodeTypeResolverFactories;

		private readonly Dictionary<TagName, Type> tagMappings;

		private readonly Dictionary<Type, Type> typeMappings;

		private readonly ITypeConverter typeConverter;

		private bool ignoreUnmatched;

		private bool duplicateKeyChecking;

		private bool attemptUnknownTypeDeserialization;

		protected override DeserializerBuilder Self => this;

		public DeserializerBuilder()
			: base((ITypeResolver)new StaticTypeResolver())
		{
			typeMappings = new Dictionary<Type, Type>();
			objectFactory = new Lazy<IObjectFactory>(() => new DefaultObjectFactory(typeMappings, settings), isThreadSafe: true);
			tagMappings = new Dictionary<TagName, Type>
			{
				{
					FailsafeSchema.Tags.Map,
					typeof(Dictionary<object, object>)
				},
				{
					FailsafeSchema.Tags.Str,
					typeof(string)
				},
				{
					JsonSchema.Tags.Bool,
					typeof(bool)
				},
				{
					JsonSchema.Tags.Float,
					typeof(double)
				},
				{
					JsonSchema.Tags.Int,
					typeof(int)
				},
				{
					DefaultSchema.Tags.Timestamp,
					typeof(DateTime)
				}
			};
			typeInspectorFactories.Add(typeof(CachedTypeInspector), (ITypeInspector inner) => new CachedTypeInspector(inner));
			typeInspectorFactories.Add(typeof(NamingConventionTypeInspector), (ITypeInspector inner) => (!(namingConvention is NullNamingConvention)) ? new NamingConventionTypeInspector(inner, namingConvention) : inner);
			typeInspectorFactories.Add(typeof(YamlAttributesTypeInspector), (ITypeInspector inner) => new YamlAttributesTypeInspector(inner));
			typeInspectorFactories.Add(typeof(YamlAttributeOverridesInspector), (ITypeInspector inner) => (overrides == null) ? inner : new YamlAttributeOverridesInspector(inner, overrides.Clone()));
			typeInspectorFactories.Add(typeof(ReadableAndWritablePropertiesTypeInspector), (ITypeInspector inner) => new ReadableAndWritablePropertiesTypeInspector(inner));
			nodeDeserializerFactories = new LazyComponentRegistrationList<Nothing, INodeDeserializer>
			{
				{
					typeof(YamlConvertibleNodeDeserializer),
					(Nothing _) => new YamlConvertibleNodeDeserializer(objectFactory.Value)
				},
				{
					typeof(YamlSerializableNodeDeserializer),
					(Nothing _) => new YamlSerializableNodeDeserializer(objectFactory.Value)
				},
				{
					typeof(TypeConverterNodeDeserializer),
					(Nothing _) => new TypeConverterNodeDeserializer(BuildTypeConverters())
				},
				{
					typeof(NullNodeDeserializer),
					(Nothing _) => new NullNodeDeserializer()
				},
				{
					typeof(ScalarNodeDeserializer),
					(Nothing _) => new ScalarNodeDeserializer(attemptUnknownTypeDeserialization, typeConverter)
				},
				{
					typeof(ArrayNodeDeserializer),
					(Nothing _) => new ArrayNodeDeserializer()
				},
				{
					typeof(DictionaryNodeDeserializer),
					(Nothing _) => new DictionaryNodeDeserializer(objectFactory.Value, duplicateKeyChecking)
				},
				{
					typeof(CollectionNodeDeserializer),
					(Nothing _) => new CollectionNodeDeserializer(objectFactory.Value)
				},
				{
					typeof(EnumerableNodeDeserializer),
					(Nothing _) => new EnumerableNodeDeserializer()
				},
				{
					typeof(ObjectNodeDeserializer),
					(Nothing _) => new ObjectNodeDeserializer(objectFactory.Value, BuildTypeInspector(), ignoreUnmatched, duplicateKeyChecking, typeConverter)
				}
			};
			nodeTypeResolverFactories = new LazyComponentRegistrationList<Nothing, INodeTypeResolver>
			{
				{
					typeof(MappingNodeTypeResolver),
					(Nothing _) => new MappingNodeTypeResolver(typeMappings)
				},
				{
					typeof(YamlConvertibleTypeResolver),
					(Nothing _) => new YamlConvertibleTypeResolver()
				},
				{
					typeof(YamlSerializableTypeResolver),
					(Nothing _) => new YamlSerializableTypeResolver()
				},
				{
					typeof(TagNodeTypeResolver),
					(Nothing _) => new TagNodeTypeResolver(tagMappings)
				},
				{
					typeof(PreventUnknownTagsNodeTypeResolver),
					(Nothing _) => new PreventUnknownTagsNodeTypeResolver()
				},
				{
					typeof(DefaultContainersNodeTypeResolver),
					(Nothing _) => new DefaultContainersNodeTypeResolver()
				}
			};
			typeConverter = new ReflectionTypeConverter();
		}

		internal ITypeInspector BuildTypeInspector()
		{
			ITypeInspector typeInspector = new WritablePropertiesTypeInspector(typeResolver, includeNonPublicProperties);
			if (!ignoreFields)
			{
				typeInspector = new CompositeTypeInspector(new ReadableFieldsTypeInspector(typeResolver), typeInspector);
			}
			return typeInspectorFactories.BuildComponentChain(typeInspector);
		}

		public DeserializerBuilder WithAttemptingUnquotedStringTypeDeserialization()
		{
			attemptUnknownTypeDeserialization = true;
			return this;
		}

		public DeserializerBuilder WithObjectFactory(IObjectFactory objectFactory)
		{
			IObjectFactory objectFactory2 = objectFactory;
			if (objectFactory2 == null)
			{
				throw new ArgumentNullException("objectFactory");
			}
			this.objectFactory = new Lazy<IObjectFactory>(() => objectFactory2, isThreadSafe: true);
			return this;
		}

		public DeserializerBuilder WithObjectFactory(Func<Type, object> objectFactory)
		{
			if (objectFactory == null)
			{
				throw new ArgumentNullException("objectFactory");
			}
			return WithObjectFactory(new LambdaObjectFactory(objectFactory));
		}

		public DeserializerBuilder WithNodeDeserializer(INodeDeserializer nodeDeserializer)
		{
			return WithNodeDeserializer(nodeDeserializer, delegate(IRegistrationLocationSelectionSyntax<INodeDeserializer> w)
			{
				w.OnTop();
			});
		}

		public DeserializerBuilder WithNodeDeserializer(INodeDeserializer nodeDeserializer, Action<IRegistrationLocationSelectionSyntax<INodeDeserializer>> where)
		{
			INodeDeserializer nodeDeserializer2 = nodeDeserializer;
			if (nodeDeserializer2 == null)
			{
				throw new ArgumentNullException("nodeDeserializer");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(nodeDeserializerFactories.CreateRegistrationLocationSelector(nodeDeserializer2.GetType(), (Nothing _) => nodeDeserializer2));
			return this;
		}

		public DeserializerBuilder WithNodeDeserializer<TNodeDeserializer>(WrapperFactory<INodeDeserializer, TNodeDeserializer> nodeDeserializerFactory, Action<ITrackingRegistrationLocationSelectionSyntax<INodeDeserializer>> where) where TNodeDeserializer : INodeDeserializer
		{
			WrapperFactory<INodeDeserializer, TNodeDeserializer> nodeDeserializerFactory2 = nodeDeserializerFactory;
			if (nodeDeserializerFactory2 == null)
			{
				throw new ArgumentNullException("nodeDeserializerFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(nodeDeserializerFactories.CreateTrackingRegistrationLocationSelector(typeof(TNodeDeserializer), (INodeDeserializer wrapped, Nothing _) => nodeDeserializerFactory2(wrapped)));
			return this;
		}

		public DeserializerBuilder WithoutNodeDeserializer<TNodeDeserializer>() where TNodeDeserializer : INodeDeserializer
		{
			return WithoutNodeDeserializer(typeof(TNodeDeserializer));
		}

		public DeserializerBuilder WithoutNodeDeserializer(Type nodeDeserializerType)
		{
			if (nodeDeserializerType == null)
			{
				throw new ArgumentNullException("nodeDeserializerType");
			}
			nodeDeserializerFactories.Remove(nodeDeserializerType);
			return this;
		}

		public DeserializerBuilder WithNodeTypeResolver(INodeTypeResolver nodeTypeResolver)
		{
			return WithNodeTypeResolver(nodeTypeResolver, delegate(IRegistrationLocationSelectionSyntax<INodeTypeResolver> w)
			{
				w.OnTop();
			});
		}

		public DeserializerBuilder WithNodeTypeResolver(INodeTypeResolver nodeTypeResolver, Action<IRegistrationLocationSelectionSyntax<INodeTypeResolver>> where)
		{
			INodeTypeResolver nodeTypeResolver2 = nodeTypeResolver;
			if (nodeTypeResolver2 == null)
			{
				throw new ArgumentNullException("nodeTypeResolver");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(nodeTypeResolverFactories.CreateRegistrationLocationSelector(nodeTypeResolver2.GetType(), (Nothing _) => nodeTypeResolver2));
			return this;
		}

		public DeserializerBuilder WithNodeTypeResolver<TNodeTypeResolver>(WrapperFactory<INodeTypeResolver, TNodeTypeResolver> nodeTypeResolverFactory, Action<ITrackingRegistrationLocationSelectionSyntax<INodeTypeResolver>> where) where TNodeTypeResolver : INodeTypeResolver
		{
			WrapperFactory<INodeTypeResolver, TNodeTypeResolver> nodeTypeResolverFactory2 = nodeTypeResolverFactory;
			if (nodeTypeResolverFactory2 == null)
			{
				throw new ArgumentNullException("nodeTypeResolverFactory");
			}
			if (where == null)
			{
				throw new ArgumentNullException("where");
			}
			where(nodeTypeResolverFactories.CreateTrackingRegistrationLocationSelector(typeof(TNodeTypeResolver), (INodeTypeResolver wrapped, Nothing _) => nodeTypeResolverFactory2(wrapped)));
			return this;
		}

		public DeserializerBuilder WithoutNodeTypeResolver<TNodeTypeResolver>() where TNodeTypeResolver : INodeTypeResolver
		{
			return WithoutNodeTypeResolver(typeof(TNodeTypeResolver));
		}

		public DeserializerBuilder WithoutNodeTypeResolver(Type nodeTypeResolverType)
		{
			if (nodeTypeResolverType == null)
			{
				throw new ArgumentNullException("nodeTypeResolverType");
			}
			nodeTypeResolverFactories.Remove(nodeTypeResolverType);
			return this;
		}

		public override DeserializerBuilder WithTagMapping(TagName tag, Type type)
		{
			if (tag.IsEmpty)
			{
				throw new ArgumentException("Non-specific tags cannot be maped");
			}
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			if (tagMappings.TryGetValue(tag, out Type value))
			{
				throw new ArgumentException($"Type already has a registered type '{value.FullName}' for tag '{tag}'", "tag");
			}
			tagMappings.Add(tag, type);
			return this;
		}

		public DeserializerBuilder WithTypeMapping<TInterface, TConcrete>() where TConcrete : TInterface
		{
			Type typeFromHandle = typeof(TInterface);
			Type typeFromHandle2 = typeof(TConcrete);
			if (!typeFromHandle.IsAssignableFrom(typeFromHandle2))
			{
				throw new InvalidOperationException("The type '" + typeFromHandle2.Name + "' does not implement interface '" + typeFromHandle.Name + "'.");
			}
			if (typeMappings.ContainsKey(typeFromHandle))
			{
				typeMappings[typeFromHandle] = typeFromHandle2;
			}
			else
			{
				typeMappings.Add(typeFromHandle, typeFromHandle2);
			}
			return this;
		}

		public DeserializerBuilder WithoutTagMapping(TagName tag)
		{
			if (tag.IsEmpty)
			{
				throw new ArgumentException("Non-specific tags cannot be maped");
			}
			if (!tagMappings.Remove(tag))
			{
				throw new KeyNotFoundException($"Tag '{tag}' is not registered");
			}
			return this;
		}

		public DeserializerBuilder IgnoreUnmatchedProperties()
		{
			ignoreUnmatched = true;
			return this;
		}

		public DeserializerBuilder WithDuplicateKeyChecking()
		{
			duplicateKeyChecking = true;
			return this;
		}

		public IDeserializer Build()
		{
			return Deserializer.FromValueDeserializer(BuildValueDeserializer());
		}

		public IValueDeserializer BuildValueDeserializer()
		{
			return new AliasValueDeserializer(new NodeValueDeserializer(nodeDeserializerFactories.BuildComponentList(), nodeTypeResolverFactories.BuildComponentList(), typeConverter));
		}
	}
	internal sealed class EmissionPhaseObjectGraphVisitorArgs
	{
		private readonly IEnumerable<IObjectGraphVisitor<Nothing>> preProcessingPhaseVisitors;

		public IObjectGraphVisitor<IEmitter> InnerVisitor { get; private set; }

		public IEventEmitter EventEmitter { get; private set; }

		public ObjectSerializer NestedObjectSerializer { get; private set; }

		public IEnumerable<IYamlTypeConverter> TypeConverters { get; private set; }

		public EmissionPhaseObjectGraphVisitorArgs(IObjectGraphVisitor<IEmitter> innerVisitor, IEventEmitter eventEmitter, IEnumerable<IObjectGraphVisitor<Nothing>> preProcessingPhaseVisitors, IEnumerable<IYamlTypeConverter> typeConverters, ObjectSerializer nestedObjectSerializer)
		{
			InnerVisitor = innerVisitor ?? throw new ArgumentNullException("innerVisitor");
			EventEmitter = eventEmitter ?? throw new ArgumentNullException("eventEmitter");
			this.preProcessingPhaseVisitors = preProcessingPhaseVisitors ?? throw new ArgumentNullException("preProcessingPhaseVisitors");
			TypeConverters = typeConverters ?? throw new ArgumentNullException("typeConverters");
			NestedObjectSerializer = nestedObjectSerializer ?? throw new ArgumentNullException("nestedObjectSerializer");
		}

		public T GetPreProcessingPhaseObjectGraphVisitor<T>() where T : IObjectGraphVisitor<Nothing>
		{
			return preProcessingPhaseVisitors.OfType<T>().Single();
		}
	}
	internal abstract class EventInfo
	{
		public IObjectDescriptor Source { get; }

		protected EventInfo(IObjectDescriptor source)
		{
			Source = source ?? throw new ArgumentNullException("source");
		}
	}
	internal class AliasEventInfo : EventInfo
	{
		public AnchorName Alias { get; }

		public bool NeedsExpansion { get; set; }

		public AliasEventInfo(IObjectDescriptor source, AnchorName alias)
			: base(source)
		{
			if (alias.IsEmpty)
			{
				throw new ArgumentNullException("alias");
			}
			Alias = alias;
		}
	}
	internal class ObjectEventInfo : EventInfo
	{
		public AnchorName Anchor { get; set; }

		public TagName Tag { get; set; }

		protected ObjectEventInfo(IObjectDescriptor source)
			: base(source)
		{
		}
	}
	internal sealed class ScalarEventInfo : ObjectEventInfo
	{
		public string RenderedValue { get; set; }

		public ScalarStyle Style { get; set; }

		public bool IsPlainImplicit { get; set; }

		public bool IsQuotedImplicit { get; set; }

		public ScalarEventInfo(IObjectDescriptor source)
			: base(source)
		{
			Style = source.ScalarStyle;
			RenderedValue = string.Empty;
		}
	}
	internal sealed class MappingStartEventInfo : ObjectEventInfo
	{
		public bool IsImplicit { get; set; }

		public MappingStyle Style { get; set; }

		public MappingStartEventInfo(IObjectDescriptor source)
			: base(source)
		{
		}
	}
	internal sealed class MappingEndEventInfo : EventInfo
	{
		public MappingEndEventInfo(IObjectDescriptor source)
			: base(source)
		{
		}
	}
	internal sealed class SequenceStartEventInfo : ObjectEventInfo
	{
		public bool IsImplicit { get; set; }

		public SequenceStyle Style { get; set; }

		public SequenceStartEventInfo(IObjectDescriptor source)
			: base(source)
		{
		}
	}
	internal sealed class SequenceEndEventInfo : EventInfo
	{
		public SequenceEndEventInfo(IObjectDescriptor source)
			: base(source)
		{
		}
	}
	internal interface IAliasProvider
	{
		AnchorName GetAlias(object target);
	}
	internal interface IDeserializer
	{
		T Deserialize<T>(string input);

		T Deserialize<T>(TextReader input);

		object? Deserialize(TextReader input);

		object? Deserialize(string input, Type type);

		object? Deserialize(TextReader input, Type type);

		T Deserialize<T>(IParser parser);

		object? Deserialize(IParser parser);

		object? Deserialize(IParser parser, Type type);
	}
	internal interface IEventEmitter
	{
		void Emit(AliasEventInfo eventInfo, IEmitter emitter);

		void Emit(ScalarEventInfo eventInfo, IEmitter emitter);

		void Emit(MappingStartEventInfo eventInfo, IEmitter emitter);

		void Emit(MappingEndEventInfo eventInfo, IEmitter emitter);

		void Emit(SequenceStartEventInfo eventInfo, IEmitter emitter);

		void Emit(SequenceEndEventInfo eventInfo, IEmitter emitter);
	}
	internal interface INamingConvention
	{
		string Apply(string value);
	}
	internal interface INodeDeserializer
	{
		bool Deserialize(IParser reader, Type expectedType, Func<IParser, Type, object?> nestedObjectDeserializer, out object? value);
	}
	internal interface INodeTypeResolver
	{
		bool Resolve(NodeEvent? nodeEvent, ref Type currentType);
	}
	internal interface IObjectAccessor
	{
		void Set(string name, object target, object value);

		object? Read(string name, object target);
	}
	internal interface IObjectDescriptor
	{
		object? Value { get; }

		Type Type { get; }

		Type StaticType { get; }

		ScalarStyle ScalarStyle { get; }
	}
	internal static class ObjectDescriptorExtensions
	{
		public static object NonNullValue(this IObjectDescriptor objectDescriptor)
		{
			return objectDescriptor.Value ?? throw new InvalidOperationException("Attempted to use a IObjectDescriptor of type '" + objectDescriptor.Type.FullName + "' whose Value is null at a point whete it is invalid to do so. This may indicate a bug in YamlDotNet.");
		}
	}
	internal interface IObjectFactory
	{
		object Create(Type type);

		object? CreatePrimitive(Type type);

		bool GetDictionary(IObjectDescriptor descriptor, out IDictionary? dictionary, out Type[]? genericArguments);

		Type GetValueType(Type type);
	}
	internal interface IObjectGraphTraversalStrategy
	{
		void Traverse<TContext>(IObjectDescriptor graph, IObjectGraphVisitor<TContext> visitor, TContext context);
	}
	internal interface IObjectGraphVisitor<TContext>
	{
		bool Enter(IObjectDescriptor value, TContext context);

		bool EnterMapping(IObjectDescriptor key, IObjectDescriptor value, TContext context);

		bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, TContext context);

		void VisitScalar(IObjectDescriptor scalar, TContext context);

		void VisitMappingStart(IObjectDescriptor mapping, Type keyType, Type valueType, TContext context);

		void VisitMappingEnd(IObjectDescriptor mapping, TContext context);

		void VisitSequenceStart(IObjectDescriptor sequence, Type elementType, TContext context);

		void VisitSequenceEnd(IObjectDescriptor sequence, TContext context);
	}
	internal interface IPropertyDescriptor
	{
		string Name { get; }

		bool CanWrite { get; }

		Type Type { get; }

		Type? TypeOverride { get; set; }

		int Order { get; set; }

		ScalarStyle ScalarStyle { get; set; }

		T GetCustomAttribute<T>() where T : Attribute;

		IObjectDescriptor Read(object target);

		void Write(object target, object? value);
	}
	internal interface IRegistrationLocationSelectionSyntax<TBaseRegistrationType>
	{
		void InsteadOf<TRegistrationType>() where TRegistrationType : TBaseRegistrationType;

		void Before<TRegistrationType>() where TRegistrationType : TBaseRegistrationType;

		void After<TRegistrationType>() where TRegistrationType : TBaseRegistrationType;

		void OnTop();

		void OnBottom();
	}
	internal interface ITrackingRegistrationLocationSelectionSyntax<TBaseRegistrationType>
	{
		void InsteadOf<TRegistrationType>() where TRegistrationType : TBaseRegistrationType;
	}
	internal interface ISerializer
	{
		void Serialize(TextWriter writer, object graph);

		string Serialize(object graph);

		void Serialize(TextWriter writer, object graph, Type type);

		void Serialize(IEmitter emitter, object graph);

		void Serialize(IEmitter emitter, object graph, Type type);
	}
	internal interface ITypeInspector
	{
		IEnumerable<IPropertyDescriptor> GetProperties(Type type, object? container);

		IPropertyDescriptor GetProperty(Type type, object? container, string name, [MaybeNullWhen(true)] bool ignoreUnmatched);
	}
	internal interface ITypeResolver
	{
		Type Resolve(Type staticType, object? actualValue);
	}
	internal interface IValueDeserializer
	{
		object? DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer);
	}
	internal interface IValuePromise
	{
		event Action<object?> ValueAvailable;
	}
	internal interface IValueSerializer
	{
		void SerializeValue(IEmitter emitter, object? value, Type? type);
	}
	internal interface IYamlConvertible
	{
		void Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer);

		void Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer);
	}
	internal delegate object? ObjectDeserializer(Type type);
	internal delegate void ObjectSerializer(object? value, Type? type = null);
	[Obsolete("Please use IYamlConvertible instead")]
	internal interface IYamlSerializable
	{
		void ReadYaml(IParser parser);

		void WriteYaml(IEmitter emitter);
	}
	internal interface IYamlTypeConverter
	{
		bool Accepts(Type type);

		object? ReadYaml(IParser parser, Type type);

		void WriteYaml(IEmitter emitter, object? value, Type type);
	}
	internal sealed class LazyComponentRegistrationList<TArgument, TComponent> : IEnumerable<Func<TArgument, TComponent>>, IEnumerable
	{
		public sealed class LazyComponentRegistration
		{
			public readonly Type ComponentType;

			public readonly Func<TArgument, TComponent> Factory;

			public LazyComponentRegistration(Type componentType, Func<TArgument, TComponent> factory)
			{
				ComponentType = componentType;
				Factory = factory;
			}
		}

		public sealed class TrackingLazyComponentRegistration
		{
			public readonly Type ComponentType;

			public readonly Func<TComponent, TArgument, TComponent> Factory;

			public TrackingLazyComponentRegistration(Type componentType, Func<TComponent, TArgument, TComponent> factory)
			{
				ComponentType = componentType;
				Factory = factory;
			}
		}

		private class RegistrationLocationSelector : IRegistrationLocationSelectionSyntax<TComponent>
		{
			private readonly LazyComponentRegistrationList<TArgument, TComponent> registrations;

			private readonly LazyComponentRegistration newRegistration;

			public RegistrationLocationSelector(LazyComponentRegistrationList<TArgument, TComponent> registrations, LazyComponentRegistration newRegistration)
			{
				this.registrations = registrations;
				this.newRegistration = newRegistration;
			}

			void IRegistrationLocationSelectionSyntax<TComponent>.InsteadOf<TRegistrationType>()
			{
				if (newRegistration.ComponentType != typeof(TRegistrationType))
				{
					registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType);
				}
				int index = registrations.EnsureRegistrationExists<TRegistrationType>();
				registrations.entries[index] = newRegistration;
			}

			void IRegistrationLocationSelectionSyntax<TComponent>.After<TRegistrationType>()
			{
				registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType);
				int num = registrations.EnsureRegistrationExists<TRegistrationType>();
				registrations.entries.Insert(num + 1, newRegistration);
			}

			void IRegistrationLocationSelectionSyntax<TComponent>.Before<TRegistrationType>()
			{
				registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType);
				int index = registrations.EnsureRegistrationExists<TRegistrationType>();
				registrations.entries.Insert(index, newRegistration);
			}

			void IRegistrationLocationSelectionSyntax<TComponent>.OnBottom()
			{
				registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType);
				registrations.entries.Add(newRegistration);
			}

			void IRegistrationLocationSelectionSyntax<TComponent>.OnTop()
			{
				registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType);
				registrations.entries.Insert(0, newRegistration);
			}
		}

		private class TrackingRegistrationLocationSelector : ITrackingRegistrationLocationSelectionSyntax<TComponent>
		{
			private readonly LazyComponentRegistrationList<TArgument, TComponent> registrations;

			private readonly TrackingLazyComponentRegistration newRegistration;

			public TrackingRegistrationLocationSelector(LazyComponentRegistrationList<TArgument, TComponent> registrations, TrackingLazyComponentRegistration newRegistration)
			{
				this.registrations = registrations;
				this.newRegistration = newRegistration;
			}

			void ITrackingRegistrationLocationSelectionSyntax<TComponent>.InsteadOf<TRegistrationType>()
			{
				if (newRegistration.ComponentType != typeof(TRegistrationType))
				{
					registrations.EnsureNoDuplicateRegistrationType(newRegistration.ComponentType);
				}
				int index = registrations.EnsureRegistrationExists<TRegistrationType>();
				Func<TArgument, TComponent> innerComponentFactory = registrations.entries[index].Factory;
				registrations.entries[index] = new LazyComponentRegistration(newRegistration.ComponentType, (TArgument arg) => newRegistration.Factory(innerComponentFactory(arg), arg));
			}
		}

		private readonly List<LazyComponentRegistration> entries = new List<LazyComponentRegistration>();

		public int Count => entries.Count;

		public IEnumerable<Func<TArgument, TComponent>> InReverseOrder
		{
			get
			{
				int i = entries.Count - 1;
				while (i >= 0)
				{
					yield return entries[i].Factory;
					int num = i - 1;
					i = num;
				}
			}
		}

		public LazyComponentRegistrationList<TArgument, TComponent> Clone()
		{
			LazyComponentRegistrationList<TArgument, TComponent> lazyComponentRegistrationList = new LazyComponentRegistrationList<TArgument, TComponent>();
			foreach (LazyComponentRegistration entry in entries)
			{
				lazyComponentRegistrationList.entries.Add(entry);
			}
			return lazyComponentRegistrationList;
		}

		public void Clear()
		{
			entries.Clear();
		}

		public void Add(Type componentType, Func<TArgument, TComponent> factory)
		{
			entries.Add(new LazyComponentRegistration(componentType, factory));
		}

		public void Remove(Type componentType)
		{
			for (int i = 0; i < entries.Count; i++)
			{
				if (entries[i].ComponentType == componentType)
				{
					entries.RemoveAt(i);
					return;
				}
			}
			throw new KeyNotFoundException("A component registration of type '" + componentType.FullName + "' was not found.");
		}

		public IRegistrationLocationSelectionSyntax<TComponent> CreateRegistrationLocationSelector(Type componentType, Func<TArgument, TComponent> factory)
		{
			return new RegistrationLocationSelector(this, new LazyComponentRegistration(componentType, factory));
		}

		public ITrackingRegistrationLocationSelectionSyntax<TComponent> CreateTrackingRegistrationLocationSelector(Type componentType, Func<TComponent, TArgument, TComponent> factory)
		{
			return new TrackingRegistrationLocationSelector(this, new TrackingLazyComponentRegistration(componentType, factory));
		}

		public IEnumerator<Func<TArgument, TComponent>> GetEnumerator()
		{
			return entries.Select((LazyComponentRegistration e) => e.Factory).GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		private int IndexOfRegistration(Type registrationType)
		{
			for (int i = 0; i < entries.Count; i++)
			{
				if (registrationType == entries[i].ComponentType)
				{
					return i;
				}
			}
			return -1;
		}

		private void EnsureNoDuplicateRegistrationType(Type componentType)
		{
			if (IndexOfRegistration(componentType) != -1)
			{
				throw new InvalidOperationException("A component of type '" + componentType.FullName + "' has already been registered.");
			}
		}

		private int EnsureRegistrationExists<TRegistrationType>()
		{
			int num = IndexOfRegistration(typeof(TRegistrationType));
			if (num == -1)
			{
				throw new InvalidOperationException("A component of type '" + typeof(TRegistrationType).FullName + "' has not been registered.");
			}
			return num;
		}
	}
	internal static class LazyComponentRegistrationListExtensions
	{
		public static TComponent BuildComponentChain<TComponent>(this LazyComponentRegistrationList<TComponent, TComponent> registrations, TComponent innerComponent)
		{
			return registrations.InReverseOrder.Aggregate(innerComponent, (TComponent inner, Func<TComponent, TComponent> factory) => factory(inner));
		}

		public static TComponent BuildComponentChain<TArgument, TComponent>(this LazyComponentRegistrationList<TArgument, TComponent> registrations, TComponent innerComponent, Func<TComponent, TArgument> argumentBuilder)
		{
			Func<TComponent, TArgument> argumentBuilder2 = argumentBuilder;
			return registrations.InReverseOrder.Aggregate(innerComponent, (TComponent inner, Func<TArgument, TComponent> factory) => factory(argumentBuilder2(inner)));
		}

		public static List<TComponent> BuildComponentList<TComponent>(this LazyComponentRegistrationList<Nothing, TComponent> registrations)
		{
			return registrations.Select((Func<Nothing, TComponent> factory) => factory(default(Nothing))).ToList();
		}

		public static List<TComponent> BuildComponentList<TArgument, TComponent>(this LazyComponentRegistrationList<TArgument, TComponent> registrations, TArgument argument)
		{
			TArgument argument2 = argument;
			return registrations.Select((Func<TArgument, TComponent> factory) => factory(argument2)).ToList();
		}
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	internal struct Nothing
	{
	}
	internal sealed class ObjectDescriptor : IObjectDescriptor
	{
		public object? Value { get; private set; }

		public Type Type { get; private set; }

		public Type StaticType { get; private set; }

		public ScalarStyle ScalarStyle { get; private set; }

		public ObjectDescriptor(object? value, Type type, Type staticType)
			: this(value, type, staticType, ScalarStyle.Any)
		{
		}

		public ObjectDescriptor(object? value, Type type, Type staticType, ScalarStyle scalarStyle)
		{
			Value = value;
			Type = type ?? throw new ArgumentNullException("type");
			StaticType = staticType ?? throw new ArgumentNullException("staticType");
			ScalarStyle = scalarStyle;
		}
	}
	internal delegate IObjectGraphTraversalStrategy ObjectGraphTraversalStrategyFactory(ITypeInspector typeInspector, ITypeResolver typeResolver, IEnumerable<IYamlTypeConverter> typeConverters, int maximumRecursion);
	internal sealed class PropertyDescriptor : IPropertyDescriptor
	{
		private readonly IPropertyDescriptor baseDescriptor;

		public string Name { get; set; }

		public Type Type => baseDescriptor.Type;

		public Type? TypeOverride
		{
			get
			{
				return baseDescriptor.TypeOverride;
			}
			set
			{
				baseDescriptor.TypeOverride = value;
			}
		}

		public int Order { get; set; }

		public ScalarStyle ScalarStyle
		{
			get
			{
				return baseDescriptor.ScalarStyle;
			}
			set
			{
				baseDescriptor.ScalarStyle = value;
			}
		}

		public bool CanWrite => baseDescriptor.CanWrite;

		public PropertyDescriptor(IPropertyDescriptor baseDescriptor)
		{
			this.baseDescriptor = baseDescriptor;
			Name = baseDescriptor.Name;
		}

		public void Write(object target, object? value)
		{
			baseDescriptor.Write(target, value);
		}

		public T GetCustomAttribute<T>() where T : Attribute
		{
			return baseDescriptor.GetCustomAttribute<T>();
		}

		public IObjectDescriptor Read(object target)
		{
			return baseDescriptor.Read(target);
		}
	}
	internal sealed class Serializer : ISerializer
	{
		private readonly IValueSerializer valueSerializer;

		private readonly EmitterSettings emitterSettings;

		public Serializer()
			: this(new SerializerBuilder().BuildValueSerializer(), EmitterSettings.Default)
		{
		}

		private Serializer(IValueSerializer valueSerializer, EmitterSettings emitterSettings)
		{
			this.valueSerializer = valueSerializer ?? throw new ArgumentNullException("valueSerializer");
			this.emitterSettings = emitterSettings ?? throw new ArgumentNullException("emitterSettings");
		}

		public static Serializer FromValueSerializer(IValueSerializer valueSerializer, EmitterSettings emitterSettings)
		{
			return new Serializer(valueSerializer, emitterSettings);
		}

		public void Serialize(TextWriter writer, object graph)
		{
			Serialize(new Emitter(writer, emitterSettings), graph);
		}

		public string Serialize(object graph)
		{
			using StringWriter stringWriter = new StringWriter();
			Serialize(stringWriter, graph);
			return stringWriter.ToString();
		}

		public void Serialize(TextWriter writer, object graph, Type type)
		{
			Serialize(new Emitter(writer, emitterSettings), graph, type);
		}

		public void Serialize(IEmitter emitter, object graph)
		{
			if (emitter == null)
			{
				throw new ArgumentNullException("emitter");
			}
			EmitDocument(emitter, graph, null);
		}

		public void Serialize(IEmitter emitter, object graph, Type type)
		{
			if (emitter == null)
			{
				throw new ArgumentNullException("emitter");
			}
			if (type == null)
			{
				throw new ArgumentNullException("type");
			}
			EmitDocument(emitter, graph, type);
		}

		private void EmitDocument(IEmitter emitter, object graph, Type? type)
		{
			emitter.Emit(new YamlDotNet.Core.Events.StreamStart());
			emitter.Emit(new YamlDotNet.Core.Events.DocumentStart());
			valueSerializer.SerializeValue(emitter, graph, type);
			emitter.Emit(new YamlDotNet.Core.Events.DocumentEnd(isImplicit: true));
			emitter.Emit(new YamlDotNet.Core.Events.StreamEnd());
		}
	}
	internal sealed class SerializerBuilder : BuilderSkeleton<SerializerBuilder>
	{
		private class ValueSerializer : IValueSerializer
		{
			private readonly IObjectGraphTraversalStrategy traversalStrategy;

			private readonly IEventEmitter eventEmitter;

			private readonly IEnumerable<IYamlTypeConverter> typeConverters;

			private readonly LazyComponentRegistrationList<IEnumerable<IYamlTypeConverter>, IObjectGraphVisitor<Nothing>> preProcessingPhaseObjectGraphVisitorFactories;

			private readonly LazyComponentRegistrationList<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>> emissionPhaseObjectGraphVisitorFactories;

			public ValueSerializer(IObjectGraphTraversalStrategy traversalStrategy, IEventEmitter eventEmitter, IEnumerable<IYamlTypeConverter> typeConverters, LazyComponentRegistrationList<IEnumerable<IYamlTypeConverter>, IObjectGraphVisitor<Nothing>> preProcessingPhaseObjectGraphVisitorFactories, LazyComponentRegistrationList<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>> emissionPhaseObjectGraphVisitorFactories)
			{
				this.traversalStrategy = traversalStrategy;
				this.eventEmitter = eventEmitter;
				this.typeConverters = typeConverters;
				this.preProcessingPhaseObjectGraphVisitorFactories = preProcessingPhaseObjectGraphVisitorFactories;
				this.emissionPhaseObjectGraphVisitorFactories = emissionPhaseObjectGraphVisitorFactories;
			}

			public void SerializeValue(IEmitter emitter, object? value, Type? type)
			{
				IEmitter emitter2 = emitter;
				Type type2 = type ?? ((value != null) ? value.GetType() : typeof(object));
				Type staticType = type ?? typeof(object);
				ObjectDescriptor graph = new ObjectDescriptor(value, type2, staticType);
				List<IObjectGraphVisitor<Nothing>> preProcessingPhaseObjectGraphVisitors = preProcessingPhaseObjectGraphVisitorFactories.BuildComponentList(typeConverters);
				foreach (IObjectGraphVisitor<Nothing> item in preProcessingPhaseObjectGraphVisitors)
				{
					traversalStrategy.Traverse(graph, item, default(Nothing));
				}
				IObjectGraphVisitor<IEmitter> visitor = emissionPhaseObjectGraphVisitorFactories.BuildComponentChain<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>>(new EmittingObjectGraphVisitor(eventEmitter), (IObjectGraphVisitor<IEmitter> inner) => new EmissionPhaseObjectGraphVisitorArgs(inner, eventEmitter, preProcessingPhaseObjectGraphVisitors, typeConverters, NestedObjectSerializer));
				traversalStrategy.Traverse(graph, visitor, emitter2);
				void NestedObjectSerializer(object? v, Type? t)
				{
					SerializeValue(emitter2, v, t);
				}
			}
		}

		private ObjectGraphTraversalStrategyFactory objectGraphTraversalStrategyFactory;

		private readonly LazyComponentRegistrationList<IEnumerable<IYamlTypeConverter>, IObjectGraphVisitor<Nothing>> preProcessingPhaseObjectGraphVisitorFactories;

		private readonly LazyComponentRegistrationList<EmissionPhaseObjectGraphVisitorArgs, IObjectGraphVisitor<IEmitter>> emissionPhaseObjectGraphVisitorFactories;

		private readonly Laz