Decompiled source of CargoToGo v1.0.0

CargoToGo.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using AzuCraftyBoxes;
using AzuCraftyBoxes.IContainers;
using AzuCraftyBoxes.Util;
using AzuCraftyBoxes.Util.Functions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("kydldev")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CargoToGo")]
[assembly: AssemblyTitle("CargoToGo")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace CargoToGo;

internal static class AzuCompat
{
	public const string Guid = "Azumatt.AzuCraftyBoxes";

	private static bool? _installed;

	public static bool Installed
	{
		get
		{
			if (!_installed.HasValue)
			{
				_installed = Chainloader.PluginInfos.ContainsKey("Azumatt.AzuCraftyBoxes");
			}
			return _installed.Value;
		}
	}

	public static bool Active
	{
		get
		{
			if (Installed)
			{
				return CargoToGoPlugin.UseAzuCraftyBoxes.Value;
			}
			return false;
		}
	}
}
internal static class AzuBridge
{
	private sealed class AzuSource : Source
	{
		private readonly object _box;

		public override SourceKind Kind => SourceKind.Azu;

		public AzuSource(object container)
		{
			_box = container;
		}

		public override int Count(string sharedName, string itemPrefab)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			try
			{
				IContainer val = (IContainer)_box;
				string prefabName = val.GetPrefabName();
				if (string.IsNullOrWhiteSpace(prefabName))
				{
					return 0;
				}
				if (!API.CanItemBePulled(prefabName, itemPrefab))
				{
					return 0;
				}
				return Mathf.Max(0, LeaveOne(val.ItemCount(sharedName)));
			}
			catch (Exception ex)
			{
				Log.Debug("Counting in an AzuCraftyBoxes container failed: " + ex.GetType().Name + ": " + ex.Message);
				return 0;
			}
		}

		public override int Take(string sharedName, string itemPrefab, int amount)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			try
			{
				IContainer val = (IContainer)_box;
				int num = Mathf.Min(amount, Count(sharedName, itemPrefab));
				if (num <= 0)
				{
					return 0;
				}
				ClaimOwnership(val);
				return Mathf.Clamp(val.ProcessContainerInventory(sharedName, 0, num), 0, num);
			}
			catch (Exception e)
			{
				Log.Error("Taking items from an AzuCraftyBoxes container failed", e);
				return 0;
			}
		}
	}

	private static bool _resolved;

	private static bool _lookupFailureLogged;

	private static Func<bool> _shouldPrevent;

	private static Func<int, int> _leaveOne;

	public static List<Source> Collect(Player p, HashSet<Inventory> alreadyCovered)
	{
		List<Source> list = new List<Source>();
		try
		{
			if ((Object)(object)p == (Object)null || Prevented(p))
			{
				return list;
			}
			List<IContainer> nearbyContainers = API.GetNearbyContainers<Player>(p, AzuCraftyBoxesPlugin.mRange.Value);
			if (nearbyContainers == null)
			{
				return list;
			}
			foreach (IContainer item in nearbyContainers)
			{
				if (item != null)
				{
					Inventory inventory = item.GetInventory();
					if (inventory == null || !alreadyCovered.Contains(inventory))
					{
						list.Add(new AzuSource(item));
					}
				}
			}
		}
		catch (Exception e)
		{
			if (!_lookupFailureLogged)
			{
				_lookupFailureLogged = true;
				Log.Error("AzuCraftyBoxes lookup failed, continuing without it (logged once)", e);
			}
		}
		return list;
	}

	private static void Resolve()
	{
		if (_resolved)
		{
			return;
		}
		_resolved = true;
		try
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(MiscFunctions), "ShouldPrevent", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				_shouldPrevent = (Func<bool>)Delegate.CreateDelegate(typeof(Func<bool>), methodInfo);
			}
			MethodInfo methodInfo2 = AccessTools.Method(typeof(Boxes), "CheckAndDecrement", new Type[1] { typeof(int) }, (Type[])null);
			if (methodInfo2 != null)
			{
				_leaveOne = (Func<int, int>)Delegate.CreateDelegate(typeof(Func<int, int>), methodInfo2);
			}
		}
		catch (Exception ex)
		{
			Log.Warn("Could not hook AzuCraftyBoxes internals, using fallbacks: " + ex.GetType().Name + ": " + ex.Message);
		}
		Log.Info("AzuCraftyBoxes integration ready (pull gate: " + ((_shouldPrevent != null) ? "Azu ShouldPrevent" : "IsPullingAllowed fallback") + ", leave-one rule: " + ((_leaveOne != null) ? "mirrored" : "not available") + ").");
	}

	private static bool Prevented(Player p)
	{
		Resolve();
		try
		{
			if (_shouldPrevent != null)
			{
				return _shouldPrevent();
			}
			return !PlayerPullingExtensions.IsPullingAllowed(p);
		}
		catch (Exception ex)
		{
			Log.Debug("Azu pull gate check failed, treating as 'prevented': " + ex.GetType().Name + ": " + ex.Message);
			return true;
		}
	}

	private static int LeaveOne(int count)
	{
		Resolve();
		if (_leaveOne == null)
		{
			return count;
		}
		return _leaveOne(count);
	}

	private static void ClaimOwnership(IContainer c)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		if (!(c is VanillaContainer))
		{
			return;
		}
		try
		{
			Inventory inventory = c.GetInventory();
			if (inventory == null)
			{
				return;
			}
			Collider[] array = Physics.OverlapSphere(c.GetPosition(), 3f);
			for (int i = 0; i < array.Length; i++)
			{
				Container componentInParent = ((Component)array[i]).GetComponentInParent<Container>();
				if (!((Object)(object)componentInParent == (Object)null) && componentInParent.GetInventory() == inventory)
				{
					ZNetView component = ((Component)componentInParent).GetComponent<ZNetView>();
					if ((Object)(object)component != (Object)null && component.IsValid())
					{
						component.ClaimOwnership();
					}
					return;
				}
			}
			Log.Debug("Could not locate the chest at " + ((object)c.GetPosition()/*cast due to .constrained prefix*/).ToString() + " to claim ownership.");
		}
		catch (Exception ex)
		{
			Log.Debug("Claiming ownership of an AzuCraftyBoxes chest failed: " + ex.GetType().Name + ": " + ex.Message);
		}
	}
}
internal static class CargoFactory
{
	public const string PrefabPrefix = "CC_Cargo_";

	public const string NamePrefix = "Cargo: ";

	private static GameObject _holder;

	private static int RestrictedCount;

