Decompiled source of PlayerTradingReforged v1.0.1

plugins/PlayerTradingReforged.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PlayerTradingReforged.GUI;
using PlayerTradingReforged.Patterns;
using PlayerTradingReforged.Trading;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Player Trading Reforged")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Player Trading Reforged")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("F9B815D6-6EF4-44DB-9A0F-436849B24670")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PlayerTradingReforged
{
	[Serializable]
	public class StringLocalization
	{
		public string TradePending = "Trade confirmation pending. Items are held safely until the other player reconnects.";

		public string TradeInvalid = "Trade cancelled: the offered items could not be read. Both players need the same mod and item versions.";

		public string ReturnedItems = "Trade items returned. Make inventory space to recover any remaining items.";

		public string RequestTrade = "Request Trade";

		public string AcceptRequest = "Accept Trade";

		public string TradeRequestSent = "Trade request sent";

		public string TradeRecentlySent = "Trade request recently sent";

		public string StartedTradeWithX = "Started trading with";

		public string XWantsToTrade = "wants to trade";

		public string XHasCancelledTrade = "has cancelled the trade";

		public string LocalPlayerCancelledTrade = "You have cancelled the trade";

		public string CantStartNewTradeInstance = "You cannot start a new trade session";

		public string TradeSuccessful = "Trade successful";

		public string NotEnoughInventorySlots = "Not enough inventory slots";

		public string ToGiveWindowText = "You Will Give";

		public string ToReceiveWindowText = "You Will Receive";

		public string PartnerInventoryText = "Partner's Inventory";

		public string ReservedForTradeText = "{0} reserved for trade";

		public string YourInventoryText = "Your Inventory";

		public string NamedInventoryText = "{0}’s Inventory";

		public string ProjectedWeightText = "After trade";

		public string PartnerInventoryWaiting = "Waiting for Partner's Inventory";

		public string PartnerInventoryUnavailable = "Partner's Inventory Unavailable";

		public string AcceptTradeButtonText = "Accept Trade";

		public string ChangeTradeButtonText = "Change Trade";

		public string CancelTradeButtonText = "Cancel Trade";

		public string EditModeOn = "Edit UI Mode ON";

		public string EditModeOff = "Edit UI Mode OFF";
	}
	[BepInPlugin("augusdogus.mods.PlayerTradingReforged", "Player Trading Reforged", "1.0.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginId = "augusdogus.mods.PlayerTradingReforged";

		public const string PluginVersion = "1.0.1";

		private static Plugin? _instance;

		private readonly Harmony _harmony = new Harmony("augusdogus.mods.PlayerTradingReforged");

		private TradeHandler? _handler;

		private ZRoutedRpc? _network;

		public static StringLocalization Localization { get; private set; } = new StringLocalization();

		private static ConfigFile Settings => ((BaseUnityPlugin)(_instance ?? throw new InvalidOperationException("Player Trading Reforged has not initialized."))).Config;

		public static ConfigEntry<bool> UseModifierKey => Settings.Bind<bool>("Keybinds", "useModifierKey", false, "Require a modifier when requesting or accepting a trade.");

		public static ConfigEntry<KeyCode> ModifierKey => Settings.Bind<KeyCode>("Keybinds", "modifierKey", (KeyCode)308, "Trade modifier key.");

		public static ConfigEntry<KeyCode> EditWindowLayoutKey => Settings.Bind<KeyCode>("Keybinds", "editWindowLayoutKey", (KeyCode)292, "Toggle window placement mode.");

		public static ConfigEntry<Vector2> ToGiveUserOffset => Offset("toGiveUserOffset");

		public static ConfigEntry<Vector2> ToReceiveUserOffset => Offset("toReceiveUserOffset");

		public static ConfigEntry<Vector2> PartnerInventoryUserOffset => Offset("partnerInventoryUserOffset");

		public static ConfigEntry<Vector2> AcceptButtonUserOffset => Offset("acceptButtonUserOffset");

		public static ConfigEntry<Vector2> CancelButtonUserOffset => Offset("cancelButtonUserOffset");

		internal static event Action? OnLocalPlayerChanged;

		private static ConfigEntry<Vector2> Offset(string key)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			return Settings.Bind<Vector2>("Offsets", key, Vector2.zero, "Trade UI position offset. Set to 0, 0 to reset.");
		}

		private void Awake()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)SystemInfo.graphicsDeviceType == 4)
			{
				((Behaviour)this).enabled = false;
				return;
			}
			_instance = this;
			_ = UseModifierKey;
			_ = ModifierKey;
			_ = EditWindowLayoutKey;
			_ = ToGiveUserOffset;
			_ = ToReceiveUserOffset;
			_ = AcceptButtonUserOffset;
			_ = CancelButtonUserOffset;
			_ = PartnerInventoryUserOffset;
			InitLocalization();
			_harmony.PatchAll(typeof(Plugin).Assembly);
		}

		private void InitLocalization()
		{
			string text = Path.Combine(Paths.ConfigPath, "augusdogus.mods.PlayerTradingReforged.strings.json");
			try
			{
				Directory.CreateDirectory(Paths.ConfigPath);
				if (File.Exists(text))
				{
					JsonUtility.FromJsonOverwrite(File.ReadAllText(text), (object)Localization);
				}
				else
				{
					File.WriteAllText(text, JsonUtility.ToJson((object)Localization, true));
				}
				if (Localization.PartnerInventoryText == "Partner's Inventory (Read Only)")
				{
					Localization.PartnerInventoryText = new StringLocalization().PartnerInventoryText;
				}
			}
			catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException || ex is ArgumentException)
			{
				Localization = new StringLocalization();
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Cannot load localization at " + text + ": " + ex.Message + ". Using English. Your file is unchanged; correct its JSON or file permissions and restart."));
			}
		}

		private void Update()
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_handler != (Object)null && (_network != ZRoutedRpc.instance || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)InventoryGui.instance)))
			{
				_handler.Shutdown();
				Object.Destroy((Object)(object)((Component)_handler).gameObject);
				_handler = null;
			}
			if (!((Object)(object)_handler != (Object)null) && Object.op_Implicit((Object)(object)Player.m_localPlayer) && Object.op_Implicit((Object)(object)InventoryGui.instance) && ZRoutedRpc.instance != null)
			{
				_network = ZRoutedRpc.instance;
				_handler = new GameObject("PlayerTradingReforged").AddComponent<TradeHandler>();
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_handler != (Object)null)
			{
				_handler.Shutdown();
				Object.Destroy((Object)(object)((Component)_handler).gameObject);
			}
			_harmony.UnpatchSelf();
			_instance = null;
		}

		internal static void Warn(string message)
		{
			Plugin? instance = _instance;
			if (instance != null)
			{
				((BaseUnityPlugin)instance).Logger.LogWarning((object)message);
			}
		}

		public static void NewLocalPlayer()
		{
			Plugin.OnLocalPlayerChanged?.Invoke();
		}
	}
	public static class HUDTools
	{
		private static readonly Dictionary<GameObject, bool> States = new Dictionary<GameObject, bool>();

		public static void SetHUDsActive(bool active)
		{
			if (active)
			{
				foreach (KeyValuePair<GameObject, bool> state in States)
				{
					if (Object.op_Implicit((Object)(object)state.Key))
					{
						state.Key.SetActive(state.Value);
					}
				}
				States.Clear();
			}
			else if (Object.op_Implicit((Object)(object)InventoryGui.instance) && States.Count == 0)
			{
				GameObject[] array = (GameObject[])(object)new GameObject[3]
				{
					((Component)InventoryGui.instance.m_crafting).gameObject,
					((Component)InventoryGui.instance.m_info).gameObject,
					((Component)InventoryGui.instance.m_armor.transform.parent).gameObject
				};
				foreach (GameObject val in array)
				{
					States[val] = val.activeSelf;
					val.SetActive(false);
				}
			}
		}
	}
	internal static class ZNetUtils
	{
		public static Player? GetPlayer(long peer)
		{
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if (Object.op_Implicit((Object)(object)allPlayer) && ((Character)allPlayer).GetOwner() == peer)
				{
					return allPlayer;
				}
			}
			return null;
		}

		public static Player? GetCharacter(long character)
		{
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if (Object.op_Implicit((Object)(object)allPlayer) && allPlayer.GetPlayerID() == character)
				{
					return allPlayer;
				}
			}
			return null;
		}
	}
	internal sealed class TradeHandler : MonoSingleton<TradeHandler>
	{
		private sealed class Request
		{
			public string Session { get; }

			public float Expires { get; }

			public Request(string session)
			{
				Session = session;
				Expires = Time.unscaledTime + 10f;
			}
		}

		private const string RequestRpc = "augusdogus.mods.PlayerTradingReforged.v1.Request";

		private const string StartRpc = "augusdogus.mods.PlayerTradingReforged.v1.Start";

		private const string MessageRpc = "augusdogus.mods.PlayerTradingReforged.v1.Message";

		private const string RecoveryRpc = "augusdogus.mods.PlayerTradingReforged.v1.Recovery";

		private const float MaxDistance = 5f;

		private readonly Dictionary<long, Request> _sent = new Dictionary<long, Request>();

		private readonly Dictionary<long, Request> _received = new Dictionary<long, Request>();

		private TradeInstance? _trade;

		private ZRoutedRpc? _network;

		private Player? _player;

		private float _nextRecovery;

		private bool _shutdown;

		private bool Available
		{
			get
			{
				if (_trade == null && (Object)(object)_player != (Object)null && !TradeRecovery.HasPending(_player))
				{
					return !IsTradeWindowsOpen();
				}
				return false;
			}
		}

		public bool CanEditOffer
		{
			get
			{
				if (_trade != null && _trade.Session.CanEdit)
				{
					return !MonoSingleton<TradeWindowManager>.Instance.IsInWindowPositionMode();
				}
				return false;
			}
		}

		protected override void Init()
		{
			_network = ZRoutedRpc.instance;
			_player = Player.m_localPlayer;
			((Component)this).gameObject.AddComponent<TradeWindowManager>();
			_network.Register<string>("augusdogus.mods.PlayerTradingReforged.v1.Request", (Action<long, string>)ReceiveRequest);
			_network.Register<string>("augusdogus.mods.PlayerTradingReforged.v1.Start", (Action<long, string>)ReceiveStart);
			_network.Register<ZPackage>("augusdogus.mods.PlayerTradingReforged.v1.Message", (Action<long, ZPackage>)ReceiveMessage);
			_network.Register<string, string>("augusdogus.mods.PlayerTradingReforged.v1.Recovery", (Action<long, string, string>)ReceiveRecovery);
			Plugin.OnLocalPlayerChanged += OnNewLocalPlayer;
		}

		private void Update()
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			if (_shutdown || (Object)(object)_player == (Object)null)
			{
				return;
			}
			_trade?.Tick();
			if (_trade == null && Time.unscaledTime >= _nextRecovery)
			{
				_nextRecovery = Time.unscaledTime + 3f;
				RecoverItems();
			}
			if (((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) || Console.IsVisible() || Menu.IsVisible() || TextInput.IsVisible())
			{
				return;
			}
			if (Input.GetKeyDown(Plugin.EditWindowLayoutKey.Value))
			{
				MonoSingleton<TradeWindowManager>.Instance.ToggleWindowPositionMode();
			}
			if (_trade == null && !IsTradeWindowsOpen() && !InventoryGui.IsVisible() && !((Character)_player).IsDead() && !((Character)_player).IsTeleporting() && (ZInput.GetButtonDown("Use") || ZInput.GetButtonDown("JoyUse")) && (!Plugin.UseModifierKey.Value || Input.GetKey(Plugin.ModifierKey.Value)))
			{
				_player.UpdateHover();
				Character hoveringCreature = _player.m_hoveringCreature;
				Player val = (Player)(object)((hoveringCreature is Player) ? hoveringCreature : null);
				if (val != null && CanTradeWith(val))
				{
					RequestTrade(val);
				}
			}
		}

		private bool CanTradeWith(Player target)
		{
			//IL_0059: 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)
			if ((Object)(object)_player != (Object)null && (Object)(object)target != (Object)(object)_player && Object.op_Implicit((Object)(object)target) && !((Character)target).IsDead() && !((Character)_player).IsDead() && !((Character)_player).IsTeleporting() && !((Character)target).IsTeleporting())
			{
				return Vector3.Distance(((Component)_player).transform.position, ((Component)target).transform.position) <= 5f;
			}
			return false;
		}

		private static bool ValidSession(string id)
		{
			Guid result;
			if (id.Length == 32)
			{
				return Guid.TryParseExact(id, "N", out result);
			}
			return false;
		}

		private static bool Active(Dictionary<long, Request> requests, long peer, out Request? request)
		{
			if (requests.TryGetValue(peer, out Request value) && value.Expires >= Time.unscaledTime)
			{
				request = value;
				return true;
			}
			requests.Remove(peer);
			request = null;
			return false;
		}

		private void RequestTrade(Player target)
		{
			if (!Available)
			{
				Show(Plugin.Localization.CantStartNewTradeInstance);
				return;
			}
			long owner = ((Character)target).GetOwner();
			Request request2;
			if (Active(_received, owner, out Request request) && request != null)
			{
				if (!((Object)(object)_player != (Object)null) || !Active(_sent, owner, out request2) || ((Character)_player).GetOwner() >= owner)
				{
					StartTrade(target, request.Session, coordinator: false);
					ZRoutedRpc? network = _network;
					if (network != null)
					{
						network.InvokeRoutedRPC(owner, "augusdogus.mods.PlayerTradingReforged.v1.Start", new object[1] { request.Session });
					}
				}
			}
			else if (Active(_sent, owner, out request2))
			{
				Show(Plugin.Localization.TradeRecentlySent);
			}
			else
			{
				Request request3 = new Request(Guid.NewGuid().ToString("N"));
				_sent[owner] = request3;
				ZRoutedRpc? network2 = _network;
				if (network2 != null)
				{
					network2.InvokeRoutedRPC(owner, "augusdogus.mods.PlayerTradingReforged.v1.Request", new object[1] { request3.Session });
				}
				Show(Plugin.Localization.TradeRequestSent);
			}
		}

		private void ReceiveRequest(long sender, string session)
		{
			if (!ValidSession(session) || !Available)
			{
				return;
			}
			Player player = ZNetUtils.GetPlayer(sender);
			if (!((Object)(object)player == (Object)null) && CanTradeWith(player) && !Active(_received, sender, out Request _))
			{
				_received[sender] = new Request(session);
				if (Object.op_Implicit((Object)(object)MessageHud.instance))
				{
					MessageHud.instance.ShowBiomeFoundMsg(player.GetPlayerName() + " " + Plugin.Localization.XWantsToTrade, false);
				}
			}
		}

		private void ReceiveStart(long sender, string session)
		{
			if (Available && Active(_sent, sender, out Request request) && request != null && !(request.Session != session))
			{
				Player player = ZNetUtils.GetPlayer(sender);
				if ((Object)(object)player != (Object)null && CanTradeWith(player))
				{
					StartTrade(player, session, coordinator: true);
				}
			}
		}

		private void StartTrade(Player target, string session, bool coordinator)
		{
			if (!((Object)(object)_player == (Object)null))
			{
				_sent.Clear();
				_received.Clear();
				_trade = new TradeInstance(this, _player, target, new TradeSession(session, ((Character)target).GetOwner(), coordinator));
				_trade.Open();
				Show(Plugin.Localization.StartedTradeWithX + " " + target.GetPlayerName());
			}
		}

		private void ReceiveMessage(long sender, ZPackage package)
		{
			if (_trade == null || sender != _trade.Session.Peer || package.Size() > 524288)
			{
				return;
			}
			try
			{
				string id = package.ReadString();
				if (_trade.Session.Matches(sender, id))
				{
					string kind = package.ReadString();
					int num = package.ReadInt();
					int num2 = package.ReadInt();
					string items = package.ReadString();
					if (package.GetPos() != package.Size() || num < 0 || num2 < 0)
					{
						_trade.Cancel();
					}
					else
					{
						_trade.Receive(kind, num, num2, items);
					}
				}
			}
			catch (Exception ex) when (ex is IOException || ex is ArgumentException || ex is OverflowException)
			{
				Plugin.Warn($"Rejected malformed trade message from {sender}: {ex.Message}");
				_trade?.Cancel();
			}
		}

		internal void Send(TradeSession session, string kind, string items = "")
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(session.Id);
			val.Write(kind);
			val.Write(session.LocalRevision);
			val.Write(session.RemoteRevision);
			val.Write(items);
			ZRoutedRpc? network = _network;
			if (network != null)
			{
				network.InvokeRoutedRPC(session.Peer, "augusdogus.mods.PlayerTradingReforged.v1.Message", new object[1] { val });
			}
		}

		internal void Close(TradeInstance trade)
		{
			if (_trade == trade)
			{
				_trade = null;
				MonoSingleton<TradeWindowManager>.Instance.CancelInstance();
			}
		}

		private void RecoverItems()
		{
			if ((Object)(object)_player == (Object)null || ((Character)_player).IsDead() || ((Character)_player).IsTeleporting())
			{
				return;
			}
			TradeRecovery.Entry entry = TradeRecovery.Read(_player);
			if (entry == null || !ValidSession(entry.Session))
			{
				return;
			}
			if (entry.State == TradeRecovery.RecoveryState.AwaitingDecision)
			{
				Player character = ZNetUtils.GetCharacter(entry.PeerCharacter);
				if ((Object)(object)character != (Object)null)
				{
					ZRoutedRpc? network = _network;
					if (network != null)
					{
						network.InvokeRoutedRPC(((Character)character).GetOwner(), "augusdogus.mods.PlayerTradingReforged.v1.Recovery", new object[2] { entry.Session, "query" });
					}
				}
			}
			else
			{
				bool flag = entry.State == TradeRecovery.RecoveryState.CoordinatorOffer && TradeRecovery.Decision(_player, entry.Session, entry.PeerCharacter) == "commit";
				if (entry.State == TradeRecovery.RecoveryState.CoordinatorOffer && !flag)
				{
					TradeRecovery.RecordDecision(_player, entry.Session, entry.PeerCharacter, committed: false);
				}
				if (TradeRecovery.Resolve(_player, entry, flag))
				{
					Show(Plugin.Localization.ReturnedItems);
				}
			}
		}

		private void ReceiveRecovery(long sender, string session, string decision)
		{
			if ((Object)(object)_player == (Object)null || !ValidSession(session))
			{
				return;
			}
			Player player = ZNetUtils.GetPlayer(sender);
			if ((Object)(object)player == (Object)null || (Object)(object)player == (Object)(object)_player)
			{
				return;
			}
			if (decision == "query")
			{
				if (_trade != null && _trade.Session.Matches(sender, session) && _trade.Session.IsCoordinator)
				{
					_trade.Cancel();
				}
				string text = TradeRecovery.Decision(_player, session, player.GetPlayerID());
				if (text != null)
				{
					ZRoutedRpc? network = _network;
					if (network != null)
					{
						network.InvokeRoutedRPC(sender, "augusdogus.mods.PlayerTradingReforged.v1.Recovery", new object[2] { session, text });
					}
				}
			}
			else if (!((Character)_player).IsDead() && !((Character)_player).IsTeleporting() && (!(decision != "commit") || !(decision != "abort")))
			{
				TradeRecovery.Entry entry = TradeRecovery.Read(_player);
				if (entry != null && entry.State == TradeRecovery.RecoveryState.AwaitingDecision && !(entry.Session != session) && entry.PeerCharacter == player.GetPlayerID())
				{
					TradeRecovery.Resolve(_player, entry, decision == "commit");
					Show((decision == "commit") ? Plugin.Localization.TradeSuccessful : Plugin.Localization.ReturnedItems);
				}
			}
		}

		public bool IsTradeWindowsOpen()
		{
			if (_trade == null)
			{
				if ((Object)(object)MonoSingleton<TradeWindowManager>.Current != (Object)null)
				{
					return MonoSingleton<TradeWindowManager>.Current.IsInWindowPositionMode();
				}
				return false;
			}
			return true;
		}

		public bool InTradeInstance()
		{
			return _trade != null;
		}

		public Inventory? TryGetToTradeInventory()
		{
			return _trade?.Give;
		}

		public float GetMaxDistance()
		{
			return 5f;
		}

		public string GetAction(Player target)
		{
			if (!Active(_received, ((Character)target).GetOwner(), out Request _))
			{
				return Plugin.Localization.RequestTrade;
			}
			return Plugin.Localization.AcceptRequest;
		}

		public void TryCancelTradeInstance()
		{
			_trade?.Cancel();
		}

		public void TryCancelWindowEditMode()
		{
			MonoSingleton<TradeWindowManager>.Current?.DisableWindowPositionMode();
		}

		public void OnNewLocalPlayer()
		{
			_trade?.Cancel();
			_player = Player.m_localPlayer;
			_sent.Clear();
			_received.Clear();
		}

		internal static void Show(string message)
		{
			if (Object.op_Implicit((Object)(object)MessageHud.instance))
			{
				MessageHud.instance.ShowMessage((MessageType)1, message, 0, (Sprite)null, false, true);
			}
		}

		public void Shutdown()
		{
			if (_shutdown)
			{
				return;
			}
			_shutdown = true;
			_trade?.Cancel();
			if ((Object)(object)MonoSingleton<TradeWindowManager>.Current != (Object)null)
			{
				MonoSingleton<TradeWindowManager>.Current.DisableWindowPositionMode();
			}
			Plugin.OnLocalPlayerChanged -= OnNewLocalPlayer;
			if (_network != null)
			{
				string[] array = new string[4] { "augusdogus.mods.PlayerTradingReforged.v1.Request", "augusdogus.mods.PlayerTradingReforged.v1.Start", "augusdogus.mods.PlayerTradingReforged.v1.Message", "augusdogus.mods.PlayerTradingReforged.v1.Recovery" };
				foreach (string text in array)
				{
					_network.m_functions.Remove(StringExtensionMethods.GetStableHashCode(text));
				}
			}
		}

		private void OnDestroy()
		{
			Shutdown();
		}
	}
	internal sealed class TradeInstance
	{
		private readonly TradeHandler _handler;

		private readonly Player _local;

		private readonly Player _peer;

		private readonly long _peerCharacter;

		private readonly TradeWindowManager _windows;

		private bool _closed;

		private float _prepareStarted;

		private float _lastHeartbeat;

		private float _nextHeartbeat;

		private float _nextInventoryPreview;

		private string? _lastInventoryPreview;

		private float? _lastCarryCapacity;

		private string? _lastWeights;

		private string? _lastReservedPreview;

		private bool _receivedReservedPreview;

		public TradeSession Session { get; }

		public Inventory Give { get; }

		private Inventory ReceiveItems { get; }

		public TradeInstance(TradeHandler handler, Player local, Player peer, TradeSession session)
		{
			_handler = handler;
			_local = local;
			_peer = peer;
			Session = session;
			_peerCharacter = peer.GetPlayerID();
			_windows = MonoSingleton<TradeWindowManager>.Instance;
			Give = _windows.GetToTradeInventory();
			ReceiveItems = _windows.GetToReceiveInventory();
			_lastHeartbeat = Time.unscaledTime;
		}

		public void Open()
		{
			_windows.StartNewInstance();
			_windows.SetPartnerName(_peer.GetPlayerName());
			_windows.OnTradeAcceptPressed += Accept;
			_windows.OnChangeTradePressed += Change;
			_windows.OnCancelTradePressed += Cancel;
			Inventory give = Give;
			give.m_onChanged = (Action)Delegate.Combine(give.m_onChanged, new Action(OfferChanged));
			Persist();
		}

		private void Persist()
		{
			TradeRecovery.Store(_local, Session, _peerCharacter, Give, ReceiveItems);
		}

		private void RefreshAcceptance()
		{
			_windows.SetToTradeAccepted(Session.LocalAccepted);
			_windows.SetToReceiveAccepted(Session.RemoteAccepted);
		}

		public void OfferChanged()
		{
			if (!_closed && Session.ChangeOffer())
			{
				Persist();
				RefreshAcceptance();
				_handler.Send(Session, "offer", TradeInventory.Save(Give));
			}
		}

		private void Accept()
		{
			if (_closed || !TradeInventory.CanFit(((Humanoid)_local).GetInventory(), ReceiveItems))
			{
				TradeHandler.Show(Plugin.Localization.NotEnoughInventorySlots);
			}
			else if (Session.Accept())
			{
				InventoryGui.instance.SetupDragItem((ItemData)null, (Inventory)null, 1);
				RefreshAcceptance();
				_handler.Send(Session, "accept");
				TryPrepare();
			}
		}

		private void Change()
		{
			if (Session.Change())
			{
				Persist();
				RefreshAcceptance();
				_handler.Send(Session, "offer", TradeInventory.Save(Give));
			}
		}

		private void TryPrepare()
		{
			if (Session.BeginPrepare())
			{
				_prepareStarted = Time.unscaledTime;
				_handler.Send(Session, "prepare");
			}
		}

		public void Receive(string kind, int theirs, int ours, string items)
		{
			if (_closed)
			{
				return;
			}
			_lastHeartbeat = Time.unscaledTime;
			if (kind == null)
			{
				return;
			}
			switch (kind.Length)
			{
			case 9:
				switch (kind[0])
				{
				case 'h':
					_ = kind == "heartbeat";
					break;
				case 'i':
					if (kind == "inventory" && !_receivedReservedPreview)
					{
						_windows.ShowPartnerInventory(TradeInventory.TryLoadPreview(items, out Inventory inventory) ? inventory : null);
					}
					break;
				}
				break;
			case 7:
				switch (kind[0])
				{
				case 'w':
					if (kind == "weights")
					{
						_windows.SetPartnerWeights(TradeWeightSnapshot.Parse(items));
					}
					break;
				case 'p':
					if (kind == "prepare")
					{
						if (!TradeInventory.CanFit(((Humanoid)_local).GetInventory(), ReceiveItems) || !Session.Prepare(theirs, ours))
						{
							Cancel();
							break;
						}
						Persist();
						_prepareStarted = Time.unscaledTime;
						_handler.Send(Session, "ready");
					}
					break;
				}
				break;
			case 5:
				switch (kind[0])
				{
				case 'o':
					if (!(kind == "offer"))
					{
						break;
					}
					if (Session.State == TradeSession.Phase.Preparing)
					{
						Cancel();
					}
					else if (theirs > Session.RemoteRevision && Session.State == TradeSession.Phase.Editing)
					{
						if (!TradeInventory.TryLoad(items, out Inventory inventory2))
						{
							TradeHandler.Show(Plugin.Localization.TradeInvalid);
							Cancel();
						}
						else if (Session.ReceiveOffer(theirs))
						{
							TradeInventory.Replace(ReceiveItems, inventory2);
							Persist();
							RefreshAcceptance();
							_windows.RefreshToReceiveWindow();
						}
					}
					break;
				case 'r':
					if (kind == "ready")
					{
						if (!Session.IsCoordinator || !TradeInventory.CanFit(((Humanoid)_local).GetInventory(), ReceiveItems))
						{
							Cancel();
						}
						else if (Session.Commit(theirs, ours))
						{
							TradeRecovery.RecordDecision(_local, Session.Id, _peerCharacter, committed: true);
							_handler.Send(Session, "commit");
							Finish();
						}
					}
					break;
				case 'a':
					if (kind == "abort" && !Session.IsCoordinator && Session.Cancel(coordinatorAborted: true))
					{
						Refund(localCancellation: false);
					}
					break;
				}
				break;
			case 6:
				switch (kind[1])
				{
				case 'c':
					if (kind == "accept" && Session.ReceiveAccept(theirs, ours))
					{
						RefreshAcceptance();
						TryPrepare();
					}
					break;
				case 'o':
					if (kind == "commit" && !Session.IsCoordinator && Session.Commit(theirs, ours))
					{
						Finish();
					}
					break;
				case 'a':
					if (kind == "cancel" && Session.IsCoordinator)
					{
						Cancel();
					}
					break;
				}
				break;
			case 8:
				if (kind == "capacity")
				{
					_windows.SetPartnerCapacity((float.TryParse(items, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && !float.IsNaN(result) && !float.IsInfinity(result) && result >= 0f) ? new float?(result) : ((float?)null));
				}
				break;
			case 22:
				if (kind == "inventory-reservations")
				{
					_receivedReservedPreview = true;
					_windows.ShowPartnerPreview(TradePreviewSnapshot.Parse(items));
				}
				break;
			}
		}

		private void Finish()
		{
			_closed = true;
			_windows.ClearOfferedView();
			Give.RemoveAll();
			TradeRecovery.Entry entry = new TradeRecovery.Entry
			{
				Session = Session.Id,
				PeerCharacter = _peerCharacter,
				Give = TradeInventory.Save(ReceiveItems),
				Receive = TradeInventory.Save(ReceiveItems)
			};
			TradeRecovery.Resolve(_local, entry, committed: true);
			TradeHandler.Show(Plugin.Localization.TradeSuccessful);
			Close();
		}

		public void Tick()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if (_closed)
			{
				return;
			}
			if (!Object.op_Implicit((Object)(object)_local) || !Object.op_Implicit((Object)(object)_peer) || ((Character)_local).IsDead() || ((Character)_peer).IsDead() || ((Character)_local).IsTeleporting() || ((Character)_peer).IsTeleporting() || Vector3.Distance(((Component)_local).transform.position, ((Component)_peer).transform.position) > _handler.GetMaxDistance() || Time.unscaledTime - _lastHeartbeat > 15f)
			{
				Cancel();
				return;
			}
			if (Time.unscaledTime >= _nextHeartbeat)
			{
				_nextHeartbeat = Time.unscaledTime + 2f;
				_handler.Send(Session, "heartbeat");
			}
			if (Time.unscaledTime >= _nextInventoryPreview)
			{
				_nextInventoryPreview = Time.unscaledTime + 0.5f;
				float maxCarryWeight = _local.GetMaxCarryWeight();
				if (maxCarryWeight != _lastCarryCapacity)
				{
					_handler.Send(Session, "capacity", maxCarryWeight.ToString("R", CultureInfo.InvariantCulture));
					_lastCarryCapacity = maxCarryWeight;
				}
				string text = TradeWeightSnapshot.Encode(((Humanoid)_local).GetInventory().GetTotalWeight(), Give.GetTotalWeight(), maxCarryWeight);
				if (text != _lastWeights)
				{
					_handler.Send(Session, "weights", text);
					_lastWeights = text;
				}
				string text2 = TradeInventory.SavePreview(((Humanoid)_local).GetInventory());
				if (text2 != _lastInventoryPreview)
				{
					_handler.Send(Session, "inventory", text2);
					_lastInventoryPreview = text2;
				}
				string text3 = new TradePreviewSnapshot(((Humanoid)_local).GetInventory(), _windows.GetReservedInventory()).Encode();
				if (text3 != _lastReservedPreview)
				{
					_handler.Send(Session, "inventory-reservations", text3);
					_lastReservedPreview = text3;
				}
			}
			if ((Session.State == TradeSession.Phase.Preparing || Session.State == TradeSession.Phase.Prepared) && Time.unscaledTime - _prepareStarted > 10f)
			{
				Cancel();
			}
		}

		public void Cancel()
		{
			if (!_closed)
			{
				if (!Session.Cancel())
				{
					Persist();
					_closed = true;
					TradeHandler.Show(Plugin.Localization.TradePending);
					Give.RemoveAll();
					Close();
				}
				else
				{
					_handler.Send(Session, Session.IsCoordinator ? "abort" : "cancel");
					Refund(localCancellation: true);
				}
			}
		}

		private void Refund(bool localCancellation)
		{
			_closed = true;
			_windows.ClearOfferedView();
			if (Session.IsCoordinator)
			{
				TradeRecovery.RecordDecision(_local, Session.Id, _peerCharacter, committed: false);
			}
			TradeRecovery.Entry entry = new TradeRecovery.Entry
			{
				Session = Session.Id,
				PeerCharacter = _peerCharacter,
				Give = TradeInventory.Save(Give)
			};
			TradeRecovery.Resolve(_local, entry, committed: false);
			Give.RemoveAll();
			TradeHandler.Show(localCancellation ? Plugin.Localization.LocalPlayerCancelledTrade : Plugin.Localization.XHasCancelledTrade);
			Close();
		}

		private void Close()
		{
			Inventory give = Give;
			give.m_onChanged = (Action)Delegate.Remove(give.m_onChanged, new Action(OfferChanged));
			_windows.OnTradeAcceptPressed -= Accept;
			_windows.OnChangeTradePressed -= Change;
			_windows.OnCancelTradePressed -= Cancel;
			_handler.Close(this);
		}
	}
}
namespace PlayerTradingReforged.Trading
{
	internal sealed class ReservationLedger<T> where T : class
	{
		internal sealed class Portion
		{
			public int Slot { get; }

