using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using PlayerTraders.Core; using Splatform; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("PlayerTraders")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.6.5.0")] [assembly: AssemblyInformationalVersion("0.6.5")] [assembly: AssemblyProduct("PlayerTraders")] [assembly: AssemblyTitle("PlayerTraders")] [assembly: AssemblyVersion("0.6.5.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 PlayerTraders { internal static class DurableSave { public static void Save() { Check.That(!SaveSystem.HasSessionFlag((SaveSystemSessionFlags)1) && !ZNet.instance.HardSaveBlock(), "The game blocked character saving; the transaction remains in the journal"); PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); playerProfile.SavePlayerData(Player.m_localPlayer); Check.That(playerProfile.Save(), "Could not save the character: the transaction is awaiting recovery"); } } [HarmonyPatch(typeof(Humanoid), "Pickup")] internal static class PausePickup { private static bool Prefix(Humanoid __instance, ref bool __result) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Network.Busy) { return true; } __result = false; return false; } } internal static class Items { public static Item Encode(ItemData i, int width = 10) { //IL_0108: Unknown result type (might be due to invalid IL or missing references) return new Item { Prefab = (Object.op_Implicit((Object)(object)i.m_dropPrefab) ? ((Object)i.m_dropPrefab).name : ((Object)ObjectDB.instance.GetItemPrefab(i.m_shared)).name), Count = i.m_stack, Max = i.m_shared.m_maxStackSize, Quality = i.m_quality, Variant = i.m_variant, WorldLevel = i.m_worldLevel, Durability = i.m_durability, Crafter = i.m_crafterID, CrafterName = (i.m_crafterName ?? ""), PickedUp = i.m_pickedUp, Cheated = i.m_cheated, Equipped = i.m_equipped, Data = new SortedDictionary(i.m_customData, StringComparer.Ordinal), Slot = i.m_gridPos.y * width + i.m_gridPos.x, EquipSlot = EquipmentSlot(i.m_shared.m_itemType) }; } public static string EquipmentSlot(ItemType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 if ((int)type <= 7) { if ((int)type == 6) { return "Голова"; } if ((int)type == 7) { return "Торс"; } } else { if ((int)type == 11) { return "Ноги"; } if ((int)type == 17) { return "Плечи"; } if ((int)type == 18) { return "Аксессуар"; } } return ""; } public static bool Tradeable(string prefab) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Invalid comparison between Unknown and I4 GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab); ItemDrop val = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent() : null); if (Object.op_Implicit((Object)(object)val) && prefab != "Coins" && !val.m_itemData.m_shared.m_questItem) { return (int)val.m_itemData.m_shared.m_itemType != 10; } return false; } public static List KnownItems() { return (from go in ObjectDB.instance.m_items where Object.op_Implicit((Object)(object)go) && Tradeable(((Object)go).name) && Player.m_localPlayer.IsKnownMaterial(go.GetComponent().m_itemData.m_shared.m_name) select Factory(((Object)go).name)).OrderBy(Name).ToList(); } public static string Description(Item item) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item.Prefab); if (!Object.op_Implicit((Object)(object)itemPrefab)) { return ""; } return Localization.instance.Localize(itemPrefab.GetComponent().m_itemData.m_shared.m_description); } public static Item Factory(string prefab) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab); Check.That(Object.op_Implicit((Object)(object)itemPrefab) && Object.op_Implicit((Object)(object)itemPrefab.GetComponent()), "Unknown item: " + prefab); ItemData obj = itemPrefab.GetComponent().m_itemData.Clone(); obj.m_dropPrefab = itemPrefab; obj.m_stack = 1; return Encode(obj).Part(1); } public static ItemData Decode(Item i, int width = 10) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) i.Validate(); GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(i.Prefab); Check.That(Object.op_Implicit((Object)(object)itemPrefab) && Object.op_Implicit((Object)(object)itemPrefab.GetComponent()), "Game item missing: " + i.Prefab); ItemData val = itemPrefab.GetComponent().m_itemData.Clone(); Check.That(i.Max == val.m_shared.m_maxStackSize && i.EquipSlot == EquipmentSlot(val.m_shared.m_itemType), "Item properties do not match the game"); val.m_dropPrefab = itemPrefab; val.m_stack = i.Count; val.m_quality = i.Quality; val.m_variant = i.Variant; val.m_worldLevel = i.WorldLevel; val.m_durability = i.Durability; val.m_crafterID = i.Crafter; val.m_crafterName = i.CrafterName; val.m_pickedUp = i.PickedUp; val.m_cheated = i.Cheated; val.m_equipped = i.Equipped; val.m_customData = new Dictionary(i.Data); val.m_gridPos = new Vector2i(Math.Max(0, i.Slot) % width, Math.Max(0, i.Slot) / width); return val; } public static Bag Snapshot(Inventory inventory) { Bag bag = new Bag(); bag.Width = inventory.GetWidth(); bag.Height = inventory.GetHeight(); bag.Items = (from i in inventory.GetAllItems() select Encode(i, inventory.GetWidth()) into i orderby i.Slot select i).ToList(); bag.Validate(); return bag; } public static bool Same(Bag a, Bag b) { return Json.Write(a) == Json.Write(b); } public static void Validate(Bag bag) { bag.Validate(); foreach (Item item in bag.Items) { Decode(item, bag.Width); } } public static void Apply(Bag before, Bag after) { Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory(); Check.That(Same(Snapshot(inventory), before), "Inventory changed during the transaction; recovery required"); Check.That(after.Width == inventory.GetWidth() && after.Height == inventory.GetHeight(), "Inventory size changed"); List source = inventory.GetAllItems().ToList(); List list = new List(); foreach (Item i in after.Items.OrderBy((Item x) => x.Slot)) { if (i.Equipped) { ItemData val = ((IEnumerable)source).SingleOrDefault((Func)((ItemData x) => x.m_equipped && x.m_gridPos.y * after.Width + x.m_gridPos.x == i.Slot)); Check.That(val != null && Json.Write(Encode(val, after.Width)) == Json.Write(i), "Player equipment changed"); list.Add(val); } else { list.Add(Decode(i, after.Width)); } } foreach (ItemData item in source.Where((ItemData x) => x.m_equipped)) { Check.That(list.Contains(item), "Cannot remove an item the player is wearing"); } inventory.GetAllItems().Clear(); inventory.GetAllItems().AddRange(list); AccessTools.Method(typeof(Inventory), "Changed", (Type[])null, (Type[])null).Invoke(inventory, new object[2] { InventoryNotice.ReceivedCheatedItem(before, after), true }); } public static string Name(Item i) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(i.Prefab); if (!Object.op_Implicit((Object)(object)itemPrefab)) { return i.Prefab; } return Localization.instance.Localize(itemPrefab.GetComponent().m_itemData.m_shared.m_name); } public static Sprite Icon(Item i) { return Decode(i).GetIcon(); } } internal static class NativeInventoryMove { public static Inventory Mirror(Bag bag, bool strictStacks = false) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown Inventory val = new Inventory("PlayerTraders", (Sprite)null, bag.Width, bag.Height); AccessTools.Field(typeof(Inventory), "m_temoraryInventory").SetValue(val, true); foreach (Item item in bag.Items) { ItemData val2 = Items.Decode(item, bag.Width); if (strictStacks) { val2.m_shared = (SharedData)AccessTools.Method(typeof(object), "MemberwiseClone", (Type[])null, (Type[])null).Invoke(val2.m_shared, null); SharedData shared = val2.m_shared; shared.m_name = shared.m_name + "#" + item.Key; } val.GetAllItems().Add(val2); } return val; } public static void Apply(Bag player, Bag stock, Request r, bool fillFromTop = false) { //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Expected O, but got Unknown //IL_025f: Unknown result type (might be due to invalid IL or missing references) string text = Json.Write(new Bag[2] { player, stock }); Inventory val = Mirror(player, strictStacks: true); Inventory val2 = Mirror(stock, strictStacks: true); Inventory val3 = ((r.Source == "player") ? val : val2); Inventory val4 = ((r.Target == "player") ? val : val2); ItemData itemAt = val3.GetItemAt(r.Slot % val3.GetWidth(), r.Slot / val3.GetWidth()); Check.That(val3 == val4 || !itemAt.m_shared.m_questItem, "This item cannot be given to a trader"); if (r.TargetSlot < 0) { Check.That(val3 != val4, "Choose another slot"); Check.That(r.Count == itemAt.m_stack, "Not enough items"); if (!fillFromTop) { val4.MoveItemToThis(val3, itemAt); } else { for (int i = 0; i < 2; i++) { if (itemAt.m_stack <= 0) { break; } for (int j = 0; j < val4.GetHeight(); j++) { if (itemAt.m_stack <= 0) { break; } for (int k = 0; k < val4.GetWidth() && itemAt.m_stack > 0; k++) { ItemData itemAt2 = val4.GetItemAt(k, j); bool num; if (i != 0) { num = itemAt2 == null; } else { if (itemAt2 == null || !(itemAt2.m_shared.m_name == itemAt.m_shared.m_name)) { continue; } num = itemAt2.m_stack < itemAt2.m_shared.m_maxStackSize; } if (num) { val4.MoveItemToThis(val3, itemAt, itemAt.m_stack, k, j); } } } } } } else { Vector2i val5 = default(Vector2i); ((Vector2i)(ref val5))..ctor(r.TargetSlot % val4.GetWidth(), r.TargetSlot / val4.GetWidth()); ItemData itemAt3 = val4.GetItemAt(val5.x, val5.y); Check.That(val3 == val4 || itemAt3 == null || !itemAt3.m_shared.m_questItem, "This item cannot be given to a trader"); GameObject val6 = new GameObject("PT_InventoryCalculation"); val6.SetActive(false); try { InventoryGrid val7 = val6.AddComponent(); AccessTools.Field(typeof(InventoryGrid), "m_inventory").SetValue(val7, val4); val7.DropItem(val3, itemAt, r.Count, val5); } finally { Object.Destroy((Object)(object)val6); } } player.Items = Items.Snapshot(val).Items; stock.Items = Items.Snapshot(val2).Items; Check.That(text != Json.Write(new Bag[2] { player, stock }), "No space to move the item"); } public static void Place(Bag target, Item item, int slot) { Check.That(slot >= 0 && slot < target.Capacity, "Duplicate inventory slot"); Check.That(target.Items.All((Item i) => i.Slot != slot), "Choose an empty slot"); Bag bag = new Bag { Width = 1, Height = 1 }; Item item2 = Json.Copy(item); item2.Slot = 0; bag.Items.Add(item2); Bag beforePlayer = Json.Copy(target); Bag beforeStock = Json.Copy(bag); Apply(target, bag, new Request { Source = "stock", Target = "player", Slot = 0, TargetSlot = slot, Count = 1 }); Check.That(bag.Items.Count == 0, "Not enough space"); MoveGuard.Verify(beforePlayer, beforeStock, target, bag); } } internal sealed class Wire { public string Kind; public string Text = ""; public string Session = ""; public string Actor = ""; public string Id = ""; public long World; public long Sequence; public Dictionary Cost; public ShopView View; public ClientTransfer Transfer; public float[] Position; } internal sealed class ClientTransfer { public string Id; public string Phase; public string Trader; public long Sequence; public Bag Before; public Bag After; } internal sealed class ClientJournal { public long World; public Request Request; public ClientTransfer Transfer; public bool Applied; } internal static class Network { private const string Method = "PT_Request_v1"; private const string Reply = "PT_Reply_v1"; public static Ledger Host; private static Sessions sessions = new Sessions(); private static ZNet current; private static string hostError; private static readonly Dictionary requests = new Dictionary(); private static readonly Queue localQueue = new Queue(); private static readonly HashSet actions = new HashSet { "hello", "ready", "applied", "abort", "close", "open", "heartbeat", "create", "dismantle", "move", "prices", "order", "removeOrder", "sell", "fund", "buy", "cash", "look", "equipPlayer", "unequip" }; private static double nextTick; private static double nextHello; private static double nextHeartbeat; private static double lastReply; private static double nextPrune; public static long World; public static long Sequence; public static string Actor = ""; public static string Session = ""; public static string OpenId = ""; private static string pendingOpenId = ""; private static Store clientStore; private static ClientJournal journal; private static bool clientBlocked; public static bool Busy { get { if (journal != null) { if (journal.Request == null) { return journal.Transfer != null; } return true; } return false; } } public static bool BlockInput { get { if (Busy && !clientBlocked && Now - lastReply < 12.0 && Object.op_Implicit((Object)(object)Player.m_localPlayer) && !((Character)Player.m_localPlayer).IsDead() && Object.op_Implicit((Object)(object)ZNet.instance)) { if (!ZNet.instance.IsServer()) { ZRpc serverRPC = ZNet.instance.GetServerRPC(); if (serverRPC == null || !serverRPC.IsConnected()) { goto IL_006c; } } return true; } goto IL_006c; IL_006c: return TraderUI.Visible; } } public static string LocalActor => Canonical(((IUser)PlatformManager.DistributionPlatform.LocalUser).PlatformUserID); private static double Now => Time.realtimeSinceStartupAsDouble; private static string DataRoot => Path.Combine(Paths.ConfigPath, "PlayerTraders"); private unsafe static string Canonical(PlatformUserID id) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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) Check.That(((PlatformUserID)(ref id)).IsValid, "Invalid platform ID"); Platform platform = id.m_platform; return ((object)(*(Platform*)(&platform))/*cast due to .constrained prefix*/).ToString().ToLowerInvariant() + ":" + id.m_userID; } private static string PeerActor(ZNetPeer peer) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) string hostName = peer.m_socket.GetHostName(); return Canonical((peer.m_socket is ZSteamSocket) ? new PlatformUserID("Steam", hostName) : new PlatformUserID(hostName)); } public static void Register(ZNetPeer peer) { peer.m_rpc.Register("PT_Request_v1", (Action)delegate(ZRpc rpc, ZPackage package) { Receive(rpc, package); }); peer.m_rpc.Register("PT_Reply_v1", (Action)delegate(ZRpc rpc, ZPackage package) { if (!Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.IsServer() || ZNet.instance.GetServerRPC() != rpc) { return; } try { Accept(Parse(package)); } catch (Exception e) { Fail(e); } }); } private static T Parse(ZPackage package) { return PacketCodec.Read(package); } private static ZPackage Package(object value) { return PacketCodec.Create(value); } private static void SendTo(ZRpc rpc, Wire value) { ZPackage p = Package(value); if (rpc == null) { localQueue.Enqueue(delegate { Accept(Parse(p)); }); } else { rpc.Invoke("PT_Reply_v1", new object[1] { p }); } } public static void Send(Request request) { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return; } if (ZNet.instance.IsServer()) { localQueue.Enqueue(delegate { Receive(null, Package(request)); }); return; } ZRpc serverRPC = ZNet.instance.GetServerRPC(); if (serverRPC == null || !serverRPC.IsConnected()) { OpenId = ""; Session = ""; TraderUI.Close(send: false); TraderUI.Notify("Connection lost"); } else { serverRPC.Invoke("PT_Request_v1", new object[1] { Package(request) }); } } public static void Reset() { TraderUI.Close(send: false); current = null; Host = null; hostError = null; sessions = new Sessions(); requests.Clear(); localQueue.Clear(); World = 0L; Sequence = 0L; Actor = (Session = (OpenId = (pendingOpenId = ""))); journal = null; clientStore = null; clientBlocked = false; nextTick = (nextHello = (nextHeartbeat = (lastReply = (nextPrune = 0.0)))); WorldDrops.Reset(); WorldObjects.Reset(); Plugin.ResetConfiguration(); } public static void Tick() { //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) if (current != ZNet.instance) { Reset(); current = ZNet.instance; } if (localQueue.Count > 0) { try { localQueue.Dequeue()(); } catch (Exception e) { Fail(e); } } if (!Object.op_Implicit((Object)(object)current) || Now < nextTick) { return; } nextTick = Now + 1.0; if (Now >= nextPrune) { nextPrune = Now + 60.0; string[] array = (from p in requests where Now - p.Value > 60.0 select p.Key).ToArray(); foreach (string key in array) { requests.Remove(key); } } if (current.IsServer() && Host == null && hostError == null) { if (!Object.op_Implicit((Object)(object)ZNetScene.instance) || ZDOMan.instance == null || !Object.op_Implicit((Object)(object)ObjectDB.instance) || !Object.op_Implicit((Object)(object)WorldObjects.TraderPrefab)) { return; } try { Plugin.LoadServerConfiguration(); long worldUID = current.GetWorldUID(); Check.That(worldUID != 0, "World ID is unavailable"); string text = Path.Combine(DataRoot, "worlds", worldUID + ".json"); Store store = new Store(text); Host = new Ledger(store, worldUID); if (!File.Exists(text)) { store.Save(Host.Data); } WorldObjects.Reconcile(Host.Data); Plugin.LogInfo("Trader registry ready: " + text + "; traders: " + Host.Data.Traders.Count); } catch (Exception ex) { Host = null; hostError = "Trader storage is locked: " + ex.Message; Plugin.Error(ex); } } if (Host != null) { WorldDrops.Tick(); sessions.Expire(Now); sessions.Prune((string id, string actor) => Host.Data.Traders.TryGetValue(id, out var value) && AliveNear(actor, value.Position)); } if (Plugin.Headless) { return; } if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead()) { TraderUI.Close(); return; } TraderMap.Tick(); if (OpenId.Length > 0 && TraderUI.Visible) { TraderNPC traderNPC = TraderNPC.Find(OpenId); if (!Object.op_Implicit((Object)(object)traderNPC) || Vector3.Distance(((Component)traderNPC).transform.position, ((Component)Player.m_localPlayer).transform.position) > 5f || Now - lastReply > 12.0) { TraderUI.Close(); TraderUI.Notify("Connection lost or trader too far away"); } else if (Now >= nextHeartbeat) { nextHeartbeat = Now + 3.0; Send(new Request { Action = "heartbeat", Trader = OpenId, Session = Session }); } } if ((World == 0L || Busy) && Now >= nextHello) { nextHello = Now + 5.0; Send(new Request { Action = "hello", Id = (journal?.Request?.Id ?? journal?.Transfer?.Id ?? "") }); } } private static (string actor, string name, Vector3 position, long character) Identity(ZRpc rpc) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) if (rpc == null) { Check.That(ZNet.instance.IsServer() && Object.op_Implicit((Object)(object)Player.m_localPlayer) && !((Character)Player.m_localPlayer).IsDead(), "Player unavailable"); return (actor: LocalActor, name: Player.m_localPlayer.GetPlayerName(), position: ((Component)Player.m_localPlayer).transform.position, character: CharacterAccess.Require(Player.m_localPlayer.GetPlayerID())); } ZNetPeer val = ((IEnumerable)ZNet.instance.GetPeers()).SingleOrDefault((Func)((ZNetPeer x) => x.m_rpc == rpc)); Check.That(val != null && val.IsReady() && rpc.IsConnected(), "Connection not confirmed"); string text = PeerActor(val); Check.That(!string.IsNullOrWhiteSpace(text) && text.Length <= 256, "Connection owner is unavailable"); ZDO zDO = ZDOMan.instance.GetZDO(val.m_characterID); Check.That(zDO != null && !zDO.GetBool("dead", false), "Character unavailable"); long item = CharacterAccess.Require(zDO.GetLong(ZDOVars.s_playerID, 0L)); return (actor: text, name: val.m_playerName, position: zDO.GetPosition(), character: item); } private static bool AliveNear(string actor, float[] position) { //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) try { if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && actor == LocalActor) { return !((Character)Player.m_localPlayer).IsDead() && Vector3.Distance(((Component)Player.m_localPlayer).transform.position, Vec(position)) <= 5f; } ZNetPeer val = ((IEnumerable)ZNet.instance.GetPeers()).FirstOrDefault((Func)((ZNetPeer p) => p.IsReady() && PeerActor(p) == actor)); if (val == null) { return false; } ZDO zDO = ZDOMan.instance.GetZDO(val.m_characterID); return zDO != null && !zDO.GetBool("dead", false) && Vector3.Distance(zDO.GetPosition(), Vec(position)) <= 5f; } catch { return false; } } public static Vector3 Vec(float[] p) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) Check.That(p != null && p.Length == 3 && p.All((float x) => !float.IsNaN(x) && !float.IsInfinity(x)), "Invalid position"); return new Vector3(p[0], p[1], p[2]); } private static ClientTransfer ClientPart(Transfer p) { return new ClientTransfer { Id = p.Id, Sequence = p.Sequence, Phase = p.Phase, Before = p.PlayerBefore, After = p.PlayerAfter, Trader = p.After.Id }; } private static ShopView View(Trader t, string actor, long character) { return ShopView.For(t, actor, character); } private static void Receive(ZRpc rpc, ZPackage package) { //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_05fa: Unknown result type (might be due to invalid IL or missing references) //IL_062c: Unknown result type (might be due to invalid IL or missing references) //IL_09df: Unknown result type (might be due to invalid IL or missing references) //IL_09ef: Unknown result type (might be due to invalid IL or missing references) //IL_0a18: Unknown result type (might be due to invalid IL or missing references) //IL_0aa2: Unknown result type (might be due to invalid IL or missing references) //IL_0aae: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer()) { return; } string text = ""; string key = ""; try { (string, string, Vector3, long) tuple = Identity(rpc); key = tuple.Item1; Request r = Parse(package); text = r.Id; Check.That(hostError == null && Host != null, hostError ?? "The world is still loading"); Host.Data.Pending.TryGetValue(key, out var value); CharacterAccess.CheckPending(value, tuple.Item4); Check.That(r.Action != null && actions.Contains(r.Action) && (r.Trader?.Length ?? 0) <= 64 && (r.Session?.Length ?? 0) <= 64 && (r.Id?.Length ?? 0) <= 64 && (r.Key?.Length ?? 0) <= 128, "Invalid request"); string key2 = tuple.Item1 + ":" + r.Action; Check.That(!requests.TryGetValue(key2, out var value2) || Now - value2 >= 0.12, "Too many requests"); requests[key2] = Now; if (r.Action == "dismantle") { if (rpc == null && !Host.Data.Traders.ContainsKey(r.Trader) && !Host.Data.Drops.ContainsKey(r.Trader) && WorldObjects.RemoveOrphan(r.Trader, tuple.Item3, out var removedPosition)) { SendTo(rpc, new Wire { Kind = "removed", Id = r.Trader, Position = new float[3] { removedPosition.x, removedPosition.y, removedPosition.z }, Text = "Removed a trader with missing data. Its belongings are not in the registry." }); return; } bool flag = false; DropPlan dropPlan; if (Host.Data.Drops.TryGetValue(r.Trader, out var value3)) { Check.That(value3.Owner == tuple.Item1 && value3.OwnerCharacter == tuple.Item4 && Vector3.Distance(tuple.Item3, Vec(value3.Position)) <= 5f, "Only the owner can do this"); dropPlan = value3; } else { Check.That(Host.Data.Traders.TryGetValue(r.Trader, out var value4), "Trader not found"); Check.That(value4.IsOwner(tuple.Item1, tuple.Item4) && Vector3.Distance(tuple.Item3, Vec(value4.Position)) <= 5f, "Only the owner can do this"); string token = sessions.Open(r.Trader, tuple.Item1, Now); sessions.Check(r.Trader, tuple.Item1, token, Now); WorldObjects.ValidateDrops(DropPlan.From(value4)); dropPlan = Host.Dismantle(r.Trader, tuple.Item1, r.Revision, tuple.Item4); flag = true; } WorldObjects.ApplyDrops(dropPlan); sessions.Close(r.Trader, tuple.Item1); SendTo(rpc, new Wire { Kind = "removed", Id = r.Trader, Position = (flag ? dropPlan.Position : null) }); return; } if (r.Action == "hello") { Host.Data.Receipts.TryGetValue(tuple.Item1, out var value5); Host.Data.Pending.TryGetValue(tuple.Item1, out var value6); SendTo(rpc, new Wire { Kind = "hello", Actor = tuple.Item1, World = Host.Data.World, Sequence = (value5?.Sequence ?? 0), Id = (value5?.Id ?? ""), Cost = Plugin.Cost, Transfer = ((value6 == null) ? null : ClientPart(value6)) }); return; } if (r.Action == "ready" || r.Action == "applied" || r.Action == "abort") { if (r.Action == "ready") { Check.That(Host.Data.Pending.TryGetValue(tuple.Item1, out var value7) && value7.Id == r.Id, "Transaction not found"); if (value7.Phase == "prepared" && Vector3.Distance(tuple.Item3, Vec((value7.Action == "create") ? value7.After.Position : value7.Before.Position)) > 5f) { Host.Abort(tuple.Item1, r.Id); SendTo(rpc, new Wire { Kind = "aborted", Id = r.Id, Sequence = Host.Data.Receipts[tuple.Item1].Sequence }); } else { Transfer transfer = Host.Commit(tuple.Item1, r.Id); WorldObjects.Apply(transfer.After); SendTo(rpc, new Wire { Kind = "commit", Transfer = ClientPart(transfer) }); } } else if (r.Action == "abort") { Host.Abort(tuple.Item1, r.Id); SendTo(rpc, new Wire { Kind = "done", Id = r.Id, Sequence = Host.Data.Receipts[tuple.Item1].Sequence }); } else { Host.Data.Pending.TryGetValue(tuple.Item1, out var value8); Host.Applied(tuple.Item1, r.Id); Wire wire = new Wire { Kind = "done", Id = r.Id, Sequence = Host.Data.Receipts[tuple.Item1].Sequence }; if (value8 != null && value8.After.Place == PlaceState.Placed) { wire.View = View(value8.After, tuple.Item1, tuple.Item4); } SendTo(rpc, wire); } return; } if (r.Action == "close") { sessions.Close(r.Trader, tuple.Item1); return; } if (!string.IsNullOrEmpty(r.Id) && Host.Data.Pending.TryGetValue(tuple.Item1, out var value9) && value9.Id == r.Id) { SendTo(rpc, new Wire { Kind = ((value9.Phase == "prepared") ? "prepare" : "commit"), Transfer = ClientPart(value9) }); return; } if (!string.IsNullOrEmpty(r.Id) && Host.Data.Receipts.TryGetValue(tuple.Item1, out var value10) && value10.Id == r.Id) { SendTo(rpc, new Wire { Kind = "done", Id = r.Id, Sequence = value10.Sequence }); return; } Trader value11 = null; if (r.Action != "create") { Check.That(Host.Data.Traders.TryGetValue(r.Trader, out value11), "Trader not found"); } if (r.Action == "create") { Check.That(Vector3.Distance(tuple.Item3, Vec(r.Position)) <= 5f, "Too far away to build"); Check.That(!Location.IsInsideNoBuildLocation(Vec(r.Position)), "Building is not allowed here"); Check.That(Math.Abs(r.Position[0]) < 20000f && Math.Abs(r.Position[2]) < 20000f && r.Position[1] > -1000f && r.Position[1] < 10000f, "Invalid placement"); } else { Check.That(value11.Place == PlaceState.Placed && Vector3.Distance(tuple.Item3, Vec(value11.Position)) <= 5f, "Too far from the trader"); } if (r.Action == "open") { Check.That(!Host.Data.Pending.Values.Any((Transfer p) => p.After.Id == r.Trader), "The trader has an unfinished transaction"); string session = sessions.Open(r.Trader, tuple.Item1, Now); SendTo(rpc, new Wire { Kind = "view", Session = session, View = View(value11, tuple.Item1, tuple.Item4) }); return; } if (r.Action != "create") { sessions.Check(r.Trader, tuple.Item1, r.Session, Now); } if (r.Action == "heartbeat") { SendTo(rpc, new Wire { Kind = "heartbeat" }); return; } Items.Validate(r.Inventory); if (r.Action == "look") { WorldObjects.ValidateLook(r.Look); } if (r.Action == "order") { Check.That(Items.Tradeable(r.Key), "This item cannot be purchased"); } if (r.Action == "sell") { Check.That(Items.Tradeable(r.Key), "This item cannot be given to a trader"); } Transfer transfer2 = new Rules(Items.Factory) { NativeMove = NativeInventoryMove.Apply, NativePlace = NativeInventoryMove.Place, ConstructionCost = Plugin.Cost }.Prepare(Host.Data, tuple.Item1, tuple.Item2, r, (r.Action == "create") ? WorldObjects.RandomLook() : null, tuple.Item4); Package(new Wire { Kind = "prepare", Transfer = ClientPart(transfer2) }); Host.Prepare(transfer2); SendTo(rpc, new Wire { Kind = "prepare", Transfer = ClientPart(transfer2) }); } catch (Exception ex) { if (!(ex is RuleException)) { Plugin.Error(ex); } Receipt value12; bool flag2 = !string.IsNullOrEmpty(text) && Host != null && !Host.Data.Pending.ContainsKey(key) && (!Host.Data.Receipts.TryGetValue(key, out value12) || value12.Id != text); SendTo(rpc, new Wire { Kind = (flag2 ? "rejected" : "error"), Id = text, Text = ((ex is RuleException) ? ex.Message : "Operation failed. Check the log; no duplicate items were delivered.") }); } } public static void Open(string id) { if (Busy || clientBlocked) { TraderUI.Notify("Recover the unfinished transaction first"); return; } pendingOpenId = id; Send(new Request { Action = "open", Trader = id }); } private static void RefreshOpenView(ShopView updated = null) { if (TraderUI.Visible && !Busy && OpenId.Length != 0) { if (updated != null && updated.Id == OpenId) { TraderUI.Show(updated); } else { Open(OpenId); } } } public static void Close() { if (OpenId.Length > 0) { Send(new Request { Action = "close", Trader = OpenId, Session = Session }); } OpenId = ""; Session = ""; pendingOpenId = ""; } public static void Operate(Request r) { try { Check.That(World != 0L && clientStore != null, "The trader is still loading. Please try again in a moment."); Check.That(!clientBlocked, "Wait for the connection or transaction recovery"); Check.That(!Busy, "Wait for the operation to finish"); r.Id = Guid.NewGuid().ToString("N"); r.Sequence = checked(Sequence + 1); r.Session = Session; r.Inventory = Items.Snapshot(((Humanoid)Player.m_localPlayer).GetInventory()); Package(r); journal = new ClientJournal { World = World, Request = r }; clientStore.Save(journal); Send(r); } catch (Exception e) { Fail(e); } } private static void Accept(Wire wire) { lastReply = Now; try { if (wire.Kind == "hello") { if (World == 0L) { World = wire.World; Actor = wire.Actor; clientStore = new Store(Path.Combine(DataRoot, "clients", Json.Hash(Actor + ":" + Player.m_localPlayer.GetPlayerID()) + "_" + World + ".json")); if (File.Exists(clientStore.Path)) { journal = clientStore.Load(); Check.That(journal.World == World, "The journal belongs to another world"); } else { Check.That(!File.Exists(clientStore.Path + ".bak") && !File.Exists(clientStore.Path + ".tmp"), "Client journal missing; a backup was found"); } } Check.That(World == wire.World && Actor == wire.Actor, "The world or connection changed"); Sequence = wire.Sequence; if (wire.Cost != null) { WorldObjects.SetBuildCost(wire.Cost); } if (wire.Transfer != null) { ProcessTransfer(wire.Transfer); } else if (Busy) { string text = journal.Request?.Id ?? journal.Transfer?.Id; if (wire.Id == text) { Finish(text, wire.Sequence); RefreshOpenView(); } else { if (journal.Transfer != null) { throw new RuleException("The host does not recognise the recorded transaction: a save rollback may have occurred. Automatic recovery blocked."); } Check.That(Items.Same(Items.Snapshot(((Humanoid)Player.m_localPlayer).GetInventory()), journal.Request.Inventory), "Inventory changed before confirmation. Transaction blocked for inspection."); Send(journal.Request); } } } else if (wire.Kind == "view") { if (wire.View.Id != pendingOpenId && wire.View.Id != OpenId) { return; } pendingOpenId = ""; OpenId = wire.View.Id; Session = wire.Session; TraderUI.Show(wire.View); } else if (wire.Kind == "removed") { if (OpenId == wire.Id) { TraderUI.Close(); } if (wire.Position != null) { WorldObjects.HammerEffects(wire.Position, 0f, removed: true); } TraderUI.Notify(string.IsNullOrEmpty(wire.Text) ? "Trader dismantled" : wire.Text); } else if (wire.Kind == "prepare" || wire.Kind == "commit") { ProcessTransfer(wire.Transfer); } else if (wire.Kind == "done") { Finish(wire.Id, wire.Sequence); RefreshOpenView(wire.View); } else if (wire.Kind == "aborted") { if (Busy && (journal.Request?.Id ?? journal.Transfer?.Id) == wire.Id) { journal = new ClientJournal { World = World }; Sequence = wire.Sequence; clientStore.Save(journal); TraderUI.Notify("You moved away from the trader. The operation was cancelled; your items are unchanged."); } } else if (wire.Kind == "rejected") { if (Busy && journal.Transfer == null && journal.Request.Id == wire.Id) { Request request = journal.Request; Plugin.Warn("Operation rejected: " + request.Action + " " + request.Source + ":" + request.Slot + " → " + request.Target + ":" + request.TargetSlot + "; " + wire.Text); journal = new ClientJournal { World = World }; clientStore.Save(journal); RefreshOpenView(); } TraderUI.Notify(wire.Text); } else if (wire.Kind == "error") { TraderUI.Notify(wire.Text); if (!Busy && OpenId.Length > 0 && wire.Text.Contains("Session")) { TraderUI.Close(); } if (Busy && journal.Transfer == null && wire.Id == journal.Request.Id) { Send(new Request { Action = "hello", Id = wire.Id }); } } } catch (Exception e) { if (wire.Kind == "prepare" || wire.Kind == "commit" || wire.Kind == "hello" || wire.Kind == "done") { clientBlocked = true; } Fail(e); } TraderUI.RefreshInput(); } private static void ProcessTransfer(ClientTransfer tx) { if (tx.Sequence > Sequence) { Check.That(!clientBlocked, "Recovery blocked; see the log"); Check.That(!Busy || (journal.Request?.Id ?? journal.Transfer?.Id) == tx.Id, "Another transaction is awaiting recovery"); if (journal == null) { journal = new ClientJournal { World = World }; } journal.Transfer = tx; clientStore.Save(journal); string key = "PT.receipt." + World; Player localPlayer = Player.m_localPlayer; Bag a = Items.Snapshot(((Humanoid)localPlayer).GetInventory()); string value; switch (Recovery.Decide(tx.Phase, localPlayer.m_customData.TryGetValue(key, out value) && value == tx.Id, Items.Same(a, tx.Before))) { case RecoveryStep.Acknowledge: Check.That(tx.Phase == "committed", "The character receipt does not match the host journal"); DurableSave.Save(); journal.Applied = true; clientStore.Save(journal); Send(new Request { Action = "applied", Id = tx.Id }); break; case RecoveryStep.Abort: journal.Transfer = null; journal.Request = new Request { Id = tx.Id, Sequence = tx.Sequence, Inventory = tx.Before, Action = "abort" }; clientStore.Save(journal); Send(new Request { Action = "abort", Id = tx.Id }); break; case RecoveryStep.Ready: Send(new Request { Action = "ready", Id = tx.Id }); break; default: Items.Apply(tx.Before, tx.After); localPlayer.m_customData[key] = tx.Id; DurableSave.Save(); journal.Applied = true; clientStore.Save(journal); Send(new Request { Action = "applied", Id = tx.Id }); break; } } } private static void Finish(string id, long sequence) { if (Busy && sequence <= Sequence && (journal.Request?.Id ?? journal.Transfer?.Id) != id) { return; } if (!Busy) { Sequence = Math.Max(Sequence, sequence); return; } Check.That((journal.Request?.Id ?? journal.Transfer?.Id) == id, "Transaction receipt mismatch"); if (journal.Transfer != null) { Check.That(Player.m_localPlayer.m_customData.TryGetValue("PT.receipt." + World, out var value) && value == id, "Character receipt missing; recovery required"); } if (journal.Request != null) { TraderUI.Traded(journal.Request.Trader, journal.Request.Action); } Request request = ((journal.Applied && journal.Request != null && journal.Request.Action == "create") ? journal.Request : null); Sequence = sequence; journal = new ClientJournal { World = World }; clientStore.Save(journal); TraderUI.Notify("Done"); if (request != null) { WorldObjects.HammerEffects(request.Position, request.Yaw, removed: false); } } public static void Fail(Exception e) { if (!(e is RuleException)) { Plugin.Error(e); } TraderUI.Notify((e is RuleException) ? e.Message : ("Error: " + e.Message)); } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] internal static class RegisterRpc { private static void Postfix(ZNetPeer peer) { Network.Register(peer); } } internal static class PacketCodec { public const int Limit = 1048576; public static ZPackage Create(object value) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown string text = Json.Write(value); Check.That(Encoding.UTF8.GetByteCount(text) < 1048544, "Too much custom item data"); ZPackage val = new ZPackage(); val.Write(text); val.SetPos(0); return val; } public static T Read(ZPackage package) { Check.That(package.Size() > 0 && package.Size() <= 1048576, "The network message is too large"); package.SetPos(0); try { return Json.Read(package.ReadString()); } catch (EndOfStreamException) { throw new RuleException("Could not read trader network data. Please try again."); } } } internal static class TraderAppearance { public static void Write(ZDO z, Look look, Dictionary equipment) { Publish(look, equipment, delegate(int key, int value) { z.Set(key, value, false); }, delegate(int key, Vector3 value) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) z.Set(key, value); }); } internal static void Publish(Look look, Dictionary equipment, Action number, Action color) { //IL_0037: 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) number(ZDOVars.s_modelIndex, look.Body); color(ZDOVars.s_skinColor, new Vector3(look.Skin[0], look.Skin[1], look.Skin[2])); color(ZDOVars.s_hairColor, new Vector3(look.HairColor[0], look.HairColor[1], look.HairColor[2])); number(ZDOVars.s_hairItem, Hash(look.Hair)); number(ZDOVars.s_beardItem, Hash(look.Beard)); number(ZDOVars.s_helmetItem, Hash(Slot("Голова")?.Prefab)); number(ZDOVars.s_chestItem, Hash(Slot("Торс")?.Prefab)); number(ZDOVars.s_legItem, Hash(Slot("Ноги")?.Prefab)); number(ZDOVars.s_utilityItem, Hash(Slot("Аксессуар")?.Prefab)); Item item = Slot("Плечи"); number(ZDOVars.s_shoulderItem, Hash(item?.Prefab)); number(ZDOVars.s_shoulderItemVariant, item?.Variant ?? 0); number(ZDOVars.s_shoulderItemQuality, item?.Quality ?? 1); static int Hash(string prefab) { if (!string.IsNullOrEmpty(prefab)) { return StringExtensionMethods.GetStableHashCode(prefab); } return 0; } Item Slot(string slot) { if (equipment == null || !equipment.TryGetValue(slot, out var value)) { return null; } return value; } } } internal static class TraderMap { private sealed class Entry { public ZDOID Id; public string Name; public Vector3 Position; public PinData Pin; } private static readonly Dictionary known = new Dictionary(); private static Minimap map; private static Sprite icon; public static void Observe(ZDO z, string name) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) if (z == null || z.GetBool("PT.dropped", false) || !Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return; } if (!known.TryGetValue(z.m_uid, out var value)) { Dictionary dictionary = known; ZDOID uid = z.m_uid; Entry obj = new Entry { Id = z.m_uid }; value = obj; dictionary.Add(uid, obj); } if (value.Name != name && value.Pin != null) { if (Object.op_Implicit((Object)(object)map)) { map.RemovePin(value.Pin); } value.Pin = null; } value.Name = name; value.Position = z.GetPosition(); } public static void Tick() { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Minimap.instance) || !Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return; } if ((Object)(object)map != (Object)(object)Minimap.instance) { if (Object.op_Implicit((Object)(object)map)) { Reset(); } map = Minimap.instance; } if (known.Count == 0) { return; } if (!Object.op_Implicit((Object)(object)icon)) { icon = map.m_locationIcons.Select((LocationSpriteData x) => x.m_icon).FirstOrDefault((Func)((Sprite s) => Object.op_Implicit((Object)(object)s) && ((Object)s).name == "mapicon_trader")); } if (!Object.op_Implicit((Object)(object)icon)) { return; } foreach (Entry value in known.Values) { if (value.Pin == null) { value.Pin = map.AddPin(value.Position, (PinType)8, value.Name, false, false, 0L, default(PlatformUserID)); value.Pin.m_icon = icon; value.Pin.m_doubleSize = true; } } } public static void Remove(ZDOID id) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (known.TryGetValue(id, out var value)) { if (Object.op_Implicit((Object)(object)map) && value.Pin != null) { map.RemovePin(value.Pin); } known.Remove(id); } } public static void Reset() { if (Object.op_Implicit((Object)(object)map)) { foreach (Entry value in known.Values) { if (value.Pin != null) { map.RemovePin(value.Pin); } } } known.Clear(); map = null; icon = null; } } [HarmonyPatch(typeof(ZNetScene), "OnZDODestroyed")] internal static class RemoveTraderMapPin { private static void Prefix(ZDO __0) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) TraderMap.Remove(__0.m_uid); } } public sealed class TraderMaterials : MonoBehaviour { private Material[] owned; internal void Initialize(Renderer body) { if (owned == null && Object.op_Implicit((Object)(object)body)) { owned = body.materials; } } private void OnDestroy() { if (owned != null) { Material[] array = owned; foreach (Material val in array) { if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(object)val); } } } owned = null; } } [HarmonyPatch(typeof(VisEquipment), "Awake")] internal static class TraderMaterialOwnership { private static bool Prefix(VisEquipment __instance) { if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent())) { return true; } if (Plugin.Headless) { return false; } if (!Object.op_Implicit((Object)(object)__instance.m_bodyModel)) { return true; } (((Component)__instance).gameObject.GetComponent() ?? ((Component)__instance).gameObject.AddComponent()).Initialize((Renderer)(object)__instance.m_bodyModel); return true; } } public sealed class TraderOfferMarker : MonoBehaviour { private const float VisibilityDistance = 50f; private static Sprite sprite; private Transform face; private void Awake() { ((Behaviour)this).enabled = false; } internal void Refresh(Appearance appearance) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; bool flag = false; if (Object.op_Implicit((Object)(object)localPlayer) && !((Character)localPlayer).IsDead() && Network.World != 0L && appearance != null) { Vector3 val = ((Component)localPlayer).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val)).sqrMagnitude <= 2500f) { localPlayer.m_customData.TryGetValue(OfferNews.Key(Network.World, appearance.Id), out var value); flag = OfferNews.Unread(appearance.OfferRevision, value); } } if (flag && !Object.op_Implicit((Object)(object)face)) { if (!Object.op_Implicit((Object)(object)sprite)) { Texture2D val2 = NativeWidgets.LoadTexture("offer-new.png"); sprite = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f), (float)((Texture)val2).height / 0.7f); } GameObject val3 = new GameObject("NewTradeOffers"); face = val3.transform; face.SetParent(((Component)this).transform, false); face.localPosition = new Vector3(0f, 2.55f, 0f); SpriteRenderer obj = val3.AddComponent(); obj.sprite = sprite; ((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)obj).receiveShadows = false; } if (Object.op_Implicit((Object)(object)face)) { ((Component)face).gameObject.SetActive(flag); } ((Behaviour)this).enabled = flag; } private void LateUpdate() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) Camera main = Camera.main; if (Object.op_Implicit((Object)(object)face) && Object.op_Implicit((Object)(object)main)) { face.rotation = ((Component)main).transform.rotation; } } internal static void Viewed(ShopView view) { Player localPlayer = Player.m_localPlayer; if (view == null || !Object.op_Implicit((Object)(object)localPlayer) || Network.World == 0L) { return; } string key = OfferNews.Key(Network.World, view.Id); localPlayer.m_customData.TryGetValue(key, out var value); if (OfferNews.Unread(view.OfferRevision, value)) { localPlayer.m_customData[key] = OfferNews.Remember(view.OfferRevision, value); TraderNPC traderNPC = TraderNPC.Find(view.Id); if (Object.op_Implicit((Object)(object)traderNPC)) { ((Component)traderNPC).GetComponent()?.Refresh(traderNPC.Current); } } } internal static void ReleaseAssets() { if (Object.op_Implicit((Object)(object)sprite)) { Texture2D texture = sprite.texture; Object.Destroy((Object)(object)sprite); if (Object.op_Implicit((Object)(object)texture)) { Object.Destroy((Object)(object)texture); } } sprite = null; } } internal static class TraderPose { public static void Stand(Animator animator) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Invalid comparison between Unknown and I4 //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Invalid comparison between Unknown and I4 //IL_00f1: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)animator)) { return; } AnimatorCullingMode cullingMode = animator.cullingMode; animator.cullingMode = (AnimatorCullingMode)0; animator.fireEvents = false; animator.applyRootMotion = false; animator.Update(0f); AnimatorControllerParameter[] parameters = animator.parameters; foreach (AnimatorControllerParameter val in parameters) { if ((int)val.type == 9) { animator.ResetTrigger(val.nameHash); } if ((int)val.type == 4 && (val.name == "wakeup" || val.name == "intro" || val.name == "sleeping" || val.name == "sitting" || val.name == "attached")) { animator.SetBool(val.nameHash, false); } } for (int j = 0; j < 4; j++) { animator.Update(5f); } animator.cullingMode = cullingMode; } } internal static class WorldDrops { private sealed class Snapshot { public WeakReference Ledger; public string[] Ids; } private static volatile Snapshot prepared; [ThreadStatic] private static Snapshot saving; private static readonly ConcurrentQueue completed = new ConcurrentQueue(); public static void Capture() { Ledger host = Network.Host; prepared = ((host == null) ? null : new Snapshot { Ledger = new WeakReference(host), Ids = host.Data.Drops.Keys.Where(WorldObjects.DropDelivered).ToArray() }); } public static void Begin() { saving = prepared; } public static void End(bool success) { if (success && saving != null && saving.Ids.Length != 0) { completed.Enqueue(saving); } saving = null; } public static void ClearThread() { saving = null; } public static void Reset() { prepared = null; saving = null; Snapshot result; while (completed.TryDequeue(out result)) { } } public static void Tick() { Snapshot result; while (completed.TryPeek(out result)) { if (result.Ledger.TryGetTarget(out var target) && target == Network.Host) { target.CompleteDrops(result.Ids); string[] ids = result.Ids; for (int i = 0; i < ids.Length; i++) { WorldObjects.RemoveDropMarker(ids[i]); } } completed.TryDequeue(out var _); } } } [HarmonyPatch(typeof(ZDOMan), "PrepareSave")] internal static class CaptureDropSave { private static void Postfix() { WorldDrops.Capture(); } } [HarmonyPatch(typeof(ZNet), "SaveWorldThread")] internal static class WatchDropSave { private static void Prefix() { WorldDrops.Begin(); } private static Exception Finalizer(Exception __exception) { WorldDrops.ClearThread(); return __exception; } } [HarmonyPatch(typeof(SaveSystem), "EndSave")] internal static class ConfirmDropSave { private static void Postfix(bool __1) { WorldDrops.End(__1); } } internal sealed class Appearance { public string Id; public string OwnerName; [JsonIgnore] public long Revision; public Look Look; public Dictionary Equipment; public long OfferRevision; } internal static class WorldObjects { public const string Prefab = "PT_Trader"; public static GameObject TraderPrefab; public static Sprite ScalesIcon; public static string[] Hairs = Array.Empty(); public static string[] Beards = Array.Empty(); private static string[] allHairs = Array.Empty(); private static readonly Dictionary objects = new Dictionary(); private static readonly Dictionary orphans = new Dictionary(); private static readonly string[] Men = new string[6] { "Bjorn", "Eirik", "Torstein", "Ulf", "Harald", "Leif" }; private static readonly string[] Women = new string[6] { "Sigrid", "Ingrid", "Astrid", "Freydis", "Helga", "Gudrun" }; public static void Register() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown try { L.Select(Localization.instance); if (!Plugin.Headless && !Object.op_Implicit((Object)(object)ScalesIcon)) { ScalesIcon = Icon(); } TraderPrefab = BuildNpc("PT_Trader"); PieceConfig val = new PieceConfig { Name = "$pt_S080", Description = "$pt_Recipe", PieceTable = "Hammer", Category = "$pt_S134", Icon = ScalesIcon, Requirements = ((IEnumerable>)Plugin.Cost).Select((Func, RequirementConfig>)((KeyValuePair p) => new RequirementConfig(p.Key, p.Value, 0, false))).ToArray() }; PieceManager.Instance.AddPiece(new CustomPiece(TraderPrefab, true, val)); PrefabManager.OnVanillaPrefabsAvailable -= Register; } catch (Exception e) { Plugin.Error(e); } } private static GameObject BuildNpc(string name) { //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) GameObject val = PrefabManager.Instance.CreateClonedPrefab(name, "Player"); Check.That((Object)(object)val != (Object)null && !val.activeInHierarchy, "Could not safely prepare the player visual model"); VisEquipment component = val.GetComponent(); Check.That(Object.op_Implicit((Object)(object)component), "The player model has no VisEquipment"); MonoBehaviour[] array = (from b in val.GetComponentsInChildren(true) where !(b is Player) && !(b is VisEquipment) && !(b is ZNetView) select b).ToArray(); for (int num = 0; num < array.Length; num++) { Object.DestroyImmediate((Object)(object)array[num]); } Player[] componentsInChildren = val.GetComponentsInChildren(true); for (int num = 0; num < componentsInChildren.Length; num++) { Object.DestroyImmediate((Object)(object)componentsInChildren[num]); } Rigidbody[] componentsInChildren2 = val.GetComponentsInChildren(true); for (int num = 0; num < componentsInChildren2.Length; num++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[num]); } Collider[] componentsInChildren3 = val.GetComponentsInChildren(true); for (int num = 0; num < componentsInChildren3.Length; num++) { Object.DestroyImmediate((Object)(object)componentsInChildren3[num]); } AudioSource[] componentsInChildren4 = val.GetComponentsInChildren(true); for (int num = 0; num < componentsInChildren4.Length; num++) { Object.DestroyImmediate((Object)(object)componentsInChildren4[num]); } component.m_playerComponent = null; component.m_isPlayer = true; component.m_randomModelIndex = false; component.m_clothColliders.Clear(); ZNetView component2 = val.GetComponent(); component2.m_persistent = true; component2.m_type = (ObjectType)2; component2.m_distant = false; val.layer = LayerMask.NameToLayer("piece"); CapsuleCollider obj = val.AddComponent(); obj.center = new Vector3(0f, 1f, 0f); obj.height = 2f; obj.radius = 0.35f; Piece obj2 = val.AddComponent(); obj2.m_canBeRemoved = true; obj2.m_canRotate = true; obj2.m_resources = Array.Empty(); obj2.m_noInWater = true; obj2.m_clipGround = true; obj2.m_spaceRequirement = 0.4f; ((StaticTarget)obj2).m_primaryTarget = false; ((StaticTarget)obj2).m_randomTarget = false; obj2.m_targetNonPlayerBuilt = false; val.AddComponent(); if (Plugin.Headless) { ((Behaviour)component).enabled = false; Renderer[] componentsInChildren5 = val.GetComponentsInChildren(true); for (int num = 0; num < componentsInChildren5.Length; num++) { componentsInChildren5[num].enabled = false; } Animator[] componentsInChildren6 = val.GetComponentsInChildren(true); for (int num = 0; num < componentsInChildren6.Length; num++) { ((Behaviour)componentsInChildren6[num]).enabled = false; } Cloth[] componentsInChildren7 = val.GetComponentsInChildren(true); for (int num = 0; num < componentsInChildren7.Length; num++) { componentsInChildren7[num].enabled = false; } } return val; } public static void PopulateHair() { if (!((Object)(object)ObjectDB.instance == (Object)null)) { allHairs = (from i in ObjectDB.instance.GetAllItems((ItemType)10, "Hair") select ((Object)((Component)i).gameObject).name into n orderby n select n).ToArray(); Hairs = HairstyleChoices.Current(allHairs); Beards = (from i in ObjectDB.instance.GetAllItems((ItemType)10, "Beard") select ((Object)((Component)i).gameObject).name into n orderby n select n).ToArray(); } } public static void SetBuildCost(Dictionary cost) { if (Object.op_Implicit((Object)(object)TraderPrefab) && Object.op_Implicit((Object)(object)ObjectDB.instance)) { Requirement[] resources = ((IEnumerable>)cost).Select((Func, Requirement>)delegate(KeyValuePair p) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(p.Key); ItemDrop val = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent() : null); Check.That(Object.op_Implicit((Object)(object)val), "Building resource not found: " + p.Key); return new Requirement { m_resItem = val, m_amount = p.Value, m_recover = false }; }).ToArray(); Piece component = TraderPrefab.GetComponent(); component.m_resources = resources; component.m_description = "$pt_Recipe"; } } public static void ReleaseAssets() { Reset(); if (Object.op_Implicit((Object)(object)ScalesIcon)) { Texture2D texture = ScalesIcon.texture; Object.Destroy((Object)(object)ScalesIcon); if (Object.op_Implicit((Object)(object)texture)) { Object.Destroy((Object)(object)texture); } } ScalesIcon = null; Hairs = (Beards = (allHairs = Array.Empty())); } public static Look RandomLook() { if (Hairs.Length == 0) { PopulateHair(); } int num = Random.Range(0, 2); string[] array = ((num == 0) ? Men : Women); return new Look { Body = num, Name = L.Text(array[Random.Range(0, array.Length)]), Hair = ((Hairs.Length != 0) ? Hairs[Random.Range(0, Hairs.Length)] : ""), Beard = ((num == 0 && Beards.Length != 0) ? Beards[Random.Range(0, Beards.Length)] : "") }; } public static void ValidateLook(Look look) { Check.That(look != null, "No appearance selected"); look.Validate(); if (Hairs.Length == 0) { PopulateHair(); } Check.That((look.Hair == "" || allHairs.Contains(look.Hair)) && (look.Beard == "" || Beards.Contains(look.Beard)), "Unknown hairstyle or beard"); } public static void Reset() { objects.Clear(); orphans.Clear(); TraderMap.Reset(); } public static void Reconcile(Registry registry) { List list = new List(); int num = 0; while (!ZDOMan.instance.GetAllZDOsWithPrefabIterative("PT_Trader", list, ref num)) { } foreach (ZDO item in list) { string text = item.GetString("PT.id", ""); Trader value; if (item.GetBool("PT.dropped", false)) { Network.Host.CompleteDrops(new string[1] { text }); item.SetOwner(ZNet.GetUID()); ZDOMan.instance.DestroyZDO(item); } else if (registry.Drops.ContainsKey(text)) { objects[text] = item; } else if (!registry.Traders.TryGetValue(text, out value)) { Plugin.Warn("Trader without registry data left in the world: " + text + ". Other traders remain available."); if (!string.IsNullOrEmpty(text)) { orphans[text] = item; } } else if (value.Place != PlaceState.Placed || objects.ContainsKey(text)) { ZDOMan.instance.DestroyZDO(item); } else { objects[text] = item; } } foreach (Trader value2 in registry.Traders.Values) { Apply(value2); } DropPlan[] array = Network.Host.Data.Drops.Values.ToArray(); for (int i = 0; i < array.Length; i++) { ApplyDrops(array[i]); } } public static bool RemoveOrphan(string id, Vector3 playerPosition, out Vector3 removedPosition) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_007a: 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) removedPosition = Vector3.zero; if (!orphans.TryGetValue(id, out var value)) { return false; } Check.That(Vector3.Distance(playerPosition, value.GetPosition()) <= 5f, "Too far from the trader"); Check.That(!Network.Host.Data.Traders.ContainsKey(id) && !Network.Host.Data.Drops.ContainsKey(id), "Data changed: open the trader again"); removedPosition = value.GetPosition(); value.SetOwner(ZNet.GetUID()); ZDOMan.instance.DestroyZDO(value); orphans.Remove(id); return true; } public static void HammerEffects(float[] position, float yaw, bool removed) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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) try { Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)ZNetScene.instance)) { Vector3 val = Network.Vec(position); GameObject prefab = ZNetScene.instance.GetPrefab("wood_floor"); Piece val2 = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent() : null); if (Object.op_Implicit((Object)(object)val2)) { val2.m_placeEffect.Create(val, Quaternion.Euler(0f, yaw, 0f), (Transform)null, 1f, -1, ((Character)localPlayer).GetZDOID()); } if (removed) { localPlayer.m_removeEffects.Create(val, Quaternion.identity, (Transform)null, 1f, -1, ((Character)localPlayer).GetZDOID()); } } } catch (Exception e) { Plugin.Error(e); } } public static bool DropDelivered(string id) { if (objects.TryGetValue(id, out var value)) { return value.GetBool("PT.dropped", false); } return false; } public static void RemoveDropMarker(string id) { if (DropDelivered(id)) { ZDO val = objects[id]; val.SetOwner(ZNet.GetUID()); ZDOMan.instance.DestroyZDO(val); objects.Remove(id); } } public static void ValidateDrops(DropPlan plan) { plan.Validate(); foreach (Item item in plan.Items.Concat(new Item[1] { Items.Factory("Coins") })) { Check.That(Object.op_Implicit((Object)(object)Items.Decode(item).m_dropPrefab.GetComponent()), "The item has no network component: " + item.Prefab); } } public static void ApplyDrops(DropPlan plan) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) if (DropDelivered(plan.Id)) { return; } ValidateDrops(plan); if (!objects.TryGetValue(plan.Id, out var value)) { value = ZDOMan.instance.CreateNewZDO(Network.Vec(plan.Position), StringExtensionMethods.GetStableHashCode("PT_Trader")); value.Persistent = true; value.SetPrefab(StringExtensionMethods.GetStableHashCode("PT_Trader")); value.Set("PT.id", plan.Id); objects[plan.Id] = value; } value.SetOwner(ZNet.GetUID()); List list = new List(); try { int num = 0; foreach (Item item in plan.Contents(Items.Factory("Coins"))) { ItemData obj = Items.Decode(item); ZNetView component = obj.m_dropPrefab.GetComponent(); Check.That(Object.op_Implicit((Object)(object)component), "The item has no network component: " + item.Prefab); float num2 = (float)num++ * 2.399963f; Vector3 val = Network.Vec(plan.Position) + new Vector3(Mathf.Cos(num2) * 0.5f, 0.7f + (float)(num % 4) * 0.1f, Mathf.Sin(num2) * 0.5f); ZDO val2 = ZDOMan.instance.CreateNewZDO(val, StringExtensionMethods.GetStableHashCode(item.Prefab)); list.Add(val2); val2.SetOwner(ZNet.GetUID()); val2.Persistent = true; val2.Type = component.m_type; val2.SetPrefab(StringExtensionMethods.GetStableHashCode(item.Prefab)); val2.SetRotation(Quaternion.identity); ItemDrop.SaveToZDO(obj, val2, -1); } value.Set("PT.dropped", true); } catch { foreach (ZDO item2 in list) { item2.SetOwner(ZNet.GetUID()); ZDOMan.instance.DestroyZDO(item2); } throw; } TraderNPC traderNPC = TraderNPC.Find(plan.Id); if (Object.op_Implicit((Object)(object)traderNPC)) { traderNPC.Sync(); } } public static void Apply(Trader trader) { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: 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) if (trader.Place != PlaceState.Placed) { if (objects.TryGetValue(trader.Id, out var value)) { value.SetOwner(ZNet.GetUID()); ZDOMan.instance.DestroyZDO(value); objects.Remove(trader.Id); } return; } if (!objects.TryGetValue(trader.Id, out var value2)) { value2 = ZDOMan.instance.CreateNewZDO(Network.Vec(trader.Position), StringExtensionMethods.GetStableHashCode("PT_Trader")); value2.Persistent = true; value2.Type = (ObjectType)2; value2.SetPrefab(StringExtensionMethods.GetStableHashCode("PT_Trader")); objects[trader.Id] = value2; } value2.SetOwner(ZNet.GetUID()); value2.SetPosition(Network.Vec(trader.Position)); value2.SetRotation(Quaternion.Euler(0f, trader.Yaw, 0f)); TraderAppearance.Write(value2, trader.Look, trader.Equipment); value2.Set("PT.id", trader.Id); value2.Set("PT.revision", trader.Revision); value2.Set("PT.appearance", Json.Write(new Appearance { Id = trader.Id, OwnerName = trader.OwnerName, OfferRevision = OfferNews.Version(trader), Look = trader.Look, Equipment = trader.Equipment.ToDictionary((KeyValuePair p) => p.Key, (KeyValuePair p) => new Item { Prefab = p.Value.Prefab, Quality = p.Value.Quality, Variant = p.Value.Variant }) })); TraderNPC traderNPC = TraderNPC.Find(trader.Id); if (Object.op_Implicit((Object)(object)traderNPC)) { traderNPC.Sync(); } } public static Sprite Icon() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) Texture2D val = NativeWidgets.LoadTexture("merchant-icon.png"); return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); } } public sealed class TraderNPC : MonoBehaviour, Hoverable, Interactable { private static readonly HashSet active = new HashSet(); public string Id = ""; public long Revision; internal Appearance Current; private ZNetView view; private VisEquipment visual; private long revision = -1L; private Animator animator; private readonly HashSet triggers = new HashSet(); private readonly GreetingGate greeting = new GreetingGate(); private readonly HashSet presentPlayers = new HashSet(); private float nextGesture; private bool wavePending; private TraderOfferMarker offerMarker; private void Awake() { view = ((Component)this).GetComponent(); visual = ((Component)this).GetComponent(); } private void Start() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Invalid comparison between Unknown and I4 if (Plugin.Headless) { ((Behaviour)this).enabled = false; return; } animator = ((Component)this).GetComponentInChildren(); TraderPose.Stand(animator); if (!Object.op_Implicit((Object)(object)view) || !view.IsValid()) { return; } active.Add(this); offerMarker = ((Component)this).gameObject.AddComponent(); if (Object.op_Implicit((Object)(object)animator)) { animator.fireEvents = false; AnimatorControllerParameter[] parameters = animator.parameters; foreach (AnimatorControllerParameter val in parameters) { if ((int)val.type == 9) { triggers.Add(val.nameHash); } } } Sync(); ((MonoBehaviour)this).InvokeRepeating("Refresh", 1f, 1f); } private void Refresh() { //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) Sync(); if (!Object.op_Implicit((Object)(object)view) || !view.IsValid() || Current == null || !((Component)this).gameObject.activeInHierarchy) { return; } offerMarker?.Refresh(Current); TraderMap.Observe(view.GetZDO(), Current.Look.Name); presentPlayers.Clear(); foreach (Player allPlayer in Player.GetAllPlayers()) { if (Object.op_Implicit((Object)(object)allPlayer) && !((Character)allPlayer).IsDead()) { int instanceID = ((Object)allPlayer).GetInstanceID(); presentPlayers.Add(instanceID); if (greeting.Enter(instanceID, Vector3.Distance(((Component)allPlayer).transform.position, ((Component)this).transform.position))) { wavePending = true; } } } greeting.Prune(presentPlayers); if (!greeting.HasNearby) { wavePending = false; } if (wavePending && Time.unscaledTime >= nextGesture) { wavePending = false; Gesture("wave"); } } private void Gesture(string name, bool interrupt = false) { if (!Object.op_Implicit((Object)(object)animator) || (!interrupt && Time.unscaledTime < nextGesture)) { return; } int num = Animator.StringToHash("emote_" + name); if (triggers.Contains(num)) { int num2 = Animator.StringToHash("emote_stop"); if (triggers.Contains(num2)) { animator.ResetTrigger(num2); } animator.SetTrigger(num); nextGesture = Time.unscaledTime + 4f; } } internal void Farewell(string gesture) { wavePending = false; Gesture(gesture, interrupt: true); } private void OnDestroy() { active.Remove(this); ((MonoBehaviour)this).CancelInvoke(); } public static TraderNPC Find(string id) { return active.FirstOrDefault((TraderNPC n) => Object.op_Implicit((Object)(object)n) && n.Id == id); } public void Sync() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)view) || !view.IsValid()) { return; } ZDO zDO = view.GetZDO(); if (zDO.GetBool("PT.dropped", false)) { TraderMap.Remove(zDO.m_uid); ((Component)this).gameObject.SetActive(false); return; } long num = zDO.GetLong("PT.revision", -1L); if (num == revision) { return; } string text = zDO.GetString("PT.appearance", ""); if (text.Length == 0 || text.Length > 262144) { return; } try { Appearance appearance = Json.Read(text); Id = appearance.Id; Revision = num; appearance.Revision = num; Current = appearance; ApplyLook(appearance); revision = num; TraderMap.Observe(zDO, appearance.Look.Name); } catch (Exception e) { Plugin.Error(e); ((MonoBehaviour)this).CancelInvoke(); } } internal void ApplyLook(Appearance a) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)visual)) { visual = ((Component)this).GetComponent(); } if (Object.op_Implicit((Object)(object)visual)) { visual.SetModel(a.Look.Body); visual.SetSkinColor(Network.Vec(a.Look.Skin)); visual.SetHairColor(Network.Vec(a.Look.HairColor)); visual.SetHairItem((!string.IsNullOrEmpty(a.Look.Hair)) ? StringExtensionMethods.GetStableHashCode(a.Look.Hair) : 0); visual.SetBeardItem((!string.IsNullOrEmpty(a.Look.Beard)) ? StringExtensionMethods.GetStableHashCode(a.Look.Beard) : 0); visual.SetHelmetItem(Hash("Голова")); visual.SetChestItem(Hash("Торс")); visual.SetLegItem(Hash("Ноги")); visual.SetUtilityItem(Hash("Аксессуар")); Item value; Item item = ((a.Equipment != null && a.Equipment.TryGetValue("Плечи", out value)) ? value : null); visual.SetShoulderItem(Hash("Плечи"), item?.Variant ?? 0, item?.Quality ?? 1); Animator componentInChildren = ((Component)this).GetComponentInChildren(); if (Object.op_Implicit((Object)(object)componentInChildren)) { componentInChildren.applyRootMotion = false; componentInChildren.SetFloat("forward_speed", 0f); componentInChildren.SetFloat("sideway_speed", 0f); } } int Hash(string slot) { if (a.Equipment == null || !a.Equipment.TryGetValue(slot, out var value2)) { return 0; } return StringExtensionMethods.GetStableHashCode(value2.Prefab); } } public string GetHoverName() { return Current?.Look.Name ?? L.Text("Trader"); } public float GetHoverOffset() { return 1.5f; } public string GetHoverText() { return GetHoverName() + L.Text("\nOwner: ") + (Current?.OwnerName ?? "…") + "\n" + Localization.instance.Localize(L.Text("[$KEY_Use] Open trader")); } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold || Id.Length == 0) { return false; } Network.Open(Id); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] internal static class PlaceTrader { private static bool Prefix(Player __instance, Piece piece, ref bool __result) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)((Component)piece).GetComponent())) { return true; } __result = false; try { Check.That(!Network.Busy, "Wait for the operation to finish"); AccessTools.Method(typeof(Player), "UpdatePlacementGhost", (Type[])null, (Type[])null).Invoke(__instance, new object[1] { true }); Check.That(AccessTools.Field(typeof(Player), "m_placementStatus").GetValue(__instance).ToString() == "Valid", "Cannot place a trader here"); GameObject val = (GameObject)AccessTools.Field(typeof(Player), "m_placementGhost").GetValue(__instance); Check.That(Object.op_Implicit((Object)(object)val) && Vector3.Distance(val.transform.position, ((Component)__instance).transform.position) <= 5f, "Too far away to build"); Vector3 position = val.transform.position; Request request = new Request(); request.Action = "create"; request.Position = new float[3] { position.x, position.y, position.z }; request.Yaw = val.transform.eulerAngles.y; Network.Operate(request); } catch (Exception e) { Network.Fail(e); } return false; } } [HarmonyPatch(typeof(Player), "RemovePiece")] internal static class DismantleTrader { private static bool Prefix(Player __instance, ref bool __result) { Piece hoveringPiece = __instance.GetHoveringPiece(); TraderNPC traderNPC = (Object.op_Implicit((Object)(object)hoveringPiece) ? ((Component)hoveringPiece).GetComponent() : null); if (!Object.op_Implicit((Object)(object)traderNPC)) { return true; } __result = false; if (!Network.Busy) { Network.Send(new Request { Action = "dismantle", Trader = traderNPC.Id, Revision = traderNPC.Revision }); } return false; } } internal static class L { private static TranslationCatalog catalog; private static string directory; private static string language; private static readonly MethodInfo addWord = AccessTools.Method(typeof(Localization), "AddWord", (Type[])null, (Type[])null); internal static void Initialize() { directory = Path.GetDirectoryName(typeof(L).Assembly.Location); using Stream stream = typeof(L).Assembly.GetManifestResourceStream("PlayerTraders.Localization.catalog.json"); using StreamReader streamReader = new StreamReader(stream); catalog = new TranslationCatalog(streamReader.ReadToEnd()); try { TranslationCatalog.WriteTemplateIfMissing(Path.Combine(directory, "english_PlayerTraders.json"), catalog.EnglishTemplate()); } catch (Exception ex) { Plugin.Warn("Could not create the English translation template: " + ex.Message); } } internal static void Select(Localization localization, string selected = null) { if (catalog != null && localization != null) { selected = selected ?? localization.GetSelectedLanguage(); if (language != selected) { language = selected; string json = TranslationFiles.Read(directory, Paths.PluginPath, selected, Plugin.Warn); catalog.Load(json, Plugin.Warn); } string[] array = new string[3] { "S080", "Recipe", "S134" }; foreach (string text in array) { addWord.Invoke(localization, new object[2] { "pt_" + text, catalog.ByKey(text) }); } } } internal static string Text(string source) { return catalog?.Text(source) ?? source; } internal static string Message(string source) { return catalog?.Message(source) ?? source; } internal static string Format(string source, params object[] args) { return string.Format(CultureInfo.CurrentCulture, Text(source), args); } internal static void Reset() { catalog = null; directory = (language = null); } } [HarmonyPatch(typeof(Localization), "SetupLanguage")] internal static class TraderLanguage { private static void Postfix(Localization __instance, string __0) { L.Select(__instance, __0); } } [BepInPlugin("ru.playertraders", "Player Traders", "0.6.5")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Id = "ru.playertraders"; public const string ModVersion = "0.6.5"; public static Plugin Instance; public static ConfigEntry ConstructionCost; internal static Dictionary Cost = BuildCost.Parse("Coins:50"); public static ConfigEntry Diagnostics; private Harmony patches; internal static bool Headless { get { if (!GUIManager.IsHeadless()) { if (Object.op_Implicit((Object)(object)ZNet.instance)) { return ZNet.instance.IsDedicated(); } return false; } return true; } } private void Awake() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown Instance = this; L.Initialize(); patches = new Harmony("ru.playertraders"); patches.PatchAll(); PrefabManager.OnVanillaPrefabsAvailable += WorldObjects.Register; ItemManager.OnItemsRegistered += WorldObjects.PopulateHair; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Player Traders: loading 0.6.5"); } internal static void LoadServerConfiguration() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown Check.That(Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer(), "Only the server can load trader settings"); ConfigFile val = new ConfigFile(Path.Combine(Paths.ConfigPath, "PlayerTraders.config"), true); ConstructionCost = val.Bind("Construction", "Resources", "Coins:50", "Construction cost as Prefab:Amount pairs, separated by commas; up to 6 resources. Default: Coins:50 (50 coins). Restart the game/server after changing this setting."); Cost = BuildCost.Parse(ConstructionCost.Value); Diagnostics = val.Bind("Diagnostics", "VerboseLog", false, "Detailed operation messages"); WorldObjects.SetBuildCost(Cost); LogInfo("Server trader recipe: " + ConstructionCost.Value + "; config: " + val.ConfigFilePath); } internal static void ResetConfiguration() { Cost = BuildCost.Parse("Coins:50"); Diagnostics = null; ConstructionCost = null; if (Object.op_Implicit((Object)(object)WorldObjects.TraderPrefab) && Object.op_Implicit((Object)(object)ObjectDB.instance)) { WorldObjects.SetBuildCost(Cost); } } public static void Error(Exception e) { ((BaseUnityPlugin)Instance).Logger.LogError((object)e); } public static void LogInfo(string value) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)value); } public static void Warn(string value) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)value); } public static void Trace(string value) { ConfigEntry diagnostics = Diagnostics; if (diagnostics != null && diagnostics.Value) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)value); } } private void Update() { Network.Tick(); if (!Headless) { TraderUI.Update(); } } private void OnDestroy() { TraderUI.Close(send: false); TraderUI.ReleaseInput(); TraderOfferMarker.ReleaseAssets(); NativeWidgets.ReleaseAssets(); Network.Reset(); WorldObjects.ReleaseAssets(); PrefabManager.OnVanillaPrefabsAvailable -= WorldObjects.Register; ItemManager.OnItemsRegistered -= WorldObjects.PopulateHair; Harmony obj = patches; if (obj != null) { obj.UnpatchSelf(); } L.Reset(); Instance = null; } } public static class Texts { public const string InvalidPacket = "Could not read trader network data. Please try again."; public const string Connecting = "The trader is still loading. Please try again in a moment."; public const string Aborted = "You moved away from the trader. The operation was cancelled; your items are unchanged."; public const string S001 = "Empty data"; public const string S002 = "Enter a positive whole number"; public const string S003 = "The number must be greater than zero"; public const string S004 = "The name must contain 1 to 32 characters"; public const string S005 = "Invalid item data"; public const string S006 = "Invalid inventory"; public const string S007 = "Duplicate inventory slot"; public const string S008 = "The item has already been moved"; public const string S009 = "Unequip the item first"; public const string S010 = "Not enough items"; public const string S011 = "Not enough space"; public const string S012 = "Out of stock"; public const string S013 = "Not enough coins"; public const string S014 = "Bjorn"; public const string S015 = "Unknown body type"; public const string S016 = "Invalid colour"; public const string S017 = "Invalid appearance"; public const string S018 = "Invalid trader data"; public const string S019 = "The warehouse must have 100 slots"; public const string S021 = "Data size limit exceeded"; public const string S022 = "Invalid equipment"; public const string S023 = "Invalid price"; public const string S024 = "Unsupported format or different world"; public const string S025 = "Invalid ID"; public const string S026 = "Corrupted journal"; public const string S027 = "Unknown transaction stage"; public const string S028 = "The character receipt does not match the host journal"; public const string S029 = "Inventory does not match the journal; duplicate delivery blocked. Saved data needs checking."; public const string S030 = "Голова"; public const string S031 = "Торс"; public const string S032 = "Ноги"; public const string S033 = "Плечи"; public const string S034 = "Аксессуар"; public const string S035 = "Invalid transaction number"; public const string S036 = "The previous transaction needs recovery"; public const string S037 = "Duplicate or outdated transaction"; public const string S038 = "Inventory confirmation missing"; public const string S039 = "Trader not found"; public const string S040 = "The trader has an unfinished transaction"; public const string S041 = "Data changed: open the trader again"; public const string S042 = "Only the owner can do this"; public const string S043 = "The trader is not placed in the world"; public const string S045 = "The unit price must be a positive whole number"; public const string S047 = "This item is no longer for sale"; public const string S048 = "Choose an item quantity"; public const string S049 = "The total is too large; choose a smaller quantity"; public const string S050 = "Not enough coins in the till"; public const string S051 = "Appearance is not set"; public const string S052 = "Only head, chest, legs, shoulders and accessory slots are supported"; public const string S053 = "The slot is empty"; public const string S055 = "Unknown action"; public const string S056 = "Choose where to return the clothing"; public const string S057 = "Not enough materials to create a trader"; public const string S058 = "The trader is busy"; public const string S059 = "Close the other trader first"; public const string S060 = "Session ended: open the trader again"; public const string S061 = "The data file is too large"; public const string S062 = "Corrupted data; the original is preserved and operations are blocked"; public const string S063 = "Storage is full: operations stopped"; public const string S064 = "The main file is missing, but a backup or pending file exists: recovery required"; public const string S065 = "An operation is already in progress"; public const string S066 = "Transaction not found"; public const string S067 = "Receipt not found"; public const string S068 = "Transaction not confirmed"; public const string S069 = "A confirmed transaction cannot be cancelled"; public const string S070 = "The game blocked character saving; the transaction remains in the journal"; public const string S071 = "Could not save the character: the transaction is awaiting recovery"; public const string S072 = "Unknown item: "; public const string S073 = "Game item missing: "; public const string S074 = "Item properties do not match the game"; public const string S075 = "Inventory changed during the transaction; recovery required"; public const string S076 = "Inventory size changed"; public const string S077 = "Player equipment changed"; public const string S078 = "Cannot remove an item the player is wearing"; public const string S080 = "Trader"; public const string S086 = "Invalid platform ID"; public const string S087 = "The network message is too large"; public const string S088 = "Too much custom item data"; public const string S089 = "Connection lost"; public const string S090 = "World ID is unavailable"; public const string S091 = "Trader storage is locked: "; public const string S092 = "Connection lost or trader too far away"; public const string S093 = "Player unavailable"; public const string S094 = "Connection not confirmed"; public const string S095 = "Connection owner is unavailable"; public const string S096 = "Character unavailable"; public const string S097 = "Invalid position"; public const string S098 = "The world is still loading"; public const string S099 = "Invalid request"; public const string S100 = "Too many requests"; public const string S101 = "Too far away to build"; public const string S102 = "Building is not allowed here"; public const string S103 = "Invalid placement"; public const string S105 = "Too far from the trader"; public const string S107 = "Operation failed. Check the log; no duplicate items were delivered."; public const string S108 = "Recover the unfinished transaction first"; public const string S109 = "Wait for the connection or transaction recovery"; public const string S110 = "The journal belongs to another world"; public const string S111 = "Client journal missing; a backup was found"; public const string S112 = "The world or connection changed"; public const string S113 = "Inventory changed before confirmation. Transaction blocked for inspection."; public const string S114 = "The host does not recognise the recorded transaction: a save rollback may have occurred. Automatic recovery blocked."; public const string S115 = "Session"; public const string S116 = "Recovery blocked; see the log"; public const string S117 = "Another transaction is awaiting recovery"; public const string S118 = "Transaction receipt mismatch"; public const string S119 = "Character receipt missing; recovery required"; public const string S120 = "Done"; public const string S121 = "Error: "; public const string S122 = "Eirik"; public const string S123 = "Torstein"; public const string S124 = "Ulf"; public const string S125 = "Harald"; public const string S126 = "Leif"; public const string S127 = "Sigrid"; public const string S128 = "Ingrid"; public const string S129 = "Astrid"; public const string S130 = "Freydis"; public const string S131 = "Helga"; public const string S132 = "Gudrun"; public const string S139 = "Could not safely prepare the player visual model"; public const string S140 = "The player model has no VisEquipment"; public const string S141 = "No appearance selected"; public const string S142 = "Unknown hairstyle or beard"; public const string S144 = "\nOwner: "; public const string S145 = "[$KEY_Use] Open trader"; public const string S146 = "Wait for the operation to finish"; public const string S147 = "Cannot place a trader here"; public const string S170 = "Could not display item data"; } public sealed class CurrencyGlyph : BaseMeshEffect { private Image icon; private bool before; private float heightRatio; private bool pending; private bool show; private Vector2 position; private Vector2 size; public static Image Attach(Text label, bool before = false, float heightRatio = 0.85f) { CurrencyGlyph currencyGlyph = ((Component)label).gameObject.AddComponent(); currencyGlyph.before = before; currencyGlyph.heightRatio = heightRatio; currencyGlyph.icon = NativeWidgets.Icon(((Component)label).transform, TraderSkinAssets.Get("coins"), 0f, 0f, 1f); currencyGlyph.icon.preserveAspect = false; ((Behaviour)currencyGlyph.icon).enabled = false; ((Graphic)label).SetVerticesDirty(); return currencyGlyph.icon; } public override void ModifyMesh(VertexHelper mesh) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0117: 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_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) if (!((UIBehaviour)this).IsActive() || !Object.op_Implicit((Object)(object)icon) || !Object.op_Implicit((Object)(object)icon.sprite)) { return; } Text val = (Text)((BaseMeshEffect)this).graphic; IList verts = val.cachedTextGenerator.verts; pending = true; show = false; if (verts.Count < 4) { return; } float num = 1f / val.pixelsPerUnit; Vector2 val2 = Vector2.op_Implicit(verts[0].position) * num; Vector2 val3 = ((Graphic)val).PixelAdjustPoint(val2) - val2; float num2 = float.MaxValue; float num3 = float.MinValue; float num4 = float.MaxValue; float num5 = float.MinValue; for (int i = 0; i + 3 < verts.Count; i += 4) { float num6 = float.MaxValue; float num7 = float.MinValue; float num8 = float.MaxValue; float num9 = float.MinValue; for (int j = 0; j < 4; j++) { Vector2 val4 = Vector2.op_Implicit(verts[i + j].position) * num + val3; num6 = Mathf.Min(num6, val4.x); num7 = Mathf.Max(num7, val4.x); num8 = Mathf.Min(num8, val4.y); num9 = Mathf.Max(num9, val4.y); } if (!(num9 <= num8) && !(num7 <= num6)) { num2 = Mathf.Min(num2, num6); num3 = Mathf.Max(num3, num7); if (before) { num4 = Mathf.Min(num4, num8); num5 = Mathf.Max(num5, num9); } else { num4 = num8; num5 = num9; } } } float num10 = (num5 - num4) * heightRatio; if (!(num10 <= 0f) && !float.IsInfinity(num10)) { show = true; Rect rect = icon.sprite.rect; float num11 = num10 * ((Rect)(ref rect)).width; rect = icon.sprite.rect; float num12 = num11 / ((Rect)(ref rect)).height; float num13 = Mathf.Max(2f, (float)val.fontSize * 0.14f); size = new Vector2(num12, num10); position = new Vector2(before ? (num2 - num13 - num12) : (num3 + num13), num4); } } private void LateUpdate() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) if (pending && Object.op_Implicit((Object)(object)icon)) { pending = false; ((Behaviour)icon).enabled = show; if (show) { RectTransform rectTransform = ((Graphic)icon).rectTransform; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0f, 1f); rectTransform.anchorMax = val; rectTransform.anchorMin = val; rectTransform.pivot = new Vector2(0f, 0f); rectTransform.sizeDelta = size; rectTransform.anchoredPosition = position; } } } } internal static class NativeWidgets { private static Texture2D panelTexture; private static readonly Vector2 TopLeft = new Vector2(0f, 1f); public static RectTransform Rect(Transform parent, string name, float x, float y, float w, float h) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent(); Place(component, x, y, w, h); return component; } public static void Place(RectTransform r, float x, float y, float w, float h) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_002f: Unknown result type (might be due to invalid IL or missing references) Vector2 val = (r.pivot = TopLeft); Vector2 anchorMin = (r.anchorMax = val); r.anchorMin = anchorMin; r.anchoredPosition = new Vector2(x, 0f - y); r.sizeDelta = new Vector2(w, h); } public static GameObject Panel(Transform parent, float x, float y, float w, float h) { //IL_0059: 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 (!Object.op_Implicit((Object)(object)panelTexture)) { panelTexture = LoadTexture("trader-panel.png"); } RectTransform obj = Rect(parent, "TraderWindow", x, y, w, h); Fill((Transform)(object)obj, 10f, 10f, w - 20f, h - 20f, new Color(0.055f, 0.033f, 0.02f, 1f)); RawImage obj2 = ((Component)Rect((Transform)(object)obj, "Wood", 0f, 0f, w, h)).gameObject.AddComponent(); obj2.texture = (Texture)(object)panelTexture; ((Graphic)obj2).color = Color.white; return ((Component)obj).gameObject; } internal static Texture2D LoadTexture(string file) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown using Stream stream = typeof(NativeWidgets).Assembly.GetManifestResourceStream("PlayerTraders.Assets." + file); CheckPanel(stream != null); byte[] array = new byte[stream.Length]; int num; for (int i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num == 0) { throw new EndOfStreamException(); } } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true); try { CheckPanel(ImageConversion.LoadImage(val, array, true)); ((Texture)val).wrapMode = (TextureWrapMode)1; ((Texture)val).filterMode = (FilterMode)2; ((Texture)val).anisoLevel = 1; return val; } catch { Object.Destroy((Object)(object)val); throw; } } private static void CheckPanel(bool ok) { if (!ok) { throw new InvalidOperationException("Interface texture not found"); } } public static void ReleaseAssets() { if (Object.op_Implicit((Object)(object)panelTexture)) { Object.Destroy((Object)(object)panelTexture); } panelTexture = null; TraderSkinAssets.Release(); } public static Image Fill(Transform parent, float x, float y, float w, float h, Color color) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) Image obj = ((Component)Rect(parent, "Surface", x, y, w, h)).gameObject.AddComponent(); ((Graphic)obj).color = color; ((Graphic)obj).raycastTarget = false; return obj; } public static Image Paint(Transform p, string sprite, float x, float y, float w, float h, bool sliced = true) { Image obj = ((Component)Rect(p, sprite, x, y, w, h)).gameObject.AddComponent(); obj.sprite = TraderSkinAssets.Get(sprite); obj.type = (Type)(sliced ? 1 : 0); obj.pixelsPerUnitMultiplier = 4f; ((Graphic)obj).raycastTarget = false; return obj; } public static void Line(Transform p, float x, float y, float w, float h = 1f) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) if (w <= 1f && h > 1f) { Image obj = ((Component)Rect(p, "Divider", x - 1f, y, 2f, h)).gameObject.AddComponent(); obj.sprite = TraderSkinAssets.Get("line"); ((Graphic)obj).raycastTarget = false; ((Component)Paint(p, "diamond", x - 9f, y + 12f, 18f, 12f, sliced: false)).transform.localRotation = Quaternion.Euler(0f, 0f, 90f); } else { Paint(p, "line", x, y - 1f, w, 2f, sliced: false); Paint(p, "diamond", x + w / 2f - 13f, y - 8f, 26f, 17f, sliced: false); } } public static void Surface(Transform p, float x, float y, float w, float h) { Paint(p, "panel", x, y, w, h); } public static void Board(Transform p, float x, float y, float w, float h, bool raised = false) { Paint(p, "panel", x, y, w, h); } public static void Mark(Selectable control, bool selected) { TraderSkin component = ((Component)control).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.Highlight(selected); } } private static void Skin(Selectable control, string kind = "button") { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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) //IL_0064: 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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) Graphic targetGraphic = control.targetGraphic; if (Object.op_Implicit((Object)(object)targetGraphic)) { targetGraphic.color = Color.clear; targetGraphic.raycastTarget = true; } RectTransform val = Rect(((Component)control).transform, "PaintedSkin", 0f, 0f, 1f, 1f); val.anchorMin = Vector2.zero; val.anchorMax = Vector2.one; Vector2 offsetMin = (val.offsetMax = Vector2.zero); val.offsetMin = offsetMin; if (kind == "button" || kind == "input") { val.offsetMin = new Vector2(-10f, -10f); val.offsetMax = new Vector2(10f, 10f); } Image val2 = ((Component)val).gameObject.AddComponent(); val2.type = (Type)(!(kind == "close")); val2.pixelsPerUnitMultiplier = 4f; ((Graphic)val2).raycastTarget = false; ((Transform)val).SetAsFirstSibling(); control.targetGraphic = (Graphic)(object)val2; control.transition = (Transition)1; ColorBlock colors = default(ColorBlock); ((ColorBlock)(ref colors)).normalColor = Color.white; ((ColorBlock)(ref colors)).highlightedColor = Color.white; ((ColorBlock)(ref colors)).pressedColor = new Color(0.85f, 0.82f, 0.77f); ((ColorBlock)(ref colors)).selectedColor = Color.white; ((ColorBlock)(ref colors)).disabledColor = new Color(0.46f, 0.46f, 0.46f); ((ColorBlock)(ref colors)).colorMultiplier = 1f; ((ColorBlock)(ref colors)).fadeDuration = 0f; control.colors = colors; ((Component)control).gameObject.AddComponent().Initialize(control, val2, kind); } public static Button Tab(Transform p, string text, float x, float y, float w, float h, bool active, Action click) { Button obj = Button(p, text, x, y, w, h, click); Mark((Selectable)(object)obj, active); return obj; } public static Text Label(Transform parent, string value, float x, float y, float w, float h, int size = 18, bool heading = false) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown GameObject obj = GUIManager.Instance.CreateText(value, parent, TopLeft, TopLeft, Vector2.zero, heading ? GUIManager.Instance.NorseBold : GUIManager.Instance.AveriaSerif, size, heading ? new Color(1f, 0.68f, 0.24f) : new Color(0.91f, 0.79f, 0.56f), true, Color.black, w, h, false); Place((RectTransform)obj.transform, x, y, w, h); Text component = obj.GetComponent(); ((Graphic)component).raycastTarget = false; component.supportRichText = false; return component; } public static Button Button(Transform parent, string text, float x, float y, float w, float h, Action action) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_00ec: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GUIManager.Instance.CreateButton(text, parent, TopLeft, TopLeft, Vector2.zero, w, h); Place((RectTransform)obj.transform, x, y, w, h); Button component = obj.GetComponent