	private static GameObject Holder()
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		if ((Object)(object)_holder == (Object)null)
		{
			_holder = new GameObject("CargoToGoPrefabs");
			_holder.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)_holder);
		}
		return _holder;
	}

	public static void Ensure(ObjectDB db)
	{
		if ((Object)(object)db == (Object)null || db.m_items == null || db.m_items.Count == 0)
		{
			return;
		}
		HashSet<string> hashSet = new HashSet<string>();
		Dictionary<string, GameObject> dictionary = new Dictionary<string, GameObject>();
		GameObject val = null;
		GameObject val2 = null;
		foreach (GameObject item in db.m_items)
		{
			if (!((Object)(object)item == (Object)null))
			{
				hashSet.Add(((Object)item).name);
				if (((Object)item).name == "CargoCrate")
				{
					val = item;
				}
				else if (((Object)item).name == "Stone")
				{
					val2 = item;
				}
				else if (((Object)item).name.StartsWith("CC_Cargo_"))
				{
					dictionary[((Object)item).name] = item;
				}
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			val = val2;
		}
		if ((Object)(object)val == (Object)null)
		{
			Log.Error("Neither 'CargoCrate' nor 'Stone' found in ObjectDB; no cargo items were registered.");
			return;
		}
		if (((Object)val).name != "CargoCrate")
		{
			Log.Warn("Prefab 'CargoCrate' not found, using '" + ((Object)val).name + "' as the cargo base.");
		}
		int num = 0;
		RestrictedCount = 0;
		GameObject[] array = db.m_items.ToArray();
		foreach (GameObject val3 in array)
		{
			ItemDrop val4 = (((Object)(object)val3 != (Object)null) ? val3.GetComponent<ItemDrop>() : null);
			PieceTable val5 = (((Object)(object)val4 != (Object)null) ? val4.m_itemData.m_shared.m_buildPieces : null);
			if ((Object)(object)val5 == (Object)null || val5.m_pieces == null)
			{
				continue;
			}
			foreach (GameObject piece in val5.m_pieces)
			{
				Piece val6 = (((Object)(object)piece != (Object)null) ? piece.GetComponent<Piece>() : null);
				if ((Object)(object)val6 == (Object)null || (Object)(object)val6.m_icon == (Object)null || val6.m_resources == null || val6.m_resources.Length == 0)
				{
					continue;
				}
				string prefabName = Utils.GetPrefabName(piece);
				string text = "CC_Cargo_" + prefabName;
				if (!hashSet.Add(text))
				{
					if (dictionary.TryGetValue(text, out var value))
					{
						ItemDrop component = value.GetComponent<ItemDrop>();
						if ((Object)(object)component != (Object)null)
						{
							component.m_itemData.m_shared.m_teleportable = ContentsTeleportable(val6, out var _);
						}
					}
					continue;
				}
				try
				{
					if (Create(db, val, text, val6))
					{
						num++;
					}
				}
				catch (Exception e)
				{
					Log.Error("Failed to create cargo '" + text + "'", e);
				}
			}
		}
		if (num > 0)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Log.Error("ObjectDB.UpdateRegisters not found; new cargo items may not be resolvable.");
			}
			else
			{
				methodInfo.Invoke(db, null);
			}
			Log.Info("Registered " + num + " new cargo items in ObjectDB (cloned from '" + ((Object)val).name + "'); " + RestrictedCount + " of them contain materials that can't pass through portals.");
		}
	}

	private static bool Create(ObjectDB db, GameObject basePrefab, string cname, Piece piece)
	{
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Object.Instantiate<GameObject>(basePrefab, Holder().transform);
		((Object)val).name = cname;
		ItemDrop component = val.GetComponent<ItemDrop>();
		if ((Object)(object)component == (Object)null)
		{
			Log.Warn("Base prefab has no ItemDrop; skipped '" + cname + "'");
			Object.Destroy((Object)(object)val);
			return false;
		}
		SharedData shared = component.m_itemData.m_shared;
		StringBuilder stringBuilder = new StringBuilder("Sealed materials for building this piece. They can only be used for that.\nCtrl+Alt+Right-click destroys the cargo and returns the materials.\n");
		float num = 0f;
		Requirement[] resources = piece.m_resources;
		foreach (Requirement val2 in resources)
		{
			if (!((Object)(object)val2.m_resItem == (Object)null) && val2.m_amount > 0)
			{
				num += (float)val2.m_amount * val2.m_resItem.m_itemData.m_shared.m_weight;
				stringBuilder.Append("\n").Append(val2.m_amount).Append("x ")
					.Append(val2.m_resItem.m_itemData.m_shared.m_name);
			}
		}
		string blocker;
		bool flag = ContentsTeleportable(piece, out blocker);
		if (!flag)
		{
			stringBuilder.Append("\n\nContains materials that can't pass through portals (unless the world's portal rules allow everything).");
			RestrictedCount++;
			Log.Debug("Cargo '" + cname + "' is portal-restricted: contains '" + blocker + "'.");
		}
		shared.m_name = "Cargo: " + piece.m_name;
		shared.m_description = stringBuilder.ToString();
		shared.m_itemType = (ItemType)1;
		shared.m_icons = (Sprite[])(object)new Sprite[1] { piece.m_icon };
		shared.m_variants = 0;
		shared.m_maxStackSize = 1;
		shared.m_autoStack = false;
		shared.m_maxQuality = 1;
		shared.m_weight = num * CargoToGoPlugin.WeightMultiplier.Value;
		shared.m_teleportable = flag;
		shared.m_questItem = false;
		shared.m_dlc = "";
		shared.m_value = 0;
		shared.m_equipStatusEffect = null;
		shared.m_movementModifier = 0f;
		shared.m_useDurability = false;
		shared.m_canBeReparied = false;
		component.m_itemData.m_dropPrefab = val;
		db.m_items.Add(val);
		return true;
	}

	public static bool ContentsTeleportable(Piece piece, out string blocker)
	{
		blocker = null;
		if ((Object)(object)piece == (Object)null || piece.m_resources == null)
		{
			blocker = "(unknown contents)";
			return false;
		}
		Requirement[] resources = piece.m_resources;
		foreach (Requirement val in resources)
		{
			if (!((Object)(object)val.m_resItem == (Object)null) && val.m_amount > 0)
			{
				SharedData shared = val.m_resItem.m_itemData.m_shared;
				if (!shared.m_teleportable)
				{
					blocker = shared.m_name;
					return false;
				}
			}
		}
		return true;
	}

	public static void RefreshTeleportable(ItemData cargo)
	{
		string blocker;
		bool flag = ContentsTeleportable(PrefabPieceOf(cargo), out blocker);
		if (cargo.m_shared.m_teleportable != flag)
		{
			Log.Debug("Cargo '" + ((Object)cargo.m_dropPrefab).name + "' teleportable " + cargo.m_shared.m_teleportable + " -> " + flag + (flag ? "" : (" (contains '" + blocker + "')")));
		}
		cargo.m_shared.m_teleportable = flag;
	}

	public static bool IsCargo(ItemData item)
	{
		if (item != null && (Object)(object)item.m_dropPrefab != (Object)null)
		{
			return ((Object)item.m_dropPrefab).name.StartsWith("CC_Cargo_");
		}
		return false;
	}

	public static string PieceNameOf(ItemData item)
	{
		return ((Object)item.m_dropPrefab).name.Substring("CC_Cargo_".Length);
	}

	public static GameObject GetCargoPrefab(Piece piece)
	{
		if ((Object)(object)piece == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
		{
			return null;
		}
		return ObjectDB.instance.GetItemPrefab("CC_Cargo_" + Utils.GetPrefabName(((Component)piece).gameObject));
	}

	public static ItemData FindCargoFor(Inventory inv, Piece piece)
	{
		if (inv == null || (Object)(object)piece == (Object)null)
		{
			return null;
		}
		string text = "CC_Cargo_" + Utils.GetPrefabName(((Component)piece).gameObject);
		foreach (ItemData allItem in inv.GetAllItems())
		{
			if ((Object)(object)allItem.m_dropPrefab != (Object)null && ((Object)allItem.m_dropPrefab).name == text)
			{
				return allItem;
			}
		}
		return null;
	}

	public static Piece PrefabPieceOf(ItemData cargo)
	{
		GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(PieceNameOf(cargo)) : null);
		if (!((Object)(object)val != (Object)null))
		{
			return null;
		}
		return val.GetComponent<Piece>();
	}
}
internal enum SourceKind
{
	Inventory,
	Chest,
	Azu
}
internal abstract class Source
{
	public abstract SourceKind Kind { get; }

	public abstract int Count(string sharedName, string itemPrefab);

	public abstract int Take(string sharedName, string itemPrefab, int amount);
}
internal sealed class InventorySource : Source
{
	private readonly Inventory _inv;

	private readonly Container _cont;

	public override SourceKind Kind
	{
		get
		{
			if (!((Object)(object)_cont != (Object)null))
			{
				return SourceKind.Inventory;
			}
			return SourceKind.Chest;
		}
	}

	public InventorySource(Inventory inv, Container cont)
	{
		_inv = inv;
		_cont = cont;
	}

	public override int Count(string sharedName, string itemPrefab)
	{
		return _inv.CountItems(sharedName, -1, true);
	}

	public override int Take(string sharedName, string itemPrefab, int amount)
	{
		int num = Mathf.Min(amount, _inv.CountItems(sharedName, -1, true));
		if (num <= 0)
		{
			return 0;
		}
		if ((Object)(object)_cont != (Object)null)
		{
			((Component)_cont).GetComponent<ZNetView>().ClaimOwnership();
		}
		_inv.RemoveItem(sharedName, num, -1, true);
		return num;
	}
}
internal sealed class CargoPieceList : IPieceList
{
	public string DisplayName => "Cargos";

	public bool ShowTags => false;

	public bool CanCustomizeTags => false;

	public int TagCount => 0;

	public int TagSeparatorIndex => -1;

	public string GetTagDisplayName(int index)
	{
		return "";
	}

	public int GetTagIdByIndex(int index)
	{
		return -1;
	}

	public void UpdateAvailableTags(PieceTable pieceTable)
	{
	}

	public void GetAvailablePiecesWithTag(int tagId, PieceTable pieceTable, IList<Piece> resultOut)
	{
		try
		{
			Player localPlayer = Player.m_localPlayer;
			List<string> list = CargoTab.CargoPieceNames(((Object)(object)localPlayer != (Object)null) ? ((Humanoid)localPlayer).GetInventory() : null);
			CargoTab.LastSignature = CargoTab.Signature(list);
			if (list.Count == 0 || (Object)(object)pieceTable == (Object)null || pieceTable.m_pieces == null || pieceTable.m_availablePieces == null)
			{
				return;
			}
			foreach (GameObject piece in pieceTable.m_pieces)
			{
				if (!((Object)(object)piece == (Object)null))
				{
					Piece component = piece.GetComponent<Piece>();
					if (!((Object)(object)component == (Object)null) && pieceTable.m_availablePieces.Contains(component) && list.Contains(Utils.GetPrefabName(piece)))
					{
						resultOut.Add(component);
					}
				}
			}
			Log.Debug("Cargos tab: " + resultOut.Count + " piece(s) listed for " + list.Count + " distinct cargo type(s) in the inventory.");
		}
		catch (Exception e)
		{
			Log.Error("CargoPieceList.GetAvailablePiecesWithTag failed", e);
		}
	}
}
internal static class CargoTab
{
	public const string TabLabel = "Cargos";

	public static string LastSignature = "";

	private static readonly FieldInfo F_Lists = AccessTools.Field(typeof(BuildUi), "m_pieceLists");

	private static readonly FieldInfo F_TabButtons = AccessTools.Field(typeof(BuildUi), "m_tabButtons");

	private static readonly FieldInfo F_TabContainer = AccessTools.Field(typeof(BuildUi), "m_tabContainer");

	private static readonly FieldInfo F_TabHandler = AccessTools.Field(typeof(BuildUi), "m_tabHandler");

	private static readonly FieldInfo F_CurrentList = AccessTools.Field(typeof(BuildUi), "m_currentPieceList");

	private static readonly MethodInfo M_SelectPieceList = AccessTools.Method(typeof(BuildUi), "SelectPieceList", (Type[])null, (Type[])null);

	private static readonly MethodInfo M_UpdatePieceButtons = AccessTools.Method(typeof(BuildUi), "UpdatePieceButtons", (Type[])null, (Type[])null);

	private static int _index = -1;

	private static BuildUi _installedOn;

	private static float _nextPoll;

	public static List<string> CargoPieceNames(Inventory inv)
	{
		List<string> list = new List<string>();
		if (inv == null)
		{
			return list;
		}
		foreach (ItemData allItem in inv.GetAllItems())
		{
			if (CargoFactory.IsCargo(allItem))
			{
				string item = CargoFactory.PieceNameOf(allItem);
				if (!list.Contains(item))
				{
					list.Add(item);
				}
			}
		}
		return list;
	}

	public static string Signature(List<string> names)
	{
		List<string> list = new List<string>(names);
		list.Sort(StringComparer.Ordinal);
		return string.Join("|", list.ToArray());
	}