			public int Count { get; set; }

			public Portion(int slot, int count)
			{
				Slot = slot;
				Count = count;
			}
		}

		private readonly Dictionary<T, List<Portion>> _items = new Dictionary<T, List<Portion>>();

		public IEnumerable<int> Slots => (from part in _items.Values.SelectMany((List<Portion> parts) => parts)
			select part.Slot).Distinct();

		public int CountAt(int slot)
		{
			return (from part in _items.Values.SelectMany((List<Portion> parts) => parts)
				where part.Slot == slot
				select part).Sum((Portion part) => part.Count);
		}

		public IEnumerable<int> Origins(T item)
		{
			if (!_items.TryGetValue(item, out List<Portion> value))
			{
				return Enumerable.Empty<int>();
			}
			return value.Select((Portion part) => part.Slot).Distinct();
		}

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

		public void Update(IReadOnlyDictionary<T, int> before, IReadOnlyDictionary<T, int> after, int? sourceSlot)
		{
			Queue<Portion> queue = new Queue<Portion>();
			foreach (KeyValuePair<T, int> item in before)
			{
				int value;
				int num = item.Value - (after.TryGetValue(item.Key, out value) ? value : 0);
				if (num <= 0 || !_items.TryGetValue(item.Key, out List<Portion> value2))
				{
					continue;
				}
				while (num > 0 && value2.Count > 0)
				{
					Portion portion = value2[0];
					int num2 = Math.Min(num, portion.Count);
					queue.Enqueue(new Portion(portion.Slot, num2));
					portion.Count -= num2;
					num -= num2;
					if (portion.Count == 0)
					{
						value2.RemoveAt(0);
					}
				}
				if (value2.Count == 0)
				{
					_items.Remove(item.Key);
				}
			}
			int value5;
			int num3 = after.Sum<KeyValuePair<T, int>>((KeyValuePair<T, int> pair) => Math.Max(0, pair.Value - (before.TryGetValue(pair.Key, out value5) ? value5 : 0))) - queue.Sum((Portion part) => part.Count);
			if (sourceSlot.HasValue && num3 > 0)
			{
				queue.Enqueue(new Portion(sourceSlot.Value, num3));
			}
			foreach (KeyValuePair<T, int> item2 in after)
			{
				int value3;
				int num4 = item2.Value - (before.TryGetValue(item2.Key, out value3) ? value3 : 0);
				if (num4 <= 0)
				{
					continue;
				}
				if (!_items.TryGetValue(item2.Key, out List<Portion> value4))
				{
					value4 = new List<Portion>();
					_items.Add(item2.Key, value4);
				}
				while (num4 > 0 && queue.Count > 0)
				{
					Portion portion2 = queue.Peek();
					int num5 = Math.Min(num4, portion2.Count);
					value4.Add(new Portion(portion2.Slot, num5));
					portion2.Count -= num5;
					num4 -= num5;
					if (portion2.Count == 0)
					{
						queue.Dequeue();
					}
				}
			}
		}
	}
	internal static class TradeCapacity
	{
		internal readonly struct Stack
		{
			public string Name { get; }

			public int Quality { get; }

			public int WorldLevel { get; }

			public int Count { get; }

			public int Maximum { get; }

			public Stack(string name, int quality, int worldLevel, int count, int maximum)
			{
				Name = name;
				Quality = quality;
				WorldLevel = worldLevel;
				Count = count;
				Maximum = maximum;
			}

			public Stack WithCount(int count)
			{
				return new Stack(Name, Quality, WorldLevel, count, Maximum);
			}
		}

