Decompiled source of MayheimTrader v0.1.1

plugins/MayheimTrader/MayheimTrader.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using MayheimTrader.Commands;
using MayheimTrader.Localization;
using MayheimTrader.Network;
using MayheimTrader.Persistence;
using MayheimTrader.UI;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Mayhem")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Troca direta de itens entre dois jogadores, com entrega garantida via servidor.")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+4e3e54044fbbc9abd6931082b38c99cd145603ca")]
[assembly: AssemblyProduct("MayheimTrader")]
[assembly: AssemblyTitle("MayheimTrader")]
[assembly: AssemblyVersion("0.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MayheimTrader
{
	[BepInPlugin("com.mayhem.mayheimtrader", "MayheimTrader", "0.1.1")]
	internal class MayheimTraderPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.mayhem.mayheimtrader";

		public const string PluginName = "MayheimTrader";

		public const string PluginVersion = "0.1.1";

		private const float TradeManagerTickInterval = 1f;

		internal static ManualLogSource Log;

		private readonly Harmony _harmony = new Harmony("com.mayhem.mayheimtrader");

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony.PatchAll();
			TradeCommand.Register();
			((MonoBehaviour)this).InvokeRepeating("TradeManagerTick", 1f, 1f);
			Log.LogInfo((object)"MayheimTrader 0.1.1 carregado.");
		}

		private void Update()
		{
			TradeWindow.FrameUpdate();
		}

		private void TradeManagerTick()
		{
			TradeManager.Tick();
			TradeClient.Tick();
		}

		private void OnDestroy()
		{
			((MonoBehaviour)this).CancelInvoke("TradeManagerTick");
			_harmony.UnpatchSelf();
		}
	}
}
namespace MayheimTrader.UI
{
	[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")]
	internal static class PlayerGridDropPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(InventoryGui __instance, InventoryGrid grid, ItemData item, Vector2i pos)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)grid != (Object)(object)__instance.m_playerGrid)
			{
				return true;
			}
			return !TradeWindow.TryDropHeldOnPlayerGrid(item, pos);
		}
	}
	internal static class TradeWindow
	{
		private enum Mode
		{
			Closed,
			Debug,
			Session
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static Action<InventoryGrid, ItemData, Vector2i, Modifier> <0>__OnMyOfferGridSelected;

			public static Action<InventoryGrid, ItemData, Vector2i> <1>__OnMyOfferGridRightClicked;

			public static UnityAction <2>__OnConfirmClicked;

			public static UnityAction <3>__OnCloseClicked;
		}

		internal const int OfferColumns = 6;

		internal const int OfferRows = 3;

		private static readonly FieldInfo DragItemField = AccessTools.Field(typeof(InventoryGui), "m_dragItem");

		private static readonly FieldInfo DragInventoryField = AccessTools.Field(typeof(InventoryGui), "m_dragInventory");

		private static readonly FieldInfo DragAmountField = AccessTools.Field(typeof(InventoryGui), "m_dragAmount");

		private static readonly MethodInfo SetupDragItemMethod = AccessTools.Method(typeof(InventoryGui), "SetupDragItem", (Type[])null, (Type[])null);

		private static GameObject _root;

		private static InventoryGrid _myOfferGrid;

		private static InventoryGrid _theirOfferGrid;

		private static CanvasGroup _myOfferGroup;

		private static TMP_Text _myTitle;

		private static TMP_Text _theirTitle;

		private static Button _confirmButton;

		private static Button _closeButton;

		private static Inventory _myOffer;

		private static Inventory _theirOfferMirror;

		private static ItemData _heldOfferItem;

		private static GameObject _heldIcon;

		private static Mode _mode = Mode.Closed;

		private static bool _locked;

		internal static Inventory MyOffer => _myOffer;

		internal static void ToggleDebug()
		{
			if (_mode == Mode.Session)
			{
				TradeClient.ShowMessage(TradeText.Get("mt_in_real_trade"));
			}
			else if (_mode == Mode.Debug)
			{
				CloseDebug();
			}
			else if (EnsureBuilt())
			{
				_mode = Mode.Debug;
				_theirOfferMirror.RemoveAll();
				SetTitles(TradeText.Get("mt_debug_your_offer"), TradeText.Get("mt_debug_their_offer"));
				SetLocked(locked: false);
				SetButtonText(_confirmButton, TradeText.Get("mt_debug_lock"));
				SetButtonText(_closeButton, TradeText.Get("mt_close"));
				SetButtonsInteractable(interactable: true);
				ShowPanels();
			}
		}

		private static void CloseDebug()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				foreach (ItemData item in new List<ItemData>(_myOffer.GetAllItems()))
				{
					((Humanoid)localPlayer).GetInventory().MoveItemToThis(_myOffer, item);
				}
			}
			_mode = Mode.Closed;
			HidePanels();
		}

		internal static void OpenSession(string otherName)
		{
			if (_mode == Mode.Debug)
			{
				CloseDebug();
			}
			if (EnsureBuilt())
			{
				_mode = Mode.Session;
				_myOffer.RemoveAll();
				_theirOfferMirror.RemoveAll();
				SetTitles(TradeText.Get("mt_your_offer"), TradeText.Get("mt_their_offer", otherName));
				SetLocked(locked: false);
				SetButtonText(_confirmButton, TradeText.Get("mt_confirm"));
				SetButtonText(_closeButton, TradeText.Get("mt_cancel"));
				SetButtonsInteractable(interactable: true);
				ShowPanels();
			}
		}

		internal static void SetMirror(ZPackage offer)
		{
			if (_mode == Mode.Session)
			{
				_theirOfferMirror.Load(offer);
				RefreshAll();
			}
		}

		internal static void SetConfirmState(bool mine, bool theirs, string otherName)
		{
			if (_mode == Mode.Session)
			{
				SetLocked(mine);
				SetButtonText(_confirmButton, TradeText.Get(mine ? "mt_undo" : "mt_confirm"));
				SetTitles(TradeText.Get(mine ? "mt_your_offer_confirmed" : "mt_your_offer"), TradeText.Get(theirs ? "mt_their_offer_confirmed" : "mt_their_offer", otherName));
			}
		}

		internal static void SetDepositing()
		{
			if (_mode == Mode.Session)
			{
				SetLocked(locked: true);
				SetButtonsInteractable(interactable: false);
				if ((Object)(object)_myTitle != (Object)null)
				{
					_myTitle.text = TradeText.Get("mt_delivering");
				}
				RefreshAll();
			}
		}

		internal static void CloseSession()
		{
			if (_mode == Mode.Session)
			{
				_mode = Mode.Closed;
				_theirOfferMirror.RemoveAll();
				HidePanels();
			}
		}

		private static void ShowPanels()
		{
			SetHeld(null);
			_root.SetActive(true);
			_root.transform.SetAsLastSibling();
			InventoryGui.instance.Show((Container)null, 1);
			((Component)InventoryGui.instance.m_crafting).gameObject.SetActive(false);
			((Component)InventoryGui.instance.m_info).gameObject.SetActive(false);
			RefreshAll();
		}

		private static void HidePanels()
		{
			SetHeld(null);
			if ((Object)(object)_root != (Object)null)
			{
				_root.SetActive(false);
			}
			InventoryGui instance = InventoryGui.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				((Component)instance.m_crafting).gameObject.SetActive(true);
				((Component)instance.m_info).gameObject.SetActive(true);
				if (InventoryGui.IsVisible())
				{
					instance.Hide();
				}
			}
		}

		private static bool EnsureBuilt()
		{
			if ((Object)(object)_root != (Object)null)
			{
				return true;
			}
			try
			{
				Build();
			}
			catch (Exception arg)
			{
				MayheimTraderPlugin.Log.LogError((object)$"[MayheimTrader] Falha ao montar a janela de troca: {arg}");
				return false;
			}
			return (Object)(object)_root != (Object)null;
		}

		private static void Build()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0267: Expected O, but got Unknown
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Expected O, but got Unknown
			InventoryGui instance = InventoryGui.instance;
			RectTransform val = (((Object)(object)instance != (Object)null) ? instance.m_container : null);
			if ((Object)(object)val == (Object)null)
			{
				MayheimTraderPlugin.Log.LogWarning((object)"[MayheimTrader] InventoryGui.instance.m_container indisponível.");
				return;
			}
			_myOffer = new Inventory("Sua oferta", (Sprite)null, 6, 3);
			_theirOfferMirror = new Inventory("Oferta do outro jogador", (Sprite)null, 6, 3);
			Transform transform = ((Component)((Component)val).GetComponentInParent<Canvas>()).transform;
			GameObject val2 = new GameObject("MayheimTraderPanels", new Type[1] { typeof(RectTransform) });
			RectTransform val3 = (RectTransform)val2.transform;
			((Transform)val3).SetParent(transform, false);
			val3.anchorMin = new Vector2(0.5f, 0.5f);
			val3.anchorMax = new Vector2(0.5f, 0.5f);
			val3.pivot = new Vector2(0.5f, 0.5f);
			val3.anchoredPosition = Vector2.zero;
			val3.sizeDelta = Vector2.zero;
			Button obj = Object.Instantiate<Button>(instance.m_takeAllButton, val2.transform, false);
			((Component)obj).gameObject.SetActive(false);
			((Object)((Component)obj).gameObject).name = "MayheimTraderButtonTemplate";
			Rect rect = val.rect;
			float num;
			if (!(((Rect)(ref rect)).height > 0f))
			{
				num = 420f;
			}
			else
			{
				rect = val.rect;
				num = ((Rect)(ref rect)).height;
			}
			float num2 = num;
			float num3 = num2 + 20f;
			Vector2 anchor = default(Vector2);
			((Vector2)(ref anchor))..ctor(0.5f, 0.5f);
			Vector2 anchoredPosition = default(Vector2);
			((Vector2)(ref anchoredPosition))..ctor(360f, num3 / 2f);
			Vector2 val4 = default(Vector2);
			((Vector2)(ref val4))..ctor(360f, (0f - num3) / 2f);
			_myOfferGrid = ClonePanel(val, val2.transform, anchor, anchoredPosition, out _myOfferGroup, out _myTitle);
			_theirOfferGrid = ClonePanel(val, val2.transform, anchor, val4, out var _, out _theirTitle);
			_myOfferGrid.m_onSelected = OnMyOfferGridSelected;
			_myOfferGrid.m_onRightClick = OnMyOfferGridRightClicked;
			_theirOfferGrid.m_onSelected = null;
			float num4 = val4.y - num2 / 2f - 45f;
			Vector2 anchoredPosition2 = new Vector2(230f, num4);
			object obj2 = <>O.<2>__OnConfirmClicked;
			if (obj2 == null)
			{
				UnityAction val5 = OnConfirmClicked;
				<>O.<2>__OnConfirmClicked = val5;
				obj2 = (object)val5;
			}
			_confirmButton = CreateVanillaButton(obj, val3, anchoredPosition2, "Confirmar", (UnityAction)obj2);
			Vector2 anchoredPosition3 = new Vector2(490f, num4);
			object obj3 = <>O.<3>__OnCloseClicked;
			if (obj3 == null)
			{
				UnityAction val6 = OnCloseClicked;
				<>O.<3>__OnCloseClicked = val6;
				obj3 = (object)val6;
			}
			_closeButton = CreateVanillaButton(obj, val3, anchoredPosition3, "Fechar", (UnityAction)obj3);
			_root = val2;
			_root.SetActive(false);
		}

		private static InventoryGrid ClonePanel(RectTransform prefab, Transform parent, Vector2 anchor, Vector2 anchoredPosition, out CanvasGroup group, out TMP_Text title)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(((Component)prefab).gameObject, parent, false);
			val.SetActive(true);
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchorMin = anchor;
			val2.anchorMax = anchor;
			val2.pivot = anchor;
			val2.anchoredPosition = anchoredPosition;
			group = val.AddComponent<CanvasGroup>();
			Button[] componentsInChildren = val.GetComponentsInChildren<Button>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((Component)componentsInChildren[i]).gameObject.SetActive(false);
			}
			title = null;
			TMP_Text[] componentsInChildren2 = val.GetComponentsInChildren<TMP_Text>(true);
			foreach (TMP_Text val3 in componentsInChildren2)
			{
				string text = ((Object)((Component)val3).gameObject).name.ToLowerInvariant();
				if ((Object)(object)title == (Object)null && text.Contains("name"))
				{
					title = val3;
				}
				else if (text.Contains("weight"))
				{
					((Component)val3.transform.parent).gameObject.SetActive(false);
				}
			}
			InventoryGrid componentInChildren = val.GetComponentInChildren<InventoryGrid>(true);
			componentInChildren.CanDropDragOntoItem = (ItemData _) => true;
			return componentInChildren;
		}

		private static Button CreateVanillaButton(Button template, RectTransform parent, Vector2 anchoredPosition, string text, UnityAction onClick)
		{
			//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_0055: 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_006a: 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)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)template == (Object)null)
			{
				MayheimTraderPlugin.Log.LogWarning((object)"[MayheimTrader] Nenhum botão-modelo no baú clonado - botões não criados.");
				return null;
			}
			GameObject obj = Object.Instantiate<GameObject>(((Component)template).gameObject, (Transform)(object)parent, false);
			((Object)obj).name = text + "Button";
			obj.SetActive(true);
			RectTransform val = (RectTransform)obj.transform;
			val.anchorMin = new Vector2(0.5f, 0.5f);
			val.anchorMax = new Vector2(0.5f, 0.5f);
			val.pivot = new Vector2(0.5f, 0.5f);
			val.anchoredPosition = anchoredPosition;
			((Transform)val).localScale = Vector3.one;
			Button component = obj.GetComponent<Button>();
			((Selectable)component).interactable = true;
			((UnityEventBase)component.onClick).RemoveAllListeners();
			((UnityEvent)component.onClick).AddListener(onClick);
			SetButtonText(component, text);
			return component;
		}

		private static void SetTitles(string mine, string theirs)
		{
			if ((Object)(object)_myTitle != (Object)null)
			{
				_myTitle.text = mine;
			}
			if ((Object)(object)_theirTitle != (Object)null)
			{
				_theirTitle.text = theirs;
			}
		}

		private static void SetLocked(bool locked)
		{
			_locked = locked;
			SetHeld(null);
			if ((Object)(object)_myOfferGroup != (Object)null)
			{
				_myOfferGroup.alpha = (locked ? 0.6f : 1f);
			}
			RefreshAll();
		}

		private static void SetButtonsInteractable(bool interactable)
		{
			if ((Object)(object)_confirmButton != (Object)null)
			{
				((Selectable)_confirmButton).interactable = interactable;
			}
			if ((Object)(object)_closeButton != (Object)null)
			{
				((Selectable)_closeButton).interactable = interactable;
			}
		}

		private static void SetButtonText(Button button, string text)
		{
			if ((Object)(object)button == (Object)null)
			{
				return;
			}
			TMP_Text componentInChildren = ((Component)button).GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = text;
				return;
			}
			Text componentInChildren2 = ((Component)button).GetComponentInChildren<Text>(true);
			if ((Object)(object)componentInChildren2 != (Object)null)
			{
				componentInChildren2.text = text;
			}
		}

		private static void RefreshAll()
		{
			if (!((Object)(object)_root == (Object)null) && _root.activeSelf && !((Object)(object)Player.m_localPlayer == (Object)null))
			{
				_myOfferGrid.UpdateInventory(_myOffer, (Player)null, _heldOfferItem);
				_theirOfferGrid.UpdateInventory(_theirOfferMirror, (Player)null, (ItemData)null);
			}
		}

		private static void OnConfirmClicked()
		{
			if (_mode == Mode.Session)
			{
				TradeClient.ToggleConfirm();
				return;
			}
			SetLocked(!_locked);
			SetButtonText(_confirmButton, TradeText.Get(_locked ? "mt_debug_unlock" : "mt_debug_lock"));
		}

		private static void OnCloseClicked()
		{
			if (_mode == Mode.Session)
			{
				TradeClient.RequestCancel();
			}
			else
			{
				CloseDebug();
			}
		}

		private static void OnMyOfferGridSelected(InventoryGrid grid, ItemData item, Vector2i pos, Modifier modifier)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			InventoryGui instance = InventoryGui.instance;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null || _locked)
			{
				return;
			}
			ItemData val = (ItemData)DragItemField.GetValue(instance);
			Inventory val2 = (Inventory)DragInventoryField.GetValue(instance);
			if (val != null && val2 != null)
			{
				if (val.m_shared.m_questItem)
				{
					TradeClient.ShowMessage(TradeText.Get("mt_quest_item"));
					return;
				}
				if (((Humanoid)localPlayer).IsItemEquiped(val))
				{
					((Humanoid)localPlayer).UnequipItem(val, false);
				}
				int num = (int)DragAmountField.GetValue(instance);
				_myOffer.MoveItemToThis(val2, val, num, pos.x, pos.y);
				SetupDragItemMethod.Invoke(instance, new object[3] { null, null, 1 });
				SetHeld(null);
				OfferChanged();
			}
			else if (_heldOfferItem == null)
			{
				if (item != null)
				{
					SetHeld(item);
				}
				RefreshAll();
			}
			else if (item == _heldOfferItem)
			{
				SetHeld(null);
				RefreshAll();
			}
			else if (item == null)
			{
				_myOffer.MoveItemToThis(_myOffer, _heldOfferItem, _heldOfferItem.m_stack, pos.x, pos.y);
				SetHeld(null);
				OfferChanged();
			}
			else
			{
				SetHeld(item);
				RefreshAll();
			}
		}

		private static void OnMyOfferGridRightClicked(InventoryGrid grid, ItemData item, Vector2i pos)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && item != null && !_locked)
			{
				((Humanoid)localPlayer).GetInventory().MoveItemToThis(_myOffer, item);
				SetHeld(null);
				OfferChanged();
			}
		}

		private static void SetHeld(ItemData item)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			_heldOfferItem = item;
			if ((Object)(object)_heldIcon != (Object)null)
			{
				Object.Destroy((Object)(object)_heldIcon);
				_heldIcon = null;
			}
			InventoryGui instance = InventoryGui.instance;
			if (item != null && !((Object)(object)instance == (Object)null) && !((Object)(object)_root == (Object)null))
			{
				_heldIcon = Object.Instantiate<GameObject>(instance.m_dragItemPrefab, _root.transform);
				_heldIcon.transform.SetAsLastSibling();
				_heldIcon.transform.position = ZInput.pointerPosition;
				((Component)_heldIcon.transform.Find("icon")).GetComponent<Image>().sprite = item.GetIcon();
				((Component)_heldIcon.transform.Find("name")).GetComponent<TMP_Text>().text = item.m_shared.m_name;
				((Component)_heldIcon.transform.Find("amount")).GetComponent<TMP_Text>().text = ((item.m_stack > 1) ? item.m_stack.ToString() : "");
				UITooltip.HideTooltip();
			}
		}

		internal static void FrameUpdate()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_heldIcon == (Object)null))
			{
				InventoryGui instance = InventoryGui.instance;
				bool flag = (Object)(object)instance != (Object)null && DragItemField.GetValue(instance) != null;
				if (ZInput.GetMouseButton(1) || flag || !IsVisibleNow())
				{
					SetHeld(null);
					RefreshAll();
				}
				else
				{
					_heldIcon.transform.position = ZInput.pointerPosition;
				}
			}
		}

		private static bool IsVisibleNow()
		{
			if ((Object)(object)_root != (Object)null)
			{
				return _root.activeSelf;
			}
			return false;
		}

		internal static bool TryDropHeldOnPlayerGrid(ItemData target, Vector2i pos)
		{
			//IL_0045: 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 (_heldOfferItem == null || !IsVisibleNow())
			{
				return false;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			ItemData heldOfferItem = _heldOfferItem;
			if (target == null || target.IsSameType(heldOfferItem))
			{
				((Humanoid)localPlayer).GetInventory().MoveItemToThis(_myOffer, heldOfferItem, heldOfferItem.m_stack, pos.x, pos.y);
				if (_myOffer.ContainsItem(heldOfferItem))
				{
					SetHeld(heldOfferItem);
				}
				else
				{
					SetHeld(null);
				}
				OfferChanged();
			}
			return true;
		}

		private static void OfferChanged()
		{
			RefreshAll();
			if (_mode == Mode.Session)
			{
				TradeClient.OnMyOfferChanged();
			}
		}
	}
}
namespace MayheimTrader.Persistence
{
	internal static class DepositStore
	{
		internal sealed class Entry
		{
			public string Id;