	public static void Install(BuildUi ui)
	{
		//IL_033a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0344: Expected O, but got Unknown
		//IL_0357: Unknown result type (might be due to invalid IL or missing references)
		//IL_035e: Expected O, but got Unknown
		_index = -1;
		_installedOn = null;
		if (!CargoToGoPlugin.ShowCargoTab.Value)
		{
			Log.Info("Cargos tab disabled in the config.");
			return;
		}
		if (F_Lists == null || F_TabButtons == null || F_TabContainer == null || F_TabHandler == null || M_SelectPieceList == null || M_UpdatePieceButtons == null)
		{
			Log.Error("Cargos tab: BuildUi has changed (a field or method was not found); the tab was not added. Game version incompatible?");
			return;
		}
		List<IPieceList> list = F_Lists.GetValue(ui) as List<IPieceList>;
		List<Button> list2 = F_TabButtons.GetValue(ui) as List<Button>;
		object? value = F_TabContainer.GetValue(ui);
		RectTransform val = (RectTransform)((value is RectTransform) ? value : null);
		object? value2 = F_TabHandler.GetValue(ui);
		TabHandler val2 = (TabHandler)((value2 is TabHandler) ? value2 : null);
		if (list == null || list2 == null || (Object)(object)val == (Object)null || list2.Count == 0)
		{
			Log.Error("Cargos tab: build menu structure not as expected (lists=" + (list != null) + ", buttons=" + (list2?.Count ?? (-1)) + ", container=" + ((Object)(object)val != (Object)null) + "); the tab was not added.");
			return;
		}
		foreach (IPieceList item in list)
		{
			if (item is CargoPieceList)
			{
				Log.Debug("Cargos tab already installed.");
				return;
			}
		}
		if (list2.Count != list.Count)
		{
			Log.Warn("Cargos tab: " + list2.Count + " tab buttons but " + list.Count + " piece lists; the tab was not added to keep indices aligned.");
			return;
		}
		GameObject val3 = Object.Instantiate<GameObject>(((Component)list2[list2.Count - 1]).gameObject, (Transform)(object)val);
		((Object)val3).name = "CargoToGoTab";
		Button component = val3.GetComponent<Button>();
		if ((Object)(object)component == (Object)null)
		{
			Log.Error("Cargos tab: cloned tab has no Button; aborting.");
			Object.Destroy((Object)(object)val3);
			return;
		}
		Localize[] componentsInChildren = val3.GetComponentsInChildren<Localize>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
		}
		TMP_Text[] componentsInChildren2 = val3.GetComponentsInChildren<TMP_Text>(true);
		for (int i = 0; i < componentsInChildren2.Length; i++)
		{
			componentsInChildren2[i].text = "Cargos";
		}
		Text[] componentsInChildren3 = val3.GetComponentsInChildren<Text>(true);
		for (int i = 0; i < componentsInChildren3.Length; i++)
		{
			componentsInChildren3[i].text = "Cargos";
		}
		Transform val4 = val3.transform.Find("Selected");
		if ((Object)(object)val4 != (Object)null)
		{
			((Component)val4).gameObject.SetActive(false);
		}
		((Selectable)component).interactable = true;
		((UnityEventBase)component.onClick).RemoveAllListeners();
		int count = list.Count;
		list.Add((IPieceList)(object)new CargoPieceList());
		list2.Add(component);
		int idx = count;
		((UnityEvent)component.onClick).AddListener((UnityAction)delegate
		{
			M_SelectPieceList.Invoke(ui, new object[2] { idx, false });
		});
		if ((Object)(object)val2 != (Object)null && val2.m_tabs != null)
		{
			Tab val5 = new Tab();
			val5.m_button = component;
			val5.m_default = false;
			val5.m_page = null;
			val5.m_onClick = null;
			val2.m_tabs.Add(val5);
		}
		else
		{
			Log.Warn("Cargos tab: no TabHandler found; the tab works with the mouse but Q/E cycling and highlight may not.");
		}
		_index = count;
		_installedOn = ui;
		ReLayout(val);
		Log.Info("Cargos tab added to the build menu (tab index " + count + ", " + ((Transform)val).childCount + " tabs).");
	}

	private unsafe static void ReLayout(RectTransform container)
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Expected O, but got Unknown
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0170: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_0199: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d6: Invalid comparison between Unknown and I4
		//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0206: Unknown result type (might be due to invalid IL or missing references)
		//IL_020b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0316: Unknown result type (might be due to invalid IL or missing references)
		//IL_031b: 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_0337: Unknown result type (might be due to invalid IL or missing references)
		//IL_0369: Unknown result type (might be due to invalid IL or missing references)
		//IL_036e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0379: Unknown result type (might be due to invalid IL or missing references)
		//IL_038a: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			List<RectTransform> list = new List<RectTransform>();
			foreach (Transform item in (Transform)container)
			{
				object obj = (object)item;
				RectTransform val = (RectTransform)((obj is RectTransform) ? obj : null);
				if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf)
				{
					list.Add(val);
				}
			}
			int count = list.Count;
			if (count < 2)
			{
				return;
			}
			GridLayoutGroup component = ((Component)container).GetComponent<GridLayoutGroup>();
			HorizontalLayoutGroup component2 = ((Component)container).GetComponent<HorizontalLayoutGroup>();
			LayoutGroup component3 = ((Component)container).GetComponent<LayoutGroup>();
			string[] obj2 = new string[10]
			{
				"Tab container '",
				((Object)container).name,
				"': rect=",
				null,
				null,
				null,
				null,
				null,
				null,
				null
			};
			Rect rect = container.rect;
			obj2[3] = ((object)(*(Rect*)(&rect))/*cast due to .constrained prefix*/).ToString();
			obj2[4] = " HLG=";
			obj2[5] = ((Object)(object)component2 != (Object)null).ToString();
			obj2[6] = " Grid=";
			obj2[7] = ((Object)(object)component != (Object)null).ToString();
			obj2[8] = " otherLayout=";
			obj2[9] = ((Object)(object)component3 != (Object)null && (Object)(object)component2 == (Object)null && (Object)(object)component == (Object)null).ToString();
			Log.Debug(string.Concat(obj2));
			if ((Object)(object)component != (Object)null)
			{
				rect = container.rect;
				float num = ((Rect)(ref rect)).width - (float)((LayoutGroup)component).padding.left - (float)((LayoutGroup)component).padding.right - component.spacing.x * (float)(count - 1);
				if (num > 0f)
				{
					component.cellSize = new Vector2(num / (float)count, component.cellSize.y);
				}
				if ((int)component.constraint == 1)
				{
					component.constraintCount = count;
				}
			}
			else if ((Object)(object)component2 != (Object)null)
			{
				if (!((HorizontalOrVerticalLayoutGroup)component2).childControlWidth)
				{
					rect = container.rect;
					float num2 = ((Rect)(ref rect)).width - (float)((LayoutGroup)component2).padding.left - (float)((LayoutGroup)component2).padding.right - ((HorizontalOrVerticalLayoutGroup)component2).spacing * (float)(count - 1);
					if (num2 > 0f)
					{
						foreach (RectTransform item2 in list)
						{
							item2.SetSizeWithCurrentAnchors((Axis)0, num2 / (float)count);
						}
					}
				}
			}
			else if ((Object)(object)component3 == (Object)null)
			{
				list.Sort((RectTransform a, RectTransform b) => LocalLeft(container, a).CompareTo(LocalLeft(container, b)));
				RectTransform val2 = list.Find((RectTransform r) => ((Object)((Component)r).gameObject).name == "CargoToGoTab");
				if ((Object)(object)val2 != (Object)null)
				{
					list.Remove(val2);
					list.Add(val2);
				}
				RectTransform val3 = list[0];
				RectTransform val4 = list[count - 2];
				float num3 = LocalLeft(container, val3);
				float num4 = LocalLeft(container, val4);
				rect = val4.rect;
				float num5 = num4 + ((Rect)(ref rect)).width * ((Transform)val4).lossyScale.x / ((Transform)container).lossyScale.x;
				float num6;
				if (count <= 2)
				{
					num6 = 0f;
				}
				else
				{
					float num7 = LocalLeft(container, list[1]);
					rect = val3.rect;
					num6 = Mathf.Max(0f, num7 - (num3 + ((Rect)(ref rect)).width * ((Transform)val3).lossyScale.x / ((Transform)container).lossyScale.x));
				}
				float num8 = num6;
				float num9 = (num5 - num3 - num8 * (float)(count - 1)) / (float)count;
				if (num9 <= 1f)
				{
					Log.Warn("Cargos tab: computed tab width " + num9 + " is too small; layout left unchanged.");
					return;
				}
				for (int num10 = 0; num10 < count; num10++)
				{
					list[num10].SetInsetAndSizeFromParentEdge((Edge)0, num3 + (float)num10 * (num9 + num8), num9);
				}
			}
			LayoutRebuilder.ForceRebuildLayoutImmediate(container);
		}
		catch (Exception ex)
		{
			Log.Warn("Cargos tab: re-layout failed (the tab still exists): " + ex.GetType().Name + ": " + ex.Message);
		}
	}

	private static float LocalLeft(RectTransform container, RectTransform rt)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		Vector3[] array = (Vector3[])(object)new Vector3[4];
		rt.GetWorldCorners(array);
		float x = ((Transform)container).InverseTransformPoint(array[0]).x;
		Rect rect = container.rect;
		return x - ((Rect)(ref rect)).xMin;
	}

	public static void Tick(BuildUi ui)
	{
		if (_index < 0 || (Object)(object)ui == (Object)null || (Object)(object)_installedOn != (Object)(object)ui || Time.unscaledTime < _nextPoll)
		{
			return;
		}
		_nextPoll = Time.unscaledTime + 0.2f;
		try
		{
			if (F_CurrentList == null || Convert.ToInt32(F_CurrentList.GetValue(ui)) != _index)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				string text = Signature(CargoPieceNames(((Humanoid)localPlayer).GetInventory()));
				if (!(text == LastSignature))
				{
					Log.Debug("Cargos tab: inventory cargos changed ('" + LastSignature + "' -> '" + text + "'), rebuilding the grid.");
					LastSignature = text;
					M_UpdatePieceButtons.Invoke(ui, null);
				}
			}
		}
		catch (Exception e)
		{
			Log.Error("Cargos tab refresh failed", e);
		}
	}
}
[HarmonyPatch(typeof(BuildUi), "Awake")]
internal static class BuildUi_Awake
{
	private static void Postfix(BuildUi __instance)
	{
		try
		{
			CargoTab.Install(__instance);
		}
		catch (Exception e)
		{
			Log.Error("Adding the Cargos tab failed; the build menu keeps its 4 vanilla tabs", e);
		}
	}
}
[HarmonyPatch(typeof(BuildUi), "Update")]
internal static class BuildUi_Update
{
	private static void Postfix(BuildUi __instance)
	{
		CargoTab.Tick(__instance);
	}
}
internal static class KeyHintUi
{
	private static KeyHints _builtFor;