		public static bool CanFit(int slots, IReadOnlyList<Stack> existing, IReadOnlyList<Stack> incoming)
		{
			List<Stack> list = new List<Stack>(existing);
			foreach (Stack item in incoming)
			{
				if (item.Count <= 0 || item.Maximum <= 0 || item.Count > item.Maximum)
				{
					return false;
				}
				int num = item.Count;
				if (item.Maximum > 1)
				{
					for (int i = 0; i < list.Count; i++)
					{
						if (num <= 0)
						{
							break;
						}
						Stack stack = list[i];
						if (!(stack.Name != item.Name) && stack.Quality == item.Quality && stack.WorldLevel == item.WorldLevel)
						{
							int num2 = Math.Min(num, Math.Max(0, stack.Maximum - stack.Count));
							list[i] = stack.WithCount(stack.Count + num2);
							num -= num2;
						}
					}
				}
				if (num != 0)
				{
					if (list.Count >= slots)
					{
						return false;
					}
					list.Add(item.WithCount(num));
				}
			}
			return true;
		}
	}
	internal static class TradeInventory
	{
		private enum Purpose
		{
			Offer,
			Preview
		}

		public const int Width = 6;

		public const int Height = 4;

		public const int MaxPackageBytes = 262144;

		private const int MaxPreviewWidth = 16;

