Decompiled source of CraftingStorageCompatibility v1.1.2

plugins/MultiCraftAzuCompatibility.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using AdventureBackpacks.API;
using AzuCraftyBoxes;
using AzuCraftyBoxes.IContainers;
using AzuCraftyBoxes.Util.Functions;
using BepInEx;
using BepInEx.Bootstrap;
using EpicLoot_UnityLib;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using MultiCraft;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyCompany("MultiCraftAzuCompatibility")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.2.0")]
[assembly: AssemblyInformationalVersion("1.1.2")]
[assembly: AssemblyProduct("MultiCraftAzuCompatibility")]
[assembly: AssemblyTitle("MultiCraftAzuCompatibility")]
[assembly: AssemblyVersion("1.1.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
internal static class BackpackAccess
{
	private static readonly Func<bool> CraftEnabled = Bind<bool>("IsCraftFromBackpackEnabled");

	private static readonly Func<bool> LeaveOne = Bind<bool>("IsLeaveOneItemInBackpackEnabled");

	private static readonly Func<string> Priority = Bind<string>("GetConsumptionPriority");

	private static readonly Action<string> Suppress = BindAction("SuppressNativeCrafting");

	private static readonly Action<string> Unsuppress = BindAction("UnsuppressNativeCrafting");

	[ThreadStatic]
	private static int paymentDepth;

	internal static bool Modern => CraftEnabled != null;

	internal static bool KeepOne => LeaveOne?.Invoke() ?? false;

	internal static bool First => Priority?.Invoke() == "BackpackFirst";

	private static Action<string> BindAction(string name)
	{
		MethodInfo method = typeof(ABAPI).GetMethod(name, new Type[1] { typeof(string) });
		if (!(method == null))
		{
			return (Action<string>)Delegate.CreateDelegate(typeof(Action<string>), method);
		}
		return null;
	}

	internal static void BeginCheckedPayment(out bool __state)
	{
		__state = RuneforgingApi.Active && ABAPI.IsLoaded() && Suppress != null && Unsuppress != null;
		if (__state && paymentDepth++ == 0)
		{
			Suppress("local.multicraft.azucraftyboxes.compatibility");
		}
	}

	internal static void EndCheckedPayment(bool __state)
	{
		if (__state && --paymentDepth == 0)
		{
			Unsuppress("local.multicraft.azucraftyboxes.compatibility");
		}
	}

	private static Func<T> Bind<T>(string name)
	{
		MethodInfo method = typeof(ABAPI).GetMethod(name, Type.EmptyTypes);
		if (!(method == null))
		{
			return (Func<T>)Delegate.CreateDelegate(typeof(Func<T>), method);
		}
		return null;
	}

	internal static bool TryGet(Player player, out Inventory inventory)
	{
		inventory = null;
		if (!Object.op_Implicit((Object)(object)player) || !ABAPI.IsLoaded() || !ABAPI.IsBackpackEquipped(player))
		{
			return false;
		}
		if (CraftEnabled != null && !CraftEnabled())
		{
			return false;
		}
		if (!ABAPI.TryGetEquippedBackpackInventory(player, out inventory) || inventory == null)
		{
			return false;
		}
		if (CraftEnabled != null)
		{
			return true;
		}
		Inventory candidate = inventory;
		if (Plugin.UseStorage(((Humanoid)player).GetInventory()) && API.GetNearbyContainers<Player>(player, AzuCraftyBoxesPlugin.mRange.Value).Any((IContainer c) => c != null && c.GetInventory() == candidate))
		{
			return true;
		}
		inventory = null;
		return false;
	}
}
internal static class CraftPaymentGate
{
	private static readonly FieldInfo RecipeField = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe");

	private static readonly FieldInfo UpgradeField = AccessTools.Field(typeof(InventoryGui), "m_craftUpgradeItem");

	private static readonly FieldInfo MultiField = AccessTools.Field(typeof(InventoryGui), "m_multiCrafting");

	private static readonly FieldInfo AmountField = AccessTools.Field(typeof(InventoryGui), "m_multiCraftAmount");

	internal static void Insert(List<CodeInstruction> result, CodeInstruction selected, CodeInstruction amount, ILGenerator generator)
	{
		//IL_0161: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Expected O, but got Unknown
		//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Expected O, but got Unknown
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c4: Expected O, but got Unknown
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d8: Expected O, but got Unknown
		//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fb: Expected O, but got Unknown
		//IL_0209: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: Expected O, but got Unknown
		//IL_0217: Unknown result type (might be due to invalid IL or missing references)
		//IL_021d: Expected O, but got Unknown
		CodeInstruction[] array = result.Where((CodeInstruction i) => CodeInstructionExtensions.LoadsField(i, AccessTools.Field(typeof(InventoryGui), "m_craftVariant"), false)).ToArray();
		CodeInstruction[] array2 = result.Where((CodeInstruction i) => CodeInstructionExtensions.Calls(i, AccessTools.Method(typeof(Player), "ConsumeResources", (Type[])null, (Type[])null))).ToArray();
		CodeInstruction[] array3 = result.Where((CodeInstruction i) => CodeInstructionExtensions.Calls(i, AccessTools.Method(typeof(Inventory), "ItemCheated", new Type[3]
		{
			typeof(Requirement[]),
			typeof(int),
			typeof(bool)
		}, (Type[])null))).ToArray();
		if (array.Length != 1 || array2.Length != 1 || array3.Length != 1 || result.Any((CodeInstruction i) => i.blocks.Count != 0))
		{
			throw new InvalidOperationException("Unrecognized crafting transaction boundary");
		}
		int index = result.IndexOf(array[0]) - 1;
		if (result[index].opcode != OpCodes.Ldarg_0)
		{
			throw new InvalidOperationException("Unrecognized crafting output boundary");
		}
		array2[0].opcode = OpCodes.Call;
		array2[0].operand = AccessTools.Method(typeof(CraftPaymentGate), "FinishResources", (Type[])null, (Type[])null);
		array3[0].opcode = OpCodes.Call;
		array3[0].operand = AccessTools.Method(typeof(CraftPaymentGate), "MaterialsCheated", (Type[])null, (Type[])null);
		Label label = generator.DefineLabel();
		CodeInstruction val = result[index];
		CodeInstruction val2 = new CodeInstruction(OpCodes.Ldarg_0, (object)null);
		val2.labels.AddRange(val.labels);
		val.labels.Clear();
		val.labels.Add(label);
		result.InsertRange(index, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[7]
		{
			val2,
			new CodeInstruction(OpCodes.Ldarg_1, (object)null),
			new CodeInstruction(selected.opcode, selected.operand),
			new CodeInstruction(amount.opcode, amount.operand),
			new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(CraftPaymentGate), "PayBeforeOutput", (Type[])null, (Type[])null)),
			new CodeInstruction(OpCodes.Brtrue, (object)label),
			new CodeInstruction(OpCodes.Ret, (object)null)
		});
	}

	private static bool PayBeforeOutput(InventoryGui gui, Player player, ItemData selected, int amount)
	{
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: 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
		if (player.NoCostCheat() || ZoneSystem.instance.GetGlobalKey((GlobalKeys)25))
		{
			return true;
		}
		SingleIngredientPayment.Scope current = SingleIngredientPayment.Current;
		if (current == null || current.Paid)
		{
			throw new InvalidOperationException("Invalid crafting transaction scope");
		}
		Recipe val = (Recipe)RecipeField.GetValue(gui);
		ItemData val2 = (ItemData)UpgradeField.GetValue(gui);
		CraftingStation currentCraftingStation = player.GetCurrentCraftingStation();
		bool flag = Object.op_Implicit((Object)(object)currentCraftingStation) && currentCraftingStation.m_upgrader;
		if (flag && !val.m_resources.Any((Requirement r) => r.m_upgraderResource && Object.op_Implicit((Object)(object)r.m_resItem)))
		{
			return false;
		}
		int quality = ((val2 == null) ? 1 : (val2.m_quality + 1));
		int multiplier = ((!(bool)MultiField.GetValue(gui)) ? 1 : ((int)AmountField.GetValue(gui)));
		IEnumerable<InventoryPaymentPlan.Cost> enumerable2;
		if (selected != null)
		{
			IEnumerable<InventoryPaymentPlan.Cost> enumerable = new InventoryPaymentPlan.Cost[1]
			{
				new InventoryPaymentPlan.Cost
				{
					Item = selected.m_dropPrefab.GetComponent<ItemDrop>(),
					Amount = amount,
					Quality = selected.m_quality
				}
			};
			enumerable2 = enumerable;
		}
		else
		{
			enumerable2 = InventoryPaymentPlan.Requirements(val.m_resources, quality, multiplier, flag);
		}
		IEnumerable<InventoryPaymentPlan.Cost> costs = enumerable2;
		Inventory inventory;
		bool chestsOnly = selected != null && !((Humanoid)player).GetInventory().ContainsItem(selected) && (!BackpackAccess.Modern || !BackpackAccess.TryGet(player, out inventory));
		InventoryPaymentPlan inventoryPaymentPlan = InventoryPaymentPlan.Create(player, costs, chestsOnly);
		current.Cheated = ((Humanoid)player).GetInventory().ItemCheated(val.m_resources, -1, true);
		if (inventoryPaymentPlan == null || !inventoryPaymentPlan.Commit(notify: false))
		{
			return false;
		}
		current.Plan = inventoryPaymentPlan;
		current.Paid = true;
		return true;
	}

	private static bool MaterialsCheated(Inventory inventory, Requirement[] resources, int quality, bool worldLevel)
	{
		if (SingleIngredientPayment.Current?.Plan == null)
		{
			return inventory.ItemCheated(resources, quality, worldLevel);
		}
		return SingleIngredientPayment.Current.Cheated;
	}

	private static void FinishResources(Player player, Requirement[] resources, int quality, int itemQuality, int multiplier)
	{
		if (SingleIngredientPayment.Current?.Plan == null)
		{
			player.ConsumeResources(resources, quality, itemQuality, multiplier);
		}
	}
}
internal static class ImproveInteraction
{
	private sealed class Selection
	{
		internal ItemData Item;

