Decompiled source of StorageConsole v1.2.1

GraveyardKeeper2.StorageConsole.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using LazyBearTechnology;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("GraveyardKeeper2.StorageConsole")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0")]
[assembly: AssemblyProduct("GraveyardKeeper2.StorageConsole")]
[assembly: AssemblyTitle("GraveyardKeeper2.StorageConsole")]
[assembly: AssemblyVersion("1.2.0.0")]
namespace GK2.StorageConsole;

public static class ConsoleSearchMatcher
{
	public static bool Matches(string query, string localizedName, string id, IReadOnlyList<string> groupIds)
	{
		if (string.IsNullOrWhiteSpace(query))
		{
			return true;
		}
		string needle = query.Trim();
		if (Contains(localizedName, needle))
		{
			return true;
		}
		if (Contains(id, needle))
		{
			return true;
		}
		if (groupIds == null)
		{
			return false;
		}
		for (int i = 0; i < groupIds.Count; i++)
		{
			if (Contains(groupIds[i], needle))
			{
				return true;
			}
		}
		return false;
	}

	private static bool Contains(string value, string needle)
	{
		if (!string.IsNullOrEmpty(value))
		{
			return value.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0;
		}
		return false;
	}
}
public enum ConsoleSortMode
{
	NameAscending,
	QuantityDescending
}
public static class ConsoleSortPolicy
{
	public static void Sort(List<StorageAggregateItem> items, ConsoleSortMode mode, Func<string, string> displayName)
	{
		if (items == null)
		{
			return;
		}
		if (mode == ConsoleSortMode.QuantityDescending)
		{
			items.Sort(delegate(StorageAggregateItem a, StorageAggregateItem b)
			{
				int num = b.TotalCount.CompareTo(a.TotalCount);
				return (num != 0) ? num : CompareName(a, b, displayName);
			});
		}
		else
		{
			items.Sort((StorageAggregateItem a, StorageAggregateItem b) => CompareName(a, b, displayName));
		}
	}

	private static int CompareName(StorageAggregateItem a, StorageAggregateItem b, Func<string, string> displayName)
	{
		object obj = ((displayName != null) ? displayName(a.ItemId) : a.ItemId);
		string text = ((displayName != null) ? displayName(b.ItemId) : b.ItemId);
		if (obj == null)
		{
			obj = string.Empty;
		}
		text = text ?? string.Empty;
		int num = string.Compare((string?)obj, text, StringComparison.OrdinalIgnoreCase);
		if (num != 0)
		{
			return num;
		}
		return string.Compare(a.ItemId, b.ItemId, StringComparison.Ordinal);
	}
}
public static class ItemTransferPolicy
{
	public static bool CanBulkTransfer(bool hasDefinition, bool isBag, bool hasDurability, bool hasUniqueInstances, int stackSize, int count, bool isEquipment, bool isQuestItem)
	{
		if (!hasDefinition)
		{
			return false;
		}
		if (isBag)
		{
			return false;
		}
		if (hasDurability)
		{
			return false;
		}
		if (hasUniqueInstances)
		{
			return false;
		}
		if (isEquipment)
		{
			return false;
		}
		if (isQuestItem)
		{
			return false;
		}
		if (stackSize <= 1)
		{
			return false;
		}
		return count > 0;
	}
}
public static class StorageAggregator
{
	private sealed class AggregateBuilder
	{
		public string ItemId { get; }

		public int TotalCount { get; set; }

		public HashSet<string> ContainerIds { get; } = new HashSet<string>(StringComparer.Ordinal);

		public HashSet<string> Zones { get; } = new HashSet<string>(StringComparer.Ordinal);

		public Dictionary<string, int> ByZone { get; } = new Dictionary<string, int>(StringComparer.Ordinal);

		public bool Transferable { get; set; } = true;

		public string LockReason { get; set; } = string.Empty;

		public AggregateBuilder(string itemId)
		{
			ItemId = itemId;
		}
	}

	public static List<StorageAggregateItem> Aggregate(IReadOnlyList<StorageItemSnapshot> items, IReadOnlyList<StorageContainerSnapshot> containers)
	{
		List<StorageAggregateItem> list = new List<StorageAggregateItem>();
		if (items == null || items.Count == 0)
		{
			return list;
		}
		Dictionary<string, StorageContainerSnapshot> dictionary = new Dictionary<string, StorageContainerSnapshot>(StringComparer.Ordinal);
		if (containers != null)
		{
			for (int i = 0; i < containers.Count; i++)
			{
				StorageContainerSnapshot storageContainerSnapshot = containers[i];
				if (storageContainerSnapshot != null && !string.IsNullOrEmpty(storageContainerSnapshot.InventoryId) && !dictionary.ContainsKey(storageContainerSnapshot.InventoryId))
				{
					dictionary.Add(storageContainerSnapshot.InventoryId, storageContainerSnapshot);
				}
			}
		}
		Dictionary<string, AggregateBuilder> dictionary2 = new Dictionary<string, AggregateBuilder>(StringComparer.Ordinal);
		for (int j = 0; j < items.Count; j++)
		{
			StorageItemSnapshot storageItemSnapshot = items[j];
			if (storageItemSnapshot == null || string.IsNullOrEmpty(storageItemSnapshot.ItemId) || !dictionary.TryGetValue(storageItemSnapshot.InventoryId, out var value))
			{
				continue;
			}
			if (!dictionary2.TryGetValue(storageItemSnapshot.ItemId, out var value2))
			{
				value2 = new AggregateBuilder(storageItemSnapshot.ItemId);
				dictionary2.Add(storageItemSnapshot.ItemId, value2);
			}
			value2.TotalCount += storageItemSnapshot.Count;
			value2.ContainerIds.Add(value.InventoryId);
			value2.Zones.Add(value.ZoneId);
			value2.ByZone.TryGetValue(value.ZoneId, out var value3);
			value2.ByZone[value.ZoneId] = value3 + storageItemSnapshot.Count;
			if (!storageItemSnapshot.EligibleForBulkTransfer)
			{
				value2.Transferable = false;
				if (string.IsNullOrEmpty(value2.LockReason))
				{
					value2.LockReason = (string.IsNullOrEmpty(storageItemSnapshot.LockReason) ? "not-safe" : storageItemSnapshot.LockReason);
				}
			}
		}
		foreach (AggregateBuilder value4 in dictionary2.Values)
		{
			StorageAggregateItem storageAggregateItem = new StorageAggregateItem(value4.ItemId);
			storageAggregateItem.TotalCount = value4.TotalCount;
			storageAggregateItem.ContainerCount = value4.ContainerIds.Count;
			storageAggregateItem.ZoneCount = value4.Zones.Count;
			storageAggregateItem.Transferable = value4.Transferable;
			storageAggregateItem.LockReason = value4.LockReason ?? string.Empty;
			foreach (KeyValuePair<string, int> item in value4.ByZone)
			{
				storageAggregateItem.ByZone.Add(item.Key, item.Value);
			}
			list.Add(storageAggregateItem);
		}
		list.Sort((StorageAggregateItem a, StorageAggregateItem b) => string.CompareOrdinal(a.ItemId, b.ItemId));
		return list;
	}
}
public sealed class StorageContainerSnapshot
{
	public string InventoryId { get; }

	public string ZoneId { get; }

	public int Capacity { get; }

	public StorageContainerSnapshot(string inventoryId, string zoneId, int capacity)
	{
		InventoryId = inventoryId ?? string.Empty;
		ZoneId = zoneId ?? string.Empty;
		Capacity = ((capacity >= 0) ? capacity : 0);
	}
}
public sealed class StorageItemSnapshot
{
	public string ItemId { get; }

	public string InventoryId { get; }

	public int Count { get; }

	public int StackSize { get; }

	public bool EligibleForBulkTransfer { get; }

	public string LockReason { get; }

	public StorageItemSnapshot(string itemId, string inventoryId, int count, int stackSize, bool eligibleForBulkTransfer, string lockReason = null)
	{
		ItemId = itemId ?? string.Empty;
		InventoryId = inventoryId ?? string.Empty;
		Count = ((count >= 0) ? count : 0);
		StackSize = ((stackSize >= 0) ? stackSize : 0);
		EligibleForBulkTransfer = eligibleForBulkTransfer;
		LockReason = lockReason ?? string.Empty;
	}
}
public sealed class StorageAggregateItem
{
	public string ItemId { get; }

	public int TotalCount { get; internal set; }

	public int ContainerCount { get; internal set; }

	public int ZoneCount { get; internal set; }

	public Dictionary<string, int> ByZone { get; }

	public bool Transferable { get; internal set; } = true;

	public string LockReason { get; internal set; } = string.Empty;

	internal StorageAggregateItem(string itemId)
	{
		ItemId = itemId ?? string.Empty;
		ByZone = new Dictionary<string, int>(StringComparer.Ordinal);
	}
}
public sealed class TransferSource
{
	public string InventoryId { get; }

	public int Available { get; }

	public TransferSource(string inventoryId, int available)
	{
		InventoryId = inventoryId ?? string.Empty;
		Available = ((available >= 0) ? available : 0);
	}
}
public sealed class TransferTarget
{
	public string InventoryId { get; }