		private const int MaxPreviewHeight = 32;

		public static Inventory Create()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			return new Inventory("Trade", (Sprite)null, 6, 4);
		}

		public static string Save(Inventory inventory)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			inventory.Save(val);
			return val.GetBase64();
		}

		public static bool TryLoad(string encoded, out Inventory inventory)
		{
			return TryLoad(encoded, Purpose.Offer, out inventory);
		}

		public static string SavePreview(Inventory inventory)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			if (!ValidPreviewDimensions(inventory.GetWidth(), inventory.GetHeight()))
			{
				return "";
			}
			ZPackage val = new ZPackage();
			val.Write(inventory.GetWidth());
			val.Write(inventory.GetHeight());
			inventory.Save(val);
			if (val.Size() > 262144)
			{
				return "";
			}
			return val.GetBase64();
		}

		public static bool TryLoadPreview(string encoded, out Inventory inventory)
		{
			return TryLoad(encoded, Purpose.Preview, out inventory);
		}

		private static bool ValidPreviewDimensions(int width, int height)
		{
			if (width >= 1 && width <= 16 && height >= 1)
			{
				return height <= 32;
			}
			return false;
		}

		private static bool TryLoad(string encoded, Purpose purpose, out Inventory inventory)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			inventory = Create();
			if (encoded.Length == 0 || encoded.Length > 349529)
			{
				return false;
			}
			try
			{
				ZPackage val = new ZPackage(encoded);
				if (val.Size() > 262144)
				{
					return false;
				}
				int num = 6;
				int num2 = 4;
				if (purpose == Purpose.Preview)
				{
					num = val.ReadInt();
					num2 = val.ReadInt();
					if (!ValidPreviewDimensions(num, num2))
					{
						return false;
					}
					inventory = new Inventory("Preview", (Sprite)null, num, num2);
				}
				ZPackage val2 = new ZPackage();
				Create().Save(val2);
				val2.SetPos(0);
				int num3 = val2.ReadInt();
				if (val.ReadInt() != num3)
				{
					return false;
				}
				int num4 = val.ReadUShort();
				if (num4 > num * num2)
				{
					return false;
				}
				HashSet<Vector2i> hashSet = new HashSet<Vector2i>();
				ItemDrop val3 = default(ItemDrop);
				for (int i = 0; i < num4; i++)
				{
					ValueTuple<int, ItemData> valueTuple = ItemData.Load(val, (Item)num3);
					int item = valueTuple.Item1;
					ItemData item2 = valueTuple.Item2;
					GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item);
					if ((Object)(object)itemPrefab == (Object)null || !itemPrefab.TryGetComponent<ItemDrop>(ref val3))
					{
						return false;
					}
					item2.m_shared = val3.m_itemData.m_shared;
					item2.m_dropPrefab = itemPrefab;
					if (item2.m_stack <= 0 || item2.m_stack > item2.m_shared.m_maxStackSize || (purpose == Purpose.Offer && item2.m_shared.m_questItem) || item2.m_quality < 1 || item2.m_quality > item2.m_shared.m_maxQuality || item2.m_variant < 0 || item2.m_variant >= item2.m_shared.m_icons.Length || float.IsNaN(item2.m_durability) || float.IsInfinity(item2.m_durability) || item2.m_durability < 0f || item2.m_gridPos.x < 0 || item2.m_gridPos.x >= num || item2.m_gridPos.y < 0 || item2.m_gridPos.y >= num2 || !hashSet.Add(item2.m_gridPos))
					{
						return false;
					}
					if (purpose == Purpose.Offer)
					{
						item2.m_equipped = false;
					}
					inventory.m_inventory.Add(item2);
				}
				if (val.GetPos() != val.Size())
				{
					return false;
				}
				inventory.Changed(false, false);
				return true;
			}
			catch (Exception ex) when (ex is FormatException || ex is IOException || ex is ArgumentException || ex is OverflowException)
			{
				Plugin.Warn("Rejected unreadable trade inventory: " + ex.Message);
				return false;
			}
		}

		public static bool CanFit(Inventory destination, Inventory incoming)
		{
			return TradeCapacity.CanFit(destination.GetWidth() * destination.GetHeight(), destination.GetAllItems().Select(Describe).ToArray(), incoming.GetAllItems().Select(Describe).ToArray());
			static TradeCapacity.Stack Describe(ItemData item)
			{
				return new TradeCapacity.Stack(item.m_shared.m_name, item.m_quality, item.m_worldLevel, item.m_stack, item.m_shared.m_maxStackSize);
			}
		}

		public static void Replace(Inventory target, Inventory source)
		{
			target.RemoveAll();
			foreach (ItemData allItem in source.GetAllItems())
			{
				target.m_inventory.Add(allItem.Clone());
			}
			target.Changed(false, false);
		}
	}
	internal sealed class TradePreviewSnapshot
	{
		public Inventory Available { get; }

		public Inventory Reserved { get; }

		public TradePreviewSnapshot(Inventory available, Inventory reserved)
		{
			Available = available;
			Reserved = reserved;
		}

		public string Encode()
		{
			string text = TradeInventory.SavePreview(Available);
			string text2 = TradeInventory.SavePreview(Reserved);
			string text3 = text + "|" + text2;
			if (text.Length <= 0 || text2.Length <= 0 || text3.Length > 524288)
			{
				return "";
			}
			return text3;
		}

		public static TradePreviewSnapshot? Parse(string text)
		{
			if (text.Length > 524288)
			{
				return null;
			}
			int num = text.IndexOf('|');
			if (num < 1 || text.IndexOf('|', num + 1) >= 0 || !TradeInventory.TryLoadPreview(text.Substring(0, num), out Inventory inventory) || !TradeInventory.TryLoadPreview(text.Substring(num + 1), out Inventory inventory2) || inventory.GetWidth() != inventory2.GetWidth() || inventory.GetHeight() != inventory2.GetHeight())
			{
				return null;
			}
			foreach (ItemData allItem in inventory2.GetAllItems())
			{
				if (allItem.m_equipped || allItem.m_shared.m_questItem)
				{
					return null;
				}
				ItemData itemAt = inventory.GetItemAt(allItem.m_gridPos.x, allItem.m_gridPos.y);
				if (itemAt != null && (!itemAt.IsSameType(allItem) || allItem.m_stack > itemAt.m_shared.m_maxStackSize - itemAt.m_stack))
				{
					return null;
				}
			}
			return new TradePreviewSnapshot(inventory, inventory2);
		}
	}
	internal static class TradeRecovery
	{
		internal enum RecoveryState
		{
			Refund,
			AwaitingDecision,
			CoordinatorOffer
		}

		[Serializable]
		internal sealed class Entry
		{
			public string Session = "";

			public long PeerCharacter;

			public RecoveryState State;

			public string Give = "";

			public string Receive = "";
		}

		private const string ActiveKey = "augusdogus.mods.PlayerTradingReforged.escrow.v1";

		private const string ReceiptPrefix = "augusdogus.mods.PlayerTradingReforged.receipt.v1.";

		public static void Store(Player player, TradeSession session, long peerCharacter, Inventory give, Inventory receive)
		{
			player.m_customData["augusdogus.mods.PlayerTradingReforged.escrow.v1"] = JsonUtility.ToJson((object)new Entry
			{
				Session = session.Id,
				PeerCharacter = peerCharacter,
				State = ((session.State == TradeSession.Phase.Prepared) ? RecoveryState.AwaitingDecision : (session.IsCoordinator ? RecoveryState.CoordinatorOffer : RecoveryState.Refund)),
				Give = TradeInventory.Save(give),
				Receive = TradeInventory.Save(receive)
			});
		}

		public static Entry? Read(Player player)
		{
			if (!player.m_customData.TryGetValue("augusdogus.mods.PlayerTradingReforged.escrow.v1", out var value))
			{
				return null;
			}
			try
			{
				Entry entry = JsonUtility.FromJson<Entry>(value);
				if (entry != null && Guid.TryParseExact(entry.Session, "N", out var _) && entry.PeerCharacter != 0L && Enum.IsDefined(typeof(RecoveryState), entry.State))
				{
					return entry;
				}
			}
			catch (ArgumentException ex)
			{
				Plugin.Warn("Cannot read saved trade: " + ex.Message);
			}
			Plugin.Warn("Saved trade recovery data is invalid. New trades remain blocked; preserve the character save and inspect its PlayerTradingReforged custom data before recovery.");
			return null;
		}

		public static bool HasPending(Player player)
		{
			return player.m_customData.ContainsKey("augusdogus.mods.PlayerTradingReforged.escrow.v1");
		}

		public static void Clear(Player player)
		{
			player.m_customData.Remove("augusdogus.mods.PlayerTradingReforged.escrow.v1");
		}

		public static void RecordDecision(Player player, string session, long peerCharacter, bool committed)
		{
			player.m_customData["augusdogus.mods.PlayerTradingReforged.receipt.v1." + session] = peerCharacter.ToString(CultureInfo.InvariantCulture) + (committed ? ":commit" : ":abort");
		}

		public static string? Decision(Player player, string session, long peerCharacter)
		{
			if (!player.m_customData.TryGetValue("augusdogus.mods.PlayerTradingReforged.receipt.v1." + session, out var value))
			{
				return null;
			}
			string text = peerCharacter.ToString(CultureInfo.InvariantCulture) + ":";
			if (!value.StartsWith(text, StringComparison.Ordinal))
			{
				return null;
			}
			return value.Substring(text.Length);
		}

		public static bool Resolve(Player player, Entry entry, bool committed)
		{
			entry.Give = (committed ? entry.Receive : entry.Give);
			entry.Receive = "";
			entry.State = RecoveryState.Refund;
			player.m_customData["augusdogus.mods.PlayerTradingReforged.escrow.v1"] = JsonUtility.ToJson((object)entry);
			if (!TradeInventory.TryLoad(entry.Give, out Inventory inventory))
			{
				Plugin.Warn("Saved trade items could not be read. Escrow is preserved in character custom data; restore the matching item mods before retrying.");
				return false;
			}
			((Humanoid)player).GetInventory().MoveAll(inventory);
			if (inventory.NrOfItems() != 0)
			{
				entry.State = RecoveryState.Refund;
				entry.Give = TradeInventory.Save(inventory);
				entry.Receive = TradeInventory.Save(TradeInventory.Create());
				player.m_customData["augusdogus.mods.PlayerTradingReforged.escrow.v1"] = JsonUtility.ToJson((object)entry);
				return false;
			}
			Clear(player);
			return true;
		}
	}
	internal sealed class TradeSession
	{
		internal enum Phase
		{
			Editing,
			Preparing,
			Prepared,
			Committed,
			Cancelled
		}

		public string Id { get; }

		public long Peer { get; }

		public bool IsCoordinator { get; }

		public Phase State { get; private set; }

		public int LocalRevision { get; private set; }

		public int RemoteRevision { get; private set; }

		public bool LocalAccepted { get; private set; }

		public bool RemoteAccepted { get; private set; }

		public bool CanEdit => State == Phase.Editing;

		public bool BothAccepted
		{
			get
			{
				if (LocalAccepted)
				{
					return RemoteAccepted;
				}
				return false;
			}
		}

		public TradeSession(string id, long peer, bool coordinator)
		{
			Id = id;
			Peer = peer;
			IsCoordinator = coordinator;
		}

		public bool Matches(long sender, string id)
		{
			if (sender == Peer)
			{
				return id == Id;
			}
			return false;
		}

		public bool ChangeOffer()
		{
			if (State != Phase.Editing)
			{
				return false;
			}
			LocalRevision++;
			ResetAcceptance();
			return true;
		}

		public bool ReceiveOffer(int revision)
		{
			if (State != Phase.Editing || revision <= RemoteRevision)
			{
				return false;
			}
			RemoteRevision = revision;
			ResetAcceptance();
			return true;
		}

		public bool Accept()
		{
			if (State != Phase.Editing)
			{
				return false;
			}
			LocalAccepted = true;
			return true;
		}

		public bool ReceiveAccept(int theirRevision, int ourRevision)
		{
			if (State != Phase.Editing || !MatchesRevisions(theirRevision, ourRevision))
			{
				return false;
			}
			RemoteAccepted = true;
			return true;
		}

		public bool Change()
		{
			if (State != Phase.Editing)
			{
				return false;
			}
			return ChangeOffer();
		}

		public bool BeginPrepare()
		{
			if (!IsCoordinator || State != Phase.Editing || !BothAccepted)
			{
				return false;
			}
			State = Phase.Preparing;
			return true;
		}

		public bool Prepare(int theirRevision, int ourRevision)
		{
			if (IsCoordinator || !BothAccepted || !MatchesRevisions(theirRevision, ourRevision))
			{
				return false;
			}
			if (State == Phase.Prepared)
			{
				return true;
			}
			if (State != Phase.Editing)
			{
				return false;
			}
			State = Phase.Prepared;
			return true;
		}

		public bool Commit(int theirRevision, int ourRevision)
		{
			if (!MatchesRevisions(theirRevision, ourRevision))
			{
				return false;
			}
			if (State != (Phase)(IsCoordinator ? 1 : 2))
			{
				return false;
			}
			State = Phase.Committed;
			return true;
		}

		public bool Cancel(bool coordinatorAborted = false)
		{
			if (State == Phase.Committed || State == Phase.Cancelled)
			{
				return false;
			}
			if (State == Phase.Prepared && !coordinatorAborted)
			{
				return false;
			}
			State = Phase.Cancelled;
			return true;
		}

		private bool MatchesRevisions(int theirs, int ours)
		{
			if (theirs == RemoteRevision)
			{
				return ours == LocalRevision;
			}
			return false;
		}

		private void ResetAcceptance()
		{
			LocalAccepted = false;
			RemoteAccepted = false;
		}
	}
	internal sealed class TradeWeightSnapshot
	{
		public float Current { get; }

		public float InBag { get; }

		public float Capacity { get; }

		private TradeWeightSnapshot(float current, float inBag, float capacity)
		{
			Current = current;
			InBag = inBag;
			Capacity = capacity;
		}

		public static string Encode(float inBag, float offered, float capacity)
		{
			return (inBag + offered).ToString("R", CultureInfo.InvariantCulture) + ";" + inBag.ToString("R", CultureInfo.InvariantCulture) + ";" + capacity.ToString("R", CultureInfo.InvariantCulture);
		}

		public static TradeWeightSnapshot? Parse(string text)
		{
			if (text.Length > 128)
			{
				return null;
			}
			string[] array = text.Split(';');
			if (array.Length != 3 || !Read(array[0], out var value) || !Read(array[1], out var value2) || !Read(array[2], out var value3) || value < value2)
			{
				return null;
			}
			return new TradeWeightSnapshot(value, value2, value3);
		}

		private static bool Read(string text, out float value)
		{
			if (float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out value) && !float.IsNaN(value) && !float.IsInfinity(value))
			{
				return value >= 0f;
			}
			return false;
		}
	}
}
namespace PlayerTradingReforged.Patterns
{
	public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
	{
		private static T? _instance;

		public static T? Current
		{
			get
			{
				if (!((Object)(object)_instance != (Object)null))
				{
					return null;
				}
				return _instance;
			}
		}

		public static T Instance => Current ?? throw new InvalidOperationException(typeof(T).Name + " has not initialized.");

		private void Awake()
		{
			if ((Object)(object)Current != (Object)null)
			{
				Object.Destroy((Object)(object)this);
			}
			else if (this is T instance)
			{
				_instance = instance;
				Init();
			}
		}

		protected virtual void Init()
		{
		}
	}
}
namespace PlayerTradingReforged.Patches
{
	internal static class InventoryGuiPatches
	{
		[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
		private static class UpdateContainer
		{
			private static bool Prefix(InventoryGui __instance)
			{
				if (!Active || (Object)(object)__instance.m_currentContainer != (Object)null)
				{
					return true;
				}
				Inventory val = Offer ?? MonoSingleton<TradeWindowManager>.Instance.GetToTradeInventory();
				if (__instance.m_animator.GetBool("visible"))
				{
					((Component)__instance.m_container).gameObject.SetActive(true);
					__instance.m_containerGrid.UpdateInventory(val, (Player)null, __instance.m_dragItem);
					__instance.m_containerName.text = val.GetName();
					if (__instance.m_firstContainerUpdate)
					{
						__instance.m_containerGrid.ResetView();
						__instance.m_firstContainerUpdate = false;
					}
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateContainerWeight")]
		private static class UpdateWeight
		{
			private static bool Prefix(InventoryGui __instance)
			{
				if (!Active || (Object)(object)__instance.m_currentContainer != (Object)null)
				{
					return true;
				}
				Inventory val = Offer ?? MonoSingleton<TradeWindowManager>.Instance.GetToTradeInventory();
				__instance.m_containerWeight.text = Mathf.CeilToInt(val.GetTotalWeight()).ToString();
				return false;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "IsContainerOpen")]
		private static class IsContainerOpen
		{
			private static void Postfix(ref bool __result)
			{
				if (Active)
				{
					__result = true;
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Update")]
		private static class KeepOpenOnUse
		{
			private static void Prefix()
			{
				if (Active)
				{
					ZInput.ResetButtonStatus("Use");
					ZInput.ResetButtonStatus("JoyUse");
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "Hide")]
		private static class CancelOnHide
		{
			private static void Prefix()
			{
				if (Active)
				{
					MonoSingleton<TradeHandler>.Current?.TryCancelTradeInstance();
					MonoSingleton<TradeHandler>.Current?.TryCancelWindowEditMode();
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnTakeAll")]
		private static class TakeAll
		{
			private static bool Prefix(InventoryGui __instance)
			{
				if (!Active || (Object)(object)__instance.m_currentContainer != (Object)null)
				{
					return true;
				}
				if (Editable)
				{
					Inventory offer = Offer;
					if (offer != null && !((Character)Player.m_localPlayer).IsTeleporting())
					{
						__instance.SetupDragItem((ItemData)null, (Inventory)null, 1);
						ItemData[] array = offer.GetAllItems().ToArray();
						foreach (ItemData val in array)
						{
							((Humanoid)Player.m_localPlayer).GetInventory().MoveItemToThis(offer, val);
						}
					}
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")]
		private static class SelectItem
		{
			private static bool Prefix(InventoryGui __instance, InventoryGrid grid, ItemData item, Modifier mod)
			{
				//IL_0068: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Invalid comparison between Unknown and I4
				//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00be: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
				if (!Active || (Object)(object)__instance.m_currentContainer != (Object)null)
				{
					return true;
				}
				if (Editable)
				{
					Inventory offer = Offer;
					if (offer != null)
					{
						Player localPlayer = Player.m_localPlayer;
						if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting())
						{
							return false;
						}
						if (grid.GetInventory() != offer && grid.GetInventory() != ((Humanoid)localPlayer).GetInventory())
						{
							return false;
						}
						if (Object.op_Implicit((Object)(object)__instance.m_dragGo) || (int)mod != 2)
						{
							return true;
						}
						if (item == null || item.m_shared.m_questItem)
						{
							return false;
						}
						((Humanoid)localPlayer).RemoveEquipAction(item);
						((Humanoid)localPlayer).UnequipItem(item, true);
						((grid.GetInventory() == offer) ? ((Humanoid)localPlayer).GetInventory() : offer).MoveItemToThis(grid.GetInventory(), item);
						__instance.m_moveItemEffects.Create(((Component)__instance).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
						return false;
					}
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnRightClickItem")]
		private static class UseItem
		{
			private static bool Prefix(InventoryGrid grid)
			{
				if (Active)
				{
					if (Editable)
					{
						return grid.GetInventory() == ((Humanoid)Player.m_localPlayer).GetInventory();
					}
					return false;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnDropOutside")]
		private static class DropItem
		{
			private static bool Prefix()
			{
				if (Active)
				{
					return Editable;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "UpdateGamepad")]
		private static class Gamepad
		{
			private static bool Prefix(InventoryGui __instance)
			{
				if (!Active || (Object)(object)__instance.m_currentContainer != (Object)null)
				{
					return true;
				}
				if (__instance.m_inventoryGroup.IsActive)
				{
					if (ZInput.GetButtonDown("JoyTabLeft"))
					{
						__instance.SetActiveGroup(1, true);
					}
					if (ZInput.GetButtonDown("JoyTabRight"))
					{
						__instance.SetActiveGroup(0, true);
					}
					if (__instance.m_activeGroup != 0 && __instance.m_activeGroup != 1)
					{
						__instance.SetActiveGroup(1, true);
					}
				}
				return false;
			}
		}

		private static bool Active
		{
			get
			{
				if ((Object)(object)MonoSingleton<TradeHandler>.Current != (Object)null)
				{
					return MonoSingleton<TradeHandler>.Current.IsTradeWindowsOpen();
				}
				return false;
			}
		}

		private static Inventory? Offer => MonoSingleton<TradeHandler>.Current?.TryGetToTradeInventory();

		private static bool Editable
		{
			get
			{
				if ((Object)(object)MonoSingleton<TradeHandler>.Current != (Object)null)
				{
					return MonoSingleton<TradeHandler>.Current.CanEditOffer;
				}
				return false;
			}
		}
	}
	internal static class MessageHudPatches
	{
		[HarmonyPatch(typeof(MessageHud), "UpdateBiomeFound")]
		private static class MessageWrapping
		{
			private static void Postfix(MessageHud __instance)
			{
				if (!((Object)(object)__instance.m_biomeMsgInstance == (Object)null))
				{
					TMP_Text componentInChildren = __instance.m_biomeMsgInstance.GetComponentInChildren<TMP_Text>();
					if ((Object)(object)componentInChildren != (Object)null)
					{
						componentInChildren.overflowMode = (TextOverflowModes)0;
					}
				}
			}
		}
	}
	internal static class PlayerPatches
	{
		[HarmonyPatch(typeof(Player), "GetHoverText")]
		private static class Hover
		{
			private static void Postfix(Player __instance, ref string __result)
			{
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				TradeHandler current = MonoSingleton<TradeHandler>.Current;
				if (!((Object)(object)current == (Object)null) && !current.IsTradeWindowsOpen() && !((Object)(object)__instance == (Object)(object)Player.m_localPlayer))
				{
					string text = (Plugin.UseModifierKey.Value ? (((object)Plugin.ModifierKey.Value/*cast due to .constrained prefix*/).ToString() + " + ") : "");
					__result += Localization.instance.Localize("\n[<color=yellow><b>" + text + "$KEY_Use</b></color>] " + current.GetAction(__instance));
				}
			}
		}

		[HarmonyPatch(typeof(Player), "SetLocalPlayer")]
		private static class LocalPlayer
		{
			private static void Postfix()
			{
				Plugin.NewLocalPlayer();
			}
		}

		[HarmonyPatch(typeof(Player), "OnDeath")]
		private static class Death
		{
			private static void Prefix(Player __instance)
			{
				if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
				{
					MonoSingleton<TradeHandler>.Current?.TryCancelTradeInstance();
				}
			}
		}
	}
	internal static class TradeReservationPatches
	{
		[HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[]
		{
			typeof(Inventory),
			typeof(ItemData)
		})]
		private static class QuickMove
		{
			private static void Prefix(Inventory __instance, Inventory fromInventory, ItemData item, out OfferedInventoryView.Transfer? __state)
			{
				__state = View?.Begin(__instance, fromInventory, item);
			}

			private static void Finalizer(OfferedInventoryView.Transfer? __state)
			{
				if (__state != null)
				{
					View?.End(__state);
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[]
		{
			typeof(Inventory),
			typeof(ItemData),
			typeof(int),
			typeof(int),
			typeof(int)
		})]
		private static class MoveToSlot
		{
			private static void Prefix(Inventory __instance, Inventory fromInventory, ItemData item, out OfferedInventoryView.Transfer? __state)
			{
				__state = View?.Begin(__instance, fromInventory, item);
			}

			private static void Finalizer(OfferedInventoryView.Transfer? __state)
			{
				if (__state != null)
				{
					View?.End(__state);
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "FindEmptySlot")]
		private static class EmptySlot
		{
			private static bool Prefix(Inventory __instance, bool topFirst, ref Vector2i __result)
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				OfferedInventoryView view = View;
				if (view == null || !view.IsPlayerInventory(__instance))
				{
					return true;
				}
				__result = view.FindEmptySlot(topFirst);
				return false;
			}
		}

		[HarmonyPatch(typeof(Inventory), "GetEmptySlots")]
		private static class EmptyCount
		{
			private static void Postfix(Inventory __instance, ref int __result)
			{
				OfferedInventoryView view = View;
				if (view != null && view.IsPlayerInventory(__instance))
				{
					__result = Math.Max(0, __result - view.EmptyReservedSlots);
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "HaveEmptySlot")]
		private static class HasSlot
		{
			private static void Postfix(Inventory __instance, ref bool __result)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				OfferedInventoryView view = View;
				if (view != null && view.IsPlayerInventory(__instance))
				{
					__result = view.FindEmptySlot(topFirst: true).x >= 0;
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
		{
			typeof(ItemData),
			typeof(int),
			typeof(int),
			typeof(int),
			typeof(bool)
		})]
		private static class AddToSlot
		{
			private static bool Prefix(Inventory __instance, int x, int y, ref bool __result)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				OfferedInventoryView view = View;
				if (view == null || !view.IsPlayerInventory(__instance) || view.CanAdd(new Vector2i(x, y)))
				{
					return true;
				}
				__result = false;
				return false;
			}
		}

		[HarmonyPatch(typeof(Inventory), "FindFreeStackItem")]
		private static class FreeStack
		{
			private static void Postfix(Inventory __instance, string name, int quality, float worldLevel, ref ItemData? __result)
			{
				//IL_001b: 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)
				OfferedInventoryView view = View;
				if (view == null || !view.IsPlayerInventory(__instance) || __result == null || view.CanAdd(__result.m_gridPos))
				{
					return;
				}
				__result = null;
				foreach (ItemData allItem in __instance.GetAllItems())
				{
					if (allItem.m_shared.m_name == name && allItem.m_quality == quality && (float)allItem.m_worldLevel == worldLevel && allItem.m_stack < allItem.m_shared.m_maxStackSize && view.CanAdd(allItem.m_gridPos))
					{
						__result = allItem;
						break;
					}
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGrid), "DropItem")]
		private static class DropOnReservation
		{
			private static bool Prefix(InventoryGrid __instance, Inventory fromInventory, ItemData item, Vector2i pos, ref bool __result)
			{
				//IL_0013: 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_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_007a: Unknown result type (might be due to invalid IL or missing references)
				OfferedInventoryView view = View;
				if (view == null)
				{
					return true;
				}
				Inventory inventory = __instance.GetInventory();
				ItemData itemAt = inventory.GetItemAt(pos.x, pos.y);
				if ((view.IsOfferInventory(inventory) || view.IsOfferInventory(fromInventory)) && itemAt != null && itemAt != item && (!itemAt.IsSameType(item) || itemAt.m_shared.m_maxStackSize == 1))
				{
					__result = false;
					return false;
				}
				if (!view.IsPlayerInventory(inventory) || !view.Reserved(pos))
				{
					return true;
				}
				if (!view.IsPlayerInventory(fromInventory) && view.CanReturn(item, pos))
				{
					return true;
				}
				__result = false;
				return false;
			}
		}

		[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
		private static class DrawReservations
		{
			private static void Postfix(InventoryGrid __instance)
			{
				OfferedInventoryView view = View;
				if (view != null && (Object)(object)__instance == (Object)(object)InventoryGui.instance.m_playerGrid)
				{
					view.Draw(__instance);
				}
			}
		}

		private static OfferedInventoryView? View => MonoSingleton<TradeWindowManager>.Current?.OfferedView;
	}
}
namespace PlayerTradingReforged.GUI
{
	internal sealed class ContainerTradeWindow : TradeWindow
	{
		private bool _flipped;

		private RectTransform? _takeAll;

		private RectTransform? _gridRoot;

		private GameObject? _stackAll;

		private bool _stackAllWasActive;

		private Transform? _originalParent;

		private int _originalSibling;

		public void Initialize()
		{
			InventoryGui instance = InventoryGui.instance;
			Initialize(instance.m_container, Plugin.Localization.ToGiveWindowText, left: true, Plugin.ToGiveUserOffset);
			_originalParent = ((Transform)instance.m_container).parent;
			_originalSibling = ((Transform)instance.m_container).GetSiblingIndex();
			_takeAll = ((Component)instance.m_takeAllButton).GetComponent<RectTransform>();
			_gridRoot = ((Component)((Component)base.Grid).transform.Find("Root")).GetComponent<RectTransform>();
			_stackAll = ((Component)instance.m_stackAllButton).gameObject;
		}

		public override void Show()
		{
			((Transform)base.Panel).SetParent(InventoryGui.instance.m_inventoryRoot, false);
			if (!_flipped)
			{
				Flip();
			}
			base.Show();
			if ((Object)(object)_stackAll != (Object)null)
			{
				_stackAllWasActive = _stackAll.activeSelf;
				_stackAll.SetActive(false);
			}
			InventoryGui.instance.m_containerName.text = base.Inventory.GetName();
			InventoryGui.instance.Show((Container)null, 1);
		}

		public override void Hide()
		{
			base.Hide();
			if (_flipped && Object.op_Implicit((Object)(object)InventoryGui.instance))
			{
				Flip();
			}
			if ((Object)(object)_originalParent != (Object)null && Object.op_Implicit((Object)(object)InventoryGui.instance))
			{
				((Transform)base.Panel).SetParent(_originalParent, false);
				((Transform)base.Panel).SetSiblingIndex(_originalSibling);
			}
			RestorePosition();
			if ((Object)(object)_stackAll != (Object)null)
			{
				_stackAll.SetActive(_stackAllWasActive);
			}
			if (Object.op_Implicit((Object)(object)InventoryGui.instance))
			{
				InventoryGui.instance.CloseContainer();
				InventoryGui.instance.Hide();
			}
		}

		private void Flip()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_takeAll == (Object)null) && !((Object)(object)_gridRoot == (Object)null))
			{
				Vector2 anchoredPosition = _takeAll.anchoredPosition;
				RectTransformUtility.FlipLayoutOnAxis(base.Panel, 0, true, true);
				RectTransformUtility.FlipLayoutOnAxis(_gridRoot, 0, true, true);
				_takeAll.anchoredPosition = anchoredPosition;
				_flipped = !_flipped;
			}
		}

		public override void Reset()
		{
			if (base.Inventory.NrOfItems() != 0)
			{
				throw new InvalidOperationException("Cannot open a trade before its previous items are recovered.");
			}
			base.Reset();
		}
	}
	internal sealed class OfferedInventoryView
	{
		internal sealed class Transfer
		{
			public Dictionary<ItemData, int> Before { get; }

			public int? SourceSlot { get; }

			public ItemData? PreviousReturn { get; }

			public Transfer(Dictionary<ItemData, int> before, int? sourceSlot, ItemData? previousReturn)
			{
				Before = before;
				SourceSlot = sourceSlot;
				PreviousReturn = previousReturn;
			}
		}

		private readonly Inventory _player;

		private readonly Inventory _offer;

		private readonly ReservationLedger<ItemData> _ledger = new ReservationLedger<ItemData>();

		private readonly Dictionary<int, ItemData> _templates = new Dictionary<int, ItemData>();

		private Dictionary<ItemData, int> _last = new Dictionary<ItemData, int>();

		private ItemData? _returning;

		public int EmptyReservedSlots => _ledger.Slots.Count((int slot) => _player.GetItemAt(Position(slot).x, Position(slot).y) == null);

		public OfferedInventoryView(Inventory player, Inventory offer)
		{
			_player = player;
			_offer = offer;
		}

		public bool IsPlayerInventory(Inventory inventory)
		{
			return inventory == _player;
		}

		public bool IsOfferInventory(Inventory inventory)
		{
			return inventory == _offer;
		}

		private int Slot(Vector2i position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return position.y * _player.GetWidth() + position.x;
		}

		private Vector2i Position(int slot)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2i(slot % _player.GetWidth(), slot / _player.GetWidth());
		}

		private Dictionary<ItemData, int> Snapshot()
		{
			return _offer.GetAllItems().ToDictionary((ItemData item) => item, (ItemData item) => item.m_stack);
		}

		public bool Reserved(Vector2i position)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return _ledger.CountAt(Slot(position)) > 0;
		}

		public bool CanReturn(ItemData item, Vector2i position)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			return _ledger.Origins(item).Contains(Slot(position));
		}

		public bool CanAdd(Vector2i position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (Reserved(position))
			{
				if (_returning != null)
				{
					return CanReturn(_returning, position);
				}
				return false;
			}
			return true;
		}

		public Transfer? Begin(Inventory destination, Inventory source, ItemData item)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (source != _offer && destination != _offer)
			{
				return null;
			}
			Reconcile();
			int? sourceSlot = ((source == _player && destination == _offer) ? new int?(Slot(item.m_gridPos)) : ((int?)null));
			if (sourceSlot.HasValue)
			{
				_templates[sourceSlot.Value] = item.Clone();
			}
			Transfer result = new Transfer(Snapshot(), sourceSlot, _returning);
			if (source == _offer && destination == _player)
			{
				_returning = item;
			}
			return result;
		}

		public void End(Transfer transfer)
		{
			try
			{
				Dictionary<ItemData, int> dictionary = Snapshot();
				_ledger.Update(transfer.Before, dictionary, transfer.SourceSlot);
				_last = dictionary;
			}
			finally
			{
				_returning = transfer.PreviousReturn;
			}
		}

		private void Reconcile()
		{
			Dictionary<ItemData, int> dictionary = Snapshot();
			_ledger.Update(_last, dictionary, null);
			_last = dictionary;
		}

		public Vector2i FindEmptySlot(bool topFirst)
		{
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			if (_returning != null)
			{
				foreach (int item in _ledger.Origins(_returning))
				{
					Vector2i val = Position(item);
					if (_player.GetItemAt(val.x, val.y) == null)
					{
						return val;
					}
				}
			}
			for (int i = 0; i < _player.GetHeight(); i++)
			{
				int num = (topFirst ? i : (_player.GetHeight() - 1 - i));
				for (int j = 0; j < _player.GetWidth(); j++)
				{
					if (_player.GetItemAt(j, num) == null && !Reserved(new Vector2i(j, num)))
					{
						return new Vector2i(j, num);
					}
				}
			}
			return new Vector2i(-1, -1);
		}

		public Inventory CreateReservations()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			Reconcile();
			Inventory val = new Inventory("Reservations", (Sprite)null, _player.GetWidth(), _player.GetHeight());
			foreach (int slot in _ledger.Slots)
			{
				if (_templates.TryGetValue(slot, out ItemData value))
				{
					ItemData val2 = value.Clone();
					val2.m_stack = _ledger.CountAt(slot);
					val2.m_gridPos = Position(slot);
					val2.m_equipped = false;
					val.m_inventory.Add(val2);
				}
			}
			val.Changed(false, false);
			return val;
		}

		public void Draw(InventoryGrid grid)
		{
			ReservedInventoryRenderer.Draw(grid, _player, CreateReservations());
		}

		public void Clear()
		{
			_ledger.Clear();
			_templates.Clear();
			_last.Clear();
			_returning = null;
		}
	}
	internal sealed class PlayerInventoryFrame
	{
		public const float HeaderHeight = 50f;

		private readonly GameObject _original;

		private readonly RectTransform _frame;

		private bool _wasActive;

		public PlayerInventoryFrame(RectTransform player, RectTransform partner)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			_original = ((Component)((Transform)player).Find("Bkg")).gameObject;
			_frame = Object.Instantiate<RectTransform>(((Component)((Transform)partner).Find("Bkg")).GetComponent<RectTransform>(), (Transform)(object)player, false);
			((Object)_frame).name = "PlayerTradingReforgedPlayerFrame";
			((Transform)_frame).SetSiblingIndex(_original.transform.GetSiblingIndex());
			_frame.anchorMin = Vector2.zero;
			_frame.anchorMax = Vector2.one;
			_frame.offsetMin = Vector2.zero;
			_frame.offsetMax = new Vector2(0f, 50f);
			TMP_Text obj = Object.Instantiate<TMP_Text>(((Component)((Transform)partner).Find("container_name")).GetComponent<TMP_Text>(), (Transform)(object)_frame, false);
			obj.text = Plugin.Localization.YourInventoryText;
			((Graphic)obj).raycastTarget = false;
			obj.alignment = (TextAlignmentOptions)514;
			RectTransform rectTransform = obj.rectTransform;
			rectTransform.anchorMin = new Vector2(0f, 1f);
			rectTransform.anchorMax = Vector2.one;
			rectTransform.pivot = new Vector2(0.5f, 1f);
			rectTransform.sizeDelta = new Vector2(0f, 50f);
			rectTransform.anchoredPosition = Vector2.zero;
			((Component)_frame).gameObject.SetActive(false);
		}

		public void Show()
		{
			_wasActive = _original.activeSelf;
			_original.SetActive(false);
			((Component)_frame).gameObject.SetActive(true);
		}

		public void Hide()
		{
			if (Object.op_Implicit((Object)(object)_original))
			{
				_original.SetActive(_wasActive);
			}
			if (Object.op_Implicit((Object)(object)_frame))
			{
				((Component)_frame).gameObject.SetActive(false);
			}
		}

		public void Destroy()
		{
			if (Object.op_Implicit((Object)(object)_frame))
			{
				Object.Destroy((Object)(object)((Component)_frame).gameObject);
			}
		}
	}
	internal sealed class PreviewTradeWindow : TradeWindow
	{
		private GameObject? _clone;

		private TMP_Text? _weight;

		private TMP_Text? _title;

		private float _horizontalPadding;

		private Inventory? _reservations;

		public void Initialize(string name, string title, ConfigEntry<Vector2> offset)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_011a: Unknown result type (might be due to invalid IL or missing references)
			RectTransform container = InventoryGui.instance.m_container;
			_clone = Object.Instantiate<GameObject>(((Component)container).gameObject, InventoryGui.instance.m_inventoryRoot, false);
			((Object)_clone).name = name;
			Initialize(_clone.GetComponent<RectTransform>(), title, left: false, offset);
			Rect rect = base.Panel.rect;
			float width = ((Rect)(ref rect)).width;
			rect = ((Component)base.Grid).GetComponent<RectTransform>().rect;
			_horizontalPadding = Mathf.Max(0f, width - ((Rect)(ref rect)).width);
			base.Grid.m_onSelected = null;
			base.Grid.m_onRightClick = null;
			base.Grid.m_onReleased = null;
			base.Grid.m_onEnter = null;
			base.Grid.OnMoveToUpperInventoryGrid = null;
			base.Grid.OnMoveToLowerInventoryGrid = null;
			base.Grid.OnSetTouchSelection = null;
			base.Grid.CanDropDragOntoItem = (ItemData _) => false;
			foreach (Transform item in (Transform)base.Grid.m_gridRoot)
			{
				Object.Destroy((Object)(object)((Component)item).gameObject);
			}
			base.Grid.m_elements.Clear();
			base.Grid.m_width = 0;
			base.Grid.m_height = 0;
			_title = ((Component)_clone.transform.Find("container_name")).GetComponent<TMP_Text>();
			_title.richText = false;
			_title.text = title;
			Button[] componentsInChildren = _clone.GetComponentsInChildren<Button>(true);
			for (int num = 0; num < componentsInChildren.Length; num++)
			{
				((Component)componentsInChildren[num]).gameObject.SetActive(false);
			}
			_weight = ((Component)_clone.transform.Find("Weight")).GetComponentInChildren<TMP_Text>(true);
			base.Group.ResetActiveElement();
			base.Group.SetActive(false);
			Hide();
		}

		public void SetTitle(string title)
		{
			if ((Object)(object)_title != (Object)null)
			{
				_title.text = title;
			}
		}

		public void Display(Inventory inventory, string title, Inventory? reservations = null)
		{
			base.Inventory = inventory;
			_reservations = reservations;
			if ((Object)(object)_title != (Object)null)
			{
				_title.text = title;
			}
			base.Panel.SetSizeWithCurrentAnchors((Axis)0, _horizontalPadding + (float)inventory.GetWidth() * base.Grid.m_elementSpace);
			Refresh();
		}

		protected override void Update()
		{
			base.Update();
			if (base.Visible)
			{
				Refresh();
			}
		}

		public override void Show()
		{
			base.Show();
			if ((Object)(object)_clone != (Object)null)
			{
				_clone.SetActive(true);
			}
		}

		public override void Hide()
		{
			_reservations = null;
			base.Hide();
			if ((Object)(object)_clone != (Object)null)
			{
				_clone.SetActive(false);
			}
		}

		public override void Reset()
		{
			_reservations = null;
			base.Inventory.RemoveAll();
			base.Reset();
			Refresh();
		}

		public override void Refresh()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			base.Refresh();
			foreach (InventoryElement element in base.Grid.m_elements)
			{
				ItemData itemAt = base.Inventory.GetItemAt(element.Position.x, element.Position.y);
				((Behaviour)element.m_equiped).enabled = itemAt?.m_equipped ?? false;
				((Graphic)element.m_equiped).color = new Color(0.35f, 0.65f, 0.59f, 0.65f);
			}
			if (_reservations != null)
			{
				ReservedInventoryRenderer.Draw(base.Grid, base.Inventory, _reservations);
			}
			if ((Object)(object)_weight != (Object)null)
			{
				_weight.text = Mathf.CeilToInt(base.Inventory.GetTotalWeight()).ToString();
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_clone != (Object)null)
			{
				Object.Destroy((Object)(object)_clone);
			}
		}
	}
	internal static class ReservedInventoryRenderer
	{
		public static void Draw(InventoryGrid grid, Inventory availableInventory, Inventory reservations)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			foreach (ItemData allItem in reservations.GetAllItems())
			{
				Vector2i gridPos = allItem.m_gridPos;
				InventoryElement element = grid.GetElement(gridPos.x, gridPos.y, availableInventory.GetWidth());
				if ((Object)(object)element == (Object)null)
				{
					continue;
				}
				int stack = allItem.m_stack;
				ItemData itemAt = availableInventory.GetItemAt(gridPos.x, gridPos.y);
				if (itemAt == null)
				{
					((Behaviour)element.m_icon).enabled = true;
					element.m_icon.sprite = allItem.GetIcon();
					((Graphic)element.m_icon).color = Color.grey;
					((Behaviour)element.m_quality).enabled = allItem.m_shared.m_maxQuality > 1;
					element.m_quality.text = allItem.m_quality.ToString();
					((Behaviour)element.m_amount).enabled = allItem.m_shared.m_maxStackSize > 1;
					element.m_amount.text = stack + "/" + allItem.m_shared.m_maxStackSize;
					if ((Object)(object)grid.GetHoveredElement() == (Object)(object)element)
					{
						allItem.m_stack = stack;
						grid.CreateItemTooltip(allItem, element.m_tooltip);
					}
				}
				else
				{
					((Behaviour)element.m_amount).enabled = true;
					element.m_amount.text = itemAt.m_stack + "/" + itemAt.m_shared.m_maxStackSize;
				}
				if ((Object)(object)grid.GetHoveredElement() == (Object)(object)element)
				{
					UITooltip tooltip = element.m_tooltip;
					tooltip.m_text = tooltip.m_text + "\n" + string.Format(Plugin.Localization.ReservedForTradeText, stack);
				}
			}
		}
	}
	internal sealed class TradeButton : MonoBehaviour
	{
		private GameObject? _object;

		private Button? _button;

		private RectTransform? _rect;

		private TMP_Text? _text;

		private Image? _image;

		private Color _original;

		private ConfigEntry<Vector2>? _offset;

		private bool _editing;

		private bool _moving;

		public void Initialize(string title, UnityAction action, ConfigEntry<Vector2> offset, UIGroupHandler group, string joyButton, string joyHint)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			_offset = offset;
			_object = Object.Instantiate<GameObject>(((Component)InventoryGui.instance.m_takeAllButton).gameObject, InventoryGui.instance.m_inventoryRoot, false);
			((Object)_object).name = "PlayerTradingReforged" + joyHint;
			_button = _object.GetComponent<Button>();
			_rect = _object.GetComponent<RectTransform>();
			_text = ((Component)_button).GetComponentInChildren<TMP_Text>(true);
			_image = _object.GetComponent<Image>();
			_original = ((Graphic)_image).color;
			UIGamePad component = _object.GetComponent<UIGamePad>();
			component.m_zinputKey = joyButton;
			component.m_group = group;
			((Component)_object.transform.Find("gamepad_hint")).GetComponentInChildren<TMP_Text>(true).text = joyHint;
			SetText(title);
			SetAction(action);
			SetActive(active: false);
		}

		private void Update()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_object == (Object)null || !_object.activeInHierarchy || (Object)(object)_rect == (Object)null || _offset == null || !_editing)
			{
				return;
			}
			Vector2 val = Vector2.op_Implicit(((Transform)_rect).InverseTransformPoint(Input.mousePosition));
			if (Input.GetMouseButtonDown(0))
			{
				Rect rect = _rect.rect;
				if (((Rect)(ref rect)).Contains(val))
				{
					_moving = true;
				}
			}
			if (Input.GetMouseButtonUp(0))
			{
				_moving = false;
			}
			if (_moving)
			{
				ConfigEntry<Vector2>? offset = _offset;
				offset.Value += new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y")) * 8f;
			}
		}

		public void Place(RectTransform root, Vector2 position, float scale)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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)
			if (!((Object)(object)_rect == (Object)null) && _offset != null)
			{
				_rect.pivot = new Vector2(0.5f, 1f);
				((Transform)_rect).localScale = Vector3.one * scale;
				((Transform)_rect).position = ((Transform)root).TransformPoint(Vector2.op_Implicit(position + _offset.Value));
			}
		}

		public void SetText(string text)
		{
			if ((Object)(object)_text != (Object)null)
			{
				_text.text = text;
			}
		}

		public void SetAction(UnityAction action)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			if (!((Object)(object)_button == (Object)null))
			{
				_button.onClick = new ButtonClickedEvent();
				((UnityEvent)_button.onClick).AddListener(action);
			}
		}

		public void SetActive(bool active)
		{
			if ((Object)(object)_object != (Object)null)
			{
				_object.SetActive(active);
			}
		}

		public void SetEditMode(bool editing)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			_editing = editing;
			_moving = false;
			if ((Object)(object)_button != (Object)null)
			{
				((Selectable)_button).interactable = !editing;
			}
			if ((Object)(object)_image != (Object)null)
			{
				((Graphic)_image).color = (editing ? Color.Lerp(_original, Color.magenta, 0.35f) : _original);
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_object != (Object)null)
			{
				Object.Destroy((Object)(object)_object);
			}
		}
	}
	internal sealed class TradeWeightBadge
	{
		private readonly RectTransform _original;

		private readonly RectTransform _badge;

		private readonly TMP_Text _text;

		private readonly Color _color;

		private bool _originalActive;

		public TradeWeightBadge(RectTransform original)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			_original = original;
			_badge = Object.Instantiate<RectTransform>(original, ((Transform)original).parent, false);
			((Object)_badge).name = "PlayerTradingReforgedWeight";
			_badge.pivot = new Vector2(0f, 0.5f);
			_badge.SetSizeWithCurrentAnchors((Axis)0, 125f);
			_badge.SetSizeWithCurrentAnchors((Axis)1, 96f);
			_text = ((Component)_badge).GetComponentInChildren<TMP_Text>(true);
			_color = ((Graphic)_text).color;
			_text.enableAutoSizing = false;
			_text.fontSize = 16f;
			_text.alignment = (TextAlignmentOptions)514;
			RectTransform rectTransform = _text.rectTransform;
			rectTransform.anchorMin = Vector2.zero;
			rectTransform.anchorMax = Vector2.one;
			rectTransform.offsetMin = new Vector2(4f, 4f);
			rectTransform.offsetMax = new Vector2(-4f, -8f);
			((Component)_badge).gameObject.SetActive(false);
		}

		public void Show()
		{
			_originalActive = ((Component)_original).gameObject.activeSelf;
			((Component)_original).gameObject.SetActive(false);
			((Component)_badge).gameObject.SetActive(true);
		}

		public void Hide()
		{
			if (Object.op_Implicit((Object)(object)_original))
			{
				((Component)_original).gameObject.SetActive(_originalActive);
			}
			if (Object.op_Implicit((Object)(object)_badge))
			{
				((Component)_badge).gameObject.SetActive(false);
			}
		}

		public void Display(float? current, float? projected, float? capacity)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			RectTransform badge = _badge;
			RectTransform badge2 = _badge;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(1f, 0f);
			badge2.anchorMax = val;
			badge.anchorMin = val;
			_badge.anchoredPosition = new Vector2(0f, 65f);
			string text = Format(capacity);
			string text2 = Format(projected) + "/" + text;
			if (projected.HasValue && capacity.HasValue && projected.Value > capacity.Value)
			{
				text2 = "<color=#FF5555>" + text2 + "</color>";
			}
			((Graphic)_text).color = _color;
			_text.text = Format(current) + "/" + text + "\n<size=12>" + Plugin.Localization.ProjectedWeightText + "</size>\n" + text2;
		}

		private static string Format(float? value)
		{
			if (!value.HasValue)
			{
				return "?";
			}
			return Mathf.CeilToInt(value.Value).ToString();
		}

		public void Destroy()
		{
			if (Object.op_Implicit((Object)(object)_badge))
			{
				Object.Destroy((Object)(object)((Component)_badge).gameObject);
			}
		}
	}
	internal abstract class TradeWindow : MonoBehaviour
	{
		private RectTransform? _panel;

