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;
}
}