	private static GameObject _row;

	private static GameObject _packHint;

	private static GameObject _repackHint;

	private static TMP_Text _packKey;

	private static TMP_Text _repackKey;

	private static bool _disabled;

	private static int _lastRefresh;

	public static void Tick(KeyHints kh)
	{
		if (_disabled || (Object)(object)kh == (Object)null)
		{
			return;
		}
		try
		{
			GameObject buildHints = kh.m_buildHints;
			if ((Object)(object)buildHints == (Object)null)
			{
				return;
			}
			bool flag = CargoToGoPlugin.ShowKeyHints.Value && buildHints.activeInHierarchy && !ZInput.IsGamepadActive();
			if ((Object)(object)_row == (Object)null || (Object)(object)_builtFor != (Object)(object)kh)
			{
				if (!flag)
				{
					return;
				}
				if ((Object)(object)_row != (Object)null)
				{
					Object.Destroy((Object)(object)_row);
				}
				if (!Build(kh))
				{
					_disabled = true;
					return;
				}
			}
			if (_row.activeSelf != flag)
			{
				_row.SetActive(flag);
			}
			if (flag)
			{
				_packHint.SetActive(CargoToGoPlugin.PackInWorld.Value);
				Position(buildHints);
				if (Time.frameCount - _lastRefresh > 60)
				{
					_lastRefresh = Time.frameCount;
					RefreshKeys();
				}
			}
		}
		catch (Exception e)
		{
			_disabled = true;
			Log.Error("Key hint bar extension failed and was disabled for this session", e);
		}
	}

	private static bool Build(KeyHints kh)
	{
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_024f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0259: Expected O, but got Unknown
		//IL_0273: Unknown result type (might be due to invalid IL or missing references)
		//IL_0278: Unknown result type (might be due to invalid IL or missing references)
		//IL_0281: Unknown result type (might be due to invalid IL or missing references)
		//IL_0282: Unknown result type (might be due to invalid IL or missing references)
		//IL_0294: Unknown result type (might be due to invalid IL or missing references)
		//IL_029b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
		GameObject buildHints = kh.m_buildHints;
		TMP_Text val = null;
		TMP_Text val2 = null;
		Transform val3 = FindHintRoot(buildHints.transform);
		if ((Object)(object)val3 != (Object)null)
		{
			List<TMP_Text> list = new List<TMP_Text>(((Component)val3).GetComponentsInChildren<TMP_Text>(false));
			if (list.Count != 2)
			{
				list = new List<TMP_Text>(((Component)val3).GetComponentsInChildren<TMP_Text>(true));
			}
			if (list.Count >= 2)
			{
				val = list[0];
				val2 = list[1];
				if (list[0].transform.position.x > list[1].transform.position.x + 1f)
				{
					val = list[1];
					val2 = list[0];
				}
			}
		}
		if ((Object)(object)val == (Object)null)
		{
			TMP_Text[] componentsInChildren = buildHints.GetComponentsInChildren<TMP_Text>(true);
			if (componentsInChildren.Length == 0)
			{
				Log.Warn("Key hint bar: no TextMeshPro text found under the build hints; hints not added.");
				return false;
			}
			val = (val2 = componentsInChildren[0]);
		}
		float num = EffectiveSize(val);
		float num2 = EffectiveSize(val2);
		if (num < num2 * 0.6f)
		{
			num = num2;
		}
		if (num2 < num * 0.6f)
		{
			num2 = num;
		}
		Log.Debug("Key hint font sizes: label " + num + " (property " + val.fontSize + ", autosize " + val.enableAutoSizing + "), key " + num2 + " (property " + val2.fontSize + ", autosize " + val2.enableAutoSizing + ")");
		Image val4 = null;
		Transform val5 = val2.transform;
		while ((Object)(object)val5 != (Object)null && (Object)(object)val5 != (Object)(object)buildHints.transform)
		{
			Image component = ((Component)val5).GetComponent<Image>();
			if ((Object)(object)component != (Object)null)
			{
				val4 = component;
				break;
			}
			val5 = val5.parent;
		}
		if (Log.Verbose)
		{
			DumpHierarchy(buildHints.transform, val3, val, val2, val4);
		}
		Canvas componentInParent = buildHints.GetComponentInParent<Canvas>();
		Transform val6 = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent).transform : buildHints.transform.parent);
		_row = new GameObject("CargoToGoHints", new Type[1] { typeof(RectTransform) });
		_row.layer = buildHints.layer;
		RectTransform val7 = (RectTransform)_row.transform;
		((Transform)val7).SetParent(val6, false);
		Vector2 val8 = default(Vector2);
		((Vector2)(ref val8))..ctor(0.5f, 0.5f);
		val7.anchorMax = val8;
		val7.anchorMin = val8;
		val7.pivot = new Vector2(0.5f, 0f);
		HorizontalLayoutGroup obj = _row.AddComponent<HorizontalLayoutGroup>();
		((HorizontalOrVerticalLayoutGroup)obj).spacing = 45f;
		((LayoutGroup)obj).childAlignment = (TextAnchor)4;
		bool childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true);
		((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = childControlWidth;
		childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false);
		((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = childControlWidth;
		ContentSizeFitter obj2 = _row.AddComponent<ContentSizeFitter>();
		obj2.horizontalFit = (FitMode)2;
		obj2.verticalFit = (FitMode)2;
		_packHint = AddHint("Pack", val, val2, num, num2, val4, "Pack cargo", PackKeys(), out _packKey);
		_repackHint = AddHint("Repack", val, val2, num, num2, val4, "Repack", RepackKeys(), out _repackKey);
		_builtFor = kh;
		Log.Info("Key hint bar: added Pack/Repack hints (font " + num + "/" + num2 + ")" + (((Object)(object)val3 != (Object)null) ? (" (style copied from '" + ((Object)val3).name + "').") : " (no template hint found, used first text style)."));
		return true;
	}

	private static Transform FindHintRoot(Transform root)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Expected O, but got Unknown
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Expected O, but got Unknown
		List<Transform> list = new List<Transform>();
		foreach (Transform item3 in root)
		{
			Transform item = item3;
			list.Add(item);
		}
		for (int i = 0; i < list.Count; i++)
		{
			Transform val = list[i];
			if (!((Component)val).gameObject.activeInHierarchy)
			{
				continue;
			}
			if (((Component)val).GetComponentsInChildren<TMP_Text>(false).Length == 2)
			{
				return val;
			}
			foreach (Transform item4 in val)
			{
				Transform item2 = item4;
				list.Add(item2);
			}
		}
		return null;
	}

	private static GameObject AddHint(string name, TMP_Text labelStyle, TMP_Text keyStyle, float labelSize, float keySize, Image chipImg, string labelText, string keyText, out TMP_Text keyOut)
	{
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = NewObj("Hint_" + name, _row.transform);
		HorizontalLayoutGroup obj = val.AddComponent<HorizontalLayoutGroup>();
		((HorizontalOrVerticalLayoutGroup)obj).spacing = 10f;
		((LayoutGroup)obj).childAlignment = (TextAnchor)4;
		bool childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true);
		((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = childControlWidth;
		childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false);
		((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = childControlWidth;
		NewText("Label", val.transform, labelStyle, labelSize).text = labelText;
		GameObject val2 = NewObj("Chip", val.transform);
		if ((Object)(object)chipImg != (Object)null)
		{
			Image obj2 = val2.AddComponent<Image>();
			obj2.sprite = chipImg.sprite;
			obj2.type = chipImg.type;
			((Graphic)obj2).color = ((Graphic)chipImg).color;
			((Graphic)obj2).raycastTarget = false;
		}
		HorizontalLayoutGroup obj3 = val2.AddComponent<HorizontalLayoutGroup>();
		((HorizontalOrVerticalLayoutGroup)obj3).spacing = 0f;
		((LayoutGroup)obj3).childAlignment = (TextAnchor)4;
		childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj3).childControlHeight = true);
		((HorizontalOrVerticalLayoutGroup)obj3).childControlWidth = childControlWidth;
		childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandHeight = false);
		((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandWidth = childControlWidth;
		Spacer(val2.transform, 12f);
		TMP_Text val3 = NewText("Key", val2.transform, keyStyle, keySize);
		val3.text = keyText;
		((Component)val3).gameObject.AddComponent<LayoutElement>().minHeight = val3.preferredHeight + 12f;
		Spacer(val2.transform, 12f);
		keyOut = val3;
		return val;
	}

	private static float EffectiveSize(TMP_Text t)
	{
		try
		{
			t.ForceMeshUpdate(false, false);
			TMP_TextInfo textInfo = t.textInfo;
			if (textInfo != null && textInfo.characterCount > 0 && textInfo.characterInfo != null && textInfo.characterInfo.Length != 0 && textInfo.characterInfo[0].pointSize > 1f)
			{
				return textInfo.characterInfo[0].pointSize;
			}
		}
		catch (Exception ex)
		{
			Log.Debug("EffectiveSize failed: " + ex.Message);
		}
		if (!t.enableAutoSizing)
		{
			return t.fontSize;
		}
		return t.fontSizeMax;
	}

	private static GameObject NewObj(string name, Transform parent)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Expected O, but got Unknown
		GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) })
		{
			layer = _row.layer
		};
		val.transform.SetParent(parent, false);
		return val;
	}

	private static void Spacer(Transform parent, float width)
	{
		LayoutElement obj = NewObj("Spacer", parent).AddComponent<LayoutElement>();
		float minWidth = (obj.preferredWidth = width);
		obj.minWidth = minWidth;
	}

	private static TMP_Text NewText(string name, Transform parent, TMP_Text style, float size)
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		TextMeshProUGUI obj = NewObj(name, parent).AddComponent<TextMeshProUGUI>();
		((TMP_Text)obj).font = style.font;
		((TMP_Text)obj).fontSharedMaterial = style.fontSharedMaterial;
		((TMP_Text)obj).enableAutoSizing = false;
		((TMP_Text)obj).fontSize = size;
		((TMP_Text)obj).fontStyle = style.fontStyle;
		((Graphic)obj).color = ((Graphic)style).color;
		((TMP_Text)obj).alignment = (TextAlignmentOptions)514;
		((TMP_Text)obj).textWrappingMode = (TextWrappingModes)0;
		((TMP_Text)obj).overflowMode = (TextOverflowModes)0;
		((TMP_Text)obj).richText = false;
		((Graphic)obj).raycastTarget = false;
		return (TMP_Text)(object)obj;
	}

	private static void Position(GameObject buildHints)
	{
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_0104: Unknown result type (might be due to invalid IL or missing references)
		TMP_Text[] componentsInChildren = buildHints.GetComponentsInChildren<TMP_Text>(false);
		if (componentsInChildren.Length == 0)
		{
			return;
		}
		float num = float.MaxValue;
		float num2 = float.MinValue;
		float num3 = float.MaxValue;
		float num4 = float.MinValue;
		Vector3[] array = (Vector3[])(object)new Vector3[4];
		TMP_Text[] array2 = componentsInChildren;
		for (int i = 0; i < array2.Length; i++)
		{
			((RectTransform)array2[i].transform).GetWorldCorners(array);
			for (int j = 0; j < 4; j++)
			{
				num = Mathf.Min(num, array[j].x);
				num2 = Mathf.Max(num2, array[j].x);
				num3 = Mathf.Min(num3, array[j].y);
				num4 = Mathf.Max(num4, array[j].y);
			}
		}
		float num5 = Mathf.Max(10f, (num4 - num3) * 0.9f);
		_row.transform.position = new Vector3((num + num2) * 0.5f, num4 + num5, buildHints.transform.position.z);
	}

	private static string BoundKey(string action, string fallback)
	{
		try
		{
			ZInput instance = ZInput.instance;
			if (instance != null)
			{
				string boundKeyString = instance.GetBoundKeyString(action, true);
				if (!string.IsNullOrEmpty(boundKeyString))
				{
					boundKeyString = Localization.instance.Localize(boundKeyString);
					if (!string.IsNullOrEmpty(boundKeyString) && !boundKeyString.StartsWith("$") && !boundKeyString.StartsWith("["))
					{
						return boundKeyString;
					}
				}
			}
		}
		catch (Exception ex)
		{
			Log.Debug("BoundKey(" + action + ") failed: " + ex.Message);
		}
		return fallback;
	}

	private static string PackKeys()
	{
		return "Ctrl + Alt + " + BoundKey("Attack", "Mouse-1");
	}

	private static string RepackKeys()
	{
		return "Alt + " + BoundKey("Remove", "Mouse-3");
	}

	private static void RefreshKeys()
	{
		string text = PackKeys();
		if (_packKey.text != text)
		{
			_packKey.text = text;
		}
		string text2 = RepackKeys();
		if (_repackKey.text != text2)
		{
			_repackKey.text = text2;
		}
	}

	private static void DumpHierarchy(Transform root, Transform tpl, TMP_Text label, TMP_Text key, Image chip)
	{
		int lines = 0;
		Log.Debug("KeyHints dump: template=" + (((Object)(object)tpl != (Object)null) ? ((Object)tpl).name : "none") + " label=" + ((Object)label).name + " key=" + ((Object)key).name + " chipImage=" + (((Object)(object)chip != (Object)null) ? ((Object)chip).name : "none"));
		Walk(root, 0, ref lines);
	}

	private static void Walk(Transform t, int depth, ref int lines)
	{
		//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Expected O, but got Unknown
		if (lines++ > 150)
		{
			return;
		}
		TMP_Text component = ((Component)t).GetComponent<TMP_Text>();
		List<string> list = new List<string>();
		Component[] components = ((Component)t).GetComponents<Component>();
		foreach (Component val in components)
		{
			if ((Object)(object)val != (Object)null)
			{
				list.Add(((object)val).GetType().Name);
			}
		}
		Log.Debug("KeyHints dump: " + new string('.', depth) + ((Object)t).name + " active=" + ((Component)t).gameObject.activeSelf + " [" + string.Join(",", list.ToArray()) + "]" + (((Object)(object)component != (Object)null) ? (" text='" + component.text + "'") : ""));
		foreach (Transform item in t)
		{
			Walk(item, depth + 1, ref lines);
		}
	}
}
internal static class Log
{
	private static ManualLogSource _src;