		internal float Scroll;
	}

	private static readonly FieldInfo Selected = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe");

	private static readonly FieldInfo Available = AccessTools.Field(typeof(InventoryGui), "m_availableRecipes");

	private static readonly PropertyInfo Item = Selected.FieldType.GetProperty("ItemData");

	private static readonly MethodInfo SetRecipe = AccessTools.Method(typeof(InventoryGui), "SetRecipe", new Type[2]
	{
		typeof(int),
		typeof(bool)
	}, (Type[])null);

	private static readonly FieldInfo Queued = AccessTools.Field(typeof(MultiCraft_Logic), "WasCrafting");

	private static readonly FieldInfo[] Controls = new FieldInfo[3]
	{
		AccessTools.Field(typeof(MultiCraft_UI), "plusButton"),
		AccessTools.Field(typeof(MultiCraft_UI), "minusButton"),
		AccessTools.Field(typeof(MultiCraft_UI), "amountText")
	};

	private static readonly Dictionary<GameObject, bool> Hidden = new Dictionary<GameObject, bool>();

	internal static void Install(Harmony harmony)
	{
		//IL_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Expected O, but got Unknown
		//IL_00bb: Expected O, but got Unknown
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Expected O, but got Unknown
		//IL_0110: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Expected O, but got Unknown
		if (Selected == null || Available == null || Item == null || SetRecipe == null || Queued == null || Array.Exists(Controls, (FieldInfo f) => f == null))
		{
			throw new MissingMemberException("Improve/MultiCraft UI contract changed");
		}
		harmony.Patch((MethodBase)AccessTools.Method(RuneforgingApi.UiType, "BuildImproveList", (Type[])null, (Type[])null), new HarmonyMethod(typeof(ImproveInteraction), "RememberSelection", (Type[])null), new HarmonyMethod(typeof(ImproveInteraction), "RestoreSelection", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(RuneforgingApi.UiType, "Open", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ImproveInteraction), "Opened", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(RuneforgingApi.StateType, "Reset", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ImproveInteraction), "RestoreControls", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		PatchPrefix(harmony, typeof(MultiCraft_UI), "RefreshCustomButtonStates", "RefreshControls");
		PatchPrefix(harmony, typeof(MultiCraft_UI), "AreCustomButtonsUsable", "ButtonsUsable");
		PatchPrefix(harmony, typeof(MultiCraft_UI), "OnCraftButtonPressed", "AllowBatch");
		PatchPrefix(harmony, typeof(MultiCraft_Logic), "StartCraftingLogic", "AllowBatch");
		PatchPrefix(harmony, typeof(MultiCraft_Logic), "Update", "AllowBatch");
	}

	private static void PatchPrefix(Harmony h, Type type, string target, string patch)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Expected O, but got Unknown
		h.Patch((MethodBase)AccessTools.Method(type, target, (Type[])null, (Type[])null), new HarmonyMethod(typeof(ImproveInteraction), patch, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private static void RememberSelection(InventoryGui gui, bool focusView, out Selection __state)
	{
		__state = null;
		if (!(!RuneforgingApi.Active || focusView) && !((Object)(object)gui == (Object)null))
		{
			object? value = Item.GetValue(Selected.GetValue(gui), null);
			ItemData val = (ItemData)((value is ItemData) ? value : null);
			if (val != null)
			{
				__state = new Selection
				{
					Item = val,
					Scroll = (Object.op_Implicit((Object)(object)gui.m_recipeListScroll) ? gui.m_recipeListScroll.value : 0f)
				};
			}
		}
	}

	private static void RestoreSelection(InventoryGui gui, Selection __state)
	{
		if (__state == null || !RuneforgingApi.Active || (Object)(object)gui == (Object)null)
		{
			return;
		}
		IList list = (IList)Available.GetValue(gui);
		int num = -1;
		for (int i = 0; i < list.Count; i++)
		{
			if (Item.GetValue(list[i], null) == __state.Item)
			{
				num = i;
				break;
			}
		}
		SetRecipe.Invoke(gui, new object[2] { num, false });
		if (Object.op_Implicit((Object)(object)gui.m_recipeListScroll))
		{
			gui.m_recipeListScroll.value = __state.Scroll;
		}
	}

	private static void SuspendBatch()
	{
		MultiCraft_Logic instance = MultiCraft_Logic.instance;
		Queued.SetValue(instance, false);
		if (instance.CurrentCraftAmount != 1)
		{
			instance.CurrentCraftAmount = 1;
		}
	}

	private static bool AllowBatch()
	{
		if (!RuneforgingApi.Active)
		{
			return true;
		}
		SuspendBatch();
		return false;
	}

	private static bool ButtonsUsable(ref bool __result)
	{
		if (!RuneforgingApi.Active)
		{
			return true;
		}
		__result = false;
		return false;
	}

	private static void Opened()
	{
		if (RuneforgingApi.Active)
		{
			RefreshControls(MultiCraft_UI.instance);
		}
	}

	private static bool RefreshControls(MultiCraft_UI __instance)
	{
		if (!RuneforgingApi.Active)
		{
			RestoreControls();
			return true;
		}
		SuspendBatch();
		FieldInfo[] controls = Controls;
		for (int i = 0; i < controls.Length; i++)
		{
			object? value = controls[i].GetValue(__instance);
			RectTransform val = (RectTransform)((value is RectTransform) ? value : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				GameObject gameObject = ((Component)val).gameObject;
				if (!Hidden.ContainsKey(gameObject))
				{
					Hidden.Add(gameObject, gameObject.activeSelf);
				}
				gameObject.SetActive(false);
			}
		}
		return false;
	}

	internal static void RestoreControls()
	{
		foreach (KeyValuePair<GameObject, bool> item in Hidden)
		{
			if (Object.op_Implicit((Object)(object)item.Key))
			{
				item.Key.SetActive(item.Value);
			}
		}
		Hidden.Clear();
	}
}
internal sealed class InventoryPaymentPlan
{
	internal sealed class Cost
	{
		internal ItemDrop Item;

		internal int Amount;

		internal int Quality = -1;
	}

	private sealed class Source
	{
		internal Inventory Inventory;

		internal IContainer Container;

		internal bool Backpack;
	}

	private sealed class Debit
	{
		internal Source Source;

		internal ItemData Item;

		internal int Before;

		internal int Amount;

		internal string Name;

		internal int Quality;
	}

	private readonly List<Debit> debits = new List<Debit>();

	private readonly Player player;

	private readonly bool storage;

	private bool committed;

	private bool notified;

	private readonly bool keepOne = BackpackAccess.KeepOne;

	private readonly int worldLevel = Game.m_worldLevel;

	private static readonly Func<int, int> Spendable = (Func<int, int>)Delegate.CreateDelegate(typeof(Func<int, int>), AccessTools.Method(typeof(Boxes), "CheckAndDecrement", (Type[])null, (Type[])null));

	private static readonly Action<Inventory, bool, bool> Changed = (Action<Inventory, bool, bool>)Delegate.CreateDelegate(typeof(Action<Inventory, bool, bool>), AccessTools.Method(typeof(Inventory), "Changed", (Type[])null, (Type[])null));

	private InventoryPaymentPlan(Player player, bool storage)
	{
		this.player = player;
		this.storage = storage;
	}

	internal static bool Supported(IContainer source)
	{
		string fullName = ((object)source).GetType().FullName;
		if (!(fullName == "AzuCraftyBoxes.IContainers.VanillaContainer") && !(fullName == "AzuCraftyBoxes.IContainers.BackpackContainer"))
		{
			return fullName == "AzuCraftyBoxes.IContainers.GemBagContainer";
		}
		return true;
	}

	private static List<Source> Sources(Player player, bool chestsOnly)
	{
		bool num = Plugin.UseStorage(((Humanoid)player).GetInventory());
		List<Source> list = new List<Source>();
		HashSet<Inventory> hashSet = new HashSet<Inventory> { ((Humanoid)player).GetInventory() };
		if (!chestsOnly)
		{
			list.Add(new Source
			{
				Inventory = ((Humanoid)player).GetInventory()
			});
		}
		if (BackpackAccess.TryGet(player, out var inventory) && hashSet.Add(inventory))
		{
			list.Insert((!BackpackAccess.First) ? list.Count : 0, new Source
			{
				Inventory = inventory,
				Backpack = true
			});
		}
		if (num)
		{
			foreach (IContainer nearbyContainer in API.GetNearbyContainers<Player>(player, AzuCraftyBoxesPlugin.mRange.Value))
			{
				if (nearbyContainer != null && Supported(nearbyContainer))
				{
					Inventory inventory2 = nearbyContainer.GetInventory();
					if (inventory2 != null && hashSet.Add(inventory2))
					{
						list.Add(new Source
						{
							Inventory = inventory2,
							Container = nearbyContainer
						});
					}
				}
			}
		}
		return list;
	}

	private static int Stock(Source source, string name, int quality)
	{
		return (from i in source.Inventory.GetAllItems()
			where i.m_shared.m_name == name && (quality < 0 || i.m_quality == quality) && i.m_worldLevel >= Game.m_worldLevel && !i.m_equipped
			select i).Sum((ItemData i) => i.m_stack);
	}

	private static int Available(Source source, string name, int quality)
	{
		int num = Stock(source, name, quality);
		if (!source.Backpack)
		{
			if (source.Container != null)
			{
				return Spendable(num);
			}
			return num;
		}
		return Math.Max(0, num - (BackpackAccess.KeepOne ? 1 : 0));
	}

	internal static int CountAvailable(Player player, string name)
	{
		int num = 0;
		foreach (Source item in Sources(player, chestsOnly: false))
		{
			ItemData val = ((IEnumerable<ItemData>)item.Inventory.GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => i.m_shared.m_name == name));
			if (val != null && (item.Container == null || (Object.op_Implicit((Object)(object)val.m_dropPrefab) && API.CanItemBePulled(item.Container.GetPrefabName(), ((Object)val.m_dropPrefab).name))))
			{
				num = checked(num + Available(item, name, -1));
			}
		}
		return num;
	}

	internal static IEnumerable<Inventory> CandidateInventories(Player player)
	{
		return from s in Sources(player, chestsOnly: false)
			select s.Inventory;
	}

	internal static InventoryPaymentPlan Create(Player player, IEnumerable<Cost> costs, bool chestsOnly = false)
	{
		if (!Object.op_Implicit((Object)(object)player) || costs == null)
		{
			return null;
		}
		InventoryPaymentPlan inventoryPaymentPlan = new InventoryPaymentPlan(player, Plugin.UseStorage(((Humanoid)player).GetInventory()));
		List<Source> list = Sources(player, chestsOnly);
		foreach (Cost cost in costs.OrderByDescending((Cost c) => c.Quality >= 0))
		{
			if (cost.Amount <= 0)
			{
				continue;
			}
			if (!Object.op_Implicit((Object)(object)cost.Item))
			{
				return null;
			}
			int num = cost.Amount;
			string name = cost.Item.m_itemData.m_shared.m_name;
			foreach (Source source in list)
			{
				if (source.Container != null && !API.CanItemBePulled(source.Container.GetPrefabName(), ((Object)((Component)cost.Item).gameObject).name))
				{
					continue;
				}
				int num2 = inventoryPaymentPlan.debits.Where((Debit d) => d.Source.Inventory == source.Inventory && d.Name == name && (cost.Quality < 0 || d.Quality == cost.Quality)).Sum((Debit d) => d.Amount);
				int val = Math.Max(0, Available(source, name, cost.Quality) - num2);
				int num3 = Math.Min(num, val);
				foreach (ItemData item in source.Inventory.GetAllItems())
				{
					if (item.m_shared.m_name != name || (cost.Quality >= 0 && item.m_quality != cost.Quality) || item.m_worldLevel < Game.m_worldLevel || item.m_equipped)
					{
						continue;
					}
					Debit debit = inventoryPaymentPlan.debits.FirstOrDefault((Debit d) => d.Item == item && d.Source.Inventory == source.Inventory);
					int num4 = Math.Min(num3, item.m_stack - (debit?.Amount ?? 0));
					if (num4 > 0)
					{
						if (debit == null)
						{
							debit = new Debit
							{
								Source = source,
								Item = item,
								Before = item.m_stack,
								Name = name,
								Quality = item.m_quality
							};
							inventoryPaymentPlan.debits.Add(debit);
						}
						debit.Amount += num4;
						num -= num4;
						num3 -= num4;
						if (num3 == 0)
						{
							break;
						}
					}
				}
				if (num == 0)
				{
					break;
				}
			}
			if (num != 0)
			{
				return null;
			}
		}
		return inventoryPaymentPlan;
	}

	internal bool Commit(bool notify = true)
	{
		if (committed || !Object.op_Implicit((Object)(object)player) || worldLevel != Game.m_worldLevel || (storage && !Plugin.UseStorage(((Humanoid)player).GetInventory())))
		{
			return false;
		}
		foreach (Debit debit in debits)
		{
			if (debit.Source.Backpack && (keepOne != BackpackAccess.KeepOne || !BackpackAccess.TryGet(player, out var inventory) || inventory != debit.Source.Inventory))
			{
				return false;
			}
			if (!debit.Source.Inventory.ContainsItem(debit.Item) || debit.Item.m_stack != debit.Before || debit.Item.m_shared.m_name != debit.Name || debit.Item.m_quality != debit.Quality || debit.Item.m_worldLevel < worldLevel || debit.Item.m_equipped || (debit.Source.Container != null && debit.Source.Container.GetInventory() != debit.Source.Inventory))
			{
				return false;
			}
		}
		foreach (var item2 in from d in debits
			group d by new { d.Source, d.Name })
		{
			if (item2.Sum((Debit d) => d.Amount) > Available(item2.Key.Source, item2.Key.Name, -1))
			{
				return false;
			}
		}
		committed = true;
		foreach (Debit debit2 in debits)
		{
			ItemData item = debit2.Item;
			item.m_stack -= debit2.Amount;
			if (debit2.Item.m_stack == 0)
			{
				debit2.Source.Inventory.GetAllItems().Remove(debit2.Item);
			}
		}
		if (notify)
		{
			Notify();
		}
		return true;
	}

	internal void Notify()
	{
		if (!committed || notified)
		{
			return;
		}
		notified = true;
		foreach (Source item in from d in debits
			select d.Source into s
			group s by s.Inventory into g
			select g.First())
		{
			try
			{
				if (item.Container != null)
				{
					item.Container.Save();
				}
				else
				{
					Changed(item.Inventory, arg2: false, arg3: false);
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[CraftingStorageCompatibility] Paid inventory notification failed: " + ex));
			}
		}
	}

	internal static IEnumerable<Cost> Requirements(Requirement[] requirements, int quality, int multiplier, bool upgrader = false)
	{
		return from r in requirements
			where r != null && Object.op_Implicit((Object)(object)r.m_resItem) && r.m_upgraderResource == upgrader
			select new Cost
			{
				Item = r.m_resItem,
				Amount = checked(r.GetAmount(quality) * multiplier)
			};
	}

	internal static IEnumerable<Cost> Improve(IList costs)
	{
		foreach (object cost in costs)
		{
			yield return new Cost
			{
				Item = RuneforgingApi.Resource(cost),
				Amount = RuneforgingApi.Amount(cost)
			};
		}
	}
}
internal static class LegacyImprovePayment
{
	internal static void Install(Harmony harmony)
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Expected O, but got Unknown
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Expected O, but got Unknown
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Expected O, but got Unknown
		harmony.Patch((MethodBase)AccessTools.Method(RuneforgingApi.CostType, "PlayerHasCost", (Type[])null, (Type[])null), new HarmonyMethod(typeof(LegacyImprovePayment), "Have", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(RuneforgingApi.CostType, "Consume", (Type[])null, (Type[])null), new HarmonyMethod(typeof(LegacyImprovePayment), "Consume", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(RuneforgingApi.UiType, "CompleteImprove", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(LegacyImprovePayment), "RequirePayment", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private static bool Have(Player player, IList cost, ref bool __result)
	{
		__result = InventoryPaymentPlan.Create(player, InventoryPaymentPlan.Improve(cost)) != null;
		return false;
	}

	internal static bool TryConsume(Player player, IList cost)
	{
		if (!Object.op_Implicit((Object)(object)player))
		{
			return false;
		}
		if (player.NoCostCheat() || ZoneSystem.instance.GetGlobalKey((GlobalKeys)25))
		{
			return true;
		}
		return InventoryPaymentPlan.Create(player, InventoryPaymentPlan.Improve(cost))?.Commit() ?? false;
	}

	private static bool Consume(Player player, IList cost)
	{
		if (!TryConsume(player, cost))
		{
			throw new InvalidOperationException("Improve payment could not be completed");
		}
		return false;
	}

	internal static IEnumerable<CodeInstruction> RequirePayment(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
	{
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		//IL_0151: Expected O, but got Unknown
		List<CodeInstruction> list = instructions.Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction i) => new CodeInstruction(i))).ToList();
		CodeInstruction[] array = list.Where((CodeInstruction i) => CodeInstructionExtensions.Calls(i, AccessTools.Method(RuneforgingApi.CostType, "Consume", (Type[])null, (Type[])null))).ToArray();
		CodeInstruction[] array2 = list.Where((CodeInstruction i) => i.opcode == OpCodes.Ldstr && object.Equals(i.operand, "$msg_missingrequirement")).ToArray();
		if (array.Length != 1 || array2.Length != 1)
		{
			throw new InvalidOperationException("Unrecognized legacy Improve completion");
		}
		int num = list.IndexOf(array2[0]) - 2;
		if (num < 0 || list[num].opcode != OpCodes.Ldarg_1 || list[num + 1].opcode != OpCodes.Ldc_I4_2)
		{
			throw new InvalidOperationException("Unrecognized legacy missing-material branch");
		}
		Label label = generator.DefineLabel();
		list[num].labels.Add(label);
		int num2 = list.IndexOf(array[0]);
		array[0].opcode = OpCodes.Call;
		array[0].operand = AccessTools.Method(typeof(LegacyImprovePayment), "TryConsume", (Type[])null, (Type[])null);
		list.Insert(num2 + 1, new CodeInstruction(OpCodes.Brfalse, (object)label));
		return list;
	}
}
internal static class ModernImprove
{
	internal static readonly MethodInfo HaveMethod = AccessTools.Method(typeof(Player), "HaveRequirements", new Type[4]
	{
		typeof(Recipe),
		typeof(bool),
		typeof(int),
		typeof(int)
	}, (Type[])null);

	private static readonly MethodInfo InvokeMethod = AccessTools.Method(typeof(MethodBase), "Invoke", new Type[2]
	{
		typeof(object),
		typeof(object[])
	}, (Type[])null);

	private static readonly FieldInfo SelectedRecipe = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe");

	private static PropertyInfo selectedItem;

	internal static void Install(Harmony harmony)
	{
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Expected O, but got Unknown
		//IL_00ec: Expected O, but got Unknown
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Expected O, but got Unknown
		if (HaveMethod == null || SelectedRecipe == null)
		{
			throw new MissingMethodException("Unsupported Valheim recipe API");
		}
		Type type = RuneforgingApi.CostType.Assembly.GetType("BalrondItemRarity.Resources.ImproveResourceService", throwOnError: true);
		Patch(harmony, type, "ResolveExternalContract", "FixContractLookup");
		Patch(harmony, type, "ExternalHasRequirements", "FixRequirementInvocation");
		Patch(harmony, type, "ExternalConsume", "FixConsumptionInvocation");
		string[] array = new string[3] { "UpdateRecipe", "UpdateCraftingPanel", "OnCraftPressed" };
		foreach (string text in array)
		{
			harmony.Patch((MethodBase)AccessTools.Method(typeof(InventoryGui), text, (Type[])null, (Type[])null), new HarmonyMethod(typeof(BackpackAccess), "BeginCheckedPayment", (Type[])null)
			{
				priority = 800
			}, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(BackpackAccess), "EndCheckedPayment", (Type[])null)
			{
				priority = 0
			}, (HarmonyMethod)null);
		}
		array = new string[2] { "UpdateRecipe", "UpdateCraftingPanel" };
		foreach (string text2 in array)
		{
			harmony.Patch((MethodBase)AccessTools.Method(typeof(InventoryGui), text2, (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ModernImprove), "ShowCounts", (Type[])null)
			{
				priority = 0
			}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}
		AccessTools.Method(type, "RefreshExternalContract", (Type[])null, (Type[])null).Invoke(null, null);
	}

	private static void Patch(Harmony harmony, Type type, string method, string transpiler)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(type, method, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			throw new MissingMethodException(type.FullName, method);
		}
		harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ModernImprove), transpiler, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
	}

	internal static IEnumerable<CodeInstruction> FixContractLookup(IEnumerable<CodeInstruction> instructions)
	{
		List<CodeInstruction> list = instructions.Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction i) => new CodeInstruction(i))).ToList();
		int num = 0;
		foreach (CodeInstruction item in list)
		{
			if (!(item.opcode != OpCodes.Ldsfld) && item.operand is FieldInfo fieldInfo && !(fieldInfo.Name != "HaveRequirementsMethod") && !(fieldInfo.DeclaringType?.FullName != "BalrondItemRarity.Resources.ImproveResourceService"))
			{
				item.operand = AccessTools.Field(typeof(ModernImprove), "HaveMethod");
				num++;
			}
		}
		if (num != 3)
		{
			throw new InvalidOperationException("Unsupported Runeforging contract lookup: " + num);
		}
		return list;
	}

	internal static IEnumerable<CodeInstruction> FixRequirementInvocation(IEnumerable<CodeInstruction> instructions)
	{
		return ReplaceInvoke(instructions, "InvokeRequirements", 1);
	}

	internal static IEnumerable<CodeInstruction> FixConsumptionInvocation(IEnumerable<CodeInstruction> instructions)
	{
		List<CodeInstruction> result = ReplaceInvoke(instructions, "InvokeConsumption", 2).ToList();
		foreach (int item in from i in Enumerable.Range(0, result.Count)
			where CodeInstructionExtensions.Calls(result[i], AccessTools.Method(typeof(ModernImprove), "InvokeConsumption", (Type[])null, (Type[])null))
			select i)
		{
			if (result[item + 1].opcode != OpCodes.Pop || result[item + 2].opcode != OpCodes.Ldc_I4_1 || result[item + 1].labels.Count != 0 || result[item + 2].labels.Count != 0)
			{
				throw new InvalidOperationException("Unrecognized Improve payment result");
			}
			result[item + 1].opcode = OpCodes.Nop;
			result[item + 2].opcode = OpCodes.Nop;
		}
		return result;
	}

	private static IEnumerable<CodeInstruction> ReplaceInvoke(IEnumerable<CodeInstruction> instructions, string replacement, int expected)
	{
		List<CodeInstruction> list = instructions.Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction i) => new CodeInstruction(i))).ToList();
		int num = 0;
		foreach (CodeInstruction item in list)
		{
			if (CodeInstructionExtensions.Calls(item, InvokeMethod))
			{
				item.opcode = OpCodes.Call;
				item.operand = AccessTools.Method(typeof(ModernImprove), replacement, (Type[])null, (Type[])null);
				num++;
			}
		}
		if (num != expected)
		{
			throw new InvalidOperationException("Unsupported Runeforging invocation: " + replacement + " / " + num);
		}
		return list;
	}

	private static object InvokeRequirements(MethodBase method, object target, object[] args)
	{
		if (!(method != HaveMethod))
		{
			Player val = (Player)((target is Player) ? target : null);
			if (val != null && args.Length == 3 && args[0] is Requirement[] requirements)
			{
				return InventoryPaymentPlan.Create(val, InventoryPaymentPlan.Requirements(requirements, 1, 1)) != null;
			}
		}
		throw new InvalidOperationException("Unexpected Improve requirements contract");
	}

	private static bool InvokeConsumption(MethodBase method, object target, object[] args)
	{
		object obj = ((target is Player) ? target : null);
		if (obj == null || !(args[0] is Requirement[] requirements))
		{
			throw new InvalidOperationException("Unexpected Improve consumption contract");
		}
		return InventoryPaymentPlan.Create((Player)obj, InventoryPaymentPlan.Requirements(requirements, 1, 1))?.Commit() ?? false;
	}

	internal static int CountUncached(Player player, List<IContainer> containers, string name)
	{
		int num = ((Humanoid)player).GetInventory().CountItems(name, -1, true);
		HashSet<Inventory> hashSet = new HashSet<Inventory> { ((Humanoid)player).GetInventory() };
		HashSet<IContainer> hashSet2 = new HashSet<IContainer>();
		foreach (IContainer container in containers)
		{
			if (container != null && hashSet2.Add(container))
			{
				Inventory inventory = container.GetInventory();
				if (inventory == null || hashSet.Add(inventory))
				{
					num = checked(num + container.ItemCount(name));
				}
			}
		}
		return num;
	}

	private static void ShowCounts(InventoryGui __instance)
	{
		Player localPlayer = Player.m_localPlayer;
		if (!RuneforgingApi.Active || RuneforgingApi.IsImproving || (Object)(object)localPlayer == (Object)null || (Object)(object)__instance == (Object)null || !((Behaviour)__instance.m_recipeIcon).enabled)
		{
			return;
		}
		object value = SelectedRecipe.GetValue(__instance);
		if (value == null)
		{
			return;
		}
		if (selectedItem == null)
		{
			selectedItem = value.GetType().GetProperty("ItemData");
		}
		object? obj = selectedItem?.GetValue(value, null);
		ItemData val = (ItemData)((obj is ItemData) ? obj : null);
		if (val != null)
		{
			IList cost = RuneforgingApi.GetCost(val);
			for (int i = 0; i < cost.Count && i < __instance.m_recipeRequirementList.Length; i++)
			{
				Plugin.ShowImproveCount(__instance.m_recipeRequirementList[i].transform, localPlayer, cost[i]);
			}
		}
	}

	internal static void Cleanup()
	{
	}
}
[BepInPlugin("local.multicraft.azucraftyboxes.compatibility", "Crafting Storage Compatibility", "1.1.2")]
[BepInDependency("maximods.valheim.multicraft", "1.5.0")]
[BepInDependency("Azumatt.AzuCraftyBoxes", "1.8.19")]
[BepInDependency("balrond.astafaraios.Runeforging", "1.0.3")]
[BepInDependency("randyknapp.mods.epicloot", "0.14.13")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class Plugin : BaseUnityPlugin
{
	public const string Id = "local.multicraft.azucraftyboxes.compatibility";

	private static Func<bool> shouldPrevent;

	private Harmony harmony;

	private Harmony improveHarmony;

	private Harmony interactionHarmony;

	private Harmony paymentHarmony;

	private Harmony stationHarmony;

	private void Awake()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Expected O, but got Unknown
		//IL_0123: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: Expected O, but got Unknown
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: Expected O, but got Unknown
		//IL_0285: Unknown result type (might be due to invalid IL or missing references)
		//IL_028f: Expected O, but got Unknown
		//IL_0347: Unknown result type (might be due to invalid IL or missing references)
		//IL_0354: Expected O, but got Unknown
		try
		{
			stationHarmony = new Harmony("local.multicraft.azucraftyboxes.compatibility.station");
			if (ReforgedStationGuard.Install(stationHarmony))
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Corrected ReforgedPotential nullable crafting-station accesses.");
			}
		}
		catch (Exception ex)
		{
			Harmony obj = stationHarmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			((BaseUnityPlugin)this).Logger.LogWarning((object)("ReforgedPotential station guard was not installed: " + ex.Message));
		}
		try
		{
			Type type = typeof(AzuCraftyBoxesPlugin).Assembly.GetType("AzuCraftyBoxes.Util.Functions.MiscFunctions", throwOnError: true);
			shouldPrevent = (Func<bool>)Delegate.CreateDelegate(typeof(Func<bool>), AccessTools.Method(type, "ShouldPrevent", (Type[])null, (Type[])null));
			MethodInfo methodInfo = AccessTools.Method(((object)Chainloader.PluginInfos["maximods.valheim.multicraft"].Instance).GetType().Assembly.GetType("MultiCraft.Helper", throwOnError: true), "GetAvailableItems", new Type[1] { typeof(string) }, (Type[])null);
			if (methodInfo == null)
			{
				throw new MissingMethodException("MultiCraft.Helper.GetAvailableItems");
			}
			harmony = new Harmony("local.multicraft.azucraftyboxes.compatibility");
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Plugin), "CountAvailable", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Enabled MultiCraft storage counts.");
		}
		catch (Exception ex2)
		{
			Harmony obj2 = harmony;
			if (obj2 != null)
			{
				obj2.UnpatchSelf();
			}
			((BaseUnityPlugin)this).Logger.LogError((object)("Could not enable MultiCraft storage counts. " + ex2));
			return;
		}
		try
		{
			if (Chainloader.PluginInfos["Azumatt.AzuCraftyBoxes"].Metadata.Version == new Version(1, 8, 19))
			{
				paymentHarmony = new Harmony("local.multicraft.azucraftyboxes.compatibility.payment");
				SingleIngredientPayment.Install(paymentHarmony);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Enabled checked crafting payment before output creation; recipe previews cannot queue charges.");
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Azu version not verified for the single-ingredient payment fix; payment patches skipped.");
			}
		}
		catch (Exception ex3)
		{
			Harmony obj3 = paymentHarmony;
			if (obj3 != null)
			{
				obj3.UnpatchSelf();
			}
			((BaseUnityPlugin)this).Logger.LogError((object)("Could not enable single-ingredient payment protection; all payment patches removed. " + ex3));
		}
		try
		{
			Version version = Chainloader.PluginInfos["balrond.astafaraios.Runeforging"].Metadata.Version;
			if (version == new Version(1, 1, 5) || version == new Version(1, 0, 3))
			{
				RuneforgingApi.Bind(((object)Chainloader.PluginInfos["balrond.astafaraios.Runeforging"].Instance).GetType().Assembly);
			}
			improveHarmony = new Harmony("local.multicraft.azucraftyboxes.compatibility.improve");
			if (version == new Version(1, 1, 5))
			{
				ModernImprove.Install(improveHarmony);
				InstallInteraction();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Enabled Runeforging 1.1.5 vanilla-contract adapter and Improve counts; protected Improve methods untouched.");
			}
			else if (version != new Version(1, 0, 3))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Runeforging " + version?.ToString() + " has not been verified. Keeping MultiCraft support; leaving Improve to Runeforging."));
			}
			else
			{
				LegacyImprovePayment.Install(improveHarmony);
				PatchImprove("SetupCostRequirement", RuneforgingApi.UiType);
				improveHarmony.Patch((MethodBase)AccessTools.Method(RuneforgingApi.UiType, "SetupCostRequirement", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "ShowImproveCount", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Enabled MultiCraft stock counts and Runeforging Improve storage support. Radius/access/toggle inherited from AzuCraftyBoxes.");
				InstallInteraction();
			}
		}
		catch (Exception ex4)
		{
			Harmony obj4 = improveHarmony;
			if (obj4 != null)
			{
				obj4.UnpatchSelf();
			}
			((BaseUnityPlugin)this).Logger.LogError((object)("Could not enable Improve compatibility; MultiCraft support remains enabled. " + ex4));
		}
	}

	private void InstallInteraction()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown
		try
		{
			interactionHarmony = new Harmony("local.multicraft.azucraftyboxes.compatibility.interaction");
			ImproveInteraction.Install(interactionHarmony);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Improve keeps the selected item and uses one improvement per click; MultiCraft batches remain in Craft.");
		}
		catch (Exception ex)
		{
			Harmony obj = interactionHarmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			((BaseUnityPlugin)this).Logger.LogError((object)("Could not enable Improve UI fixes; storage integration remains enabled. " + ex));
		}
	}

	private void PatchImprove(string method, Type type)
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Expected O, but got Unknown
		improveHarmony.Patch((MethodBase)AccessTools.Method(type, method, (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "RedirectImproveInventory", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private static IEnumerable<CodeInstruction> RedirectImproveInventory(IEnumerable<CodeInstruction> instructions, MethodBase original)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Expected O, but got Unknown
		List<CodeInstruction> list = new List<CodeInstruction>();
		foreach (CodeInstruction instruction in instructions)
		{
			list.Add(new CodeInstruction(instruction));
		}
		MethodInfo methodInfo = AccessTools.Method(typeof(Inventory), "CountItems", new Type[3]
		{
			typeof(string),
			typeof(int),
			typeof(bool)
		}, (Type[])null);
		MethodInfo methodInfo2 = AccessTools.Method(typeof(Inventory), "RemoveItem", new Type[4]
		{
			typeof(string),
			typeof(int),
			typeof(int),
			typeof(bool)
		}, (Type[])null);
		int num = 0;
		foreach (CodeInstruction item in list)
		{
			string text = (CodeInstructionExtensions.Calls(item, methodInfo) ? "CountImproveMaterial" : (CodeInstructionExtensions.Calls(item, methodInfo2) ? "RemoveImproveMaterial" : null));
			if (text != null)
			{
				item.opcode = OpCodes.Call;
				item.operand = AccessTools.Method(typeof(Plugin), text, (Type[])null, (Type[])null);
				num++;
			}
		}
		if (num != 1)
		{
			throw new InvalidOperationException("Unexpected Improve method: " + original.Name + " (" + num + " inventory calls)");
		}
		return list;
	}

	internal static bool UseStorage(Inventory inventory)
	{
		if ((Object)(object)Player.m_localPlayer != (Object)null && inventory == ((Humanoid)Player.m_localPlayer).GetInventory())
		{
			return !shouldPrevent();
		}
		return false;
	}

	private static int CountImproveMaterial(Inventory inventory, string name, int quality, bool matchWorldLevel)
	{
		if (!UseStorage(inventory) && !BackpackAccess.TryGet(Player.m_localPlayer, out var _))
		{
			return inventory.CountItems(name, quality, matchWorldLevel);
		}
		return InventoryPaymentPlan.CountAvailable(Player.m_localPlayer, name);
	}

	private static void RemoveImproveMaterial(Inventory inventory, string name, int amount, int quality, bool worldLevelBased)
	{
		if (UseStorage(inventory))
		{
			InventoryManagement.Instance.RemoveItem(name, amount);
		}
		else
		{
			inventory.RemoveItem(name, amount, quality, worldLevelBased);
		}
	}

	internal static void ShowImproveCount(Transform elementRoot, Player player, object entry)
	{
		if ((Object)(object)player == (Object)null || entry == null)
		{
			return;
		}
		ItemDrop val = RuneforgingApi.Resource(entry);
		if (!((Object)(object)val == (Object)null))
		{
			Transform obj = elementRoot.Find("res_amount");
			TMP_Text val2 = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null);
			if (!((Object)(object)val2 == (Object)null))
			{
				int num = CountImproveMaterial(((Humanoid)player).GetInventory(), val.m_itemData.m_shared.m_name, -1, matchWorldLevel: true);
				val2.text = RuneforgingApi.Amount(entry) + "/" + num;
				val2.enableAutoSizing = true;
				val2.fontSizeMin = 10f;
				val2.fontSizeMax = 16f;
			}
		}
	}

	private static bool CountAvailable(string itemName, ref int __result)
	{
		if ((Object)(object)Player.m_localPlayer == (Object)null || (shouldPrevent() && !BackpackAccess.TryGet(Player.m_localPlayer, out var _)))
		{
			return true;
		}
		__result = InventoryPaymentPlan.CountAvailable(Player.m_localPlayer, itemName);
		return false;
	}

	private void OnDestroy()
	{
		Harmony obj = stationHarmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
		Harmony obj2 = paymentHarmony;
		if (obj2 != null)
		{
			obj2.UnpatchSelf();
		}
		Harmony obj3 = interactionHarmony;
		if (obj3 != null)
		{
			obj3.UnpatchSelf();
		}
		ImproveInteraction.RestoreControls();
		Harmony obj4 = improveHarmony;
		if (obj4 != null)
		{
			obj4.UnpatchSelf();
		}
		Harmony obj5 = harmony;
		if (obj5 != null)
		{
			obj5.UnpatchSelf();
		}
		ModernImprove.Cleanup();
	}
}
internal static class ReforgedStationGuard
{
	internal static bool Install(Harmony harmony)
	{
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Expected O, but got Unknown
		if (!Chainloader.PluginInfos.TryGetValue("akuichi.ReforgedPotential", out var value))
		{
			return false;
		}
		if (value.Metadata.Version != new Version(2, 0, 4))
		{
			return false;
		}
		MethodInfo methodInfo = AccessTools.Method(((object)value.Instance).GetType().Assembly.GetType("ReforgedPotential.ReforgedPotential+InventoryGuiPatch", throwOnError: true), "DoCraftingPrefix", (Type[])null, (Type[])null);
		if (methodInfo == null || methodInfo.ReturnType != typeof(bool) || methodInfo.GetParameters().Length != 3)
		{
			throw new MissingMethodException("ReforgedPotential crafting contract changed");
		}
		harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ReforgedStationGuard), "NullableStation", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
		return true;
	}

	private static bool IsUpgrader(CraftingStation station)
	{
		if (Object.op_Implicit((Object)(object)station))
		{
			return station.m_upgrader;
		}
		return false;
	}

	private static string StationName(Object station)
	{
		if (!Object.op_Implicit(station))
		{
			return "(hand crafting)";
		}
		return station.name;
	}

	internal static IEnumerable<CodeInstruction> NullableStation(IEnumerable<CodeInstruction> instructions)
	{
		List<CodeInstruction> list = instructions.Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction i) => new CodeInstruction(i))).ToList();
		CodeInstruction[] array = list.Where((CodeInstruction i) => CodeInstructionExtensions.LoadsField(i, AccessTools.Field(typeof(CraftingStation), "m_upgrader"), false)).ToArray();
		if (array.Length != 1)
		{
			throw new InvalidOperationException("Unrecognized ReforgedPotential station access");
		}
		int num = list.IndexOf(array[0]);
		int num2 = list.FindIndex(num + 1, (CodeInstruction i) => CodeInstructionExtensions.Calls(i, AccessTools.PropertyGetter(typeof(Object), "name")));
		if (num2 < 1 || num2 - num > 30 || !CodeInstructionExtensions.IsLdloc(list[num2 - 1], (LocalBuilder)null) || list[num2 - 1].opcode != list[num - 1].opcode || !object.Equals(list[num2 - 1].operand, list[num - 1].operand))
		{
			throw new InvalidOperationException("Unrecognized ReforgedPotential station diagnostic");
		}
		array[0].opcode = OpCodes.Call;
		array[0].operand = AccessTools.Method(typeof(ReforgedStationGuard), "IsUpgrader", (Type[])null, (Type[])null);
		list[num2].opcode = OpCodes.Call;
		list[num2].operand = AccessTools.Method(typeof(ReforgedStationGuard), "StationName", (Type[])null, (Type[])null);
		return list;
	}
}
internal static class RuneforgingApi
{
	internal static Type CostType;