			public string RecipientKey;

			public byte[] Items;

			public bool Held;
		}

		private const int FileVersion = 1;

		private static readonly List<Entry> Entries = new List<Entry>();

		private static readonly HashSet<string> KnownDeposits = new HashSet<string>();

		private static string _loadedPath;

		private static string CurrentPath()
		{
			World world = ZNet.World;
			if (world == null)
			{
				return null;
			}
			string worldsSaveRootPath = SaveSystem.GetWorldsSaveRootPath((FileSource)2);
			Directory.CreateDirectory(worldsSaveRootPath);
			return Path.Combine(worldsSaveRootPath, world.m_name + ".mayheimtrader.deposits");
		}

		private static bool EnsureLoaded()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			string text = CurrentPath();
			if (text == null)
			{
				return false;
			}
			if (text == _loadedPath)
			{
				return true;
			}
			Entries.Clear();
			KnownDeposits.Clear();
			_loadedPath = text;
			if (File.Exists(text))
			{
				ZPackage val = new ZPackage(File.ReadAllBytes(text));
				int num = val.ReadInt();
				if (num != 1)
				{
					MayheimTraderPlugin.Log.LogError((object)$"[MayheimTrader] Depósito em formato desconhecido ({num}) em {text} - NÃO vou sobrescrever. Resolva manualmente.");
					_loadedPath = null;
					return false;
				}
				int num2 = val.ReadInt();
				for (int i = 0; i < num2; i++)
				{
					Entries.Add(new Entry
					{
						Id = val.ReadString(),
						RecipientKey = val.ReadString(),
						Held = val.ReadBool(),
						Items = val.ReadByteArray()
					});
				}
				int num3 = val.ReadInt();
				for (int j = 0; j < num3; j++)
				{
					KnownDeposits.Add(val.ReadString());
				}
				bool flag = false;
				foreach (Entry entry in Entries)
				{
					if (entry.Held)
					{
						entry.Held = false;
						flag = true;
					}
				}
				MayheimTraderPlugin.Log.LogInfo((object)$"[MayheimTrader] Depósito carregado: {Entries.Count} entrega(s) pendente(s).");
				if (flag)
				{
					Save();
				}
			}
			return true;
		}