	public static bool Verbose;

	public static void Init()
	{
		_src = Logger.CreateLogSource("CargoToGo");
	}

	private static string Fmt(string level, string text)
	{
		return DateTime.UtcNow.ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'") + "-CargoToGo-" + level + "-" + text;
	}

	public static void Info(string text)
	{
		if (_src != null)
		{
			_src.LogInfo((object)Fmt("INFO", text));
		}
	}

	public static void Warn(string text)
	{
		if (_src != null)
		{
			_src.LogWarning((object)Fmt("WARN", text));
		}
	}

	public static void Error(string text)
	{
		if (_src != null)
		{
			_src.LogError((object)Fmt("ERROR", text));
		}
	}

	public static void Error(string text, Exception e)
	{
		Error(text + " | " + e.GetType().Name + ": " + e.Message + " | " + (e.StackTrace ?? "").Replace("\n", " <- ").Replace("\r", ""));
	}

	public static void Debug(string text)
	{
		if (Verbose && _src != null)
		{
			_src.LogInfo((object)Fmt("DEBUG", text));
		}
	}
}
internal static class Packer
{
	public const string BuiltFromCargoKey = "CC_FromCargo";

	private static readonly MethodInfo CheckAccess = AccessTools.Method(typeof(Container), "CheckAccess", (Type[])null, (Type[])null);

	private static int _cacheFrame = -1;

	private static List<Container> _cache = new List<Container>();

	private static float _lastPack;

	private static int _sourcesFrame = -1;

	private static List<Source> _sourcesCache = new List<Source>();

	public static bool Alt
	{
		get
		{
			if (!ZInput.GetKey((KeyCode)308, false))
			{
				return ZInput.GetKey((KeyCode)307, false);
			}
			return true;
		}
	}

	public static bool Ctrl
	{
		get
		{
			if (!ZInput.GetKey((KeyCode)306, false))
			{
				return ZInput.GetKey((KeyCode)305, false);
			}
			return true;
		}
	}

	public static bool PackChord
	{
		get
		{
			if (Alt)
			{
				return Ctrl;
			}
			return false;
		}
	}

	public static void Say(Player p, string text)
	{
		((Character)p).Message((MessageType)2, text, 0, (Sprite)null, false);
	}

	public static string PName(Player p)
	{
		if (!((Object)(object)p != (Object)null))
		{
			return "?";
		}
		return p.GetPlayerName();
	}

	public static string PrefabOf(ItemDrop r)
	{
		return Utils.GetPrefabName(((Component)r).gameObject);
	}