	internal static Type UiType;

	internal static Type StateType;

	private static Func<bool> active;

	private static Func<bool> improving;

	private static Func<ItemData, IList> costs;

	private static Func<object, ItemDrop> resource;

	private static Func<object, int> amount;

	internal static bool Active
	{
		get
		{
			if (active != null)
			{
				return active();
			}
			return false;
		}
	}

	internal static bool IsImproving
	{
		get
		{
			if (improving != null)
			{
				return improving();
			}
			return false;
		}
	}

	internal static IList GetCost(ItemData item)
	{
		return costs(item);
	}

	internal static ItemDrop Resource(object entry)
	{
		return resource(entry);
	}

	internal static int Amount(object entry)
	{
		return amount(entry);
	}

	internal static void Bind(Assembly assembly)
	{
		CostType = assembly.GetType("BalrondItemRarity.UI.ImproveCost", throwOnError: true);
		UiType = assembly.GetType("BalrondItemRarity.UI.ImproveUI", throwOnError: true);
		StateType = assembly.GetType("BalrondItemRarity.UI.ImproveUIState", throwOnError: true);
		Type type = assembly.GetType("BalrondItemRarity.UI.ImproveCostEntry", throwOnError: true);
		active = ReadFlag("Active");
		improving = ReadFlag("IsImproving");
		ParameterExpression parameterExpression = Expression.Parameter(typeof(ItemData), "item");
		costs = Expression.Lambda<Func<ItemData, IList>>(Expression.Convert(Expression.Call(AccessTools.Method(CostType, "GetCost", new Type[1] { typeof(ItemData) }, (Type[])null), parameterExpression), typeof(IList)), new ParameterExpression[1] { parameterExpression }).Compile();
		ParameterExpression parameterExpression2 = Expression.Parameter(typeof(object), "entry");
		UnaryExpression expression = Expression.Convert(parameterExpression2, type);
		resource = Expression.Lambda<Func<object, ItemDrop>>(Expression.Field(expression, "Item"), new ParameterExpression[1] { parameterExpression2 }).Compile();
		amount = Expression.Lambda<Func<object, int>>(Expression.Field(expression, "Amount"), new ParameterExpression[1] { parameterExpression2 }).Compile();
	}