		private static void Save()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			if (_loadedPath == null)
			{
				return;
			}
			ZPackage val = new ZPackage();
			val.Write(1);
			val.Write(Entries.Count);
			foreach (Entry entry in Entries)
			{
				val.Write(entry.Id);
				val.Write(entry.RecipientKey);
				val.Write(entry.Held);
				val.Write(entry.Items);
			}
			val.Write(KnownDeposits.Count);
			foreach (string knownDeposit in KnownDeposits)
			{
				val.Write(knownDeposit);
			}
			string text = _loadedPath + ".tmp";
			File.WriteAllBytes(text, val.GetArray());
			if (File.Exists(_loadedPath))
			{
				File.Replace(text, _loadedPath, null);
			}
			else
			{
				File.Move(text, _loadedPath);
			}
		}

		internal static bool WasDepositReceived(string depositId)
		{
			if (EnsureLoaded())
			{
				return KnownDeposits.Contains(depositId);
			}
			return false;
		}

		internal static string Hold(string depositId, string ownerKey, byte[] items)
		{
			if (!EnsureLoaded())
			{
				return null;
			}
			Entry entry = new Entry
			{
				Id = Guid.NewGuid().ToString("N"),
				RecipientKey = ownerKey,
				Items = items,
				Held = true
			};
			Entries.Add(entry);
			KnownDeposits.Add(depositId);
			Save();
			return entry.Id;
		}

		internal static void Release(string entryId, string recipientKey)
		{
			if (EnsureLoaded())
			{
				Entry entry = Entries.Find((Entry e) => e.Id == entryId);
				if (entry != null)
				{
					entry.RecipientKey = recipientKey;
					entry.Held = false;
					Save();
				}
			}
		}

		internal static void Swap(string entryA, string keyA, string entryB, string keyB)
		{
			if (EnsureLoaded())
			{
				Entry entry = Entries.Find((Entry e) => e.Id == entryA);
				Entry entry2 = Entries.Find((Entry e) => e.Id == entryB);
				if (entry != null && entry2 != null)
				{
					entry.RecipientKey = keyB;
					entry.Held = false;
					entry2.RecipientKey = keyA;
					entry2.Held = false;
					Save();
				}
			}
		}

		internal static List<Entry> Deliverable(string recipientKey)
		{
			List<Entry> list = new List<Entry>();
			if (!EnsureLoaded())
			{
				return list;
			}
			foreach (Entry entry in Entries)
			{
				if (!entry.Held && entry.RecipientKey == recipientKey)
				{
					list.Add(entry);
				}
			}
			return list;
		}

		internal static void Acknowledge(string entryId, byte[] leftovers, bool hasLeftovers)
		{
			if (!EnsureLoaded())
			{
				return;
			}
			Entry entry = Entries.Find((Entry e) => e.Id == entryId);
			if (entry != null)
			{
				Entries.Remove(entry);
				if (hasLeftovers)
				{
					Entries.Add(new Entry
					{
						Id = Guid.NewGuid().ToString("N"),
						RecipientKey = entry.RecipientKey,
						Items = leftovers,
						Held = false
					});
				}
				Save();
			}
		}
	}
}
namespace MayheimTrader.Network
{
	[HarmonyPatch]
	internal static class ConnectionPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "OnSpawned")]
		private static void OnSpawnedPostfix(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				TradeClient.OnLocalPlayerSpawned();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(ZNet), "Disconnect")]
		private static void DisconnectPrefix(ZNet __instance, ZNetPeer peer)
		{
			if (__instance.IsServer() && peer != null)
			{
				TradeManager.OnPeerDisconnected(peer.m_uid, peer.m_socket.GetHostName());
			}
		}
	}
	internal static class TradeClient
	{
		private enum EscrowState
		{
			Offering,
			Deposited
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static PopupButtonCallback <>9__17_0;

			public static PopupButtonCallback <>9__17_1;

			internal void <OnInvite>b__17_0()
			{
				AnswerInvite(accepted: true);
			}

			internal void <OnInvite>b__17_1()
			{
				AnswerInvite(accepted: false);
			}
		}

		private const string EscrowKey = "mayheimtrader_escrow";

		private const string AppliedKey = "mayheimtrader_applied";

		private const int MaxAppliedIds = 200;

		private static string _otherName;

		private static int _otherVersionSeen;

		private static bool _myConfirmed;

		private static bool _depositing;

		private static bool _cancelRequested;

		private static bool _invitePopupOpen;

		private static bool _suppressNextDeliveryMessage;

		internal static string ActiveSessionId { get; private set; }

		internal static bool InSession => ActiveSessionId != null;

		internal static void OnInvite(string requesterName)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			if (!UnifiedPopup.IsAvailable())
			{
				ShowMessage(TradeText.Get("mt_invite_no_popup", requesterName));
				return;
			}
			if (_invitePopupOpen)
			{
				UnifiedPopup.Pop();
			}
			_invitePopupOpen = true;
			string text = TradeText.Get("mt_invite_header");
			string text2 = TradeText.Get("mt_invite_text", requesterName);
			object obj = <>c.<>9__17_0;
			if (obj == null)
			{
				PopupButtonCallback val = delegate
				{
					AnswerInvite(accepted: true);
				};
				<>c.<>9__17_0 = val;
				obj = (object)val;
			}
			object obj2 = <>c.<>9__17_1;
			if (obj2 == null)
			{
				PopupButtonCallback val2 = delegate
				{
					AnswerInvite(accepted: false);
				};
				<>c.<>9__17_1 = val2;
				obj2 = (object)val2;
			}
			UnifiedPopup.Push((PopupBase)new YesNoPopup(text, text2, (PopupButtonCallback)obj, (PopupButtonCallback)obj2, false, false));
		}

		private static void AnswerInvite(bool accepted)
		{
			if (_invitePopupOpen)
			{
				_invitePopupOpen = false;
				UnifiedPopup.Pop();
			}
			TradeRpc.SendInviteResponse(accepted);
		}

		internal static void OnInviteClosed()
		{
			if (_invitePopupOpen)
			{
				_invitePopupOpen = false;
				if (UnifiedPopup.IsAvailable())
				{
					UnifiedPopup.Pop();
				}
			}
		}

		internal static void OnTradeStarted(string sessionId, string otherName)
		{
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				ActiveSessionId = sessionId;
				_otherName = otherName;
				_otherVersionSeen = 0;
				_myConfirmed = false;
				_depositing = false;
				_cancelRequested = false;
				TradeWindow.OpenSession(otherName);
				ShowMessage(TradeText.Get("mt_trade_opened", otherName));
			}
		}

		internal static void OnMyOfferChanged()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			if (InSession && !_depositing)
			{
				WriteEscrow(EscrowState.Offering, ActiveSessionId, TradeWindow.MyOffer);
				ZPackage val = new ZPackage();
				TradeWindow.MyOffer.Save(val);
				TradeRpc.SendOfferUpdate(ActiveSessionId, val);
			}
		}

		internal static void OnOfferMirror(string sessionId, int version, ZPackage offer)
		{
			if (!(sessionId != ActiveSessionId))
			{
				_otherVersionSeen = version;
				TradeWindow.SetMirror(offer);
			}
		}

		internal static void OnConfirmState(string sessionId, bool mine, bool theirs)
		{
			if (!(sessionId != ActiveSessionId))
			{
				_myConfirmed = mine;
				TradeWindow.SetConfirmState(mine, theirs, _otherName);
			}
		}

		internal static void ToggleConfirm()
		{
			if (InSession && !_depositing)
			{
				TradeRpc.SendConfirm(ActiveSessionId, !_myConfirmed, _otherVersionSeen);
			}
		}

		internal static void RequestCancel()
		{
			if (InSession && !_depositing && !_cancelRequested)
			{
				_cancelRequested = true;
				TradeRpc.SendCancel(ActiveSessionId);
			}
		}

		internal static void OnRequestDeposit(string sessionId)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			if (!(sessionId != ActiveSessionId) && !_depositing)
			{
				_depositing = true;
				Inventory myOffer = TradeWindow.MyOffer;
				ZPackage val = new ZPackage();
				myOffer.Save(val);
				WriteEscrow(EscrowState.Deposited, sessionId, myOffer);
				myOffer.RemoveAll();
				TradeRpc.SendDeposit(sessionId, val);
				TradeWindow.SetDepositing();
			}
		}

		internal static void OnDepositAck(string sessionId)
		{
			if (ReadEscrow(out var state, out var sessionId2, out var _) && state == EscrowState.Deposited && sessionId2 == sessionId)
			{
				ClearEscrow();
			}
		}

		internal static void OnTradeCompleted(string sessionId, string otherName)
		{
			if (!(sessionId != ActiveSessionId))
			{
				EndSession();
				_suppressNextDeliveryMessage = true;
				ShowMessage(TradeText.Get(TradeText.CompletedKeys[Random.Range(0, TradeText.CompletedKeys.Length)], otherName));
			}
		}

		internal static void OnTradeCancelled(string sessionId, string reason)
		{
			if (!(sessionId != ActiveSessionId))
			{
				if (!_depositing)
				{
					ReturnOfferToInventory();
				}
				EndSession();
				ShowMessage(reason);
			}
		}

		private static void EndSession()
		{
			ActiveSessionId = null;
			_depositing = false;
			_cancelRequested = false;
			TradeWindow.CloseSession();
		}

		private static void ReturnOfferToInventory()
		{
			Player localPlayer = Player.m_localPlayer;
			Inventory myOffer = TradeWindow.MyOffer;
			if ((Object)(object)localPlayer == (Object)null || myOffer == null)
			{
				return;
			}
			foreach (ItemData item in myOffer.GetAllItems().ToList())
			{
				((Humanoid)localPlayer).GetInventory().MoveItemToThis(myOffer, item);
			}
			if (myOffer.NrOfItems() > 0)
			{
				WriteEscrow(EscrowState.Offering, "", myOffer);
				myOffer.RemoveAll();
				ShowMessage(TradeText.Get("mt_offer_kept"));
			}
			else
			{
				ClearEscrow();
			}
		}

		internal static void OnDeliver(ZPackage pkg)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			List<string> list = ReadApplied();
			ZPackage val = new ZPackage();
			int num = pkg.ReadInt();
			val.Write(num);
			int num2 = 0;
			for (int i = 0; i < num; i++)
			{
				string text = pkg.ReadString();
				byte[] array = pkg.ReadByteArray();
				Inventory val2 = new Inventory("leftovers", (Sprite)null, 16, 16);
				if (!list.Contains(text))
				{
					Inventory val3 = new Inventory("incoming", (Sprite)null, 16, 16);
					val3.Load(new ZPackage(array));
					foreach (ItemData item in val3.GetAllItems().ToList())
					{
						num2 += AddOrKeep(((Humanoid)localPlayer).GetInventory(), item, val2);
					}
					list.Add(text);
				}
				ZPackage val4 = new ZPackage();
				val2.Save(val4);
				val.Write(text);
				val.Write(val2.NrOfItems());
				val.Write(val4.GetArray());
			}
			WriteApplied(list);
			Game instance = Game.instance;
			if (instance != null)
			{
				instance.SavePlayerProfile(false, false);
			}
			TradeRpc.SendDeliverAck(val);
			if (_suppressNextDeliveryMessage)
			{
				_suppressNextDeliveryMessage = false;
			}
			else if (num2 > 0)
			{
				ShowMessage(TradeText.Get("mt_items_arrived"));
			}
		}

		internal static void OnLocalPlayerSpawned()
		{
			if (InSession)
			{
				TradeRpc.SendCancel(ActiveSessionId);
			}
			ActiveSessionId = null;
			_depositing = false;
			_cancelRequested = false;
			_invitePopupOpen = false;
			TradeWindow.CloseSession();
			RecoverEscrow();
			TradeRpc.SendClaimPending();
		}

		internal static void Claim()
		{
			if (InSession)
			{
				ShowMessage(TradeText.Get("mt_finish_current"));
				return;
			}
			RecoverEscrow();
			TradeRpc.SendClaimPending();
		}

		private static void RecoverEscrow()
		{
			if (ReadEscrow(out var state, out var sessionId, out var _))
			{
				if (state == EscrowState.Offering)
				{
					RestoreEscrowToInventory();
				}
				else
				{
					TradeRpc.SendQueryDeposit(sessionId);
				}
			}
		}

		internal static void OnDepositStatus(string sessionId, bool received)
		{
			if (ReadEscrow(out var state, out var sessionId2, out var _) && state == EscrowState.Deposited && !(sessionId2 != sessionId))
			{
				if (received)
				{
					ClearEscrow();
				}
				else
				{
					RestoreEscrowToInventory();
				}
			}
		}

		private static void RestoreEscrowToInventory()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !ReadEscrow(out var _, out var _, out var items))
			{
				return;
			}
			Inventory val = new Inventory("leftovers", (Sprite)null, 16, 16);
			int num = 0;
			foreach (ItemData item in items.GetAllItems().ToList())
			{
				num += AddOrKeep(((Humanoid)localPlayer).GetInventory(), item, val);
			}
			if (val.NrOfItems() > 0)
			{
				WriteEscrow(EscrowState.Offering, "", val);
				ShowMessage(TradeText.Get("mt_restore_full"));
				return;
			}
			ClearEscrow();
			if (num > 0)
			{
				ShowMessage(TradeText.Get("mt_restored", num.ToString()));
			}
		}

		internal static void Tick()
		{
			if (InSession && !_depositing && !_cancelRequested && !InventoryGui.IsVisible())
			{
				RequestCancel();
			}
		}

		private static void WriteEscrow(EscrowState state, string sessionId, Inventory items)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				ZPackage val = new ZPackage();
				val.Write((int)state);
				val.Write(sessionId ?? "");
				items.Save(val);
				localPlayer.m_customData["mayheimtrader_escrow"] = val.GetBase64();
			}
		}

		private static bool ReadEscrow(out EscrowState state, out string sessionId, out Inventory items)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			state = EscrowState.Offering;
			sessionId = null;
			items = null;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !localPlayer.m_customData.TryGetValue("mayheimtrader_escrow", out var value))
			{
				return false;
			}
			try
			{
				ZPackage val = new ZPackage(value);
				state = (EscrowState)val.ReadInt();
				sessionId = val.ReadString();
				items = new Inventory("escrow", (Sprite)null, 16, 16);
				items.Load(val);
				return true;
			}
			catch (Exception arg)
			{
				MayheimTraderPlugin.Log.LogError((object)$"[MayheimTrader] Escrow ilegível, deixando intacto pra análise: {arg}");
				return false;
			}
		}

		private static void ClearEscrow()
		{
			Player.m_localPlayer?.m_customData.Remove("mayheimtrader_escrow");
		}

		private static int AddOrKeep(Inventory target, ItemData item, Inventory keep)
		{
			ItemData val = item.Clone();
			int stack = val.m_stack;
			if (target.AddItem(val))
			{
				return stack;
			}
			int result = stack - val.m_stack;
			keep.AddItem(val);
			return result;
		}

		private static List<string> ReadApplied()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !localPlayer.m_customData.TryGetValue("mayheimtrader_applied", out var value) || string.IsNullOrEmpty(value))
			{
				return new List<string>();
			}
			return value.Split(new char[1] { ',' }).ToList();
		}

		private static void WriteApplied(List<string> applied)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				List<string> values = ((applied.Count > 200) ? applied.Skip(applied.Count - 200).ToList() : applied);
				localPlayer.m_customData["mayheimtrader_applied"] = string.Join(",", values);
			}
		}

		internal static void ShowMessage(string text)
		{
			MayheimTraderPlugin.Log.LogInfo((object)("[MayheimTrader] " + text));
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}
	}
	internal static class TradeManager
	{
		private sealed class PendingInvite
		{
			public long RequesterPeer;

			public string RequesterName;

			public long TargetPeer;

			public string TargetName;

			public double ExpiresAt;
		}

		private readonly struct TradePlayer
		{
			public readonly long Uid;

			public readonly string Name;

			public readonly ZDOID CharacterId;

			public readonly string Key;

			public TradePlayer(long uid, string name, ZDOID characterId, string key)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				Uid = uid;
				Name = name;
				CharacterId = characterId;
				Key = key;
			}
		}

		internal const float InviteTimeoutSeconds = 30f;

		internal const float MaxTradeDistance = 15f;

		internal const float DepositTimeoutSeconds = 30f;

		private static readonly Dictionary<long, PendingInvite> InvitesByRequester = new Dictionary<long, PendingInvite>();

		private static readonly Dictionary<long, TradeSession> SessionsByPeer = new Dictionary<long, TradeSession>();

		private static readonly HashSet<string> DeliveriesInFlight = new HashSet<string>();

		private static bool IsServer
		{
			get
			{
				if ((Object)(object)ZNet.instance != (Object)null)
				{
					return ZNet.instance.IsServer();
				}
				return false;
			}
		}

		internal static void HandleRequestTrade(long requesterPeer, string nameQuery)
		{
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer)
			{
				return;
			}
			ZNet instance = ZNet.instance;
			if (SessionsByPeer.ContainsKey(requesterPeer))
			{
				TradeRpc.SendSystemMessage(requesterPeer, "mt_already_trading");
			}
			else
			{
				if (!TryResolvePlayer(requesterPeer, out var player))
				{
					return;
				}
				TradePlayer nearest;
				if (string.IsNullOrWhiteSpace(nameQuery))
				{
					if (!TryFindNearest(player, out nearest))
					{
						TradeRpc.SendSystemMessage(requesterPeer, "mt_no_players");
						return;
					}
				}
				else
				{
					List<TradePlayer> list = (from c in Candidates(requesterPeer)
						where c.Name.IndexOf(nameQuery, StringComparison.OrdinalIgnoreCase) >= 0
						select c).ToList();
					if (list.Count == 0)
					{
						TradeRpc.SendSystemMessage(requesterPeer, "mt_no_match", nameQuery);
						return;
					}
					if (list.Count > 1)
					{
						string text = string.Join(", ", list.Select((TradePlayer p) => p.Name));
						TradeRpc.SendSystemMessage(requesterPeer, "mt_multiple_matches", nameQuery, text);
						return;
					}
					nearest = list[0];
				}
				if (SessionsByPeer.ContainsKey(nearest.Uid))
				{
					TradeRpc.SendSystemMessage(requesterPeer, "mt_target_busy", nearest.Name);
					return;
				}
				if (!IsWithinTradeDistance(player.CharacterId, nearest.CharacterId, out var distance))
				{
					TradeRpc.SendSystemMessage(requesterPeer, "mt_too_far", nearest.Name, distance.ToString("0"), 15f.ToString("0"));
					return;
				}
				if (InvitesByRequester.TryGetValue(nearest.Uid, out var value) && value.TargetPeer == requesterPeer)
				{
					InvitesByRequester.Remove(nearest.Uid);
					TradeRpc.SendInviteClosed(requesterPeer);
					StartSession(nearest, player);
					return;
				}
				if (InvitesByRequester.TryGetValue(requesterPeer, out var value2))
				{
					TradeRpc.SendInviteClosed(value2.TargetPeer);
				}
				InvitesByRequester[requesterPeer] = new PendingInvite
				{
					RequesterPeer = requesterPeer,
					RequesterName = player.Name,
					TargetPeer = nearest.Uid,
					TargetName = nearest.Name,
					ExpiresAt = instance.GetTimeSeconds() + 30.0
				};
				TradeRpc.SendInvite(nearest.Uid, player.Name);
				TradeRpc.SendSystemMessage(requesterPeer, "mt_invite_sent", nearest.Name);
			}
		}

		internal static void HandleInviteResponse(long responderPeer, bool accepted)
		{
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer)
			{
				return;
			}
			PendingInvite pendingInvite = null;
			foreach (KeyValuePair<long, PendingInvite> item in InvitesByRequester)
			{
				if (item.Value.TargetPeer == responderPeer)
				{
					pendingInvite = item.Value;
					break;
				}
			}
			if (pendingInvite == null)
			{
				TradeRpc.SendSystemMessage(responderPeer, "mt_invite_gone");
				return;
			}
			InvitesByRequester.Remove(pendingInvite.RequesterPeer);
			TradePlayer player;
			TradePlayer player2;
			float distance;
			if (!accepted)
			{
				TradeRpc.SendSystemMessage(pendingInvite.RequesterPeer, "mt_invite_declined", pendingInvite.TargetName);
			}
			else if (SessionsByPeer.ContainsKey(pendingInvite.RequesterPeer) || SessionsByPeer.ContainsKey(responderPeer))
			{
				TradeRpc.SendSystemMessage(responderPeer, "mt_invite_busy");
				TradeRpc.SendSystemMessage(pendingInvite.RequesterPeer, "mt_invite_busy");
			}
			else if (!TryResolvePlayer(pendingInvite.RequesterPeer, out player) || !TryResolvePlayer(responderPeer, out player2))
			{
				TradeRpc.SendSystemMessage(responderPeer, "mt_other_unavailable");
			}
			else if (!IsWithinTradeDistance(player.CharacterId, player2.CharacterId, out distance))
			{
				string text = distance.ToString("0");
				TradeRpc.SendSystemMessage(responderPeer, "mt_both_too_far", player.Name, player2.Name, text);
				TradeRpc.SendSystemMessage(pendingInvite.RequesterPeer, "mt_both_too_far", player.Name, player2.Name, text);
			}
			else
			{
				StartSession(player, player2);
			}
		}

		internal static void HandleOfferUpdate(long sender, string sessionId, ZPackage offer)
		{
			if (IsServer && TryGetSession(sender, sessionId, out var session) && session.State == TradeState.Negotiating)
			{
				session.BumpVersion(sender);
				session.ResetConfirmations();
				TradeRpc.SendOfferMirror(session.OtherPeer(sender), sessionId, session.VersionOf(sender), offer);
				BroadcastConfirmState(session);
			}
		}

		internal static void HandleConfirm(long sender, string sessionId, bool confirm, int seenOtherVersion)
		{
			if (!IsServer || !TryGetSession(sender, sessionId, out var session) || session.State != TradeState.Negotiating)
			{
				return;
			}
			long peerUid = session.OtherPeer(sender);
			if (confirm && seenOtherVersion != session.VersionOf(peerUid))
			{
				TradeRpc.SendSystemMessage(sender, "mt_offer_changed", session.NameOf(peerUid));
				BroadcastConfirmState(session);
				return;
			}
			session.SetConfirmed(sender, confirm);
			BroadcastConfirmState(session);
			if (session.BothConfirmed)
			{
				session.State = TradeState.Depositing;
				session.DepositDeadline = ZNet.instance.GetTimeSeconds() + 30.0;
				TradeRpc.SendRequestDeposit(session.PeerA, sessionId);
				TradeRpc.SendRequestDeposit(session.PeerB, sessionId);
			}
		}

		internal static void HandleCancel(long sender, string sessionId)
		{
			if (IsServer && TryGetSession(sender, sessionId, out var session))
			{
				if (session.State != TradeState.Negotiating)
				{
					TradeRpc.SendSystemMessage(sender, "mt_cannot_cancel");
					return;
				}
				CancelSession(session, "mt_cancelled_by", session.NameOf(sender));
			}
		}

		internal static string DepositId(string sessionId, string ownerKey)
		{
			return sessionId + "|" + ownerKey;
		}

		internal static void HandleDeposit(long sender, string sessionId, ZPackage items)
		{
			if (!IsServer || !TryResolvePlayer(sender, out var player))
			{
				return;
			}
			string depositId = DepositId(sessionId, player.Key);
			if (DepositStore.WasDepositReceived(depositId))
			{
				TradeRpc.SendDepositAck(sender, sessionId);
				return;
			}
			string text = DepositStore.Hold(depositId, player.Key, items.GetArray());
			if (text == null)
			{
				MayheimTraderPlugin.Log.LogError((object)("[MayheimTrader] Não consegui gravar o depósito de " + player.Name + " - NÃO confirmado, o item continua com o cliente."));
				return;
			}
			TradeRpc.SendDepositAck(sender, sessionId);
			if (!TryGetSession(sender, sessionId, out var session) || session.State != TradeState.Depositing)
			{
				DepositStore.Release(text, player.Key);
				TryDeliverPending(sender);
				return;
			}
			session.SetDepositEntry(sender, text);
			if (session.BothDeposited)
			{
				DepositStore.Swap(session.DepositEntryA, session.KeyA, session.DepositEntryB, session.KeyB);
				LogCompletedTrade(session);
				CloseSession(session);
				TradeRpc.SendTradeCompleted(session.PeerA, sessionId, session.NameB);
				TradeRpc.SendTradeCompleted(session.PeerB, sessionId, session.NameA);
				TryDeliverPending(session.PeerA);
				TryDeliverPending(session.PeerB);
			}
		}

		internal static void HandleQueryDeposit(long sender, string sessionId)
		{
			if (IsServer && TryResolvePlayer(sender, out var player))
			{
				bool received = DepositStore.WasDepositReceived(DepositId(sessionId, player.Key));
				TradeRpc.SendDepositStatus(sender, sessionId, received);
			}
		}

		internal static void HandleClaimPending(long sender)
		{
			if (IsServer)
			{
				TryDeliverPending(sender, notifyIfEmpty: true);
			}
		}

		internal static void TryDeliverPending(long peer, bool notifyIfEmpty = false)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			if (!TryResolvePlayer(peer, out var player) || DeliveriesInFlight.Contains(player.Key))
			{
				return;
			}
			List<DepositStore.Entry> list = DepositStore.Deliverable(player.Key);
			if (list.Count == 0)
			{
				if (notifyIfEmpty)
				{
					TradeRpc.SendSystemMessage(peer, "mt_nothing_pending");
				}
				return;
			}
			ZPackage val = new ZPackage();
			val.Write(list.Count);
			foreach (DepositStore.Entry item in list)
			{
				val.Write(item.Id);
				val.Write(item.Items);
			}
			DeliveriesInFlight.Add(player.Key);
			TradeRpc.SendDeliver(peer, val);
		}

		internal static void HandleDeliverAck(long sender, ZPackage ack)
		{
			if (IsServer && TryResolvePlayer(sender, out var player))
			{
				int num = ack.ReadInt();
				int num2 = 0;
				for (int i = 0; i < num; i++)
				{
					string entryId = ack.ReadString();
					int num3 = ack.ReadInt();
					byte[] leftovers = ack.ReadByteArray();
					DepositStore.Acknowledge(entryId, leftovers, num3 > 0);
					num2 += num3;
				}
				DeliveriesInFlight.Remove(player.Key);
				if (num2 > 0)
				{
					TradeRpc.SendSystemMessage(sender, "mt_inventory_full_pending", num2.ToString());
				}
			}
		}

		internal static void OnPeerDisconnected(long peer, string key)
		{
			if (!IsServer)
			{
				return;
			}
			DeliveriesInFlight.Remove(key);
			if (InvitesByRequester.TryGetValue(peer, out var value))
			{
				InvitesByRequester.Remove(peer);
				TradeRpc.SendInviteClosed(value.TargetPeer);
			}
			foreach (KeyValuePair<long, PendingInvite> item in InvitesByRequester.Where((KeyValuePair<long, PendingInvite> kv) => kv.Value.TargetPeer == peer).ToList())
			{
				InvitesByRequester.Remove(item.Key);
				TradeRpc.SendSystemMessage(item.Key, "mt_invite_target_left", item.Value.TargetName);
			}
			if (SessionsByPeer.TryGetValue(peer, out var value2))
			{
				CancelSession(value2, "mt_disconnected", value2.NameOf(peer));
			}
		}

		internal static void Tick()
		{
			if (IsServer)
			{
				ExpireInvites(ZNet.instance);
				RecheckActiveSessionDistances();
			}
		}

		private static void ExpireInvites(ZNet znet)
		{
			if (InvitesByRequester.Count == 0)
			{
				return;
			}
			double now = znet.GetTimeSeconds();
			foreach (KeyValuePair<long, PendingInvite> item in InvitesByRequester.Where((KeyValuePair<long, PendingInvite> kv) => kv.Value.ExpiresAt <= now).ToList())
			{
				InvitesByRequester.Remove(item.Key);
				TradeRpc.SendSystemMessage(item.Key, "mt_invite_expired", item.Value.TargetName);
				TradeRpc.SendInviteClosed(item.Value.TargetPeer);
			}
		}

		private static void RecheckActiveSessionDistances()
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if (SessionsByPeer.Count == 0)
			{
				return;
			}
			double timeSeconds = ZNet.instance.GetTimeSeconds();
			foreach (TradeSession item in SessionsByPeer.Values.Distinct().ToList())
			{
				TradePlayer player;
				TradePlayer player2;
				float distance;
				if (item.State == TradeState.Depositing && timeSeconds > item.DepositDeadline)
				{
					CancelSession(item, "mt_deposit_timeout");
				}
				else if (item.State == TradeState.Negotiating && TryResolvePlayer(item.PeerA, out player) && TryResolvePlayer(item.PeerB, out player2) && !IsWithinTradeDistance(player.CharacterId, player2.CharacterId, out distance))
				{
					CancelSession(item, "mt_walked_away", item.NameA, item.NameB);
				}
			}
		}

		private static void StartSession(TradePlayer a, TradePlayer b)
		{
			TradeSession tradeSession = new TradeSession(Guid.NewGuid().ToString("N"), a.Uid, a.Name, a.Key, b.Uid, b.Name, b.Key);
			SessionsByPeer[a.Uid] = tradeSession;
			SessionsByPeer[b.Uid] = tradeSession;
			TradeRpc.SendTradeStarted(a.Uid, tradeSession.Id, b.Name);
			TradeRpc.SendTradeStarted(b.Uid, tradeSession.Id, a.Name);
		}

		private static void CloseSession(TradeSession session)
		{
			SessionsByPeer.Remove(session.PeerA);
			SessionsByPeer.Remove(session.PeerB);
			session.State = TradeState.Closed;
		}

		private static void CancelSession(TradeSession session, string reasonKey, params string[] reasonArgs)
		{
			CloseSession(session);
			if (session.DepositEntryA != null)
			{
				DepositStore.Release(session.DepositEntryA, session.KeyA);
			}
			if (session.DepositEntryB != null)
			{
				DepositStore.Release(session.DepositEntryB, session.KeyB);
			}
			TradeRpc.SendTradeCancelled(session.PeerA, session.Id, reasonKey, reasonArgs);
			TradeRpc.SendTradeCancelled(session.PeerB, session.Id, reasonKey, reasonArgs);
			if (session.DepositEntryA != null)
			{
				TryDeliverPending(session.PeerA);
			}
			if (session.DepositEntryB != null)
			{
				TryDeliverPending(session.PeerB);
			}
		}

		private static bool TryGetSession(long peer, string sessionId, out TradeSession session)
		{
			if (SessionsByPeer.TryGetValue(peer, out session))
			{
				return session.Id == sessionId;
			}
			return false;
		}

		private static void BroadcastConfirmState(TradeSession session)
		{
			TradeRpc.SendConfirmState(session.PeerA, session.Id, session.ConfirmedA, session.ConfirmedB);
			TradeRpc.SendConfirmState(session.PeerB, session.Id, session.ConfirmedB, session.ConfirmedA);
		}

		private static void LogCompletedTrade(TradeSession session)
		{
			try
			{
				DepositStore.Entry entry = DepositStore.Deliverable(session.KeyB).Find((DepositStore.Entry e) => e.Id == session.DepositEntryA);
				DepositStore.Entry entry2 = DepositStore.Deliverable(session.KeyA).Find((DepositStore.Entry e) => e.Id == session.DepositEntryB);
				MayheimTraderPlugin.Log.LogInfo((object)($"[MayheimTrader] TROCA {session.Id} em {DateTime.Now:yyyy-MM-dd HH:mm:ss}: " + session.NameA + " deu [" + Describe(entry?.Items) + "] | " + session.NameB + " deu [" + Describe(entry2?.Items) + "]"));
			}
			catch (Exception ex)
			{
				MayheimTraderPlugin.Log.LogWarning((object)("[MayheimTrader] Troca " + session.Id + " concluída, mas falhou ao descrever os itens no log: " + ex.Message));
			}
		}

		private static string Describe(byte[] items)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			if (items == null)
			{
				return "?";
			}
			Inventory val = new Inventory("log", (Sprite)null, 16, 16);
			val.Load(new ZPackage(items));
			return string.Join(", ", val.GetAllItems().Select(delegate(ItemData i)
			{
				GameObject dropPrefab = i.m_dropPrefab;
				return $"{((dropPrefab != null) ? ((Object)dropPrefab).name : null) ?? i.m_shared.m_name} x{i.m_stack} q{i.m_quality}";
			}));
		}

		private static List<TradePlayer> Candidates(long excludeUid)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			List<TradePlayer> list = new List<TradePlayer>();
			foreach (ZNetPeer connectedPeer in ZNet.instance.GetConnectedPeers())
			{
				if (connectedPeer.IsReady() && connectedPeer.m_uid != excludeUid)
				{
					list.Add(new TradePlayer(connectedPeer.m_uid, connectedPeer.m_playerName, connectedPeer.m_characterID, connectedPeer.m_socket.GetHostName()));
				}
			}
			if (TryResolveHost(out var host) && host.Uid != excludeUid)
			{
				list.Add(host);
			}
			return list;
		}

		private static bool TryFindNearest(TradePlayer from, out TradePlayer nearest)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			nearest = default(TradePlayer);
			ZDO zDO = ZDOMan.instance.GetZDO(from.CharacterId);
			if (zDO == null)
			{
				return false;
			}
			Vector3 position = zDO.GetPosition();
			float num = float.MaxValue;
			bool result = false;
			foreach (TradePlayer item in Candidates(from.Uid))
			{
				ZDO zDO2 = ZDOMan.instance.GetZDO(item.CharacterId);
				if (zDO2 != null)
				{
					float num2 = Vector3.Distance(position, zDO2.GetPosition());
					if (num2 < num)
					{
						num = num2;
						nearest = item;
						result = true;
					}
				}
			}
			return result;
		}

		private static bool IsWithinTradeDistance(ZDOID a, ZDOID b, out float distance)
		{
			//IL_000c: 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)
			//IL_0029: 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)
			distance = float.MaxValue;
			ZDO zDO = ZDOMan.instance.GetZDO(a);
			ZDO zDO2 = ZDOMan.instance.GetZDO(b);
			if (zDO == null || zDO2 == null)
			{
				return false;
			}
			distance = Vector3.Distance(zDO.GetPosition(), zDO2.GetPosition());
			return distance <= 15f;
		}

		private static bool TryResolvePlayer(long peerUid, out TradePlayer player)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			ZNetPeer peer = ZNet.instance.GetPeer(peerUid);
			if (peer != null && peer.IsReady())
			{
				player = new TradePlayer(peer.m_uid, peer.m_playerName, peer.m_characterID, peer.m_socket.GetHostName());
				return true;
			}
			if (TryResolveHost(out var host) && host.Uid == peerUid)
			{
				player = host;
				return true;
			}
			player = default(TradePlayer);
			return false;
		}

		private static bool TryResolveHost(out TradePlayer host)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				host = default(TradePlayer);
				return false;
			}
			host = new TradePlayer(ZNet.GetUID(), localPlayer.GetPlayerName(), ((Character)localPlayer).GetZDOID(), "host:" + localPlayer.GetPlayerID());
			return true;
		}
	}
	[HarmonyPatch(typeof(ZRoutedRpc))]
	internal static class TradeRpc
	{
		private const char ArgSeparator = '\u001f';

		[HarmonyPostfix]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		private static void OnConstructed(ZRoutedRpc __instance)
		{
			__instance.Register<string>("MT_RequestTrade", (Action<long, string>)TradeManager.HandleRequestTrade);
			__instance.Register<bool>("MT_InviteResponse", (Action<long, bool>)TradeManager.HandleInviteResponse);
			__instance.Register<string, ZPackage>("MT_OfferUpdate", (Action<long, string, ZPackage>)TradeManager.HandleOfferUpdate);
			__instance.Register<string, bool, int>("MT_Confirm", (Action<long, string, bool, int>)TradeManager.HandleConfirm);
			__instance.Register<string>("MT_Cancel", (Action<long, string>)TradeManager.HandleCancel);
			__instance.Register<string, ZPackage>("MT_Deposit", (Action<long, string, ZPackage>)TradeManager.HandleDeposit);
			__instance.Register<string>("MT_QueryDeposit", (Action<long, string>)TradeManager.HandleQueryDeposit);
			__instance.Register("MT_ClaimPending", (Action<long>)TradeManager.HandleClaimPending);
			__instance.Register<ZPackage>("MT_DeliverAck", (Action<long, ZPackage>)TradeManager.HandleDeliverAck);
			__instance.Register<string>("MT_Invite", (Action<long, string>)delegate(long _, string requesterName)
			{
				TradeClient.OnInvite(requesterName);
			});
			__instance.Register("MT_InviteClosed", (Action<long>)delegate
			{
				TradeClient.OnInviteClosed();
			});
			__instance.Register<string, string>("MT_TradeStarted", (Action<long, string, string>)delegate(long _, string sessionId, string otherName)
			{
				TradeClient.OnTradeStarted(sessionId, otherName);
			});
			__instance.Register<string, int, ZPackage>("MT_OfferMirror", (Action<long, string, int, ZPackage>)delegate(long _, string sessionId, int version, ZPackage offer)
			{
				TradeClient.OnOfferMirror(sessionId, version, offer);
			});
			__instance.Register<string, bool, bool>("MT_ConfirmState", (Action<long, string, bool, bool>)delegate(long _, string sessionId, bool mine, bool theirs)
			{
				TradeClient.OnConfirmState(sessionId, mine, theirs);
			});
			__instance.Register<string>("MT_RequestDeposit", (Action<long, string>)delegate(long _, string sessionId)
			{
				TradeClient.OnRequestDeposit(sessionId);
			});
			__instance.Register<string>("MT_DepositAck", (Action<long, string>)delegate(long _, string sessionId)
			{
				TradeClient.OnDepositAck(sessionId);
			});
			__instance.Register<string, bool>("MT_DepositStatus", (Action<long, string, bool>)delegate(long _, string sessionId, bool received)
			{
				TradeClient.OnDepositStatus(sessionId, received);
			});
			__instance.Register<string, string>("MT_TradeCompleted", (Action<long, string, string>)delegate(long _, string sessionId, string otherName)
			{
				TradeClient.OnTradeCompleted(sessionId, otherName);
			});
			__instance.Register<string, string, string>("MT_TradeCancelled", (Action<long, string, string, string>)delegate(long _, string sessionId, string key, string args)
			{
				TradeClient.OnTradeCancelled(sessionId, TradeText.Get(key, SplitArgs(args)));
			});
			__instance.Register<ZPackage>("MT_Deliver", (Action<long, ZPackage>)delegate(long _, ZPackage pkg)
			{
				TradeClient.OnDeliver(pkg);
			});
			__instance.Register<string, string>("MT_SystemMessage", (Action<long, string, string>)delegate(long _, string key, string args)
			{
				TradeClient.ShowMessage(TradeText.Get(key, SplitArgs(args)));
			});
		}

		internal static void SendRequestTrade(string nameQuery)
		{
			ToServer("MT_RequestTrade", nameQuery);
		}

		internal static void SendInviteResponse(bool accepted)
		{
			ToServer("MT_InviteResponse", accepted);
		}

		internal static void SendOfferUpdate(string sessionId, ZPackage offer)
		{
			ToServer("MT_OfferUpdate", sessionId, offer);
		}

		internal static void SendConfirm(string sessionId, bool confirm, int seenOtherVersion)
		{
			ToServer("MT_Confirm", sessionId, confirm, seenOtherVersion);
		}

		internal static void SendCancel(string sessionId)
		{
			ToServer("MT_Cancel", sessionId);
		}

		internal static void SendDeposit(string sessionId, ZPackage items)
		{
			ToServer("MT_Deposit", sessionId, items);
		}

		internal static void SendQueryDeposit(string sessionId)
		{
			ToServer("MT_QueryDeposit", sessionId);
		}

		internal static void SendClaimPending()
		{
			ToServer("MT_ClaimPending");
		}

		internal static void SendDeliverAck(ZPackage ack)
		{
			ToServer("MT_DeliverAck", ack);
		}

		private static void ToServer(string method, params object[] args)
		{
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(method, args);
			}
		}

		internal static void SendInvite(long peer, string requesterName)
		{
			ToPeer(peer, "MT_Invite", requesterName);
		}

		internal static void SendInviteClosed(long peer)
		{
			ToPeer(peer, "MT_InviteClosed");
		}

		internal static void SendTradeStarted(long peer, string sessionId, string otherName)
		{
			ToPeer(peer, "MT_TradeStarted", sessionId, otherName);
		}

		internal static void SendOfferMirror(long peer, string sessionId, int version, ZPackage offer)
		{
			ToPeer(peer, "MT_OfferMirror", sessionId, version, offer);
		}

		internal static void SendConfirmState(long peer, string sessionId, bool mine, bool theirs)
		{
			ToPeer(peer, "MT_ConfirmState", sessionId, mine, theirs);
		}

		internal static void SendRequestDeposit(long peer, string sessionId)
		{
			ToPeer(peer, "MT_RequestDeposit", sessionId);
		}

		internal static void SendDepositAck(long peer, string sessionId)
		{
			ToPeer(peer, "MT_DepositAck", sessionId);
		}

		internal static void SendDepositStatus(long peer, string sessionId, bool received)
		{
			ToPeer(peer, "MT_DepositStatus", sessionId, received);
		}

		internal static void SendTradeCompleted(long peer, string sessionId, string otherName)
		{
			ToPeer(peer, "MT_TradeCompleted", sessionId, otherName);
		}

		internal static void SendDeliver(long peer, ZPackage pkg)
		{
			ToPeer(peer, "MT_Deliver", pkg);
		}

		internal static void SendSystemMessage(long peer, string key, params string[] args)
		{
			ToPeer(peer, "MT_SystemMessage", key, JoinArgs(args));
		}

		internal static void SendTradeCancelled(long peer, string sessionId, string key, params string[] args)
		{
			ToPeer(peer, "MT_TradeCancelled", sessionId, key, JoinArgs(args));
		}

		private static string JoinArgs(string[] args)
		{
			return string.Join('\u001f'.ToString(), args);
		}

		private static string[] SplitArgs(string joined)
		{
			if (!string.IsNullOrEmpty(joined))
			{
				return joined.Split(new char[1] { '\u001f' });
			}
			return new string[0];
		}

		private static void ToPeer(long peer, string method, params object[] args)
		{
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(peer, method, args);
			}
		}
	}
	internal enum TradeState
	{
		Negotiating,
		Depositing,
		Closed
	}
	internal sealed class TradeSession
	{
		public readonly string Id;

		public readonly long PeerA;

		public readonly long PeerB;

		public readonly string NameA;

		public readonly string NameB;

		public readonly string KeyA;

		public readonly string KeyB;

		public TradeState State;

		public bool ConfirmedA;

		public bool ConfirmedB;

		public int VersionA;

		public int VersionB;

		public string DepositEntryA;

		public string DepositEntryB;

		public double DepositDeadline;

		public bool BothConfirmed
		{
			get
			{
				if (ConfirmedA)
				{
					return ConfirmedB;
				}
				return false;
			}
		}

		public bool BothDeposited
		{
			get
			{
				if (DepositEntryA != null)
				{
					return DepositEntryB != null;
				}
				return false;
			}
		}

		public TradeSession(string id, long peerA, string nameA, string keyA, long peerB, string nameB, string keyB)
		{
			Id = id;
			PeerA = peerA;
			NameA = nameA;
			KeyA = keyA;
			PeerB = peerB;
			NameB = nameB;
			KeyB = keyB;
		}

		public bool IsA(long peerUid)
		{
			return peerUid == PeerA;
		}

		public long OtherPeer(long peerUid)
		{
			if (peerUid != PeerA)
			{
				return PeerA;
			}
			return PeerB;
		}

		public string NameOf(long peerUid)
		{
			if (peerUid != PeerA)
			{
				return NameB;
			}
			return NameA;
		}

		public string OtherName(long peerUid)
		{
			if (peerUid != PeerA)
			{
				return NameA;
			}
			return NameB;
		}

		public string KeyOf(long peerUid)
		{
			if (peerUid != PeerA)
			{
				return KeyB;
			}
			return KeyA;
		}

		public int VersionOf(long peerUid)
		{
			if (peerUid != PeerA)
			{
				return VersionB;
			}
			return VersionA;
		}

		public bool ConfirmedOf(long peerUid)
		{
			if (peerUid != PeerA)
			{
				return ConfirmedB;
			}
			return ConfirmedA;
		}

		public void ResetConfirmations()
		{
			ConfirmedA = false;
			ConfirmedB = false;
		}

		public void SetConfirmed(long peerUid, bool confirmed)
		{
			if (peerUid == PeerA)
			{
				ConfirmedA = confirmed;
			}
			else if (peerUid == PeerB)
			{
				ConfirmedB = confirmed;
			}
		}

		public void BumpVersion(long peerUid)
		{
			if (peerUid == PeerA)
			{
				VersionA++;
			}
			else if (peerUid == PeerB)
			{
				VersionB++;
			}
		}

		public void SetDepositEntry(long peerUid, string entryId)
		{
			if (peerUid == PeerA)
			{
				DepositEntryA = entryId;
			}
			else if (peerUid == PeerB)
			{
				DepositEntryB = entryId;
			}
		}

		public string DepositEntryOf(long peerUid)
		{
			if (peerUid != PeerA)
			{
				return DepositEntryB;
			}
			return DepositEntryA;
		}
	}
	[HarmonyPatch(typeof(ZNet))]
	internal static class VersionCheckPatch
	{
		private const string RpcName = "MayheimTrader_Version";

		private const int ErrorVersion = 3;

		private static readonly HashSet<ZRpc> VerifiedPeers = new HashSet<ZRpc>();

		private static bool _serverVerified;

		private static readonly FieldInfo ConnectionStatusField = AccessTools.Field(typeof(ZNet), "m_connectionStatus");

		[HarmonyPostfix]
		[HarmonyPatch("OnNewConnection")]
		private static void OnNewConnectionPostfix(ZNet __instance, ZNetPeer peer)
		{
			VerifiedPeers.RemoveWhere((ZRpc rpc) => rpc == null || !rpc.IsConnected());
			peer.m_rpc.Register<string>("MayheimTrader_Version", (Action<ZRpc, string>)OnVersionRpc);
			if (!__instance.IsServer())
			{
				_serverVerified = false;
				peer.m_rpc.Invoke("MayheimTrader_Version", new object[1] { "0.1.1" });
			}
		}

		private static void OnVersionRpc(ZRpc rpc, string remoteVersion)
		{
			string text = "0.1.1";
			bool flag = remoteVersion == text;
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
			{
				if (flag)
				{
					VerifiedPeers.Add(rpc);
					rpc.Invoke("MayheimTrader_Version", new object[1] { text });
					return;
				}
				MayheimTraderPlugin.Log.LogWarning((object)("Cliente recusado: MayheimTrader " + remoteVersion + " (servidor: " + text + ")."));
				rpc.Invoke("Error", new object[1] { 3 });
			}
			else if (flag)
			{
				_serverVerified = true;
			}
			else
			{
				MayheimTraderPlugin.Log.LogWarning((object)("Servidor com MayheimTrader " + remoteVersion + ", este cliente tem " + text + ". Desconectando."));
				SetClientError();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("RPC_PeerInfo")]
		private static bool PeerInfoPrefix(ZNet __instance, ZRpc rpc)
		{
			if (__instance.IsServer())
			{
				if (VerifiedPeers.Contains(rpc))
				{
					return true;
				}
				MayheimTraderPlugin.Log.LogWarning((object)"Cliente sem MayheimTrader tentou conectar; recusado.");
				rpc.Invoke("Error", new object[1] { 3 });
				return false;
			}
			if (_serverVerified)
			{
				return true;
			}
			MayheimTraderPlugin.Log.LogWarning((object)"Servidor sem MayheimTrader (não respondeu à checagem de versão). Desconectando.");
			SetClientError();
			return false;
		}

		private static void SetClientError()
		{
			ConnectionStatusField.SetValue(null, (object)(ConnectionStatus)3);
		}
	}
}
namespace MayheimTrader.Localization
{
	[HarmonyPatch(typeof(Localization), "SetupLanguage")]
	internal static class TradeText
	{
		private static readonly MethodInfo AddWord = AccessTools.Method(typeof(Localization), "AddWord", (Type[])null, (Type[])null);