	public int Capacity { get; }

	public TransferTarget(string inventoryId, int capacity)
	{
		InventoryId = inventoryId ?? string.Empty;
		Capacity = ((capacity >= 0) ? capacity : 0);
	}
}
public sealed class TransferAddition
{
	public string InventoryId { get; }

	public int Count { get; }

	public TransferAddition(string inventoryId, int count)
	{
		InventoryId = inventoryId ?? string.Empty;
		Count = count;
	}
}
public sealed class TransferRemoval
{
	public string InventoryId { get; }

	public int Count { get; }

	public TransferRemoval(string inventoryId, int count)
	{
		InventoryId = inventoryId ?? string.Empty;
		Count = count;
	}
}
public sealed class StorageTransferPlan
{
	public bool Success { get; internal set; }

	public string FailureReason { get; internal set; } = string.Empty;

	public int Total { get; internal set; }

	public List<TransferAddition> Additions { get; }

	public List<TransferRemoval> Removals { get; }

	public StorageTransferPlan()
	{
		Additions = new List<TransferAddition>();
		Removals = new List<TransferRemoval>();
	}
}
public sealed class StorageIndexOptions
{
	public bool IncludeInactiveZones { get; set; }

	public HashSet<string> ExcludedZoneIds { get; } = new HashSet<string>(StringComparer.Ordinal);
}
public static class StorageScopeFilter
{
	public static bool IsZoneIncluded(bool isContainer, bool isActive, string zoneId, StorageIndexOptions options)
	{
		if (!isContainer)
		{
			return false;
		}
		if (!isActive && (options == null || !options.IncludeInactiveZones))
		{
			return false;
		}
		if (options != null && !string.IsNullOrEmpty(zoneId) && options.ExcludedZoneIds.Contains(zoneId))
		{
			return false;
		}
		return true;
	}

	public static bool IsContainerIncluded(bool openInMultiInventory, int definedInventorySize, int runtimeInventorySize)
	{
		if (openInMultiInventory && definedInventorySize != 0)
		{
			return runtimeInventorySize > 0;
		}
		return false;
	}
}
public static class TransferPlanner
{
	public static StorageTransferPlan Plan(int requested, IReadOnlyList<TransferSource> sources, IReadOnlyList<TransferTarget> targets)
	{
		StorageTransferPlan storageTransferPlan = new StorageTransferPlan();
		if (requested <= 0)
		{
			storageTransferPlan.FailureReason = "requested-invalid";
			return storageTransferPlan;
		}
		if (sources == null || targets == null)
		{
			storageTransferPlan.FailureReason = "missing-input";
			return storageTransferPlan;
		}
		int num = 0;
		for (int i = 0; i < sources.Count; i++)
		{
			if (sources[i] != null)
			{
				num += sources[i].Available;
			}
		}
		int num2 = 0;
		for (int j = 0; j < targets.Count; j++)
		{
			if (targets[j] != null)
			{
				num2 += targets[j].Capacity;
			}
		}
		int num3 = Math.Min(requested, Math.Min(num, num2));
		if (num3 <= 0)
		{
			storageTransferPlan.FailureReason = ((num <= 0) ? "source-empty" : "destination-full");
			return storageTransferPlan;
		}
		int num4 = num3;
		for (int k = 0; k < targets.Count; k++)
		{
			if (num4 <= 0)
			{
				break;
			}
			TransferTarget transferTarget = targets[k];
			if (transferTarget != null && transferTarget.Capacity > 0 && !string.IsNullOrEmpty(transferTarget.InventoryId))
			{
				int num5 = Math.Min(num4, transferTarget.Capacity);
				if (num5 > 0)
				{
					storageTransferPlan.Additions.Add(new TransferAddition(transferTarget.InventoryId, num5));
					num4 -= num5;
				}
			}
		}
		int num6 = num3;
		for (int l = 0; l < sources.Count; l++)
		{
			if (num6 <= 0)
			{
				break;
			}
			TransferSource transferSource = sources[l];
			if (transferSource != null && transferSource.Available > 0 && !string.IsNullOrEmpty(transferSource.InventoryId))
			{
				int num7 = Math.Min(num6, transferSource.Available);
				if (num7 > 0)
				{
					storageTransferPlan.Removals.Add(new TransferRemoval(transferSource.InventoryId, num7));
					num6 -= num7;
				}
			}
		}
		if (num4 != 0 || num6 != 0)
		{
			storageTransferPlan.FailureReason = "plan-mismatch";
			storageTransferPlan.Additions.Clear();
			storageTransferPlan.Removals.Clear();
			return storageTransferPlan;
		}
		storageTransferPlan.Success = true;
		storageTransferPlan.Total = num3;
		return storageTransferPlan;
	}
}
public sealed class RealStorageContainer
{
	public WorldZoneData Zone { get; }

	public WgoData Wgo { get; }

	public Inventory Inventory { get; }

	public string InventoryId => ReferenceId;

	public string ReferenceId
	{
		get
		{
			if (Inventory != null)
			{
				return RuntimeHelpers.GetHashCode(Inventory).ToString();
			}
			return string.Empty;
		}
	}

	public string ZoneId
	{
		get
		{
			if (Zone != null)
			{
				return ((ObjectLinkedToDefinition<WorldZoneDef>)(object)Zone).id;
			}
			return string.Empty;
		}
	}

	public RealStorageContainer(WorldZoneData zone, WgoData wgo, Inventory inventory)
	{
		Zone = zone;
		Wgo = wgo;
		Inventory = inventory;
	}
}
public sealed class StorageIndexSnapshot
{
	public List<RealStorageContainer> Containers { get; } = new List<RealStorageContainer>();

	public List<StorageContainerSnapshot> ContainerSnapshots { get; } = new List<StorageContainerSnapshot>();

	public List<StorageItemSnapshot> ItemSnapshots { get; } = new List<StorageItemSnapshot>();
}
public static class BaseStorageIndex
{
	public static StorageIndexSnapshot Build(StorageIndexOptions options)
	{
		StorageIndexSnapshot storageIndexSnapshot = new StorageIndexSnapshot();
		if (MainGame.WorldData == null || MainGame.WorldData.gameSceneDataList == null)
		{
			return storageIndexSnapshot;
		}
		HashSet<Inventory> hashSet = new HashSet<Inventory>();
		for (int i = 0; i < MainGame.WorldData.gameSceneDataList.Count; i++)
		{
			GameSceneData val = MainGame.WorldData.gameSceneDataList[i];
			if (val == null || val.worldZones == null)
			{
				continue;
			}
			for (int j = 0; j < val.worldZones.Count; j++)
			{
				WorldZoneData val2 = val.worldZones[j];
				if (val2 == null || !StorageScopeFilter.IsZoneIncluded(val2.IsContainer, val2.IsActive, ((ObjectLinkedToDefinition<WorldZoneDef>)(object)val2).id, options))
				{
					continue;
				}
				List<WgoData> multiInventoryWgoDatas = val2.MultiInventoryWgoDatas;
				if (multiInventoryWgoDatas == null)
				{
					continue;
				}
				for (int k = 0; k < multiInventoryWgoDatas.Count; k++)
				{
					WgoData val3 = multiInventoryWgoDatas[k];
					if (val3 != null && ((ObjectLinkedToDefinition<WGODef>)(object)val3).Definition != null)
					{
						Inventory inventory = val3.Inventory;
						if (inventory != null && inventory.Data != null && StorageScopeFilter.IsContainerIncluded(((ObjectLinkedToDefinition<WGODef>)(object)val3).Definition.OpenInMultiInventory, ((ObjectLinkedToDefinition<WGODef>)(object)val3).Definition.inventorySize, inventory.Data.InventorySize) && hashSet.Add(inventory))
						{
							RealStorageContainer realStorageContainer = new RealStorageContainer(val2, val3, inventory);
							storageIndexSnapshot.Containers.Add(realStorageContainer);
							storageIndexSnapshot.ContainerSnapshots.Add(new StorageContainerSnapshot(realStorageContainer.InventoryId, realStorageContainer.ZoneId, inventory.Data.InventorySize));
						}
					}
				}
			}
		}
		for (int l = 0; l < storageIndexSnapshot.Containers.Count; l++)
		{
			RealStorageContainer realStorageContainer2 = storageIndexSnapshot.Containers[l];
			List<Item> inventory2 = realStorageContainer2.Inventory.Data.Inventory;
			if (inventory2 == null)
			{
				continue;
			}
			for (int m = 0; m < inventory2.Count; m++)
			{
				Item val4 = inventory2[m];
				if (val4 != null && !val4.IsEmpty && ((ObjectLinkedToDefinition<ItemDef>)(object)val4).Definition != null)
				{
					ItemClassifier.Evaluate(val4, out var eligible, out var lockReason);
					storageIndexSnapshot.ItemSnapshots.Add(new StorageItemSnapshot(((ObjectLinkedToDefinition<ItemDef>)(object)val4).id, realStorageContainer2.InventoryId, val4.Count, ((ObjectLinkedToDefinition<ItemDef>)(object)val4).Definition.stackCount, eligible, lockReason));
				}
			}
		}
		return storageIndexSnapshot;
	}
}
public static class ItemClassifier
{
	private static bool HasInstanceProperties(Item item)
	{
		if (item == null)
		{
			return false;
		}
		FieldInfo field = typeof(Item).GetField("properties", BindingFlags.Instance | BindingFlags.NonPublic);
		if (field == null)
		{
			return false;
		}
		if (field.GetValue(item) is IDictionary dictionary)
		{
			return dictionary.Count > 0;
		}
		return false;
	}