	private static Func<bool> ReadFlag(string name)
	{
		return Expression.Lambda<Func<bool>>(Expression.Field(null, AccessTools.Field(StateType, name)), Array.Empty<ParameterExpression>()).Compile();
	}
}
internal static class SingleIngredientPayment
{
	internal sealed class Scope
	{
		internal Scope Parent;

		internal bool Paid;

		internal InventoryPaymentPlan Plan;

		internal bool Cheated;
	}

	private static readonly MethodInfo Remove = AccessTools.Method(typeof(Inventory), "RemoveItem", new Type[4]
	{
		typeof(string),
		typeof(int),
		typeof(int),
		typeof(bool)
	}, (Type[])null);

	private static readonly MethodInfo Add = AccessTools.Method(typeof(ConcurrentBag<LaterConsumption>), "Add", (Type[])null, (Type[])null);

	[ThreadStatic]
	private static Scope current;

	internal static Scope Current => current;

	internal static void Install(Harmony harmony)
	{
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Expected O, but got Unknown
		//IL_00d7: Expected O, but got Unknown
		//IL_00d7: Expected O, but got Unknown
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: Unknown result type (might be due to invalid IL or missing references)
		//IL_0114: Expected O, but got Unknown
		//IL_0127: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Expected O, but got Unknown
		//IL_0176: Expected O, but got Unknown
		//IL_0176: Expected O, but got Unknown
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_0197: Expected O, but got Unknown
		//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Expected O, but got Unknown
		//IL_022f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0234: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Expected O, but got Unknown
		Assembly assembly = typeof(AzuCraftyBoxesPlugin).Assembly;
		MethodInfo methodInfo = AccessTools.Method(assembly.GetType("AzuCraftyBoxes.Patches.CheckNearbyForOneIngredientItems", throwOnError: true), "Postfix", (Type[])null, (Type[])null);
		MethodInfo methodInfo2 = AccessTools.Method(assembly.GetType("AzuCraftyBoxes.Patches.ConsumeLaterConsumptionItemsInventoryGuiDoCraftingPatch", throwOnError: true), "Postfix", (Type[])null, (Type[])null);
		MethodInfo methodInfo3 = AccessTools.Method(typeof(InventoryGui), "DoCrafting", new Type[1] { typeof(Player) }, (Type[])null);
		if (methodInfo == null || methodInfo2 == null || methodInfo3 == null)
		{
			throw new MissingMethodException("Azu single-ingredient payment contract changed");
		}
		harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(SingleIngredientPayment), "BeforeLookup", (Type[])null), new HarmonyMethod(typeof(SingleIngredientPayment), "AfterLookup", (Type[])null), new HarmonyMethod(typeof(SingleIngredientPayment), "ScopeEnqueue", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "GetFirstRequiredItem", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(SingleIngredientPayment), "BackpackLookup", (Type[])null)
		{
			priority = 0
		}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(SingleIngredientPayment), "Begin", (Type[])null)
		{
			priority = 800
		}, (HarmonyMethod)null, new HarmonyMethod(typeof(SingleIngredientPayment), "PaymentPoint", (Type[])null)
		{
			priority = 0
		}, new HarmonyMethod(typeof(SingleIngredientPayment), "End", (Type[])null)
		{
			priority = 0
		}, (HarmonyMethod)null);
		harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(SingleIngredientPayment), "SkipDelayedPayment", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(Recipe), "GetAmount", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(SingleIngredientPayment), "GuardMissingIngredient", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null);
		harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "HaveRequirements", new Type[4]
		{
			typeof(Recipe),
			typeof(bool),
			typeof(int),
			typeof(int)
		}, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(SingleIngredientPayment), "CheckSelectedIngredient", (Type[])null)
		{
			priority = 0
		}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		ClearQueue();
	}

	internal static void Begin(out Scope __state)
	{
		__state = new Scope
		{
			Parent = current
		};
		ClearQueue();
		current = __state;
	}

	internal static void End(Scope __state)
	{
		if (__state != null)
		{
			__state.Plan?.Notify();
			ClearQueue();
			current = __state.Parent;
		}
	}

	private static bool SkipDelayedPayment()
	{
		return false;
	}

	private static void CheckSelectedIngredient(Player __instance, Recipe recipe, bool discover, int qualityLevel, int amount, ref bool __result)
	{
		if (!(!__result || discover) && Object.op_Implicit((Object)(object)recipe))
		{
			if (recipe.m_requireOnlyOneIngredient)
			{
				int num = default(int);
				int num2 = default(int);
				__result = __instance.GetFirstRequiredItem(((Humanoid)__instance).GetInventory(), recipe, qualityLevel, ref num, ref num2, amount) != null;
				return;
			}
			CraftingStation currentCraftingStation = __instance.GetCurrentCraftingStation();
			__result = InventoryPaymentPlan.Create(__instance, InventoryPaymentPlan.Requirements(recipe.m_resources, qualityLevel, amount, Object.op_Implicit((Object)(object)currentCraftingStation) && currentCraftingStation.m_upgrader)) != null;
		}
	}

	private static void ClearQueue()
	{
		LaterConsumption result;
		while (ConsumptionManager.PendingConsumptions.TryTake(out result))
		{
		}
	}

	private static void Enqueue(ConcurrentBag<LaterConsumption> queue, LaterConsumption entry)
	{
	}

	private static void BeforeLookup(ItemData __7, out bool __state)
	{
		__state = __7 == null;
	}

	private static void BackpackLookup(Player __instance, Inventory inventory, Recipe recipe, int qualityLevel, ref int amount, ref int extraAmount, int craftMultiplier, ref ItemData __result)
	{
		if (inventory != ((Humanoid)__instance).GetInventory() || !BackpackAccess.TryGet(__instance, out var _))
		{
			return;
		}
		CraftingStation currentCraftingStation = __instance.GetCurrentCraftingStation();
		Requirement[] resources = recipe.m_resources;
		foreach (Requirement val in resources)
		{
			if (!Object.op_Implicit((Object)(object)val.m_resItem) || val.m_upgraderResource != (Object.op_Implicit((Object)(object)currentCraftingStation) && currentCraftingStation.m_upgrader))
			{
				continue;
			}
			int num = checked(val.GetAmount(qualityLevel) * craftMultiplier);
			if (num <= 0)
			{
				continue;
			}
			HashSet<int> hashSet = new HashSet<int>();
			foreach (Inventory item in InventoryPaymentPlan.CandidateInventories(__instance))
			{
				foreach (ItemData allItem in item.GetAllItems())
				{
					if (allItem.m_shared.m_name != val.m_resItem.m_itemData.m_shared.m_name || allItem.m_equipped || !hashSet.Add(allItem.m_quality))
					{
						continue;
					}
					if (!BackpackAccess.Modern && item == inventory && inventory.CountItems(allItem.m_shared.m_name, allItem.m_quality, true) < num)
					{
						hashSet.Remove(allItem.m_quality);
						continue;
					}
					bool chestsOnly = !BackpackAccess.Modern && !inventory.ContainsItem(allItem);
					if (InventoryPaymentPlan.Create(__instance, new InventoryPaymentPlan.Cost[1]
					{
						new InventoryPaymentPlan.Cost
						{
							Item = val.m_resItem,
							Amount = num,
							Quality = allItem.m_quality
						}
					}, chestsOnly) != null)
					{
						__result = allItem;
						amount = num;
						extraAmount = val.m_extraAmountOnlyOneIngredient;
						return;
					}
				}
			}
		}
		__result = null;
		amount = 0;
		extraAmount = 0;
	}

	private static List<IContainer> Inventories(Player player)
	{
		HashSet<Inventory> hashSet = new HashSet<Inventory>();
		List<IContainer> list = new List<IContainer>();
		foreach (IContainer nearbyContainer in API.GetNearbyContainers<Player>(player, AzuCraftyBoxesPlugin.mRange.Value))
		{
			Inventory val2 = ((nearbyContainer != null) ? nearbyContainer.GetInventory() : null);
			if (val2 != null && InventoryPaymentPlan.Supported(nearbyContainer) && val2 != ((Humanoid)player).GetInventory() && hashSet.Add(val2))
			{
				list.Add(nearbyContainer);
			}
		}
		return list;
	}

	private static void AfterLookup(Player __0, Inventory __1, Recipe __2, int __3, ref int __4, ref int __5, int __6, ref ItemData __7, bool __state)
	{
		if (BackpackAccess.TryGet(__0, out var _) || !__state || !Plugin.UseStorage(__1))
		{
			return;
		}
		List<IContainer> list = Inventories(__0);
		ItemData val = null;
		CraftingStation currentCraftingStation = __0.GetCurrentCraftingStation();
		Requirement[] resources = __2.m_resources;
		foreach (Requirement val2 in resources)
		{
			if (!Object.op_Implicit((Object)(object)val2.m_resItem) || val2.m_upgraderResource != (Object.op_Implicit((Object)(object)currentCraftingStation) && currentCraftingStation.m_upgrader))
			{
				continue;
			}
			int num = val2.GetAmount(__3) * __6;
			if (num <= 0)
			{
				continue;
			}
			string name = val2.m_resItem.m_itemData.m_shared.m_name;
			HashSet<int> hashSet = new HashSet<int>();
			foreach (IContainer item in list)
			{
				foreach (ItemData allItem in item.GetInventory().GetAllItems())
				{
					if (!(allItem.m_shared.m_name != name) && hashSet.Add(allItem.m_quality) && InventoryPaymentPlan.Create(__0, new InventoryPaymentPlan.Cost[1]
					{
						new InventoryPaymentPlan.Cost
						{
							Item = val2.m_resItem,
							Amount = num,
							Quality = allItem.m_quality
						}
					}, chestsOnly: true) != null)
					{
						val = allItem;
						__4 = num;
						__5 = val2.m_extraAmountOnlyOneIngredient;
						break;
					}
				}
				if (val != null)
				{
					break;
				}
			}
			if (val != null)
			{
				break;
			}
		}
		__7 = val;
		if (val == null)
		{
			__4 = 0;
			__5 = 0;
		}
	}

	internal static IEnumerable<CodeInstruction> ScopeEnqueue(IEnumerable<CodeInstruction> instructions)
	{
		List<CodeInstruction> list = instructions.Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction i) => new CodeInstruction(i))).ToList();
		List<CodeInstruction> list2 = list.Where((CodeInstruction i) => CodeInstructionExtensions.Calls(i, Add)).ToList();
		if (list2.Count != 1)
		{
			throw new InvalidOperationException("Unexpected Azu deferred enqueue shape");
		}
		list2[0].opcode = OpCodes.Call;
		list2[0].operand = AccessTools.Method(typeof(SingleIngredientPayment), "Enqueue", (Type[])null, (Type[])null);
		return list;
	}

	private static int SelectedQuality(ItemData item)
	{
		return item?.m_quality ?? 1;
	}

	internal static IEnumerable<CodeInstruction> GuardMissingIngredient(IEnumerable<CodeInstruction> instructions)
	{
		List<CodeInstruction> list = instructions.Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction i) => new CodeInstruction(i))).ToList();
		FieldInfo quality = AccessTools.Field(typeof(ItemData), "m_quality");
		CodeInstruction[] array = list.Where((CodeInstruction i) => CodeInstructionExtensions.LoadsField(i, quality, false)).ToArray();
		if (array.Length != 1 || list.Count((CodeInstruction i) => CodeInstructionExtensions.Calls(i, AccessTools.Method(typeof(Player), "GetFirstRequiredItem", (Type[])null, (Type[])null))) != 1)
		{
			throw new InvalidOperationException("Unrecognized single-ingredient amount expression");
		}
		array[0].opcode = OpCodes.Call;
		array[0].operand = AccessTools.Method(typeof(SingleIngredientPayment), "SelectedQuality", (Type[])null, (Type[])null);
		return list;
	}

	internal static IEnumerable<CodeInstruction> PaymentPoint(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
	{
		//IL_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Expected O, but got Unknown
		//IL_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0215: Expected O, but got Unknown
		List<CodeInstruction> result = instructions.Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction i) => new CodeInstruction(i))).ToList();
		int[] array = (from i in Enumerable.Range(0, result.Count)
			where CodeInstructionExtensions.Calls(result[i], Remove)
			select i).ToArray();
		if (array.Length != 1)
		{
			throw new InvalidOperationException("Ambiguous single-ingredient payment point");
		}
		int num = array[0];
		FieldInfo fieldInfo = AccessTools.Field(typeof(ItemData), "m_quality");
		if (num < 3 || result[num - 1].opcode != OpCodes.Ldc_I4_1 || !CodeInstructionExtensions.LoadsField(result[num - 2], fieldInfo, false) || !CodeInstructionExtensions.IsLdloc(result[num - 3], (LocalBuilder)null) || result[num].blocks.Count != 0 || result[num - 3].labels.Count != 0 || result[num - 2].labels.Count != 0 || result[num - 1].labels.Count != 0)
		{
			throw new InvalidOperationException("Unrecognized selected-ingredient payment expression");
		}
		CodeInstruction val = new CodeInstruction(result[num - 3].opcode, result[num - 3].operand);
		val.labels.AddRange(result[num].labels);
		result[num].labels.Clear();
		result[num].opcode = OpCodes.Call;
		result[num].operand = AccessTools.Method(typeof(SingleIngredientPayment), "Pay", (Type[])null, (Type[])null);
		CodeInstruction val2 = new CodeInstruction(result[num - 4].opcode, result[num - 4].operand);
		if (!CodeInstructionExtensions.IsLdloc(val2, (LocalBuilder)null))
		{
			throw new InvalidOperationException("Unrecognized ingredient amount");
		}
		result.Insert(num, val);
		CraftPaymentGate.Insert(result, val, val2, generator);
		return result;
	}

	internal static void Pay(Inventory inventory, string name, int amount, int quality, bool matchWorldLevel, ItemData selected)
	{
		if (current == null)
		{
			throw new InvalidOperationException("Missing crafting payment scope");
		}
		if (current.Plan != null)
		{
			return;
		}
		current.Paid = true;
		ClearQueue();
		if (inventory.ContainsItem(selected))
		{
			inventory.RemoveItem(name, amount, quality, matchWorldLevel);
			return;
		}
		InventoryPaymentPlan inventoryPaymentPlan = InventoryPaymentPlan.Create(Player.m_localPlayer, new InventoryPaymentPlan.Cost[1]
		{
			new InventoryPaymentPlan.Cost
			{
				Item = selected.m_dropPrefab.GetComponent<ItemDrop>(),
				Amount = amount,
				Quality = quality
			}
		}, chestsOnly: true);
		if (inventoryPaymentPlan != null && inventoryPaymentPlan.Commit())
		{
			return;
		}
		throw new InvalidOperationException("Selected ingredient cannot fund this payment");
	}
}
namespace AdventureBackpacks.API
{
	[PublicAPI]
	internal class ABAPI
	{
		public struct Backpack
		{
			public string Name;