		private static readonly Dictionary<string, (string pt, string en)> Words = new Dictionary<string, (string, string)>
		{
			["mt_already_trading"] = ("Você já está em uma troca.", "You are already in a trade."),
			["mt_no_players"] = ("Nenhum outro jogador conectado.", "No other players online."),
			["mt_no_match"] = ("Nenhum jogador encontrado com \"$1\".", "No player found matching \"$1\"."),
			["mt_multiple_matches"] = ("Mais de um jogador corresponde a \"$1\": $2. Seja mais específico.", "More than one player matches \"$1\": $2. Be more specific."),
			["mt_target_busy"] = ("$1 já está em outra troca.", "$1 is already in another trade."),
			["mt_too_far"] = ("$1 está longe demais ($2 m, máximo $3 m).", "$1 is too far away ($2 m, max $3 m)."),
			["mt_invite_sent"] = ("Convite de troca enviado para $1.", "Trade request sent to $1."),
			["mt_invite_gone"] = ("Esse convite não existe mais.", "That trade request no longer exists."),
			["mt_invite_declined"] = ("$1 recusou a troca.", "$1 declined the trade."),
			["mt_invite_busy"] = ("Um dos dois já entrou em outra troca antes desse convite ser respondido.", "One of you started another trade before this request was answered."),
			["mt_other_unavailable"] = ("O outro jogador não está mais disponível.", "The other player is no longer available."),
			["mt_both_too_far"] = ("$1 e $2 estão longe demais ($3 m).", "$1 and $2 are too far apart ($3 m)."),
			["mt_invite_expired"] = ("O convite de troca para $1 expirou.", "Your trade request to $1 expired."),
			["mt_invite_target_left"] = ("$1 saiu - convite cancelado.", "$1 left - trade request cancelled."),
			["mt_invite_header"] = ("Pedido de troca", "Trade request"),
			["mt_invite_text"] = ("$1 quer trocar com você.", "$1 wants to trade with you."),
			["mt_invite_no_popup"] = ("$1 quer trocar com você - mas não deu pra abrir a janela de convite.", "$1 wants to trade with you - but the request window couldn't be opened."),
			["mt_trade_opened"] = ("Troca com $1 aberta.", "Trade with $1 opened."),
			["mt_offer_changed"] = ("A oferta de $1 mudou - confira de novo antes de confirmar.", "$1 changed their offer - check it again before confirming."),
			["mt_cannot_cancel"] = ("Os dois já confirmaram - a entrega está em andamento e não dá mais pra cancelar.", "You both confirmed - the exchange is underway and can no longer be cancelled."),
			["mt_cancelled_by"] = ("$1 cancelou a troca.", "$1 cancelled the trade."),
			["mt_disconnected"] = ("$1 desconectou - troca cancelada.", "$1 disconnected - trade cancelled."),
			["mt_walked_away"] = ("$1 e $2 se afastaram demais - troca cancelada.", "$1 and $2 moved too far apart - trade cancelled."),
			["mt_deposit_timeout"] = ("A entrega não completou a tempo - troca cancelada, cada um recebe seus itens de volta.", "The exchange didn't complete in time - trade cancelled, everyone gets their items back."),
			["mt_quest_item"] = ("Item de missão não pode ser trocado.", "Quest items can't be traded."),
			["mt_finish_current"] = ("Termine a troca atual primeiro.", "Finish your current trade first."),
			["mt_completed_1"] = ("Acordo selado com $1.", "Deal sealed with $1."),
			["mt_completed_2"] = ("Pacto firmado com $1. Que Odin testemunhe.", "A pact made with $1. May Odin bear witness."),
			["mt_completed_3"] = ("Negócio fechado, pela barba de Odin!", "Deal done, by Odin's beard!"),
			["mt_completed_4"] = ("Troca feita sob o olhar dos deuses.", "A trade made under the gaze of the gods."),
			["mt_nothing_pending"] = ("Nenhum item de troca pendente pra você.", "You have no pending trade items."),
			["mt_inventory_full_pending"] = ("Inventário cheio: $1 item(ns) da troca ficaram guardados. Libere espaço e digite /tradeclaim.", "Inventory full: $1 traded item(s) are being kept for you. Free up space and type /tradeclaim."),
			["mt_offer_kept"] = ("Inventário cheio: parte da sua oferta ficou guardada. Libere espaço e digite /tradeclaim.", "Inventory full: part of your offer is being kept for you. Free up space and type /tradeclaim."),
			["mt_items_arrived"] = ("Itens guardados de uma troca chegaram às suas mãos.", "Items kept from a trade have reached your hands."),
			["mt_restored"] = ("$1 item(ns) de uma troca interrompida voltaram pro seu inventário.", "$1 item(s) from an interrupted trade were returned to your inventory."),
			["mt_restore_full"] = ("Itens de uma troca interrompida voltaram, mas o inventário encheu. Libere espaço e digite /tradeclaim.", "Items from an interrupted trade came back, but your inventory is full. Free up space and type /tradeclaim."),
			["mt_your_offer"] = ("Sua oferta", "Your offer"),
			["mt_your_offer_confirmed"] = ("Sua oferta - CONFIRMADA", "Your offer - CONFIRMED"),
			["mt_their_offer"] = ("Oferta de $1", "$1's offer"),
			["mt_their_offer_confirmed"] = ("Oferta de $1 - CONFIRMOU", "$1's offer - CONFIRMED"),
			["mt_confirm"] = ("Confirmar", "Confirm"),
			["mt_undo"] = ("Desfazer", "Undo"),
			["mt_cancel"] = ("Cancelar", "Cancel"),
			["mt_delivering"] = ("Entregando...", "Exchanging..."),
			["mt_bot_host_only"] = ("/tradebot só funciona pra quem está hospedando o mundo (teste solo).", "/tradebot only works for the player hosting the world (solo test)."),
			["mt_in_real_trade"] = ("Você está numa troca de verdade agora.", "You are in a real trade right now."),
			["mt_debug_your_offer"] = ("Sua oferta (prévia de debug)", "Your offer (debug preview)"),
			["mt_debug_their_offer"] = ("Oferta do outro jogador", "Other player's offer"),
			["mt_debug_lock"] = ("Confirmar (travar)", "Confirm (lock)"),
			["mt_debug_unlock"] = ("Destravar", "Unlock"),
			["mt_close"] = ("Fechar", "Close"),
			["mt_raw"] = ("$1", "$1")
		};