		private Image? _background;

		private InventoryGrid? _grid;

		private ConfigEntry<Vector2>? _offset;

		private Color _originalColor;

		private Vector2 _anchorMin;

		private Vector2 _anchorMax;

		private Vector2 _position;

		private Vector2 _pivot;

		private Vector2 _size;

		private Vector3 _scale;

		private bool _editing;

		private bool _moving;

		private bool _accepted;

		protected bool Visible { get; private set; }

		protected bool IsLeft { get; private set; }

		public RectTransform Panel => _panel ?? throw new InvalidOperationException("Trade window has not initialized.");

		protected InventoryGrid Grid => _grid ?? throw new InvalidOperationException("Trade grid has not initialized.");

		public Inventory Inventory { get; protected set; } = TradeInventory.Create();

		protected Vector2 UserOffset => _offset?.Value ?? Vector2.zero;

		public UIGroupHandler Group => ((Component)Panel).GetComponent<UIGroupHandler>();

		protected void Initialize(RectTransform panel, string title, bool left, ConfigEntry<Vector2> offset)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			_panel = panel;
			_background = ((Component)((Transform)panel).Find("Bkg")).GetComponent<Image>();
			_grid = ((Component)panel).GetComponentInChildren<InventoryGrid>(true);
			_offset = offset;
			_originalColor = ((Graphic)_background).color;
			_pivot = panel.pivot;
			_size = panel.sizeDelta;
			_scale = ((Transform)panel).localScale;
			_anchorMin = panel.anchorMin;
			_anchorMax = panel.anchorMax;
			_position = panel.anchoredPosition;
			IsLeft = left;
			Inventory = new Inventory(title, (Sprite)null, 6, 4);
		}

		protected virtual void Update()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			if (!Visible || (Object)(object)_panel == (Object)null || _offset == null || !_editing)
			{
				return;
			}
			Vector2 val = Vector2.op_Implicit(((Transform)_panel).InverseTransformPoint(Input.mousePosition));
			if (Input.GetMouseButtonDown(0))
			{
				Rect rect = _panel.rect;
				if (((Rect)(ref rect)).Contains(val))
				{
					_moving = true;
				}
			}
			if (Input.GetMouseButtonUp(0))
			{
				_moving = false;
			}
			if (_moving)
			{
				ConfigEntry<Vector2>? offset = _offset;
				offset.Value += new Vector2(Input.GetAxis("Mouse X") * 8f, (0f - Input.GetAxis("Mouse Y")) * 8f);
			}
		}

		public void Place(RectTransform root, Vector2 position, float scale)
		{
			//IL_0010: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			Panel.pivot = new Vector2(0f, 1f);
			((Transform)Panel).localScale = Vector3.one * scale;
			((Transform)Panel).position = ((Transform)root).TransformPoint(Vector2.op_Implicit(position + new Vector2(UserOffset.x, 0f - UserOffset.y)));
		}