			public ItemData ItemData;

			public Inventory Inventory;

			public BackpackDefinition Definition;
		}

		public class BackpackDefinition
		{
			public GameObject BackPackGo;

			public AssetBundle AssetBundle;

			public string PrefabName;

			public string ItemName;

			public string ConfigSection = "";

			public string CraftingTable;

			public int StationLevel;

			public int MaxRequiredStationLevel;

			public readonly List<RecipeIngredient> RecipeIngredients = new List<RecipeIngredient>();

			public readonly List<RecipeIngredient> UpgradeIngredients = new List<RecipeIngredient>();

			public readonly List<DropTarget> DropsFrom = new List<DropTarget>();

			public readonly Dictionary<BackpackBiomes, KeyValuePair<StatusEffect, int>> EffectsToApply = new Dictionary<BackpackBiomes, KeyValuePair<StatusEffect, int>>();

			public Dictionary<int, Vector2> BackpackSizeByQuality = new Dictionary<int, Vector2>();

			public StatusEffect ItemSetStatusEffect;

			public float WeightMultiplier;

			public int CarryBonus;

			public int ArmorPerLevel = 1;

			public float SpeedMod;

			public bool ScaleSpeedModByQuality = true;

			public bool EnableFreezing;

			public BackpackBiomes BackpackBiome;