	public static List<Container> NearbyContainers(Player p)
	{
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		if (_cacheFrame == Time.frameCount)
		{
			return _cache;
		}
		_cacheFrame = Time.frameCount;
		_cache = new List<Container>();
		if (!CargoToGoPlugin.PullFromContainers.Value)
		{
			return _cache;
		}
		float value = CargoToGoPlugin.ContainerRange.Value;
		if (value <= 0f)
		{
			return _cache;
		}
		HashSet<Container> hashSet = new HashSet<Container>();
		Collider[] array = Physics.OverlapSphere(((Component)p).transform.position, value);
		for (int i = 0; i < array.Length; i++)
		{
			Container componentInParent = ((Component)array[i]).GetComponentInParent<Container>();
			if (!((Object)(object)componentInParent == (Object)null) && hashSet.Add(componentInParent) && !((Object)(object)((Component)componentInParent).GetComponent<TombStone>() != (Object)null))
			{
				ZNetView component = ((Component)componentInParent).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid() && componentInParent.GetInventory() != null && !componentInParent.IsInUse() && (!(CheckAccess != null) || (bool)CheckAccess.Invoke(componentInParent, new object[1] { p.GetPlayerID() })))
				{
					_cache.Add(componentInParent);
				}
			}
		}
		return _cache;
	}

	private static List<Source> Sources(Player p)
	{
		if (_sourcesFrame == Time.frameCount)
		{
			return _sourcesCache;
		}
		_sourcesFrame = Time.frameCount;
		List<Source> list = new List<Source>();
		HashSet<Inventory> hashSet = new HashSet<Inventory>();
		foreach (Container item2 in NearbyContainers(p))
		{
			Inventory inventory = item2.GetInventory();
			hashSet.Add(inventory);
			list.Add(new InventorySource(inventory, item2));
		}
		if (CargoToGoPlugin.PullFromContainers.Value && AzuCompat.Active)
		{
			list.AddRange(AzuBridge.Collect(p, hashSet));
		}
		List<Source> list2 = new List<Source>();
		InventorySource item = new InventorySource(((Humanoid)p).GetInventory(), null);
		if (!CargoToGoPlugin.ContainersFirst.Value)
		{
			list2.Add(item);
		}
		list2.AddRange(list);
		if (CargoToGoPlugin.ContainersFirst.Value)
		{
			list2.Add(item);
		}
		_sourcesCache = list2;
		return list2;
	}

	public static bool FreeKeyActive(Piece piece)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		ZoneSystem instance = ZoneSystem.instance;
		if ((Object)(object)instance != (Object)null && (Object)(object)piece != (Object)null)
		{
			return instance.GetGlobalKey(piece.FreeBuildKey());
		}
		return false;
	}

	public static bool BuildIsFree(Player p, Piece piece)
	{
		if (!((Object)(object)p != (Object)null) || !p.NoCostCheat())
		{
			return FreeKeyActive(piece);
		}
		return true;
	}

	public static bool CanPack(Player p, Piece piece)
	{
		if ((Object)(object)piece != (Object)null && piece.m_resources != null && piece.m_resources.Length != 0 && BuildIsFree(p, piece))
		{
			return true;
		}
		string missing;
		return CheckResources(p, piece, Sources(p), out missing);
	}

	private static bool CheckResources(Player p, Piece piece, List<Source> sources, out string missing)
	{
		missing = null;
		if ((Object)(object)piece == (Object)null || piece.m_resources == null || piece.m_resources.Length == 0)
		{
			missing = "nothing to pack";
			return false;
		}
		Requirement[] resources = piece.m_resources;
		foreach (Requirement val in resources)
		{
			if ((Object)(object)val.m_resItem == (Object)null || val.m_amount <= 0)
			{
				continue;
			}
			string name = val.m_resItem.m_itemData.m_shared.m_name;
			string itemPrefab = PrefabOf(val.m_resItem);
			int num = 0;
			foreach (Source source in sources)
			{
				num += source.Count(name, itemPrefab);
				if (num >= val.m_amount)
				{
					break;
				}
			}
			if (num < val.m_amount)
			{
				missing = name;
				return false;
			}
		}
		return true;
	}

	public static bool TryPack(Player p, Piece piece)
	{
		try
		{
			if ((Object)(object)p == (Object)null || (Object)(object)piece == (Object)null)
			{
				return false;
			}
			if (Time.time - _lastPack < 0.35f)
			{
				return false;
			}
			_lastPack = Time.time;
			string prefabName = Utils.GetPrefabName(((Component)piece).gameObject);
			GameObject cargoPrefab = CargoFactory.GetCargoPrefab(piece);
			if ((Object)(object)cargoPrefab == (Object)null)
			{
				Say(p, "This piece can't be packed into a cargo.");
				Log.Warn("Pack refused for '" + prefabName + "' by " + PName(p) + ": no cargo prefab registered for this piece.");
				return false;
			}
			Inventory inventory = ((Humanoid)p).GetInventory();
			if (!inventory.HaveEmptySlot())
			{
				Say(p, "No free inventory slot for a cargo.");
				Log.Info("Pack refused for '" + prefabName + "' by " + PName(p) + ": inventory has no free slot.");
				return false;
			}
			List<Source> list = Sources(p);
			bool flag = FreeKeyActive(piece);
			bool flag2 = flag || p.NoCostCheat();
			string missing = null;
			if (!flag2 && !CheckResources(p, piece, list, out missing))
			{
				Say(p, "Missing materials: " + Localization.instance.Localize(missing));
				Log.Info("Pack refused for '" + prefabName + "' by " + PName(p) + ": missing material " + missing + ".");
				return false;
			}
			ItemData val = cargoPrefab.GetComponent<ItemDrop>().m_itemData.Clone();
			val.m_dropPrefab = cargoPrefab;
			val.m_stack = 1;
			val.m_quality = 1;
			if (!inventory.AddItem(val))
			{
				Say(p, "No free inventory slot for a cargo.");
				Log.Warn("Pack failed for '" + prefabName + "' by " + PName(p) + ": AddItem(cargo) returned false although a free slot was reported.");
				return false;
			}
			StringBuilder stringBuilder = new StringBuilder();
			Requirement[] resources = piece.m_resources;
			foreach (Requirement val2 in resources)
			{
				if ((Object)(object)val2.m_resItem == (Object)null || val2.m_amount <= 0)
				{
					continue;
				}
				string name = val2.m_resItem.m_itemData.m_shared.m_name;
				if (flag)
				{
					stringBuilder.Append(PrefabOf(val2.m_resItem)).Append(" x").Append(val2.m_amount)
						.Append(" (free-build world key, nothing consumed); ");
					continue;
				}
				int num = val2.m_amount;
				string itemPrefab = PrefabOf(val2.m_resItem);
				int num2 = 0;
				int num3 = 0;
				int num4 = 0;
				foreach (Source item in list)
				{
					if (num <= 0)
					{
						break;
					}
					int num5 = item.Take(name, itemPrefab, num);
					if (num5 > 0)
					{
						if (item.Kind == SourceKind.Chest)
						{
							num2 += num5;
						}
						else if (item.Kind == SourceKind.Azu)
						{
							num3 += num5;
						}
						else
						{
							num4 += num5;
						}
						num -= num5;
					}
				}
				if (num > 0 && !flag2)
				{
					Log.Error("Pack of '" + prefabName + "': " + num + " of " + PrefabOf(val2.m_resItem) + " could not be removed after the availability check passed.");
				}
				stringBuilder.Append(PrefabOf(val2.m_resItem)).Append(" x").Append(val2.m_amount)
					.Append(" (chests ")
					.Append(num2)
					.Append(", azu ")
					.Append(num3)
					.Append(", inventory ")
					.Append(num4)
					.Append((num > 0) ? (", free (nocost) " + num) : "")
					.Append("); ");
			}
			if (CargoToGoPlugin.PackEffects.Value)
			{
				PlayPackEffects(p, piece);
			}
			Say(p, "Packed: " + Localization.instance.Localize(piece.m_name));
			Log.Info("Cargo created for '" + prefabName + "' by " + PName(p) + " -> " + stringBuilder.ToString().TrimEnd(Array.Empty<char>()));
			return true;
		}
		catch (Exception e)
		{
			Log.Error("TryPack threw for player " + PName(p), e);
			return false;
		}
	}

	private unsafe static void PlayPackEffects(Player p, Piece piece)
	{
		//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_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0092: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Vector3 val = ((Component)p).transform.position + ((Component)p).transform.forward * 2f;
			Quaternion rotation = ((Component)p).transform.rotation;
			GameObject value = Traverse.Create((object)p).Field("m_placementGhost").GetValue<GameObject>();
			if ((Object)(object)value != (Object)null && value.activeInHierarchy)
			{
				val = value.transform.position;
				rotation = value.transform.rotation;
			}
			int num = 0;
			if (piece.m_placeEffect != null)
			{
				piece.m_placeEffect.Create(val, rotation, (Transform)null, 1f, -1, default(ZDOID));
				num++;
			}
			WearNTear component = ((Component)piece).GetComponent<WearNTear>();
			if ((Object)(object)component != (Object)null && component.m_destroyedEffect != null)
			{
				component.m_destroyedEffect.Create(val, rotation, (Transform)null, 1f, -1, default(ZDOID));
				num++;
			}
			string text = num.ToString();
			Vector3 val2 = val;
			Log.Debug("Played " + text + " pack effect lists at " + ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString());
		}
		catch (Exception ex)
		{
			Log.Warn("Pack effects failed (cargo was still created): " + ex.GetType().Name + ": " + ex.Message);
		}
	}

	public static bool Unpack(Player p, ItemData cargo)
	{
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0115: Unknown result type (might be due to invalid IL or missing references)
		//IL_011f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_0217: Unknown result type (might be due to invalid IL or missing references)
		//IL_0218: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Piece val = CargoFactory.PrefabPieceOf(cargo);
			string text = CargoFactory.PieceNameOf(cargo);
			if ((Object)(object)val == (Object)null || val.m_resources == null)
			{
				Say(p, "Can't read this cargo's contents; not destroyed.");
				Log.Error("Unpack aborted by " + PName(p) + ": piece prefab '" + text + "' not found, cargo kept.");
				return false;
			}
			Inventory inventory = ((Humanoid)p).GetInventory();
			if (!inventory.RemoveItem(cargo))
			{
				Log.Warn("Unpack aborted by " + PName(p) + ": cargo for '" + text + "' could not be removed from the inventory.");
				return false;
			}
			if (FreeKeyActive(val))
			{
				Say(p, "Cargo unpacked: no materials returned (free build).");
				Log.Info("Cargo destroyed for '" + text + "' by " + PName(p) + " -> no materials returned (free-build world key is active).");
				return true;
			}
			Vector3 val2 = ((Component)p).transform.position + ((Component)p).transform.forward * 1.5f + Vector3.up;
			StringBuilder stringBuilder = new StringBuilder();
			bool flag = false;
			Requirement[] resources = val.m_resources;
			foreach (Requirement val3 in resources)
			{
				if ((Object)(object)val3.m_resItem == (Object)null || val3.m_amount <= 0)
				{
					continue;
				}
				int num = Mathf.Max(1, val3.m_resItem.m_itemData.m_shared.m_maxStackSize);
				int num2 = val3.m_amount;
				int num3 = 0;
				int num4 = 0;
				while (num2 > 0)
				{
					int num5 = Mathf.Min(num2, num);
					ItemData val4 = val3.m_resItem.m_itemData.Clone();
					val4.m_dropPrefab = ((Component)val3.m_resItem).gameObject;
					val4.m_stack = num5;
					val4.m_quality = 1;
					val4.m_worldLevel = Game.m_worldLevel;
					if (inventory.CanAddItem(val4, num5) && inventory.AddItem(val4))
					{
						num3 += num5;
					}
					else
					{
						ItemDrop.DropItem(val4, num5, val2, Quaternion.identity);
						num4 += num5;
					}
					num2 -= num5;
				}
				if (num4 > 0)
				{
					flag = true;
				}
				stringBuilder.Append(PrefabOf(val3.m_resItem)).Append(" x").Append(val3.m_amount)
					.Append(" (to inventory ")
					.Append(num3)
					.Append(", dropped ")
					.Append(num4)
					.Append("); ");
			}
			Say(p, flag ? "Cargo unpacked (some materials dropped: inventory full)." : "Cargo unpacked: materials returned.");
			Log.Info("Cargo destroyed for '" + text + "' by " + PName(p) + " -> materials returned: " + stringBuilder.ToString().TrimEnd(Array.Empty<char>()));
			return true;
		}
		catch (Exception e)
		{
			Log.Error("Unpack threw for player " + PName(p), e);
			return false;
		}
	}

	public static bool IsBuiltFromCargo(Piece piece)
	{
		ZNetView val = (((Object)(object)piece != (Object)null) ? ((Component)piece).GetComponent<ZNetView>() : null);
		if ((Object)(object)val != (Object)null && val.IsValid())
		{
			return val.GetZDO().GetBool("CC_FromCargo", false);
		}
		return false;
	}
}
[HarmonyPatch(typeof(ObjectDB), "Awake")]
[HarmonyPriority(0)]
internal static class ObjectDB_Awake
{
	private static void Postfix(ObjectDB __instance)
	{
		try
		{
			CargoFactory.Ensure(__instance);
		}
		catch (Exception e)
		{
			Log.Error("ObjectDB.Awake hook failed", e);
		}
	}
}
[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
[HarmonyPriority(0)]
internal static class ObjectDB_Copy
{
	private static void Postfix(ObjectDB __instance)
	{
		try
		{
			CargoFactory.Ensure(__instance);
		}
		catch (Exception e)
		{
			Log.Error("ObjectDB.CopyOtherDB hook failed", e);
		}
	}
}
[HarmonyPatch(typeof(ZNetScene), "Awake")]
[HarmonyPriority(0)]
internal static class ZNetScene_Awake
{
	private static void Postfix()
	{
		try
		{
			CargoFactory.Ensure(ObjectDB.instance);
		}
		catch (Exception e)
		{
			Log.Error("ZNetScene.Awake hook failed", e);
		}
	}
}
internal static class PlaceState
{
	public static Piece Piece;

	public static ItemData Cargo;

	public static void Clear()
	{
		Piece = null;
		Cargo = null;
	}
}
[HarmonyPatch(typeof(Player), "TryPlacePiece")]
internal static class Player_TryPlacePiece
{
	private static bool Prefix(Player __instance, Piece piece, ref bool __result)
	{
		try
		{
			PlaceState.Clear();
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)piece == (Object)null)
			{
				return true;
			}
			if (CargoToGoPlugin.PackInWorld.Value && Packer.PackChord)
			{
				Packer.TryPack(__instance, piece);
				__result = false;
				return false;
			}
			if (__instance.NoCostCheat())
			{
				return true;
			}
			ItemData val = CargoFactory.FindCargoFor(((Humanoid)__instance).GetInventory(), piece);
			if (val != null)
			{
				PlaceState.Piece = piece;
				PlaceState.Cargo = val;
				Log.Debug("Placing '" + Utils.GetPrefabName(((Component)piece).gameObject) + "' with a cargo.");
			}
		}
		catch (Exception e)
		{
			Log.Error("TryPlacePiece hook failed", e);
		}
		return true;
	}
}
[HarmonyPatch(typeof(Player), "UpdatePlacement")]
internal static class Player_UpdatePlacement
{
	private static void Postfix()
	{
		PlaceState.Clear();
	}
}
[HarmonyPatch(typeof(Player), "ConsumeResources")]
internal static class Player_ConsumeResources
{
	private static bool Prefix(Player __instance, Requirement[] requirements)
	{
		try
		{
			if (PlaceState.Cargo == null || (Object)(object)PlaceState.Piece == (Object)null)
			{
				return true;
			}
			if (requirements != PlaceState.Piece.m_resources)
			{
				return true;
			}
			ItemData cargo = PlaceState.Cargo;
			PlaceState.Cargo = null;
			bool flag = ((Humanoid)__instance).GetInventory().RemoveItem(cargo);
			if (flag)
			{
				Log.Info("Cargo used: '" + Utils.GetPrefabName(((Component)PlaceState.Piece).gameObject) + "' built from a cargo by " + Packer.PName(__instance) + ".");
			}
			else
			{
				Log.Warn("Cargo for '" + Utils.GetPrefabName(((Component)PlaceState.Piece).gameObject) + "' could not be removed from the inventory; falling back to normal material use.");
			}
			return !flag;
		}
		catch (Exception e)
		{
			Log.Error("ConsumeResources hook failed", e);
			return true;
		}
	}
}
[HarmonyPatch(typeof(Piece), "SetCreator")]
internal static class Piece_SetCreator
{
	private static void Postfix(Piece __instance)
	{
		try
		{
			if (PlaceState.Cargo != null && !((Object)(object)PlaceState.Piece == (Object)null) && !(Utils.GetPrefabName(((Component)__instance).gameObject) != Utils.GetPrefabName(((Component)PlaceState.Piece).gameObject)))
			{
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null && component.IsValid())
				{
					component.GetZDO().Set("CC_FromCargo", true);
					Log.Debug("Tagged placed '" + ((Object)__instance).name + "' as built from cargo.");
				}
			}
		}
		catch (Exception e)
		{
			Log.Error("SetCreator hook failed", e);
		}
	}
}
[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
{
	typeof(Piece),
	typeof(RequirementMode)
})]
internal static class Player_HaveRequirements
{
	private static void Postfix(Player __instance, Piece piece, RequirementMode mode, ref bool __result)
	{
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Invalid comparison between Unknown and I4
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (!__result && (int)mode != 1 && !((Object)(object)piece == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				bool flag = CargoFactory.FindCargoFor(((Humanoid)__instance).GetInventory(), piece) != null;
				if (!flag && CargoToGoPlugin.PackInWorld.Value && Packer.PackChord && (Object)(object)piece == (Object)(object)__instance.GetSelectedPiece())
				{
					flag = Packer.CanPack(__instance, piece);
				}
				if (flag && (!((Object)(object)piece.m_craftingStation != (Object)null) || Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)__instance).transform.position))) && (string.IsNullOrEmpty(piece.m_dlc) || DLCMan.instance.IsDLCInstalled(piece.m_dlc)))
				{
					__result = true;
				}
			}
		}
		catch (Exception e)
		{
			Log.Error("HaveRequirements hook failed", e);
		}
	}
}
[HarmonyPatch(typeof(Hud), "OnLeftClickPiece")]
internal static class Hud_OnLeftClickPiece
{
	private static void Postfix()
	{
		try
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && Packer.PackChord)
			{
				Piece selectedPiece = localPlayer.GetSelectedPiece();
				if ((Object)(object)selectedPiece != (Object)null)
				{
					Packer.TryPack(localPlayer, selectedPiece);
				}
			}
		}
		catch (Exception e)
		{
			Log.Error("Hud.OnLeftClickPiece hook failed", e);
		}
	}
}
[HarmonyPatch(typeof(Player), "RemovePiece")]
internal static class Player_RemovePiece
{
	public static Piece Pending;