		internal static readonly string[] CompletedKeys = new string[4] { "mt_completed_1", "mt_completed_2", "mt_completed_3", "mt_completed_4" };

		[HarmonyPostfix]
		private static void Postfix(Localization __instance, string language)
		{
			bool flag = language == "Portuguese_Brazilian" || language == "Portuguese_European";
			foreach (KeyValuePair<string, (string, string)> word in Words)
			{
				AddWord.Invoke(__instance, new object[2]
				{
					word.Key,
					flag ? word.Value.Item1 : word.Value.Item2
				});
			}
		}

		internal static string Get(string key, params string[] args)
		{
			return Localization.instance.Localize("$" + key, args);
		}
	}
}
namespace MayheimTrader.Commands
{
	internal static class TradeCommand
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__0_0;

			public static ConsoleEvent <>9__0_1;

			internal void <Register>b__0_0(ConsoleEventArgs args)
			{
				TradeRpc.SendRequestTrade((args.Length >= 2) ? args[1] : "");
			}

			internal void <Register>b__0_1(ConsoleEventArgs args)
			{
				TradeClient.Claim();
			}
		}

		internal static void Register()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: 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_0029: Expected O, but got Unknown
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			object obj = <>c.<>9__0_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					TradeRpc.SendRequestTrade((args.Length >= 2) ? args[1] : "");
				};
				<>c.<>9__0_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("trade", "/trade [nome] - troca com um jogador (sem nome: o mais próximo) | trade with a player (no name: nearest)", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj2 = <>c.<>9__0_1;
			if (obj2 == null)
			{
				ConsoleEvent val2 = delegate
				{
					TradeClient.Claim();
				};
				<>c.<>9__0_1 = val2;
				obj2 = (object)val2;
			}
			new ConsoleCommand("tradeclaim", "Recebe itens de troca guardados | claim trade items kept for you", (ConsoleEvent)obj2, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}
	}
}