			public BackpackDefinition()
			{
			}

			public BackpackDefinition(GameObject backPackGo)
			{
				BackPackGo = backPackGo;
			}

			public BackpackDefinition(AssetBundle assetBundle, string prefabName)
			{
				AssetBundle = assetBundle;
				PrefabName = prefabName;
			}
		}

		public struct DropTarget
		{
			public string Creature;

			public int Min;

			public int? Max;

			public float Chance;

			public DropTarget(string creature, float chance, int min = 1, int? max = null)
			{
				Creature = creature;
				Chance = chance;
				Min = min;
				Max = max;
			}
		}

		public struct EffectDefinition
		{
			public readonly string Name;

			public readonly string LocalizedName;

			public readonly string EffectName;

			public readonly string Description;

			public readonly StatusEffect StatusEffect;

			public EffectDefinition(string name, string localizedName, string effectName, string description, StatusEffect statusEffect)
			{
				Name = name;
				LocalizedName = localizedName;
				EffectName = effectName;
				Description = description;
				StatusEffect = statusEffect;
			}
		}

		public struct RecipeIngredient
		{
			public string ItemPrefabName;

			public int Quantity;

			public RecipeIngredient(string itemPrefabName, int quantity)
			{
				ItemPrefabName = itemPrefabName;
				Quantity = quantity;
			}
		}

