Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of MayheimTrader v0.1.1
plugins/MayheimTrader/MayheimTrader.dll
Decompiled a month agousing 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); } } }