	public static float PendingTime;

	private static bool Prefix(Player __instance)
	{
		Pending = null;
		try
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Packer.Alt)
			{
				return true;
			}
			Piece hoveringPiece = __instance.GetHoveringPiece();
			if ((Object)(object)hoveringPiece == (Object)null)
			{
				return true;
			}
			if (!Packer.IsBuiltFromCargo(hoveringPiece) && !CargoToGoPlugin.AltDestroyAnyPiece.Value)
			{
				return true;
			}
			if ((Object)(object)CargoFactory.GetCargoPrefab(hoveringPiece) == (Object)null)
			{
				Log.Warn("ALT-destroy of '" + Utils.GetPrefabName(((Component)hoveringPiece).gameObject) + "': no cargo prefab exists, using normal destroy.");
				return true;
			}
			if (!((Humanoid)__instance).GetInventory().HaveEmptySlot())
			{
				((Character)__instance).Message((MessageType)2, "No free inventory slot for a cargo.", 0, (Sprite)null, false);
				Log.Info("ALT-destroy of '" + Utils.GetPrefabName(((Component)hoveringPiece).gameObject) + "' blocked for " + Packer.PName(__instance) + ": no free inventory slot.");
				return false;
			}
			ZNetView component = ((Component)hoveringPiece).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return true;
			}
			component.ClaimOwnership();
			Pending = hoveringPiece;
			PendingTime = Time.time;
		}
		catch (Exception e)
		{
			Log.Error("RemovePiece hook failed", e);
			Pending = null;
		}
		return true;
	}

	private static void Postfix(bool __result)
	{
		if (!__result)
		{
			Pending = null;
		}
	}
}
[HarmonyPatch(typeof(Piece), "DropResources")]
internal static class Piece_DropResources
{
	private static bool Prefix(Piece __instance)
	{
		try
		{
			Piece pending = Player_RemovePiece.Pending;
			if ((Object)(object)pending == (Object)null || pending != __instance)
			{
				return true;
			}
			Player_RemovePiece.Pending = null;
			string prefabName = Utils.GetPrefabName(((Component)__instance).gameObject);
			if (Packer.FreeKeyActive(__instance))
			{
				Log.Debug("Repack of '" + prefabName + "' skipped: free-build world key is active, vanilla drops nothing.");
				return true;
			}
			if (Time.time - Player_RemovePiece.PendingTime > 1.5f)
			{
				Log.Warn("Repack of '" + prefabName + "' timed out (removal took >1.5s); normal drops used.");
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			GameObject cargoPrefab = CargoFactory.GetCargoPrefab(__instance);
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)cargoPrefab == (Object)null)
			{
				return true;
			}
			ItemData val = cargoPrefab.GetComponent<ItemDrop>().m_itemData.Clone();
			val.m_dropPrefab = cargoPrefab;
			val.m_stack = 1;
			val.m_quality = 1;
			if (!((Humanoid)localPlayer).GetInventory().AddItem(val))
			{
				Log.Warn("Repack of '" + prefabName + "' by " + Packer.PName(localPlayer) + ": AddItem failed, normal material drops used.");
				return true;
			}
			((Character)localPlayer).Message((MessageType)2, "Repacked: " + Localization.instance.Localize(__instance.m_name), 0, (Sprite)null, false);
			Log.Info("Cargo repacked from piece '" + prefabName + "' by " + Packer.PName(localPlayer) + " (normal drops skipped).");
			return false;
		}
		catch (Exception e)
		{
			Log.Error("Piece.DropResources hook failed", e);
			return true;
		}
	}
}
internal static class Rules
{
	public static bool Blocked(Inventory target, ItemData item)
	{
		if (!CargoFactory.IsCargo(item))
		{
			return false;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer != (Object)null)
		{
			return target != ((Humanoid)localPlayer).GetInventory();
		}
		return false;
	}