		public static bool IsLoaded()
		{
			return false;
		}

		public static bool IsBackpack(ItemData itemData)
		{
			return false;
		}

		public static bool IsBackpackEquipped(Player player)
		{
			return false;
		}

		public static bool CanOpenBackpack(Player player)
		{
			return false;
		}

		public static bool IsThisBackpackEquipped(Player player, ItemData itemData)
		{
			return false;
		}

		public static Backpack? GetEquippedBackpack(Player player)
		{
			return null;
		}

		public static Backpack? GetBackpack(ItemData itemData)
		{
			return null;
		}

		public static Inventory GetEquippedBackpackInventory(Player player)
		{
			return null;
		}

		public static bool TryGetEquippedBackpackInventory(Player player, out Inventory inventory)
		{
			inventory = GetEquippedBackpackInventory(player);
			return inventory != null;
		}

		public static Inventory GetBackpackInventory(ItemData itemData)
		{
			return null;
		}

		public static bool TryGetBackpackInventory(ItemData itemData, out Inventory inventory)
		{
			inventory = GetBackpackInventory(itemData);
			return inventory != null;
		}

		public static HashSet<StatusEffect> GetActiveBackpackStatusEffects()
		{
			return null;
		}

		public static HashSet<StatusEffect> GetRegisterdStatusEffects()
		{
			return null;
		}