	public static void Evaluate(Item item, out bool eligible, out string lockReason)
	{
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Invalid comparison between Unknown and I4
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Invalid comparison between Unknown and I4
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Invalid comparison between Unknown and I4
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Invalid comparison between Unknown and I4
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Invalid comparison between Unknown and I4
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Invalid comparison between Unknown and I4
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Invalid comparison between Unknown and I4
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: Invalid comparison between Unknown and I4
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_0110: Invalid comparison between Unknown and I4
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Invalid comparison between Unknown and I4
		eligible = false;
		lockReason = string.Empty;
		if (item == null || item.IsEmpty || ((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition == null)
		{
			lockReason = "empty";
			return;
		}
		if (item.IsBag)
		{
			lockReason = "bag";
			return;
		}
		if (((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.stackCount <= 1)
		{
			lockReason = "stack-size-one";
			return;
		}
		if (((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.hasDurability || item.HasProperty<DurabilitySerializedItemProperty>())
		{
			lockReason = "durability";
			return;
		}
		if (((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.CanNotBeDestroyed)
		{
			lockReason = "protected";
			return;
		}
		if (HasInstanceProperties(item))
		{
			lockReason = "instance-data";
			return;
		}
		if ((int)((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.type == 1 || (int)((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.type == 2 || (int)((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.type == 3 || (int)((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.type == 4 || (int)((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.type == 5 || (int)((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.type == 11 || (int)((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.type == 12 || (int)((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.type == 22 || (int)((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.type == 23 || (int)((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.type == 25)
		{
			lockReason = "equipment";
			return;
		}
		lockReason = string.Empty;
		eligible = ItemTransferPolicy.CanBulkTransfer(hasDefinition: true, isBag: false, hasDurability: false, hasUniqueInstances: false, ((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.stackCount, item.Count, isEquipment: false, isQuestItem: false);
	}
}
public sealed class TransferResult
{
	public bool Success { get; }

	public int Moved { get; }

	public string FailureReason { get; }

	private TransferResult(bool success, int moved, string failureReason)
	{
		Success = success;
		Moved = moved;
		FailureReason = failureReason ?? string.Empty;
	}

	public static TransferResult Ok(int moved)
	{
		return new TransferResult(success: true, moved, string.Empty);
	}

	public static TransferResult Fail(string reason)
	{
		return new TransferResult(success: false, 0, reason);
	}
}
public static class BaseStorageTransferService
{
	private sealed class RemovedBatch
	{
		public Inventory Inventory { get; }

		public List<Item> Items { get; }

		public RemovedBatch(Inventory inventory, List<Item> items)
		{
			Inventory = inventory;
			Items = items ?? new List<Item>();
		}
	}

	private sealed class AddedBatch
	{
		public Inventory Inventory { get; }

		public int Count { get; }

		public AddedBatch(Inventory inventory, int count)
		{
			Inventory = inventory;
			Count = count;
		}
	}

	public static TransferResult Withdraw(string itemId, int requested, StorageIndexSnapshot snapshot, Inventory destination)
	{
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Expected O, but got Unknown
		//IL_026e: Unknown result type (might be due to invalid IL or missing references)
		//IL_027c: Expected O, but got Unknown
		if (snapshot == null || destination == null)
		{
			return TransferResult.Fail("missing-target");
		}
		ItemDef data = ((GameBalanceBase)GameBalance.Me).GetData<ItemDef>(itemId);
		if (data == null)
		{
			return TransferResult.Fail("unknown-item");
		}
		int capacity = destination.Data.CanAddItemCountToInventory(data, requested, true, (Item)null, true);
		List<TransferSource> list = new List<TransferSource>();
		Dictionary<string, Inventory> dictionary = new Dictionary<string, Inventory>(StringComparer.Ordinal);
		for (int i = 0; i < snapshot.Containers.Count; i++)
		{
			RealStorageContainer realStorageContainer = snapshot.Containers[i];
			if (HasUnsafeMatchingItem(realStorageContainer.Inventory, itemId))
			{
				return TransferResult.Fail("source-unsafe");
			}
			int totalCountInInventory = realStorageContainer.Inventory.Data.GetTotalCountInInventory(itemId, (Item)null, true);
			if (totalCountInInventory > 0)
			{
				list.Add(new TransferSource(realStorageContainer.InventoryId, totalCountInInventory));
				dictionary[realStorageContainer.InventoryId] = realStorageContainer.Inventory;
			}
		}
		StorageTransferPlan storageTransferPlan = TransferPlanner.Plan(requested, list, new TransferTarget[1]
		{
			new TransferTarget("target", capacity)
		});
		if (!storageTransferPlan.Success)
		{
			return TransferResult.Fail(storageTransferPlan.FailureReason);
		}
		Item val = new Item(itemId, storageTransferPlan.Total);
		List<Item> items = default(List<Item>);
		if (!destination.AddItemToInventory(val, ref items, (Item)null, true))
		{
			return TransferResult.Fail("destination-rejected");
		}
		int num = SumCount(items);
		if (num <= 0)
		{
			return TransferResult.Fail("destination-added-zero");
		}
		int num2 = 0;
		List<RemovedBatch> list2 = new List<RemovedBatch>();
		for (int j = 0; j < storageTransferPlan.Removals.Count; j++)
		{
			if (num2 >= num)
			{
				break;
			}
			TransferRemoval transferRemoval = storageTransferPlan.Removals[j];
			if (dictionary.TryGetValue(transferRemoval.InventoryId, out var value))
			{
				int num3 = Math.Min(transferRemoval.Count, num - num2);
				List<Item> items2 = value.RemoveItemById(itemId, num3, (Item)null, (Item)null, true);
				int num4 = SumCount(items2);
				num2 += num4;
				if (num4 > 0)
				{
					list2.Add(new RemovedBatch(value, items2));
				}
			}
		}
		if (num2 != num)
		{
			int num5 = SumCount(destination.RemoveItemById(itemId, num, (Item)null, (Item)null, true));
			if (num5 != num)
			{
				LogCritical("withdraw rollback removed " + num5 + "/" + num);
			}
			int num6 = 0;
			List<Item> items3 = default(List<Item>);
			for (int k = 0; k < list2.Count; k++)
			{
				RemovedBatch removedBatch = list2[k];
				for (int l = 0; l < removedBatch.Items.Count; l++)
				{
					Item val2 = removedBatch.Items[l];
					if (val2 != null && !val2.IsEmpty)
					{
						removedBatch.Inventory.AddItemToInventory(new Item(((ObjectLinkedToDefinition<ItemDef>)(object)val2).id, val2.Count), ref items3, (Item)null, true);
						num6 += SumCount(items3);
					}
				}
			}
			if (num6 != num2)
			{
				LogCritical("withdraw rollback restored " + num6 + "/" + num2);
			}
			return TransferResult.Fail("removal-mismatch-rollback");
		}
		return TransferResult.Ok(num);
	}

	public static TransferResult Deposit(string itemId, int requested, StorageIndexSnapshot snapshot, Inventory source)
	{
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0152: Expected O, but got Unknown
		//IL_024c: Unknown result type (might be due to invalid IL or missing references)
		//IL_025a: Expected O, but got Unknown
		if (snapshot == null || source == null)
		{
			return TransferResult.Fail("missing-source");
		}
		ItemDef data = ((GameBalanceBase)GameBalance.Me).GetData<ItemDef>(itemId);
		if (data == null)
		{
			return TransferResult.Fail("unknown-item");
		}
		if (HasUnsafeMatchingItem(source, itemId))
		{
			return TransferResult.Fail("source-unsafe");
		}
		int totalCountInInventory = source.Data.GetTotalCountInInventory(itemId, (Item)null, true);
		List<TransferTarget> list = new List<TransferTarget>();
		Dictionary<string, Inventory> dictionary = new Dictionary<string, Inventory>(StringComparer.Ordinal);
		for (int i = 0; i < snapshot.Containers.Count; i++)
		{
			RealStorageContainer realStorageContainer = snapshot.Containers[i];
			int num = realStorageContainer.Inventory.Data.CanAddItemCountToInventory(data, requested, true, (Item)null, true);
			if (num > 0)
			{
				list.Add(new TransferTarget(realStorageContainer.InventoryId, num));
				dictionary[realStorageContainer.InventoryId] = realStorageContainer.Inventory;
			}
		}
		StorageTransferPlan storageTransferPlan = TransferPlanner.Plan(requested, new TransferSource[1]
		{
			new TransferSource("source", totalCountInInventory)
		}, list);
		if (!storageTransferPlan.Success)
		{
			return TransferResult.Fail(storageTransferPlan.FailureReason);
		}
		int num2 = 0;
		List<AddedBatch> list2 = new List<AddedBatch>();
		List<Item> items = default(List<Item>);
		for (int j = 0; j < storageTransferPlan.Additions.Count; j++)
		{
			if (num2 >= storageTransferPlan.Total)
			{
				break;
			}
			TransferAddition transferAddition = storageTransferPlan.Additions[j];
			if (!dictionary.TryGetValue(transferAddition.InventoryId, out var value))
			{
				continue;
			}
			int num3 = Math.Min(transferAddition.Count, storageTransferPlan.Total - num2);
			Item val = new Item(itemId, num3);
			if (value.AddItemToInventory(val, ref items, (Item)null, true))
			{
				int num4 = SumCount(items);
				num2 += num4;
				if (num4 > 0)
				{
					list2.Add(new AddedBatch(value, num4));
				}
			}
		}
		if (num2 <= 0)
		{
			return TransferResult.Fail("destination-added-zero");
		}
		int num5 = SumCount(source.RemoveItemById(itemId, num2, (Item)null, (Item)null, true));
		if (num5 != num2)
		{
			int num6 = 0;
			for (int k = 0; k < list2.Count; k++)
			{
				AddedBatch addedBatch = list2[k];
				num6 += SumCount(addedBatch.Inventory.RemoveItemById(itemId, addedBatch.Count, (Item)null, (Item)null, true));
			}
			if (num6 != num2)
			{
				LogCritical("deposit rollback removed " + num6 + "/" + num2);
			}
			if (num5 > 0)
			{
				List<Item> items2 = default(List<Item>);
				source.AddItemToInventory(new Item(itemId, num5), ref items2, (Item)null, true);
				if (SumCount(items2) != num5)
				{
					LogCritical("deposit rollback restored " + SumCount(items2) + "/" + num5);
				}
			}
			return TransferResult.Fail("removal-mismatch-rollback");
		}
		return TransferResult.Ok(num2);
	}

	private static void LogCritical(string message)
	{
		if (StorageConsolePlugin.Log != null)
		{
			StorageConsolePlugin.Log.LogError((object)("Storage Console CRITICAL: " + message));
		}
	}

	private static bool HasUnsafeMatchingItem(Inventory inventory, string itemId)
	{
		if (inventory == null || inventory.Data == null || inventory.Data.Inventory == null)
		{
			return false;
		}
		List<Item> inventory2 = inventory.Data.Inventory;
		for (int i = 0; i < inventory2.Count; i++)
		{
			Item val = inventory2[i];
			if (val != null && !val.IsEmpty && !(((ObjectLinkedToDefinition<ItemDef>)(object)val).id != itemId))
			{
				ItemClassifier.Evaluate(val, out var eligible, out var _);
				if (!eligible)
				{
					return true;
				}
			}
		}
		return false;
	}

	private static int SumCount(List<Item> items)
	{
		int num = 0;
		if (items == null)
		{
			return num;
		}
		for (int i = 0; i < items.Count; i++)
		{
			if (items[i] != null && items[i].Count > 0)
			{
				num += items[i].Count;
			}
		}
		return num;
	}
}
public sealed class ChestConsoleEntryButton : MonoBehaviour
{
	private UIBaseChestWindow sourceWindow;

	internal void Initialize(UIBaseChestWindow window)
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Expected O, but got Unknown
		sourceWindow = window;
		LazyButton component = ((Component)this).GetComponent<LazyButton>();
		if ((Object)(object)component != (Object)null)
		{
			((UnityEventBase)((Button)component).onClick).RemoveAllListeners();
			((UnityEvent)((Button)component).onClick).AddListener(new UnityAction(ConsoleEntryController.OpenConsole));
		}
	}

	private void OnDestroy()
	{
		LazyButton component = ((Component)this).GetComponent<LazyButton>();
		if ((Object)(object)component != (Object)null)
		{
			((UnityEventBase)((Button)component).onClick).RemoveAllListeners();
		}
		sourceWindow = null;
	}
}
internal static class ConsoleEntryController
{
	private static StorageConsoleConfig settings;

	private static StorageConsoleWindow console;

	private static readonly List<ChestConsoleEntryButton> chestEntries = new List<ChestConsoleEntryButton>();

	private static readonly List<CharacterConsoleEntryButton> characterEntries = new List<CharacterConsoleEntryButton>();

	internal static void Initialize(StorageConsoleConfig config)
	{
		settings = config;
	}

	internal static void Shutdown()
	{
		StorageConsoleWindowFactory.Destroy();
		console = null;
		DestroyEntries<ChestConsoleEntryButton>(chestEntries);
		DestroyEntries<CharacterConsoleEntryButton>(characterEntries);
	}

	internal static void AttachChest(UIBaseChestWindow window)
	{
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_025d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0268: Unknown result type (might be due to invalid IL or missing references)
		//IL_026f: Expected O, but got Unknown
		//IL_0271: Unknown result type (might be due to invalid IL or missing references)
		//IL_0276: Unknown result type (might be due to invalid IL or missing references)
		//IL_0288: Unknown result type (might be due to invalid IL or missing references)
		//IL_028d: Unknown result type (might be due to invalid IL or missing references)
		//IL_022d: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_0319: Unknown result type (might be due to invalid IL or missing references)
		//IL_031c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0326: Unknown result type (might be due to invalid IL or missing references)
		//IL_0329: Unknown result type (might be due to invalid IL or missing references)
		//IL_0333: Unknown result type (might be due to invalid IL or missing references)
		//IL_033b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0345: Unknown result type (might be due to invalid IL or missing references)
		//IL_034f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0357: Unknown result type (might be due to invalid IL or missing references)
		//IL_0363: Unknown result type (might be due to invalid IL or missing references)
		//IL_0378: Unknown result type (might be due to invalid IL or missing references)
		//IL_0382: Unknown result type (might be due to invalid IL or missing references)
		//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_03af: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)window == (Object)null || (Object)(object)((Component)window).GetComponentInChildren<ChestConsoleEntryButton>(true) != (Object)null)
		{
			return;
		}
		LazyButton field = ReflectionAccess.GetField<LazyButton>(window, "closeButton");
		if ((Object)(object)field == (Object)null)
		{
			return;
		}
		LazyButton val = Object.Instantiate<LazyButton>(field, ((Component)field).transform.parent, false);
		((Object)val).name = "GK2StorageConsoleButton";
		((Component)val).gameObject.SetActive(true);
		((UnityEventBase)((Button)val).onClick).RemoveAllListeners();
		TextMeshProUGUI field2 = ReflectionAccess.GetField<TextMeshProUGUI>(window, "headerRight");
		Image val2 = null;
		if ((Object)(object)field2 != (Object)null && (Object)(object)((TMP_Text)field2).transform.parent != (Object)null)
		{
			Transform val3 = ((TMP_Text)field2).transform.parent.Find("Background");
			if ((Object)(object)val3 != (Object)null)
			{
				val2 = ((Component)val3).GetComponent<Image>();
			}
		}
		if ((Object)(object)val2 == (Object)null)
		{
			val2 = ((Component)field).GetComponent<Image>();
		}
		if ((Object)(object)val2 == (Object)null)
		{
			val2 = ((Component)field).GetComponentInChildren<Image>(true);
		}
		Image val4 = ((Component)val).GetComponent<Image>();
		if ((Object)(object)val4 == (Object)null)
		{
			val4 = ((Component)val).gameObject.AddComponent<Image>();
			if ((Object)(object)val2 != (Object)null)
			{
				val4.sprite = val2.sprite;
				val4.type = val2.type;
				((Graphic)val4).color = ((Graphic)val2).color;
				val4.preserveAspect = val2.preserveAspect;
			}
		}
		((Selectable)val).targetGraphic = (Graphic)(object)val4;
		for (int i = 0; i < ((Component)val).transform.childCount; i++)
		{
			Graphic[] componentsInChildren = ((Component)((Component)val).transform.GetChild(i)).gameObject.GetComponentsInChildren<Graphic>(true);
			for (int j = 0; j < componentsInChildren.Length; j++)
			{
				((Behaviour)componentsInChildren[j]).enabled = false;
			}
		}
		GameObject val5 = new GameObject("Label", new Type[2]
		{
			typeof(RectTransform),
			typeof(TextMeshProUGUI)
		});
		val5.transform.SetParent(((Component)val).transform, false);
		RectTransform val6 = (RectTransform)val5.transform;
		val6.anchorMin = Vector2.zero;
		val6.anchorMax = Vector2.one;
		val6.offsetMin = Vector2.zero;
		val6.offsetMax = Vector2.zero;
		TextMeshProUGUI component = val5.GetComponent<TextMeshProUGUI>();
		((TMP_Text)component).text = ConsoleLocalization.Title;
		if ((Object)(object)field2 != (Object)null)
		{
			((TMP_Text)component).font = ((TMP_Text)field2).font;
			((Graphic)component).color = ((Graphic)field2).color;
			((TMP_Text)component).fontSize = 14f;
		}
		((TMP_Text)component).alignment = (TextAlignmentOptions)514;
		((Graphic)component).raycastTarget = false;
		RectTransform val7 = (RectTransform)((Component)val).transform;
		RectTransform val8 = (RectTransform)((Component)field).transform;
		Rect rect = val8.rect;
		float num = Mathf.Abs(((Rect)(ref rect)).width);
		rect = val8.rect;
		float num2 = Mathf.Abs(((Rect)(ref rect)).height);
		if (num < 1f || num > 80f)
		{
			num = Mathf.Abs(val8.sizeDelta.x);
		}
		if (num < 1f || num > 80f)
		{
			num = 26f;
		}
		if (num2 < 1f || num2 > 80f)
		{
			num2 = Mathf.Abs(val8.sizeDelta.y);
		}
		if (num2 < 1f || num2 > 80f)
		{
			num2 = 26f;
		}
		val7.anchorMin = val8.anchorMin;
		val7.anchorMax = val8.anchorMax;
		val7.pivot = new Vector2(1f, val8.pivot.y);
		val7.sizeDelta = new Vector2(82f, num2);
		val7.anchoredPosition = new Vector2(val8.anchoredPosition.x - num - 10f, val8.anchoredPosition.y);
		if ((Object)(object)field2 != (Object)null && (Object)(object)((TMP_Text)field2).rectTransform != (Object)null)
		{
			RectTransform rectTransform = ((TMP_Text)field2).rectTransform;
			Vector2 offsetMax = rectTransform.offsetMax;
			offsetMax.x -= 92f;
			rectTransform.offsetMax = offsetMax;
		}
		((Component)val).transform.SetSiblingIndex(((Component)field).transform.GetSiblingIndex());
		ChestConsoleEntryButton chestConsoleEntryButton = ((Component)val).gameObject.AddComponent<ChestConsoleEntryButton>();
		chestConsoleEntryButton.Initialize(window);
		Prune<ChestConsoleEntryButton>(chestEntries);
		chestEntries.Add(chestConsoleEntryButton);
	}

	internal static void MarkChestDirty(UIBaseChestWindow window)
	{
	}

	internal static void DetachChest(UIBaseChestWindow window)
	{
	}

	internal static void AttachCharacter(CharacterWindow window)
	{
		if (!((Object)(object)window == (Object)null) && !((Object)(object)((Component)window).GetComponentInChildren<CharacterConsoleEntryButton>(true) != (Object)null))
		{
			CharPageTabButton field = ReflectionAccess.GetField<CharPageTabButton>(window, "charPageTabButtonPrefab");
			GameObject field2 = ReflectionAccess.GetField<GameObject>(window, "charPageTabButtonParent");
			if (!((Object)(object)field == (Object)null) && !((Object)(object)field2 == (Object)null))
			{
				CharPageTabButton obj = MonoBehaviourExtensions.Copy<CharPageTabButton>(field, field2.transform, true, "GK2StorageConsoleTabButton");
				obj.Init(ConsoleLocalization.Title, (Action)OpenConsole, true);
				obj.UpdateState(false);
				obj.UpdateActionIndicatorStatus(false);
				CharacterConsoleEntryButton item = ((Component)obj).gameObject.AddComponent<CharacterConsoleEntryButton>();
				Prune<CharacterConsoleEntryButton>(characterEntries);
				characterEntries.Add(item);
			}
		}
	}

	internal static void OpenConsole()
	{
		if (settings == null)
		{
			return;
		}
		console = StorageConsoleWindowFactory.GetOrCreate(settings);
		if ((Object)(object)console == (Object)null)
		{
			if (StorageConsolePlugin.Log != null)
			{
				StorageConsolePlugin.Log.LogError((object)"Storage Console: console window could not be created.");
			}
		}
		else
		{
			console.ShowConsole();
		}
	}

	private static void Prune<T>(List<T> entries) where T : Component
	{
		for (int num = entries.Count - 1; num >= 0; num--)
		{
			if ((Object)(object)entries[num] == (Object)null)
			{
				entries.RemoveAt(num);
			}
		}
	}

	private static void DestroyEntries<T>(List<T> entries) where T : Component
	{
		for (int num = entries.Count - 1; num >= 0; num--)
		{
			T val = entries[num];
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
		}
		entries.Clear();
	}
}
public sealed class CharacterConsoleEntryButton : MonoBehaviour
{
}
internal static class ConsoleLocalization
{
	private static bool Zh => LL.IsCurrentLangAsian;

	public static string Title
	{
		get
		{
			if (!Zh)
			{
				return "Base Storage";
			}
			return "基地资源";
		}
	}

	public static string PlayerInventory
	{
		get
		{
			if (!Zh)
			{
				return "Player Inventory";
			}
			return "玩家背包";
		}
	}

	public static string AllBaseStorage
	{
		get
		{
			if (!Zh)
			{
				return "All Base Storage";
			}
			return "全基地资源";
		}
	}
}
internal static class ReflectionAccess
{
	public static bool HasInstanceField(object target, string name)
	{
		if (target == null || string.IsNullOrEmpty(name))
		{
			return false;
		}
		Type type = target.GetType();
		while (type != null)
		{
			if (type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null)
			{
				return true;
			}
			type = type.BaseType;
		}
		return false;
	}

	public static T GetField<T>(object target, string name) where T : class
	{
		if (target == null || string.IsNullOrEmpty(name))
		{
			return null;
		}
		Type type = target.GetType();
		while (type != null)
		{
			FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				return field.GetValue(target) as T;
			}
			type = type.BaseType;
		}
		return null;
	}

	public static void Invoke(object target, string name)
	{
		if (target == null || string.IsNullOrEmpty(name))
		{
			return;
		}
		Type type = target.GetType();
		while (type != null)
		{
			MethodInfo method = type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (method != null)
			{
				method.Invoke(target, null);
				break;
			}
			type = type.BaseType;
		}
	}

	public static void SetField(object target, string name, object value)
	{
		if (target == null || string.IsNullOrEmpty(name))
		{
			return;
		}
		Type type = target.GetType();
		while (type != null)
		{
			FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				field.SetValue(target, value);
				break;
			}
			type = type.BaseType;
		}
	}
}
internal sealed class StorageConsoleConfig
{
	private readonly ConfigEntry<bool> includeInactiveZones;

	private readonly ConfigEntry<string> excludedZoneIds;

	private readonly ConfigEntry<int> maxDisplayedItems;

	public int MaxDisplayedItems => Math.Max(1, maxDisplayedItems.Value);

	public StorageConsoleConfig(ConfigFile file)
	{
		includeInactiveZones = file.Bind<bool>("Storage", "IncludeInactiveZones", false, "Include inactive WorldZoneData in the base storage index.");
		excludedZoneIds = file.Bind<string>("Storage", "ExcludedZoneIds", string.Empty, "Comma-separated WorldZoneData ids to exclude.");
		maxDisplayedItems = file.Bind<int>("Storage", "MaxDisplayedItems", 500, "Maximum aggregate entries rendered in the console.");
	}

	public StorageIndexOptions BuildOptions()
	{
		StorageIndexOptions storageIndexOptions = new StorageIndexOptions();
		storageIndexOptions.IncludeInactiveZones = includeInactiveZones.Value;
		string[] array = (excludedZoneIds.Value ?? string.Empty).Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
		for (int i = 0; i < array.Length; i++)
		{
			string text = array[i].Trim();
			if (text.Length > 0)
			{
				storageIndexOptions.ExcludedZoneIds.Add(text);
			}
		}
		return storageIndexOptions;
	}
}
public static class StorageConsoleExternalApi
{
	public const int Version = 1;
}
[HarmonyPatch(typeof(GUIElements), "Initialize")]
internal static class Patch_GuiElementsInitialize
{
	[HarmonyPostfix]
	private static void Postfix()
	{
		StorageConsoleWindowFactory.CaptureVanillaTemplate();
	}
}
[HarmonyPatch(typeof(UIBaseChestWindow), "Open", new Type[] { typeof(UIBaseChestWindowData) })]
internal static class Patch_ChestOpen
{
	[HarmonyPostfix]
	private static void Postfix(UIBaseChestWindow __instance)
	{
		ConsoleEntryController.AttachChest(__instance);
	}
}
[HarmonyPatch(typeof(UIBaseChestWindow), "Redraw")]
internal static class Patch_ChestRedraw
{
	[HarmonyPostfix]
	private static void Postfix(UIBaseChestWindow __instance)
	{
		ConsoleEntryController.MarkChestDirty(__instance);
	}
}
[HarmonyPatch(typeof(UIBaseChestWindow), "Hide")]
internal static class Patch_ChestHide
{
	[HarmonyPostfix]
	private static void Postfix(UIBaseChestWindow __instance)
	{
		ConsoleEntryController.DetachChest(__instance);
	}
}
[HarmonyPatch(typeof(CharacterWindow), "Init")]
internal static class Patch_CharacterInit
{
	[HarmonyPostfix]
	private static void Postfix(CharacterWindow __instance)
	{
		ConsoleEntryController.AttachCharacter(__instance);
	}
}
[BepInPlugin("gk2.storageconsole", "GK2 Storage Console", "1.2.0")]
public sealed class StorageConsolePlugin : BaseUnityPlugin
{
	public const string PluginGuid = "gk2.storageconsole";

	public const string PluginName = "GK2 Storage Console";

	public const string PluginVersion = "1.2.0";

	internal static StorageConsolePlugin Instance;

	internal static ManualLogSource Log;

	internal StorageConsoleConfig Settings;

	private static readonly Type[] PatchClasses = new Type[5]
	{
		typeof(Patch_GuiElementsInitialize),
		typeof(Patch_ChestOpen),
		typeof(Patch_ChestRedraw),
		typeof(Patch_ChestHide),
		typeof(Patch_CharacterInit)
	};

	private Harmony harmony;

	private int appliedPatches;

	private void Awake()
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Expected O, but got Unknown
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		Settings = new StorageConsoleConfig(((BaseUnityPlugin)this).Config);
		harmony = new Harmony("gk2.storageconsole");
		for (int i = 0; i < PatchClasses.Length; i++)
		{
			ApplyPatch(PatchClasses[i]);
		}
		ConsoleEntryController.Initialize(Settings);
		Log.LogInfo((object)("GK2 Storage Console 1.2.0 loaded (" + appliedPatches + " patches)."));
	}

	private void ApplyPatch(Type patchClass)
	{
		try
		{
			harmony.CreateClassProcessor(patchClass).Patch();
			appliedPatches++;
		}
		catch (Exception ex)
		{
			Log.LogError((object)("GK2 Storage Console: patch " + patchClass.Name + " could not be applied; only that patch is disabled. " + ex));
		}
	}

	private void OnDestroy()
	{
		ConsoleEntryController.Shutdown();
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
	}
}
public sealed class StorageConsoleWindowData : LazyWidgetDataBase
{
}
public sealed class StorageConsoleWindow : LazyWindow<StorageConsoleWindowData>
{
	private MultiInventoryWidget leftWidget;

	private MultiInventoryWidget rightWidget;

	private TextMeshProUGUI headerLeft;

	private TextMeshProUGUI headerRight;

	private StorageConsoleConfig settings;

	private StorageIndexSnapshot index;

	private List<StorageAggregateItem> allAggregate = new List<StorageAggregateItem>();

	private List<StorageAggregateItem> aggregate = new List<StorageAggregateItem>();

	private Dictionary<string, bool> aggregateSafety = new Dictionary<string, bool>(StringComparer.Ordinal);

	private ConsoleSortMode sortMode;

	private bool initialized;

	internal bool Initialize(MultiInventoryWidget left, MultiInventoryWidget right, LazyButton closeButton, TextMeshProUGUI vanillaHeaderLeft, TextMeshProUGUI vanillaHeaderRight, StorageConsoleConfig config)
	{
		leftWidget = left;
		rightWidget = right;
		headerLeft = vanillaHeaderLeft;
		headerRight = vanillaHeaderRight;
		settings = config;
		initialized = (Object)(object)leftWidget != (Object)null && (Object)(object)rightWidget != (Object)null;
		if (!initialized)
		{
			return false;
		}
		try
		{
			ReflectionAccess.SetField(this, "closeButton", closeButton);
			((LazyWidgetBase)this).Init();
			return true;
		}
		catch (Exception ex)
		{
			if (StorageConsolePlugin.Log != null)
			{
				StorageConsolePlugin.Log.LogError((object)("Storage Console: window initialization failed. " + ex));
			}
			initialized = false;
			return false;
		}
	}

	internal void ShowConsole()
	{
		if (initialized)
		{
			RebuildIndex();
			if (!base.IsShown)
			{
				((LazyWindow<StorageConsoleWindowData>)this).ShowWindow();
			}
			RefreshVisuals();
		}
	}

	internal void RefreshAfterTransfer()
	{
		RebuildIndex();
		RefreshVisuals();
	}

	public override void Redraw()
	{
		RefreshVisuals();
	}

	public bool ToggleQuantitySort()
	{
		sortMode = ((sortMode != ConsoleSortMode.QuantityDescending) ? ConsoleSortMode.QuantityDescending : ConsoleSortMode.NameAscending);
		ApplyFilters();
		RefreshVisuals();
		return sortMode == ConsoleSortMode.QuantityDescending;
	}

	public override void Hide()
	{
		if ((Object)(object)leftWidget != (Object)null)
		{
			((LazyWidgetBase)leftWidget).Hide();
		}
		if ((Object)(object)rightWidget != (Object)null)
		{
			((LazyWidgetBase)rightWidget).Hide();
		}
		((LazyWidget<StorageConsoleWindowData>)(object)this).Hide();
	}

	protected override void TestDraw()
	{
	}

	private void OnDestroy()
	{
		if (base.IsShown)
		{
			((LazyWindow<StorageConsoleWindowData>)this).CloseWithoutCallback();
		}
		RemoveStaticHandler("OnWindowBecameVisibleInStack", "OnWindowBecameVisibleInStack");
		RemoveStaticHandler("OnWindowBecameHiddenInStack", "OnWindowBecameHiddenInStack");
	}

	private void RemoveStaticHandler(string fieldName, string methodName)
	{
		try
		{
			FieldInfo field = typeof(LazyWindowsStackController).GetField(fieldName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(field == null) && field.GetValue(null) is Delegate obj)
			{
				MethodInfo method = typeof(StorageConsoleWindow).GetMethod(methodName, BindingFlags.Instance | BindingFlags.NonPublic);
				if (!(method == null))
				{
					Delegate value = Delegate.CreateDelegate(obj.GetType(), this, method);
					field.SetValue(null, Delegate.Remove(obj, value));
				}
			}
		}
		catch (Exception)
		{
		}
	}

	private void RebuildIndex()
	{
		index = BaseStorageIndex.Build((settings != null) ? settings.BuildOptions() : new StorageIndexOptions());
		allAggregate = StorageAggregator.Aggregate(index.ItemSnapshots, index.ContainerSnapshots);
		ApplyFilters();
	}

	private void ApplyFilters()
	{
		aggregate.Clear();
		for (int i = 0; i < allAggregate.Count; i++)
		{
			StorageAggregateItem storageAggregateItem = allAggregate[i];
			if (((GameBalanceBase)GameBalance.Me).GetData<ItemDef>(storageAggregateItem.ItemId) != null)
			{
				aggregate.Add(storageAggregateItem);
			}
		}
		ConsoleSortPolicy.Sort(aggregate, sortMode, delegate(string itemId)
		{
			ItemDef data = ((GameBalanceBase)GameBalance.Me).GetData<ItemDef>(itemId);
			return (data == null) ? itemId : data.GetHeader();
		});
		if (settings != null && aggregate.Count > settings.MaxDisplayedItems)
		{
			aggregate.RemoveRange(settings.MaxDisplayedItems, aggregate.Count - settings.MaxDisplayedItems);
		}
	}

	private void RefreshVisuals()
	{
		if (initialized)
		{
			((LazyWidgetBase)leftWidget).Hide();
			((LazyWidgetBase)rightWidget).Hide();
			((LazyWidget<MultiInventoryWidgetData>)(object)leftWidget).Draw(BuildPlayerData());
			((LazyWidget<MultiInventoryWidgetData>)(object)rightWidget).Draw(BuildAggregateData());
			leftWidget.SelectFirstWidget();
			rightWidget.SelectFirstWidget();
			if (LazyInput.IsGamepadActive && (Object)(object)base.GamepadNavigationController != (Object)null)
			{
				base.GamepadNavigationController.ReinitItems(true, (List<GamepadNavigationItem>)null, (GamepadNavigationItem)null);
			}
			SetHeader();
		}
	}

	private MultiInventoryWidgetData BuildPlayerData()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Expected O, but got Unknown
		//IL_007b: Expected O, but got Unknown
		MultiInventoryWidgetData val = new MultiInventoryWidgetData((MultiInventoryWidgetMode)2)
		{
			HeaderLocaleId = ConsoleLocalization.PlayerInventory
		};
		val.AddRange(InventoryWidgetDataHelper.GetWidgetsDataForInventory(MainGame.PlayerData.Inventory, (Action<UIItemCell>)delegate
		{
		}, (Action<UIItemCell>)null, (Action<UIItemCell>)OnPlayerItemLeft, (Action<UIItemCell>)OnPlayerItemRight, (Action<UIItemCell>)null, (Func<Item, bool>)IsSafeCell, true, false, (ItemRelatedWidgetState)0, (ItemRelatedWidgetState)2));
		ApplyInventoryHeader(val, ConsoleLocalization.PlayerInventory);
		return val;
	}

	private MultiInventoryWidgetData BuildAggregateData()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Expected O, but got Unknown
		MultiInventoryWidgetData val = new MultiInventoryWidgetData((MultiInventoryWidgetMode)3);
		val.HeaderLocaleId = ConsoleLocalization.AllBaseStorage;
		Inventory val2 = Inventory.Create(Math.Max(1, aggregate.Count), false, (WhiteListItemFilter)null, (BlackListItemFilter)null, "storage_console_display");
		val2.Data.Inventory.Clear();
		aggregateSafety.Clear();
		for (int i = 0; i < aggregate.Count; i++)
		{
			StorageAggregateItem storageAggregateItem = aggregate[i];
			val2.Data.Inventory.Add(new Item(storageAggregateItem.ItemId, storageAggregateItem.TotalCount));
			aggregateSafety[storageAggregateItem.ItemId] = storageAggregateItem.Transferable;
		}
		val2.Data.InventorySize = Math.Max(1, aggregate.Count);
		val.AddRange(InventoryWidgetDataHelper.GetWidgetsDataForInventory(val2, (Action<UIItemCell>)delegate
		{
		}, (Action<UIItemCell>)null, (Action<UIItemCell>)OnBaseItemLeft, (Action<UIItemCell>)OnBaseItemRight, (Action<UIItemCell>)null, (Func<Item, bool>)AggregateCellSafe, false, false, (ItemRelatedWidgetState)0, (ItemRelatedWidgetState)2));
		ApplyInventoryHeader(val, ConsoleLocalization.AllBaseStorage);
		return val;
	}

	private bool AggregateCellSafe(Item item)
	{
		if (item == null || item.IsEmpty)
		{
			return true;
		}
		if (aggregateSafety.TryGetValue(((ObjectLinkedToDefinition<ItemDef>)(object)item).id, out var value) && value)
		{
			return IsSafeCell(item);
		}
		return false;
	}

	private bool IsSafeCell(Item item)
	{
		if (item == null || item.IsEmpty || ((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition == null)
		{
			return true;
		}
		ItemClassifier.Evaluate(item, out var eligible, out var _);
		return eligible;
	}

	private void OnPlayerItemLeft(UIItemCell cell)
	{
		if (!((Object)(object)cell == (Object)null) && cell.DisplayingItem != null)
		{
			Item displayingItem = cell.DisplayingItem;
			Inventory source = GetCellInventory(cell) ?? MainGame.PlayerData.Inventory;
			int amount = GetAmount(displayingItem, displayingItem.Count);
			if (amount > 0)
			{
				HandleResult(BaseStorageTransferService.Deposit(((ObjectLinkedToDefinition<ItemDef>)(object)displayingItem).id, amount, index, source));
			}
		}
	}

	private void OnPlayerItemRight(UIItemCell cell)
	{
		if (!((Object)(object)cell == (Object)null) && cell.DisplayingItem != null)
		{
			Inventory source = GetCellInventory(cell) ?? MainGame.PlayerData.Inventory;
			OpenCountWindow(cell.DisplayingItem, cell.DisplayingItem.Count, delegate(int count)
			{
				HandleResult(BaseStorageTransferService.Deposit(((ObjectLinkedToDefinition<ItemDef>)(object)cell.DisplayingItem).id, count, index, source));
			});
		}
	}

	private void OnBaseItemLeft(UIItemCell cell)
	{
		if ((Object)(object)cell == (Object)null || cell.DisplayingItem == null)
		{
			return;
		}
		StorageAggregateItem storageAggregateItem = FindAggregate(((ObjectLinkedToDefinition<ItemDef>)(object)cell.DisplayingItem).id);
		if (storageAggregateItem != null && storageAggregateItem.Transferable)
		{
			Item displayingItem = cell.DisplayingItem;
			int amount = GetAmount(displayingItem, displayingItem.Count);
			if (amount > 0)
			{
				HandleResult(BaseStorageTransferService.Withdraw(((ObjectLinkedToDefinition<ItemDef>)(object)displayingItem).id, amount, index, MainGame.PlayerData.Inventory));
			}
		}
	}

	private void OnBaseItemRight(UIItemCell cell)
	{
		if ((Object)(object)cell == (Object)null || cell.DisplayingItem == null)
		{
			return;
		}
		StorageAggregateItem storageAggregateItem = FindAggregate(((ObjectLinkedToDefinition<ItemDef>)(object)cell.DisplayingItem).id);
		if (storageAggregateItem != null && storageAggregateItem.Transferable)
		{
			OpenCountWindow(cell.DisplayingItem, cell.DisplayingItem.Count, delegate(int count)
			{
				HandleResult(BaseStorageTransferService.Withdraw(((ObjectLinkedToDefinition<ItemDef>)(object)cell.DisplayingItem).id, count, index, MainGame.PlayerData.Inventory));
			});
		}
	}

	private StorageAggregateItem FindAggregate(string itemId)
	{
		for (int i = 0; i < aggregate.Count; i++)
		{
			if (aggregate[i].ItemId == itemId)
			{
				return aggregate[i];
			}
		}
		return null;
	}

	private Inventory GetCellInventory(UIItemCell cell)
	{
		InventoryWidget val = (((Object)(object)cell == (Object)null) ? null : ((Component)cell).GetComponentInParent<InventoryWidget>());
		if (!((Object)(object)val != (Object)null) || val.Data == null)
		{
			return null;
		}
		return ((InventoryWidgetDataBase)val.Data).Inventory;
	}

	private void OpenCountWindow(Item item, int max, Action<int> onConfirm)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Expected O, but got Unknown
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Expected O, but got Unknown
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0065: Expected O, but got Unknown
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Expected O, but got Unknown
		if (item != null && max > 0)
		{
			UIItemCountWindowData val = new UIItemCountWindowData();
			val.Item = new Item(((ObjectLinkedToDefinition<ItemDef>)(object)item).id, max);
			val.Min = 1;
			val.Max = max;
			val.SnapStep = 1;
			val.OnConfirm = onConfirm;
			val.IsForVendor = false;
			val.OkBtnData = new ButtonData((Action)null, LLBase.L("btn_ok"), (Func<bool>)null, true, GameKey.Select, "");
			val.BackBtnData = new ButtonData((Action)null, LLBase.L("btn_cancel"), (Func<bool>)null, true, GameKey.Back, "");
			UIItemCountWindow window = LazyUI.GetWindow<UIItemCountWindow>();
			if ((Object)(object)window != (Object)null)
			{
				((LazyWindow<UIItemCountWindowData>)(object)window).Open(val);
			}
		}
	}

	private void HandleResult(TransferResult result)
	{
		if (result == null || !result.Success)
		{
			if (StorageConsolePlugin.Log != null)
			{
				StorageConsolePlugin.Log.LogWarning((object)("Storage Console: transfer failed: " + ((result == null) ? "null" : result.FailureReason)));
			}
		}
		else
		{
			RefreshAfterTransfer();
		}
	}

	private int GetAmount(Item item, int available)
	{
		if (available <= 0 || item == null || ((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition == null)
		{
			return 0;
		}
		bool num = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303);
		bool flag = Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305);
		if (num)
		{
			return available;
		}
		if (flag)
		{
			return Math.Max(1, available / 2);
		}
		return Math.Min(((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.stackCount, available);
	}

	private static void ApplyInventoryHeader(MultiInventoryWidgetData data, string header)
	{
		if (data == null || string.IsNullOrEmpty(header))
		{
			return;
		}
		for (int i = 0; i < data.inventoriesData.Count; i++)
		{
			InventoryWidgetDataBase obj = data.inventoriesData[i];
			InventoryWidgetData val = (InventoryWidgetData)(object)((obj is InventoryWidgetData) ? obj : null);
			if (val != null && val.InventoryHeaderWidgetData != null)
			{
				val.InventoryHeaderWidgetData.CustomHeaderId = header;
			}
		}
	}

	private void SetHeader()
	{
		if ((Object)(object)headerLeft != (Object)null)
		{
			((TMP_Text)headerLeft).text = ConsoleLocalization.PlayerInventory;
		}
		if ((Object)(object)headerRight != (Object)null)
		{
			((TMP_Text)headerRight).text = ConsoleLocalization.Title;
		}
	}
}
internal static class StorageConsoleWindowFactory
{
	private sealed class PartPaths
	{
		public int[] Left;

		public int[] Right;

		public int[] Close;

		public int[] HeaderLeft;

		public int[] HeaderRight;
	}

	private const string TemplateObjectName = "GK2StorageConsoleVanillaTemplate";

	private static GameObject vanillaTemplate;

	private static PartPaths partPaths;

	private static StorageConsoleWindow current;

	internal static void CaptureVanillaTemplate()
	{
		if ((Object)(object)vanillaTemplate != (Object)null)
		{
			return;
		}
		UIChestWindow val = null;
		try
		{
			val = LazyUI.GetWindow<UIChestWindow>();
		}
		catch (Exception ex)
		{
			if (StorageConsolePlugin.Log != null)
			{
				StorageConsolePlugin.Log.LogWarning((object)("Storage Console: could not capture vanilla chest template. " + ex.Message));
			}
			return;
		}
		if ((Object)(object)val == (Object)null)
		{
			if (StorageConsolePlugin.Log != null)
			{
				StorageConsolePlugin.Log.LogWarning((object)"Storage Console: vanilla chest template was not present after GUIElements.Initialize.");
			}
			return;
		}
		MultiInventoryWidget field = ReflectionAccess.GetField<MultiInventoryWidget>(val, "leftMultiInventoryWidget");
		MultiInventoryWidget field2 = ReflectionAccess.GetField<MultiInventoryWidget>(val, "rightMultiInventoryWidget");
		LazyButton field3 = ReflectionAccess.GetField<LazyButton>(val, "closeButton");
		TextMeshProUGUI field4 = ReflectionAccess.GetField<TextMeshProUGUI>(val, "headerLeft");
		TextMeshProUGUI field5 = ReflectionAccess.GetField<TextMeshProUGUI>(val, "headerRight");
		if ((Object)(object)field == (Object)null || (Object)(object)field2 == (Object)null || (Object)(object)field3 == (Object)null || (Object)(object)field4 == (Object)null || (Object)(object)field5 == (Object)null)
		{
			if (StorageConsolePlugin.Log != null)
			{
				StorageConsolePlugin.Log.LogWarning((object)"Storage Console: vanilla chest template is missing required controls.");
			}
			return;
		}
		Transform val2 = ((Component)val).transform.parent;
		if ((Object)(object)val2 == (Object)null && (Object)(object)GUIElements.Instance != (Object)null)
		{
			val2 = (Transform)(object)GUIElements.Instance.Root;
		}
		if ((Object)(object)val2 == (Object)null)
		{
			if (StorageConsolePlugin.Log != null)
			{
				StorageConsolePlugin.Log.LogWarning((object)"Storage Console: vanilla chest template has no parent transform.");
			}
			return;
		}
		GameObject obj = Object.Instantiate<GameObject>(((Component)val).gameObject, val2, false);
		((Object)obj).name = "GK2StorageConsoleVanillaTemplate";
		obj.SetActive(false);
		vanillaTemplate = obj;
		partPaths = new PartPaths
		{
			Left = BuildPath(((Component)val).transform, ((Component)field).transform),
			Right = BuildPath(((Component)val).transform, ((Component)field2).transform),
			Close = BuildPath(((Component)val).transform, ((Component)field3).transform),
			HeaderLeft = BuildPath(((Component)val).transform, ((TMP_Text)field4).transform),
			HeaderRight = BuildPath(((Component)val).transform, ((TMP_Text)field5).transform)
		};
		UIChestWindow component = obj.GetComponent<UIChestWindow>();
		if ((Object)(object)component != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component);
		}
	}

	internal static StorageConsoleWindow GetOrCreate(StorageConsoleConfig settings)
	{
		if ((Object)(object)current != (Object)null)
		{
			return current;
		}
		if ((Object)(object)vanillaTemplate == (Object)null || partPaths == null)
		{
			CaptureVanillaTemplate();
		}
		if ((Object)(object)vanillaTemplate == (Object)null || partPaths == null)
		{
			if (StorageConsolePlugin.Log != null)
			{
				StorageConsolePlugin.Log.LogError((object)"Storage Console: vanilla chest template unavailable.");
			}
			return null;
		}
		Transform val = vanillaTemplate.transform.parent;
		if ((Object)(object)val == (Object)null && (Object)(object)GUIElements.Instance != (Object)null)
		{
			val = (Transform)(object)GUIElements.Instance.Root;
		}
		if ((Object)(object)val == (Object)null)
		{
			if (StorageConsolePlugin.Log != null)
			{
				StorageConsolePlugin.Log.LogError((object)"Storage Console: console window parent unavailable.");
			}
			return null;
		}
		GameObject val2 = Object.Instantiate<GameObject>(vanillaTemplate, val, false);
		((Object)val2).name = "GK2StorageConsoleWindow";
		val2.SetActive(false);
		MultiInventoryWidget val3 = Resolve<MultiInventoryWidget>(val2.transform, partPaths.Left);
		MultiInventoryWidget val4 = Resolve<MultiInventoryWidget>(val2.transform, partPaths.Right);
		LazyButton val5 = Resolve<LazyButton>(val2.transform, partPaths.Close);
		TextMeshProUGUI val6 = Resolve<TextMeshProUGUI>(val2.transform, partPaths.HeaderLeft);
		TextMeshProUGUI val7 = Resolve<TextMeshProUGUI>(val2.transform, partPaths.HeaderRight);
		if ((Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)val6 == (Object)null || (Object)(object)val7 == (Object)null)
		{
			Object.Destroy((Object)(object)val2);
			if (StorageConsolePlugin.Log != null)
			{
				StorageConsolePlugin.Log.LogError((object)"Storage Console: vanilla chest controls missing from template clone.");
			}
			return null;
		}
		TemplateSanitizer.Strip(val2);
		ILazyGUIElement[] componentsInChildren = val2.GetComponentsInChildren<ILazyGUIElement>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			componentsInChildren[i].Init();
		}
		current = val2.AddComponent<StorageConsoleWindow>();
		if (!current.Initialize(val3, val4, val5, val6, val7, settings))
		{
			Object.Destroy((Object)(object)val2);
			current = null;
			return null;
		}
		return current;
	}

	internal static void Destroy()
	{
		if ((Object)(object)current != (Object)null)
		{
			if (((LazyWindow<StorageConsoleWindowData>)current).IsShown)
			{
				((LazyWindow<StorageConsoleWindowData>)current).CloseWithoutCallback();
			}
			Object.Destroy((Object)(object)((Component)current).gameObject);
			current = null;
		}
		if ((Object)(object)vanillaTemplate != (Object)null)
		{
			Object.Destroy((Object)(object)vanillaTemplate);
			vanillaTemplate = null;
		}
		partPaths = null;
	}

	private static int[] BuildPath(Transform root, Transform target)
	{
		if ((Object)(object)root == (Object)null || (Object)(object)target == (Object)null)
		{
			return null;
		}
		List<int> list = new List<int>();
		Transform val = target;
		while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
		{
			list.Add(val.GetSiblingIndex());
			val = val.parent;
		}
		if ((Object)(object)val != (Object)(object)root)
		{
			return null;
		}
		list.Reverse();
		return list.ToArray();
	}

	private static T Resolve<T>(Transform root, int[] path) where T : Component
	{
		if ((Object)(object)root == (Object)null || path == null)
		{
			return default(T);
		}
		Transform val = root;
		for (int i = 0; i < path.Length; i++)
		{
			if (path[i] < 0 || path[i] >= val.childCount)
			{
				return default(T);
			}
			val = val.GetChild(path[i]);
		}
		return ((Component)val).GetComponent<T>();
	}
}
internal static class TemplateSanitizer
{
	private static readonly string[] ForeignObjectNames = new string[2] { "StorageFilterBar", "GK2StorageConsoleButton" };

	private static readonly string[] GameAssemblies = new string[4] { "Assembly-CSharp", "LazyBearTechnology", "mscorlib", "netstandard" };

	internal static int Strip(GameObject root)
	{
		if ((Object)(object)root == (Object)null)
		{
			return 0;
		}
		int num = RemoveForeignObjects(root.transform);
		num += RemoveForeignComponents(root);
		if (num > 0 && StorageConsolePlugin.Log != null)
		{
			StorageConsolePlugin.Log.LogInfo((object)("Storage Console: stripped " + num + " foreign object(s)/component(s) from the window template clone."));
		}
		return num;
	}

	private static int RemoveForeignObjects(Transform parent)
	{
		int num = 0;
		for (int num2 = parent.childCount - 1; num2 >= 0; num2--)
		{
			Transform child = parent.GetChild(num2);
			if (!((Object)(object)child == (Object)null))
			{
				if (IsForeignObjectName(((Object)child).name))
				{
					Object.DestroyImmediate((Object)(object)((Component)child).gameObject);
					num++;
				}
				else
				{
					num += RemoveForeignObjects(child);
				}
			}
		}
		return num;
	}

	internal static bool IsForeignObjectName(string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return false;
		}
		for (int i = 0; i < ForeignObjectNames.Length; i++)
		{
			if (string.Equals(name, ForeignObjectNames[i], StringComparison.Ordinal))
			{
				return true;
			}
		}
		return false;
	}

	private static int RemoveForeignComponents(GameObject root)
	{
		int num = 0;
		MonoBehaviour[] componentsInChildren = root.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)null) && IsForeignComponent(((object)val).GetType()))
			{
				Object.DestroyImmediate((Object)(object)val);
				num++;
			}
		}
		return num;
	}

	private static bool IsForeignComponent(Type type)
	{
		string name = type.Assembly.GetName().Name;
		if (string.IsNullOrEmpty(name))
		{
			return false;
		}
		for (int i = 0; i < GameAssemblies.Length; i++)
		{
			if (string.Equals(name, GameAssemblies[i], StringComparison.Ordinal))
			{
				return false;
			}
		}
		if (name.StartsWith("UnityEngine", StringComparison.Ordinal))
		{
			return false;
		}
		if (name.StartsWith("Unity.", StringComparison.Ordinal))
		{
			return false;
		}
		if (name.StartsWith("System", StringComparison.Ordinal))
		{
			return false;
		}
		if (name.StartsWith("Sirenix", StringComparison.Ordinal))
		{
			return false;
		}
		return true;
	}
}