	public static void Warn(string text)
	{
		if ((Object)(object)Player.m_localPlayer != (Object)null)
		{
			((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
		}
		Log.Debug("Blocked action: " + text);
	}
}
[HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })]
internal static class Inv_Add1
{
	private static bool Prefix(Inventory __instance, ItemData item, ref bool __result)
	{
		if (!Rules.Blocked(__instance, item))
		{
			return true;
		}
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
{
	typeof(ItemData),
	typeof(Vector2i)
})]
internal static class Inv_Add2
{
	private static bool Prefix(Inventory __instance, ItemData item, ref bool __result)
	{
		if (!Rules.Blocked(__instance, item))
		{
			return true;
		}
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
{
	typeof(ItemData),
	typeof(int),
	typeof(int),
	typeof(int),
	typeof(bool)
})]
internal static class Inv_Add3
{
	private static bool Prefix(Inventory __instance, ItemData item, ref bool __result)
	{
		if (!Rules.Blocked(__instance, item))
		{
			return true;
		}
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[]
{
	typeof(Inventory),
	typeof(ItemData)
})]
internal static class Inv_Move1
{
	private static bool Prefix(Inventory __instance, ItemData item)
	{
		if (!Rules.Blocked(__instance, item))
		{
			return true;
		}
		Rules.Warn("Cargo can't leave your inventory.");
		return false;
	}
}
[HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[]
{
	typeof(Inventory),
	typeof(ItemData),
	typeof(int),
	typeof(int),
	typeof(int)
})]
internal static class Inv_Move2
{
	private static bool Prefix(Inventory __instance, ItemData item, ref bool __result)
	{
		if (!Rules.Blocked(__instance, item))
		{
			return true;
		}
		Rules.Warn("Cargo can't leave your inventory.");
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(InventoryGrid), "DropItem")]
internal static class Grid_Drop
{
	private static bool Prefix(InventoryGrid __instance, ItemData item, ref bool __result)
	{
		if (!Rules.Blocked(__instance.GetInventory(), item))
		{
			return true;
		}
		Rules.Warn("Cargo can't leave your inventory.");
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(Humanoid), "DropItem")]
internal static class Hum_Drop
{
	private static bool Prefix(ItemData item, ref bool __result)
	{
		if (!CargoFactory.IsCargo(item))
		{
			return true;
		}
		Rules.Warn("Cargo can't be dropped. Ctrl+Alt+Right-click unpacks it.");
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(Humanoid), "UseItem")]
internal static class Hum_Use
{
	private static bool Prefix(ItemData item)
	{
		if (!CargoFactory.IsCargo(item))
		{
			return true;
		}
		Rules.Warn("Cargo contents are only usable for building.");
		return false;
	}
}
[HarmonyPatch(typeof(InventoryGui), "OnRightClickItem")]
internal static class Gui_RightClick
{
	private static bool Prefix(InventoryGrid grid, ItemData item)
	{
		try
		{
			if (!CargoFactory.IsCargo(item) || !Packer.Ctrl || !Packer.Alt)
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || grid.GetInventory() != ((Humanoid)localPlayer).GetInventory())
			{
				return false;
			}
			Packer.Unpack(localPlayer, item);
			return false;
		}
		catch (Exception e)
		{
			Log.Error("OnRightClickItem hook failed", e);
			return true;
		}
	}
}
[HarmonyPatch(typeof(Inventory), "IsTeleportable")]
internal static class Inv_IsTeleportable
{
	private static void Prefix(Inventory __instance)
	{
		try
		{
			foreach (ItemData allItem in __instance.GetAllItems())
			{
				if (CargoFactory.IsCargo(allItem))
				{
					CargoFactory.RefreshTeleportable(allItem);
				}
			}
		}
		catch (Exception e)
		{
			Log.Error("Inventory.IsTeleportable hook failed", e);
		}
	}
}
[HarmonyPatch(typeof(KeyHints), "UpdateHints")]
internal static class KeyHints_UpdateHints
{
	private static void Postfix(KeyHints __instance)
	{
		KeyHintUi.Tick(__instance);
	}
}
[BepInPlugin("com.kydldev.CargoToGo", "CargoToGo", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class CargoToGoPlugin : BaseUnityPlugin
{
	public const string GUID = "com.kydldev.CargoToGo";

	public const string PluginName = "CargoToGo";

	public const string PluginVersion = "1.0.0";

	internal static ConfigEntry<float> ContainerRange;

	internal static ConfigEntry<bool> PullFromContainers;

	internal static ConfigEntry<bool> UseAzuCraftyBoxes;

	internal static ConfigEntry<bool> ContainersFirst;

	internal static ConfigEntry<bool> PackInWorld;

	internal static ConfigEntry<bool> AltDestroyAnyPiece;

	internal static ConfigEntry<bool> PackEffects;

	internal static ConfigEntry<bool> ShowKeyHints;

	internal static ConfigEntry<bool> ShowCargoTab;

	internal static ConfigEntry<bool> VerboseLogging;

	internal static ConfigEntry<float> WeightMultiplier;

	private void Awake()
	{
		//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02de: Unknown result type (might be due to invalid IL or missing references)
		Log.Init();
		ContainerRange = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ContainerRange", 20f, "Radius (m) around the player to search for chests when packing a cargo. 0 turns CargoToGo's own search off (combine with UseAzuCraftyBoxes to rely only on AzuCraftyBoxes' range).");
		PullFromContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PullFromContainers", true, "Allow packing materials from nearby chests.");
		UseAzuCraftyBoxes = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "UseAzuCraftyBoxes", true, "If AzuCraftyBoxes is installed, also pack from the containers it reaches: its own Container Range, chest toggles, item include/exclude rules, 'leave one', drawers and bags. Works even when ContainerRange is 0. Needs PullFromContainers.");
		ContainersFirst = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ContainersFirst", true, "Take materials from chests before the player's inventory.");
		PackInWorld = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PackInWorld", true, "Ctrl+Alt + left click with a piece selected (in the world) packs a cargo instead of placing the piece.");
		AltDestroyAnyPiece = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AltDestroyAnyPiece", false, "ALT + destroy returns a cargo even for pieces that were not built from a cargo.");
		PackEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "PackEffects", true, "Play build dust / sound / the piece's break effect when a cargo is packed.");
		ShowKeyHints = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowKeyHints", true, "Show the Pack cargo / Repack shortcuts in the build-mode key hint bar (keyboard only).");
		ShowCargoTab = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowCargoTab", true, "Add a 5th \"Cargos\" tab to the build menu that lists the pieces you currently hold a cargo for. Needs a game restart.");
		VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Logging", "VerboseLogging", false, "Also write DEBUG lines (blocked actions, tagging, ...) to the BepInEx log.");
		WeightMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "WeightMultiplier", 1f, "Cargo weight = contents weight x this. Needs a game restart.");
		Log.Verbose = VerboseLogging.Value;
		Log.Info("CargoToGo 1.0.0 starting. ContainerRange=" + ContainerRange.Value + " PullFromContainers=" + PullFromContainers.Value + " UseAzuCraftyBoxes=" + UseAzuCraftyBoxes.Value + " (AzuCraftyBoxes installed: " + AzuCompat.Installed + ") ContainersFirst=" + ContainersFirst.Value + " PackInWorld=" + PackInWorld.Value + " PackEffects=" + PackEffects.Value + " ShowKeyHints=" + ShowKeyHints.Value + " ShowCargoTab=" + ShowCargoTab.Value + " AltDestroyAnyPiece=" + AltDestroyAnyPiece.Value + " WeightMultiplier=" + WeightMultiplier.Value);
		try
		{
			Harmony val = new Harmony("com.kydldev.CargoToGo");
			val.PatchAll();
			int num = 0;
			foreach (MethodBase patchedMethod in val.GetPatchedMethods())
			{
				_ = patchedMethod;
				num++;
			}
			Log.Info("Harmony patched " + num + " methods.");
		}
		catch (Exception e)
		{
			Log.Error("Harmony patching failed, the mod will not work", e);
		}
	}
}