		public static void OpenBackpack(Player player, InventoryGui gui)
		{
		}

		public static void RegisterEffect(EffectDefinition effectDefinition)
		{
		}

		public static void RegisterBackpack(BackpackDefinition definition)
		{
		}

		public static bool IsCraftFromBackpackEnabled()
		{
			return false;
		}

		public static bool IsCraftingContextActive()
		{
			return false;
		}

		public static string GetConsumptionPriority()
		{
			return "PlayerInventoryFirst";
		}

		public static bool IsLeaveOneItemInBackpackEnabled()
		{
			return false;
		}

		public static bool IsDisplayTotalIngredientCountEnabled()
		{
			return false;
		}

		public static void SuppressNativeCrafting(string modIdentifier)
		{
		}

		public static void UnsuppressNativeCrafting(string modIdentifier)
		{
		}
	}
	[Flags]
	internal enum BackpackBiomes : uint
	{
		None = 0u,
		Meadows = 1u,
		BlackForest = 2u,
		Swamp = 4u,
		Mountains = 8u,
		Plains = 0x10u,
		Mistlands = 0x20u,
		Ashlands = 0x40u,
		DeepNorth = 0x80u,
		EffectBiome1 = 0x100000u,
		EffectBiome2 = 0x200000u,
		EffectBiome3 = 0x400000u,
		EffectBiome4 = 0x800000u,
		EffectBiome5 = 0x1000000u
	}
}