Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ValheimMarket v1.1.3
BepInEx/plugins/ValheimMarket/ValheimMarket.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ValheimMarket { internal sealed class MarketClient { private sealed class Pending { internal Guid Id; internal byte[] Request; internal ItemBlob Refund; internal bool RefundOnly; internal float LastSent; } private readonly Dictionary<Guid, Pending> pending = new Dictionary<Guid, Pending>(); private readonly HashSet<Guid> receivedClaims = new HashSet<Guid>(); private string journalPath; private string receiptPath; private bool loaded; private byte[] snapshotRequest; private long snapshotOwner; private float snapshotLastSent; internal MarketSnapshot Snapshot { get; private set; } internal void Reset() { pending.Clear(); receivedClaims.Clear(); Snapshot = null; journalPath = null; receiptPath = null; loaded = false; snapshotRequest = null; } internal void Update() { if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null) { return; } EnsureLoaded(); if (snapshotRequest != null) { MarketUI uI = MarketPlugin.UI; if (uI != null && uI.IsOpen && Time.realtimeSinceStartup - snapshotLastSent > 5f) { MarketTransport.Send(ServerPeer(), snapshotRequest); snapshotLastSent = Time.realtimeSinceStartup; MarketPlugin.UI.SetMessage("Retrying market..."); } } foreach (Pending item in pending.Values.ToList()) { if (item.RefundOnly) { TryRefund(item); } else if (Time.realtimeSinceStartup - item.LastSent > 8f) { MarketTransport.Send(ServerPeer(), item.Request); item.LastSent = Time.realtimeSinceStartup; } } } private static long ServerPeer() { if (ZNet.instance.IsServer()) { return ZNet.GetUID(); } List<ZNetPeer> peers = ZNet.instance.GetPeers(); if (peers.Count != 0) { return peers[0].m_uid; } return 0L; } private void EnsureLoaded() { if (loaded) { return; } string text = Path.Combine(Paths.ConfigPath, "ValheimMarket"); Directory.CreateDirectory(text); string text2 = ZNet.instance.GetWorldUID() + "_" + Player.m_localPlayer.GetPlayerID(); journalPath = Path.Combine(text, text2 + ".pending"); receiptPath = Path.Combine(text, text2 + ".receipts"); try { if (File.Exists(journalPath)) { using FileStream input = File.OpenRead(journalPath); using BinaryReader binaryReader = new BinaryReader(input); int num = binaryReader.ReadInt32(); if (num < 0 || num > 1000) { throw new InvalidDataException("Invalid pending actions"); } for (int i = 0; i < num; i++) { Pending pending = new Pending { Id = MarketCodec.ReadGuid(binaryReader), RefundOnly = binaryReader.ReadBoolean(), Refund = (binaryReader.ReadBoolean() ? ItemBlob.Read(binaryReader) : null), Request = binaryReader.ReadBytes(binaryReader.ReadInt32()), LastSent = -100f }; this.pending[pending.Id] = pending; } } if (File.Exists(receiptPath)) { using FileStream input2 = File.OpenRead(receiptPath); using BinaryReader binaryReader2 = new BinaryReader(input2); int num2 = binaryReader2.ReadInt32(); if (num2 < 0 || num2 > 100000) { throw new InvalidDataException("Invalid receipts"); } for (int j = 0; j < num2; j++) { receivedClaims.Add(MarketCodec.ReadGuid(binaryReader2)); } } } catch (Exception ex) { MarketPlugin.Instance.Log.LogError((object)("Market client journal could not be read: " + ex)); } loaded = true; } private void SavePending() { if (journalPath == null) { return; } using (FileStream fileStream = new FileStream(journalPath + ".tmp", FileMode.Create, FileAccess.Write)) { using BinaryWriter binaryWriter = new BinaryWriter(fileStream); binaryWriter.Write(pending.Count); foreach (Pending value in pending.Values) { MarketCodec.WriteGuid(binaryWriter, value.Id); binaryWriter.Write(value.RefundOnly); binaryWriter.Write(value.Refund != null); value.Refund?.Write(binaryWriter); binaryWriter.Write(value.Request.Length); binaryWriter.Write(value.Request); } binaryWriter.Flush(); fileStream.Flush(flushToDisk: true); } AtomicSwap(journalPath); } private void SaveReceipts() { if (receiptPath == null) { return; } using (FileStream fileStream = new FileStream(receiptPath + ".tmp", FileMode.Create, FileAccess.Write)) { using BinaryWriter binaryWriter = new BinaryWriter(fileStream); binaryWriter.Write(receivedClaims.Count); foreach (Guid receivedClaim in receivedClaims) { MarketCodec.WriteGuid(binaryWriter, receivedClaim); } binaryWriter.Flush(); fileStream.Flush(flushToDisk: true); } AtomicSwap(receiptPath); } private static void AtomicSwap(string path) { string sourceFileName = path + ".tmp"; if (!File.Exists(path)) { File.Move(sourceFileName, path); return; } try { File.Replace(sourceFileName, path, path + ".bak"); } catch (PlatformNotSupportedException) { File.Copy(path, path + ".bak", overwrite: true); File.Delete(path); File.Move(sourceFileName, path); } } internal void RequestSnapshot(ZDOID stall, long shopOwner) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) snapshotOwner = shopOwner; snapshotRequest = BuildRequest(Guid.NewGuid(), MarketAction.Snapshot, stall, shopOwner, Guid.Empty, 0, null); snapshotLastSent = Time.realtimeSinceStartup; MarketTransport.Send(ServerPeer(), snapshotRequest); } internal void Submit(MarketAction action, ZDOID stall, long shopOwner, Guid entityId, int number = 0, ItemData inventoryItem = null, int quantity = 0) { //IL_0105: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } EnsureLoaded(); ItemBlob itemBlob = null; ItemBlob itemBlob2 = null; Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory(); switch (action) { case MarketAction.CreateListing: case MarketAction.MakeOffer: case MarketAction.SellToNpc: if (inventoryItem == null || inventoryItem.m_equipped || quantity < 1 || quantity > inventoryItem.m_stack) { throw new InvalidDataException("Select an unequipped item and valid quantity"); } itemBlob = ItemBlob.FromItem(inventoryItem, quantity); itemBlob.Validate(); itemBlob2 = itemBlob; break; case MarketAction.Buy: { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Coins"); ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null) { throw new InvalidDataException("Coins are unavailable"); } if (number < 1 || inventory.CountItems(val.m_itemData.m_shared.m_name, -1, false) < number) { throw new InvalidDataException("Not enough coins"); } ItemData obj = val.m_itemData.Clone(); obj.m_dropPrefab = ((Component)val).gameObject; itemBlob2 = ItemBlob.FromItem(obj, 1); itemBlob2.Stack = number; break; } } Guid guid = Guid.NewGuid(); byte[] array = BuildRequest(guid, action, stall, shopOwner, entityId, number, itemBlob); if (itemBlob2 != null) { if (action == MarketAction.Buy) { ItemDrop component = ObjectDB.instance.GetItemPrefab("Coins").GetComponent<ItemDrop>(); inventory.RemoveItem(component.m_itemData.m_shared.m_name, number, -1, false); } else if (!inventory.RemoveItem(inventoryItem, quantity)) { throw new InvalidDataException("Item changed before deposit"); } pending[guid] = new Pending { Id = guid, Request = array, Refund = itemBlob2, LastSent = Time.realtimeSinceStartup }; SavePending(); Game.instance.SavePlayerProfile(false, false); } MarketTransport.Send(ServerPeer(), array); } private static byte[] BuildRequest(Guid id, MarketAction action, ZDOID stall, long shopOwner, Guid entityId, int number, ItemBlob item) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) return MarketCodec.Encode(delegate(BinaryWriter w) { w.Write((byte)1); w.Write(3); MarketCodec.WriteGuid(w, id); w.Write((byte)action); w.Write(((ZDOID)(ref stall)).UserID); w.Write(((ZDOID)(ref stall)).ID); w.Write(shopOwner); MarketCodec.WriteGuid(w, entityId); w.Write(number); w.Write(item != null); item?.Write(w); }); } internal void Handle(long sender, byte[] data) { if (sender != ServerPeer()) { return; } try { using MemoryStream input = new MemoryStream(data); using BinaryReader binaryReader = new BinaryReader(input); WireKind wireKind = (WireKind)binaryReader.ReadByte(); if (binaryReader.ReadInt32() != 3) { MarketPlugin.UI?.SetMessage("Incompatible market mod version"); return; } switch (wireKind) { case WireKind.Snapshot: Snapshot = MarketSnapshot.Read(binaryReader); if (Snapshot.ShopOwner == snapshotOwner) { snapshotRequest = null; } MarketPlugin.UI?.ShowSnapshot(Snapshot); break; case WireKind.Result: { Guid key = MarketCodec.ReadGuid(binaryReader); bool flag = binaryReader.ReadBoolean(); string message = binaryReader.ReadString(); if (pending.TryGetValue(key, out var value)) { if (flag) { pending.Remove(key); } else { value.RefundOnly = true; TryRefund(value); } SavePending(); } MarketPlugin.UI?.SetMessage(message); break; } case WireKind.ClaimGrant: { Guid claimId = MarketCodec.ReadGuid(binaryReader); ItemBlob itemBlob = ItemBlob.Read(binaryReader); EnsureLoaded(); if (!receivedClaims.Contains(claimId)) { Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory(); ItemData val = itemBlob.ToItem(); if (!inventory.CanAddItem(val, -1) || !inventory.AddItem(val)) { MarketPlugin.UI?.SetMessage("Inventory is full"); break; } receivedClaims.Add(claimId); Game.instance.SavePlayerProfile(false, false); SaveReceipts(); } MarketTransport.Send(ServerPeer(), MarketCodec.Encode(delegate(BinaryWriter w) { w.Write((byte)5); w.Write(3); MarketCodec.WriteGuid(w, claimId); })); break; } } } catch (Exception ex) { MarketPlugin.Instance.Log.LogError((object)("Market response failed: " + ex)); MarketPlugin.UI?.SetMessage(ex.Message); } } private void TryRefund(Pending p) { if (p.Refund == null) { pending.Remove(p.Id); SavePending(); return; } Player localPlayer = Player.m_localPlayer; Inventory val = ((localPlayer != null) ? ((Humanoid)localPlayer).GetInventory() : null); if (val == null) { return; } try { while (p.Refund.Stack > 0) { int num = Math.Min(ObjectDB.instance.GetItemPrefab(p.Refund.Prefab).GetComponent<ItemDrop>().m_itemData.m_shared.m_maxStackSize, p.Refund.Stack); ItemData val2 = p.Refund.ToItem(); val2.m_stack = num; if (!val.CanAddItem(val2, -1) || !val.AddItem(val2)) { break; } p.Refund.Stack -= num; Game.instance.SavePlayerProfile(false, false); SavePending(); } if (p.Refund.Stack == 0) { pending.Remove(p.Id); SavePending(); } } catch (Exception ex) { MarketPlugin.Instance.Log.LogError((object)("Refund waiting: " + ex.Message)); } } } internal enum MarketAction : byte { Snapshot = 1, CreateListing, Buy, MakeOffer, AcceptOffer, RejectOffer, CancelListing, CancelOffer, Collect, SellToNpc } internal sealed class ItemBlob { internal string Prefab; internal int Stack; internal float Durability; internal int Quality; internal int Variant; internal int WorldLevel; internal long CrafterId; internal string CrafterName; internal bool PickedUp; internal bool Cheated; internal Dictionary<string, string> CustomData = new Dictionary<string, string>(); internal static ItemBlob FromItem(ItemData item, int amount) { if (item == null || (Object)(object)item.m_dropPrefab == (Object)null || amount < 1 || amount > item.m_stack) { throw new InvalidDataException("Invalid inventory item"); } return new ItemBlob { Prefab = Utils.GetPrefabName(item.m_dropPrefab), Stack = amount, Durability = item.m_durability, Quality = item.m_quality, Variant = item.m_variant, WorldLevel = item.m_worldLevel, CrafterId = item.m_crafterID, CrafterName = (item.m_crafterName ?? ""), PickedUp = item.m_pickedUp, Cheated = item.m_cheated, CustomData = new Dictionary<string, string>(item.m_customData) }; } internal ItemData ToItem() { ObjectDB instance = ObjectDB.instance; GameObject val = ((instance != null) ? instance.GetItemPrefab(Prefab) : null); if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<ItemDrop>() == (Object)null) { throw new InvalidDataException("Unavailable item: " + Prefab); } ItemData obj = val.GetComponent<ItemDrop>().m_itemData.Clone(); obj.m_dropPrefab = val; obj.m_stack = Stack; obj.m_durability = Durability; obj.m_quality = Quality; obj.m_variant = Variant; obj.m_worldLevel = WorldLevel; obj.m_crafterID = CrafterId; obj.m_crafterName = CrafterName; obj.m_pickedUp = PickedUp; obj.m_cheated = Cheated; obj.m_customData = new Dictionary<string, string>(CustomData); obj.m_equipped = false; return obj; } internal string DisplayName() { ObjectDB instance = ObjectDB.instance; GameObject val = ((instance != null) ? instance.GetItemPrefab(Prefab) : null); ItemDrop val2 = (((Object)(object)val == (Object)null) ? null : val.GetComponent<ItemDrop>()); if (!((Object)(object)val2 == (Object)null)) { return Localization.instance.Localize(val2.m_itemData.m_shared.m_name); } return Prefab; } internal Sprite Icon() { ObjectDB instance = ObjectDB.instance; GameObject val = ((instance != null) ? instance.GetItemPrefab(Prefab) : null); Sprite[] array = (((Object)(object)val == (Object)null) ? null : val.GetComponent<ItemDrop>())?.m_itemData.m_shared.m_icons; if (array != null && array.Length != 0) { return array[0]; } return null; } internal void Write(BinaryWriter w) { w.Write(Prefab ?? ""); w.Write(Stack); w.Write(Durability); w.Write(Quality); w.Write(Variant); w.Write(WorldLevel); w.Write(CrafterId); w.Write(CrafterName ?? ""); w.Write(PickedUp); w.Write(Cheated); w.Write(CustomData.Count); foreach (KeyValuePair<string, string> customDatum in CustomData) { w.Write(customDatum.Key); w.Write(customDatum.Value); } } internal static ItemBlob Read(BinaryReader r) { ItemBlob itemBlob = new ItemBlob { Prefab = r.ReadString(), Stack = r.ReadInt32(), Durability = r.ReadSingle(), Quality = r.ReadInt32(), Variant = r.ReadInt32(), WorldLevel = r.ReadInt32(), CrafterId = r.ReadInt64(), CrafterName = r.ReadString(), PickedUp = r.ReadBoolean(), Cheated = r.ReadBoolean() }; int num = r.ReadInt32(); if (num < 0 || num > 256) { throw new InvalidDataException("Invalid item data"); } for (int i = 0; i < num; i++) { itemBlob.CustomData.Add(r.ReadString(), r.ReadString()); } return itemBlob; } internal void Validate() { ObjectDB instance = ObjectDB.instance; GameObject val = ((instance != null) ? instance.GetItemPrefab(Prefab) : null); ItemDrop val2 = (((Object)(object)val == (Object)null) ? null : val.GetComponent<ItemDrop>()); if ((Object)(object)val2 == (Object)null || Stack < 1 || Stack > val2.m_itemData.m_shared.m_maxStackSize || Quality < 1 || Quality > val2.m_itemData.m_shared.m_maxQuality || CustomData.Sum((KeyValuePair<string, string> x) => x.Key.Length + x.Value.Length) > 4096) { throw new InvalidDataException("Unsupported item or stack"); } } } internal sealed class Listing { internal Guid Id; internal long Seller; internal string SellerName; internal ItemBlob Item; internal int GoldPrice; internal bool Active = true; internal void Write(BinaryWriter w) { MarketCodec.WriteGuid(w, Id); w.Write(Seller); w.Write(SellerName ?? ""); Item.Write(w); w.Write(GoldPrice); w.Write(Active); } internal static Listing Read(BinaryReader r) { return new Listing { Id = MarketCodec.ReadGuid(r), Seller = r.ReadInt64(), SellerName = r.ReadString(), Item = ItemBlob.Read(r), GoldPrice = r.ReadInt32(), Active = r.ReadBoolean() }; } } internal sealed class Offer { internal Guid Id; internal Guid ListingId; internal long Seller; internal long Buyer; internal string BuyerName; internal ItemBlob Item; internal bool Active = true; internal void Write(BinaryWriter w) { MarketCodec.WriteGuid(w, Id); MarketCodec.WriteGuid(w, ListingId); w.Write(Seller); w.Write(Buyer); w.Write(BuyerName ?? ""); Item.Write(w); w.Write(Active); } internal static Offer Read(BinaryReader r) { return new Offer { Id = MarketCodec.ReadGuid(r), ListingId = MarketCodec.ReadGuid(r), Seller = r.ReadInt64(), Buyer = r.ReadInt64(), BuyerName = r.ReadString(), Item = ItemBlob.Read(r), Active = r.ReadBoolean() }; } } internal sealed class Claim { internal Guid Id; internal long ShopOwner; internal long Recipient; internal ItemBlob Item; internal bool Collected; internal void Write(BinaryWriter w) { MarketCodec.WriteGuid(w, Id); w.Write(ShopOwner); w.Write(Recipient); Item.Write(w); w.Write(Collected); } internal static Claim Read(BinaryReader r) { return new Claim { Id = MarketCodec.ReadGuid(r), ShopOwner = r.ReadInt64(), Recipient = r.ReadInt64(), Item = ItemBlob.Read(r), Collected = r.ReadBoolean() }; } } internal sealed class ShopSummary { internal long Owner; internal string Name; internal int Listings; internal Vector3 NearestStall; internal void Write(BinaryWriter w) { w.Write(Owner); w.Write(Name ?? ""); w.Write(Listings); w.Write(NearestStall.x); w.Write(NearestStall.y); w.Write(NearestStall.z); } internal static ShopSummary Read(BinaryReader r) { //IL_003c: 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) return new ShopSummary { Owner = r.ReadInt64(), Name = r.ReadString(), Listings = r.ReadInt32(), NearestStall = new Vector3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()) }; } } internal sealed class MarketSnapshot { internal long ShopOwner; internal bool NpcEnabled; internal bool NpcHereAlive; internal bool NpcHostileHere; internal float NpcRespawnDays; internal List<ShopSummary> Shops = new List<ShopSummary>(); internal List<Listing> Listings = new List<Listing>(); internal List<Offer> Offers = new List<Offer>(); internal List<Claim> Claims = new List<Claim>(); internal void Write(BinaryWriter w) { w.Write(ShopOwner); w.Write(NpcEnabled); w.Write(NpcHereAlive); w.Write(NpcHostileHere); w.Write(NpcRespawnDays); MarketCodec.WriteList(w, Shops, delegate(BinaryWriter x, ShopSummary s) { s.Write(x); }); MarketCodec.WriteList(w, Listings, delegate(BinaryWriter x, Listing s) { s.Write(x); }); MarketCodec.WriteList(w, Offers, delegate(BinaryWriter x, Offer s) { s.Write(x); }); MarketCodec.WriteList(w, Claims, delegate(BinaryWriter x, Claim s) { s.Write(x); }); } internal static MarketSnapshot Read(BinaryReader r) { return new MarketSnapshot { ShopOwner = r.ReadInt64(), NpcEnabled = r.ReadBoolean(), NpcHereAlive = r.ReadBoolean(), NpcHostileHere = r.ReadBoolean(), NpcRespawnDays = r.ReadSingle(), Shops = MarketCodec.ReadList(r, ShopSummary.Read), Listings = MarketCodec.ReadList(r, Listing.Read), Offers = MarketCodec.ReadList(r, Offer.Read), Claims = MarketCodec.ReadList(r, Claim.Read) }; } } internal static class MarketCodec { internal const int Protocol = 3; internal static void WriteGuid(BinaryWriter w, Guid id) { w.Write(id.ToByteArray()); } internal static Guid ReadGuid(BinaryReader r) { byte[] array = r.ReadBytes(16); if (array.Length != 16) { throw new EndOfStreamException(); } return new Guid(array); } internal static void WriteList<T>(BinaryWriter w, List<T> list, Action<BinaryWriter, T> write) { w.Write(list.Count); foreach (T item in list) { write(w, item); } } internal static List<T> ReadList<T>(BinaryReader r, Func<BinaryReader, T> read) { int num = r.ReadInt32(); if (num < 0 || num > 10000) { throw new InvalidDataException("Invalid market list"); } List<T> list = new List<T>(num); for (int i = 0; i < num; i++) { list.Add(read(r)); } return list; } internal static byte[] Encode(Action<BinaryWriter> write) { using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); write(binaryWriter); binaryWriter.Flush(); return memoryStream.ToArray(); } internal static T Decode<T>(byte[] bytes, Func<BinaryReader, T> read) { using MemoryStream input = new MemoryStream(bytes); using BinaryReader arg = new BinaryReader(input); return read(arg); } } internal enum WireKind : byte { Request = 1, Result, Snapshot, ClaimGrant, ClaimAck } internal static class MarketTransport { private sealed class Assembly { internal DateTime Created = DateTime.UtcNow; internal byte[][] Parts; internal int Count; } private const string Rpc = "VM_MarketChunk_1"; private const int ChunkSize = 3500; private static readonly Dictionary<string, Assembly> incoming = new Dictionary<string, Assembly>(); internal static void Register() { incoming.Clear(); ZRoutedRpc.instance.Register<ZPackage>("VM_MarketChunk_1", (Action<long, ZPackage>)Receive); } internal static void Send(long peer, byte[] data) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown if (data.Length > 1048576) { throw new InvalidDataException("Market message is too large"); } string text = Guid.NewGuid().ToString("N"); int num = Math.Max(1, (data.Length + 3500 - 1) / 3500); for (int i = 0; i < num; i++) { int num2 = Math.Min(3500, data.Length - i * 3500); byte[] array = new byte[num2]; Buffer.BlockCopy(data, i * 3500, array, 0, num2); ZPackage val = new ZPackage(); val.Write(text); val.Write(i); val.Write(num); val.Write(array); ZRoutedRpc.instance.InvokeRoutedRPC(peer, "VM_MarketChunk_1", new object[1] { val }); } } private static void Receive(long sender, ZPackage pkg) { try { string text = pkg.ReadString(); int num = pkg.ReadInt(); int num2 = pkg.ReadInt(); byte[] array = pkg.ReadByteArray(); if (text.Length != 32 || num2 < 1 || num2 > 300 || num < 0 || num >= num2 || array.Length > 3500) { return; } string key = sender + ":" + text; if (!incoming.TryGetValue(key, out var value)) { Dictionary<string, Assembly> dictionary = incoming; Assembly obj = new Assembly { Parts = new byte[num2][] }; value = obj; dictionary[key] = obj; } if (value.Parts.Length != num2) { incoming.Remove(key); return; } if (value.Parts[num] == null) { value.Parts[num] = array; value.Count++; } if (value.Count != num2) { return; } incoming.Remove(key); using (MemoryStream memoryStream = new MemoryStream()) { byte[][] parts = value.Parts; foreach (byte[] array2 in parts) { memoryStream.Write(array2, 0, array2.Length); } byte[] array3 = memoryStream.ToArray(); if (array3.Length > 1048576) { return; } WireKind wireKind = (WireKind)((array3.Length != 0) ? array3[0] : 0); if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && (wireKind == WireKind.Request || wireKind == WireKind.ClaimAck)) { MarketPlugin.Server?.Handle(sender, array3); } else { MarketPlugin.Client?.Handle(sender, array3); } } foreach (string item in (from x in incoming where (DateTime.UtcNow - x.Value.Created).TotalSeconds > 30.0 select x.Key).ToList()) { incoming.Remove(item); } } catch (Exception ex) { MarketPlugin.Instance.Log.LogWarning((object)("Invalid market packet: " + ex.Message)); } } } internal sealed class MarketServer { private readonly MarketStore store; private readonly long worldId; private bool failed; private readonly Dictionary<Guid, long> claimGrants = new Dictionary<Guid, long>(); internal MarketServer(long worldId) { this.worldId = worldId; try { store = MarketStore.Open(worldId); } catch (Exception ex) { MarketPlugin.Instance.Log.LogError((object)("Market save could not be loaded: " + ex)); } } internal void Handle(long sender, byte[] data) { //IL_0171: Unknown result type (might be due to invalid IL or missing references) Guid requestId = Guid.Empty; bool flag = false; try { using MemoryStream input = new MemoryStream(data); using BinaryReader binaryReader = new BinaryReader(input); WireKind wireKind = (WireKind)binaryReader.ReadByte(); int num = binaryReader.ReadInt32(); if (wireKind == WireKind.Request) { requestId = MarketCodec.ReadGuid(binaryReader); } if (num != 3) { throw new InvalidDataException("Incompatible market mod version"); } if (store == null || failed) { if (wireKind == WireKind.Request) { SendResult(sender, requestId, ok: false, "Market save is unavailable"); } return; } switch (wireKind) { case WireKind.ClaimAck: { Guid guid = MarketCodec.ReadGuid(binaryReader); long num7 = MarketPlugin.PlayerIdForSender(sender); if (claimGrants.TryGetValue(guid, out var value) && value == sender && num7 != 0L) { long num8 = store.FindClaim(guid)?.ShopOwner ?? 0; store.MarkCollected(guid, num7); flag = true; claimGrants.Remove(guid); SendResult(sender, guid, ok: true, "Collected"); if (num8 != 0L) { SendSnapshot(sender, num8); } } break; } default: throw new InvalidDataException("Unknown market message"); case WireKind.Request: { MarketAction marketAction = (MarketAction)binaryReader.ReadByte(); ZDOID id = default(ZDOID); ((ZDOID)(ref id))..ctor(binaryReader.ReadInt64(), binaryReader.ReadUInt32()); long num2 = binaryReader.ReadInt64(); Guid entityId = MarketCodec.ReadGuid(binaryReader); int num3 = binaryReader.ReadInt32(); ItemBlob itemBlob = (binaryReader.ReadBoolean() ? ItemBlob.Read(binaryReader) : null); long num4 = MarketPlugin.PlayerIdForSender(sender); if (num4 == 0L) { throw new InvalidDataException("Player is not ready"); } ZDO val = RequireNearbyStall(sender, id); bool flag2 = val.GetPrefab() == StringExtensionMethods.GetStableHashCode("VM_NpcStall"); long num5 = (flag2 ? WorldNpcManager.ShopFor(val) : val.GetLong(ZDOVars.s_creator, 0L)); if (flag2 && num5 == 0L) { throw new InvalidDataException("This trader is still preparing the stall"); } if (flag2 && !MarketPlugin.EnableNpcMerchant.Value && marketAction != MarketAction.Snapshot && marketAction != MarketAction.Collect) { throw new InvalidDataException("NPC merchant is disabled on this server"); } if (marketAction == MarketAction.Snapshot) { long num6 = ((num2 == 0L) ? num5 : num2); if (num6 == num5) { GrantClaims(sender, num5, num4); } SendSnapshot(sender, num6); break; } if (store.WasCompleted(requestId)) { flag = true; SendResult(sender, requestId, ok: true, "Already processed"); GrantClaims(sender, num5, num4); SendSnapshot(sender, num5); break; } if (flag2 && marketAction != MarketAction.Collect && !WorldNpcManager.IsAliveAt(val)) { throw new InvalidDataException("The trader will return after two in-game days"); } if (flag2 && marketAction != MarketAction.Collect && WorldNpcManager.IsHostileAt(val)) { throw new InvalidDataException("Edda refuses to trade while hostile"); } string message; switch (marketAction) { case MarketAction.SellToNpc: if (!flag2 || itemBlob == null) { throw new InvalidDataException("Visit Edda's stall with goods to sell"); } message = store.SellToNpc(requestId, num5, num4, itemBlob); break; case MarketAction.CreateListing: if (flag2 || num5 != num4) { throw new InvalidDataException("Only the shop owner may post here"); } if (itemBlob == null) { throw new InvalidDataException("Select an item"); } message = store.CreateListing(requestId, num4, MarketPlugin.PlayerNameForSender(sender), itemBlob, num3); break; case MarketAction.Buy: if (flag2) { message = store.BuyFromNpc(requestId, num4, NpcMerchant.Stock(worldId, WorldNpcManager.GameDay, num5).FirstOrDefault((Listing x) => x.Id == entityId), num3); } else { RequireListingShop(entityId, num5); message = store.Buy(requestId, entityId, num4, num3); } break; case MarketAction.MakeOffer: if (flag2) { throw new InvalidDataException("Edda does not barter"); } RequireListingShop(entityId, num5); if (itemBlob == null) { throw new InvalidDataException("Select an item"); } message = store.MakeOffer(requestId, entityId, num4, MarketPlugin.PlayerNameForSender(sender), itemBlob); break; case MarketAction.AcceptOffer: RequireOfferShop(entityId, num5); message = store.AcceptOffer(requestId, entityId, num4); break; case MarketAction.RejectOffer: RequireOfferShop(entityId, num5); message = store.RejectOffer(requestId, entityId, num4); break; case MarketAction.CancelListing: RequireListingShop(entityId, num5); message = store.CancelListing(requestId, entityId, num4); break; case MarketAction.CancelOffer: RequireOfferShop(entityId, num5); message = store.CancelOffer(requestId, entityId, num4); break; case MarketAction.Collect: { Claim claim = store.FindClaim(entityId); if (claim == null || claim.ShopOwner != num5 || claim.Recipient != num4) { throw new InvalidDataException("This collection is unavailable"); } SendClaimGrant(sender, claim); return; } default: throw new InvalidDataException("Unknown market action"); } flag = true; SendResult(sender, requestId, ok: true, message); GrantClaims(sender, num5, num4); SendSnapshot(sender, num5); break; } } } catch (Exception ex) { if (!flag && (ex is IOException || ex is UnauthorizedAccessException)) { failed = true; } MarketPlugin.Instance.Log.LogWarning((object)("Market request failed: " + ex.Message)); if (!flag) { SendResult(sender, requestId, ok: false, ex.Message); } } } private void RequireListingShop(Guid id, long owner) { Listing listing = store.FindListing(id); if (listing == null || listing.Seller != owner) { throw new InvalidDataException("Visit the selling stall"); } } private void RequireOfferShop(Guid id, long owner) { Offer offer = store.FindOffer(id); if (offer == null || offer.Seller != owner) { throw new InvalidDataException("Visit the selling stall"); } } private ZDO RequireNearbyStall(long sender, ZDOID id) { //IL_000c: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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) //IL_00af: Unknown result type (might be due to invalid IL or missing references) ZDOMan instance = ZDOMan.instance; ZDO val = ((instance != null) ? instance.GetZDO(id) : null); if (val == null || !val.IsValid() || (val.GetPrefab() != StringExtensionMethods.GetStableHashCode("VM_MarketStall") && val.GetPrefab() != StringExtensionMethods.GetStableHashCode("VM_NpcStall"))) { throw new InvalidDataException("Market stall is unavailable"); } Vector3 val2; if (sender == ZNet.GetUID()) { if ((Object)(object)Player.m_localPlayer == (Object)null) { throw new InvalidDataException("Player is not ready"); } val2 = ((Component)Player.m_localPlayer).transform.position; } else { ZNetPeer peer = ZNet.instance.GetPeer(sender); if (peer == null || ((ZDOID)(ref peer.m_characterID)).IsNone()) { throw new InvalidDataException("Player is not ready"); } val2 = peer.m_refPos; } if (Vector3.Distance(val2, val.GetPosition()) > 8f) { throw new InvalidDataException("Move closer to the market stall"); } return val; } private List<ZDO> AllStalls() { List<ZDO> list = WorldNpcManager.All("VM_MarketStall"); list.AddRange(WorldNpcManager.All("VM_NpcStall")); return list; } private void GrantClaims(long peer, long shopOwner, long recipient) { foreach (Claim item in store.Claims.Where((Claim x) => !x.Collected && x.ShopOwner == shopOwner && x.Recipient == recipient).ToList()) { SendClaimGrant(peer, item); } } private void SendClaimGrant(long peer, Claim claim) { claimGrants[claim.Id] = peer; MarketTransport.Send(peer, MarketCodec.Encode(delegate(BinaryWriter w) { w.Write((byte)4); w.Write(3); MarketCodec.WriteGuid(w, claim.Id); claim.Item.Write(w); })); } private void SendSnapshot(long peer, long selectedOwner) { //IL_004c: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_049e: Unknown result type (might be due to invalid IL or missing references) //IL_04a3: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) List<ZDO> source = AllStalls(); long actor = MarketPlugin.PlayerIdForSender(peer); Vector3 position = ((peer == ZNet.GetUID() && (Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).transform.position : (ZNet.instance.GetPeer(peer)?.m_refPos ?? Vector3.zero)); MarketSnapshot snapshot = new MarketSnapshot { ShopOwner = selectedOwner, NpcEnabled = MarketPlugin.EnableNpcMerchant.Value }; List<ZDO> list = source.Where((ZDO x) => x.GetPrefab() == StringExtensionMethods.GetStableHashCode("VM_NpcStall")).ToList(); HashSet<string> livingSites = new HashSet<string>(from x in WorldNpcManager.All("VM_NpcTrader") where x.GetFloat(ZDOVars.s_health, 1f) > 0f select x.GetString("vm_npc_site", "")); if (list.Count > 0) { foreach (IGrouping<long, ZDO> item in from x in list.GroupBy(WorldNpcManager.ShopFor) where NpcMerchant.IsOwner(x.Key) select x) { ZDO val = (from x in item orderby (!livingSites.Contains(x.GetString("vm_npc_site", ""))) ? 1 : 0, Vector3.Distance(position, x.GetPosition()) select x).First(); bool flag = snapshot.NpcEnabled && item.Any((ZDO x) => livingSites.Contains(x.GetString("vm_npc_site", ""))); snapshot.Shops.Add(new ShopSummary { Owner = item.Key, Name = NpcMerchant.ShopName(item.Key), Listings = (flag ? NpcMerchant.Stock(worldId, WorldNpcManager.GameDay, item.Key).Count : 0), NearestStall = val.GetPosition() }); } ZDO val2 = (from x in list where WorldNpcManager.ShopFor(x) == selectedOwner && Vector3.Distance(position, x.GetPosition()) < 9f orderby Vector3.Distance(position, x.GetPosition()) select x).FirstOrDefault(); if (val2 != null) { snapshot.NpcHereAlive = snapshot.NpcEnabled && livingSites.Contains(val2.GetString("vm_npc_site", "")); snapshot.NpcHostileHere = snapshot.NpcHereAlive && WorldNpcManager.IsHostileAt(val2); snapshot.NpcRespawnDays = WorldNpcManager.DaysUntilReturn(val2); } } foreach (IGrouping<long, ZDO> group in from x in source where x.GetPrefab() == StringExtensionMethods.GetStableHashCode("VM_MarketStall") group x by x.GetLong(ZDOVars.s_creator, 0L) into x where x.Key != 0 select x) { ZDO val3 = group.OrderBy((ZDO x) => Vector3.Distance(position, x.GetPosition())).First(); Listing listing = store.Listings.FirstOrDefault((Listing x) => x.Active && x.Seller == group.Key); snapshot.Shops.Add(new ShopSummary { Owner = group.Key, Name = (listing?.SellerName ?? ((group.Key == actor) ? "Your shop" : ("Viking " + group.Key))), Listings = store.Listings.Count((Listing x) => x.Active && x.Seller == group.Key), NearestStall = val3.GetPosition() }); } if (snapshot.Shops.Any((ShopSummary x) => x.Owner == selectedOwner)) { if (NpcMerchant.IsOwner(selectedOwner)) { if (snapshot.NpcEnabled && list.Any((ZDO x) => WorldNpcManager.ShopFor(x) == selectedOwner && livingSites.Contains(x.GetString("vm_npc_site", "")))) { snapshot.Listings.AddRange(NpcMerchant.Stock(worldId, WorldNpcManager.GameDay, selectedOwner)); } } else { snapshot.Listings.AddRange(store.Listings.Where((Listing x) => x.Active && x.Seller == selectedOwner)); } snapshot.Offers.AddRange(store.Offers.Where((Offer x) => x.Active && x.Seller == selectedOwner && (x.Buyer == actor || x.Seller == actor))); } snapshot.Claims.AddRange(store.Claims.Where((Claim x) => !x.Collected && x.ShopOwner == selectedOwner && x.Recipient == actor)); MarketTransport.Send(peer, MarketCodec.Encode(delegate(BinaryWriter w) { w.Write((byte)3); w.Write(3); snapshot.Write(w); })); } private static void SendResult(long peer, Guid requestId, bool ok, string message) { MarketTransport.Send(peer, MarketCodec.Encode(delegate(BinaryWriter w) { w.Write((byte)2); w.Write(3); MarketCodec.WriteGuid(w, requestId); w.Write(ok); w.Write(message ?? ""); })); } } [BepInPlugin("dev.monokaijs.valheimmarket", "Valheim Marketplace", "1.1.3")] public sealed class MarketPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ScenePatch { private static void Prefix(ZNetScene __instance) { RegisterStall(__instance); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDbPatch { private static void Postfix() { TryAddToHammer(); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private static class CopyDbPatch { private static void Postfix() { TryAddToHammer(); } } [HarmonyPatch(typeof(ZNet), "Awake")] private static class NetworkPatch { private static void Postfix(ZNet __instance) { MarketTransport.Register(); Server = (__instance.IsServer() ? new MarketServer(__instance.GetWorldUID()) : null); NpcManager = (__instance.IsServer() ? new WorldNpcManager(__instance.GetWorldUID()) : null); Client.Reset(); } } [HarmonyPatch(typeof(ZNet), "Shutdown")] private static class ShutdownPatch { private static void Prefix() { UI?.Close(); Server = null; NpcManager = null; Client?.Reset(); } } [HarmonyPatch(typeof(Player), "TakeInput")] private static class InputPatch { private static void Postfix(ref bool __result) { if (UI != null && UI.BlocksGameInput) { __result = false; } } } [HarmonyPatch(typeof(PlayerController), "TakeInput")] private static class ControllerInputPatch { private static void Postfix(ref bool __result) { if (UI != null && UI.BlocksGameInput) { __result = false; } } } [HarmonyPatch(typeof(Player), "PlayerAttackInput")] private static class AttackInputPatch { private static bool Prefix() { if (UI != null) { return !UI.BlocksGameInput; } return true; } } [HarmonyPatch(typeof(GameCamera), "UpdateCamera")] private static class CameraInputPatch { private static bool Prefix() { if (UI != null) { return !UI.IsOpen; } return true; } } [HarmonyPatch(typeof(Minimap), "AddPin")] private static class NpcPinPatch { private static void Postfix(Minimap __instance, PinData __result) { NpcMapPins.Style(__instance, __result); } } [HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")] private static class CursorPatch { private static bool Prefix() { if (UI == null || !UI.IsOpen) { return true; } ZCursor.LockState = (CursorLockMode)0; ZCursor.Show(); return false; } } [HarmonyPatch(typeof(Piece), "CanBeRemoved")] private static class RemovePiecePatch { private static void Postfix(Piece __instance, ref bool __result) { if (!((Object)(object)((Component)__instance).GetComponent<MarketStall>() == (Object)null)) { __result = __result && (Object)(object)Player.m_localPlayer != (Object)null && __instance.GetCreator() == Player.m_localPlayer.GetPlayerID(); } } } [HarmonyPatch(typeof(WearNTear), "RPC_Remove")] private static class RemoteRemovePatch { private static bool Prefix(WearNTear __instance, long sender) { MarketStall component = ((Component)__instance).GetComponent<MarketStall>(); if (!((Object)(object)component == (Object)null)) { if (component.OwnerId != 0L) { return component.OwnerId == PlayerIdForSender(sender); } return false; } return true; } } [HarmonyPatch(typeof(WearNTear), "RPC_Damage")] private static class DamagePatch { private static bool Prefix(WearNTear __instance) { return (Object)(object)((Component)__instance).GetComponent<MarketStall>() == (Object)null; } } [HarmonyPatch(typeof(WearNTear), "UpdateWear")] private static class WearPatch { private static bool Prefix(WearNTear __instance) { return (Object)(object)((Component)__instance).GetComponent<MarketStall>() == (Object)null; } } [HarmonyPatch(typeof(Character), "GetHoverText")] private static class MerchantHoverPatch { private static void Postfix(Character __instance, ref string __result) { MarketNpcCharacter component = ((Component)__instance).GetComponent<MarketNpcCharacter>(); if ((Object)(object)component != (Object)null) { __result = component.HoverText(); } } } internal const string StallPrefab = "VM_MarketStall"; internal const string NpcStallPrefab = "VM_NpcStall"; internal const string NpcCharacterPrefabName = "VM_NpcTrader"; internal static MarketPlugin Instance; internal static GameObject Prefab; internal static GameObject NpcPrefab; internal static GameObject NpcCharacterPrefab; internal static WorldNpcManager NpcManager; internal static ConfigEntry<bool> EnableNpcMerchant; internal static MarketServer Server; internal static MarketClient Client; internal static MarketUI UI; private Harmony harmony; internal ManualLogSource Log => ((BaseUnityPlugin)this).Logger; private void Awake() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown Instance = this; EnableNpcMerchant = ((BaseUnityPlugin)this).Config.Bind<bool>("NPC Merchant", "Enabled", true, "Allow the server to place regional traders and enable their trades. Enabled by default."); Client = new MarketClient(); harmony = new Harmony("dev.monokaijs.valheimmarket"); harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Marketplace loaded without Jotunn"); } private void Update() { Client?.Update(); UI?.Tick(); NpcManager?.Tick(); TryAddToHammer(); } private void OnDestroy() { UI?.Close(); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } Server = null; NpcManager = null; Instance = null; } internal static void RegisterStall(ZNetScene scene) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Expected O, but got Unknown //IL_00fd: 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) if (scene.m_prefabs.Any((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == "VM_MarketStall")) { return; } GameObject val = ((IEnumerable<GameObject>)scene.m_prefabs).FirstOrDefault((Func<GameObject, bool>)((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == "piece_chest_wood")); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogError((object)"Could not find piece_chest_wood to create a market stall"); return; } GameObject val2 = new GameObject("VM_Prefabs"); val2.transform.SetParent(((Component)scene).transform, false); val2.SetActive(false); GameObject val3 = Object.Instantiate<GameObject>(val, val2.transform); ((Object)val3).name = "VM_MarketStall"; val3.SetActive(true); Container[] componentsInChildren = val3.GetComponentsInChildren<Container>(true); for (int num = 0; num < componentsInChildren.Length; num++) { Object.DestroyImmediate((Object)(object)componentsInChildren[num]); } Piece component = val3.GetComponent<Piece>(); component.m_name = "Market Stall"; component.m_description = "Buy, sell, and barter with other Vikings"; component.m_category = (PieceCategory)4; component.m_usage = (UsageTagFlags)1024; component.m_canBeRemoved = true; component.m_icon = LoadStallIcon(); WearNTear component2 = val3.GetComponent<WearNTear>(); if ((Object)(object)component2 != (Object)null) { component2.m_noRoofWear = false; } ZNetView component3 = val3.GetComponent<ZNetView>(); if ((Object)(object)component3 != (Object)null) { component3.m_persistent = true; } GameObject? obj = ((IEnumerable<GameObject>)scene.m_prefabs).FirstOrDefault((Func<GameObject, bool>)((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == "wood_wall")); Material gameWood = ((obj != null) ? obj.GetComponentsInChildren<MeshRenderer>(true).SelectMany((MeshRenderer x) => ((Renderer)x).sharedMaterials).FirstOrDefault((Func<Material, bool>)((Material x) => (Object)(object)x != (Object)null && (Object)(object)x.mainTexture != (Object)null)) : null); MarketStallModel.Build(val3, gameWood); val3.AddComponent<MarketStall>(); scene.m_prefabs.Add(val3); Prefab = val3; GameObject val4 = Object.Instantiate<GameObject>(val3, val2.transform); ((Object)val4).name = "VM_NpcStall"; val4.GetComponent<Piece>().m_name = "Edda's Trading Stall"; val4.GetComponent<Piece>().m_description = "Sell gathered goods for coins and buy rare necessities"; MarketStallModel.BuildNpc(val4); scene.m_prefabs.Add(val4); NpcPrefab = val4; RegisterMerchantCharacter(scene, val2.transform); TryAddToHammer(); } private static Sprite LoadStallIcon() { //IL_0063: 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_0074: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ValheimMarket.StallIcon.rgba"); if (stream == null) { throw new InvalidOperationException("Market stall icon resource is missing"); } byte[] array = new byte[65536]; using (BinaryReader binaryReader = new BinaryReader(stream)) { if (binaryReader.Read(array, 0, array.Length) != array.Length) { throw new InvalidOperationException("Market stall icon resource is incomplete"); } } Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false) { name = "Market stall icon" }; val.LoadRawTextureData(array); val.Apply(false, true); return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); } private static void RegisterMerchantCharacter(ZNetScene scene, Transform holder) { //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: 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_010b: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: 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_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Expected O, but got Unknown GameObject val = new string[6] { "DvergerRogue", "DvergerMage", "DvergerMageFire", "DvergerMageIce", "DvergerMageSupport", "Dverger" }.Select((string name) => ((IEnumerable<GameObject>)scene.m_prefabs).FirstOrDefault((Func<GameObject, bool>)((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == name && (Object)(object)x.GetComponent<Humanoid>() != (Object)null && (Object)(object)x.GetComponent<MonsterAI>() != (Object)null))).FirstOrDefault<GameObject>((Func<GameObject, bool>)((GameObject x) => (Object)(object)x != (Object)null)); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogError((object)"Could not find a Dverger character for the regional trader"); return; } GameObject val2 = Object.Instantiate<GameObject>(val, holder); ((Object)val2).name = "VM_NpcTrader"; val2.SetActive(true); Character component = val2.GetComponent<Character>(); component.m_name = "Edda the Trader"; component.m_faction = (Faction)10; component.m_health = 550f; component.m_group = "VM_NpcTraders"; component.m_boss = false; component.m_defeatSetGlobalKey = ""; component.m_killedForAchievements = (AchievementInclusion)2; component.m_damageModifiers.m_frost = (DamageModifier)3; component.m_damageModifiers.m_poison = (DamageModifier)1; MonsterAI component2 = val2.GetComponent<MonsterAI>(); ((BaseAI)component2).m_aggravatable = true; component2.m_attackPlayerObjects = false; component2.m_enableHuntPlayer = false; ((BaseAI)component2).m_randomMoveRange = 2f; component2.m_maxChaseDistance = 26f; if ((Object)(object)val2.GetComponent<Talker>() == (Object)null) { val2.AddComponent<Talker>(); } val2.AddComponent<MarketNpcCharacter>(); ZNetView component3 = val2.GetComponent<ZNetView>(); if ((Object)(object)component3 != (Object)null) { component3.m_persistent = true; } CharacterDrop obj = val2.GetComponent<CharacterDrop>() ?? val2.AddComponent<CharacterDrop>(); object obj2 = ((IEnumerable<GameObject>)scene.m_prefabs).FirstOrDefault((Func<GameObject, bool>)((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == "Coins")); if (obj2 == null) { ObjectDB instance = ObjectDB.instance; obj2 = ((instance != null) ? instance.GetItemPrefab("Coins") : null); } GameObject val3 = (GameObject)obj2; obj.m_drops = (((Object)(object)val3 == (Object)null) ? new List<Drop>() : new List<Drop> { new Drop { m_prefab = val3, m_amountMin = 15, m_amountMax = 30, m_chance = 1f, m_levelMultiplier = false, m_dontScale = true } }); if ((Object)(object)val3 == (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)"Trader coin drops are unavailable: Coins prefab missing"); } scene.m_prefabs.Add(val2); NpcCharacterPrefab = val2; } internal static void ConfigureMerchantDrops() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown GameObject npcCharacterPrefab = NpcCharacterPrefab; CharacterDrop val = ((npcCharacterPrefab != null) ? npcCharacterPrefab.GetComponent<CharacterDrop>() : null); if (!((Object)(object)val == (Object)null) && val.m_drops.Count == 0) { ObjectDB instance = ObjectDB.instance; GameObject val2 = ((instance != null) ? instance.GetItemPrefab("Coins") : null); if (!((Object)(object)val2 == (Object)null)) { val.m_drops = new List<Drop> { new Drop { m_prefab = val2, m_amountMin = 15, m_amountMax = 30, m_chance = 1f, m_levelMultiplier = false, m_dontScale = true } }; } } } internal static void TryAddToHammer() { if (!((Object)(object)Prefab == (Object)null) && !((Object)(object)ObjectDB.instance == (Object)null)) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hammer"); PieceTable val = (((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_buildPieces); if ((Object)(object)val != (Object)null && !val.m_pieces.Contains(Prefab)) { val.m_pieces.Add(Prefab); } if ((Object)(object)val != (Object)null && (Object)(object)NpcPrefab != (Object)null) { val.m_pieces.Remove(NpcPrefab); } } } internal static long PlayerIdForSender(long sender) { if ((Object)(object)ZNet.instance == (Object)null) { return 0L; } if (sender == ZNet.GetUID()) { if (!((Object)(object)Player.m_localPlayer == (Object)null)) { return Player.m_localPlayer.GetPlayerID(); } return 0L; } return ZNet.instance.GetPeer(sender)?.m_playerID ?? 0; } internal static string PlayerNameForSender(long sender) { if (sender == ZNet.GetUID()) { if (!((Object)(object)Player.m_localPlayer == (Object)null)) { return Player.m_localPlayer.GetPlayerName(); } return "Viking"; } return ZNet.instance.GetPeer(sender)?.m_playerName ?? "Viking"; } } internal sealed class MarketStall : MonoBehaviour, Interactable, Hoverable { private Piece piece; private ZNetView view; private float nextNpcPinCheck; internal long OwnerId { get { if (!((Object)(object)piece == (Object)null)) { return piece.GetCreator(); } return 0L; } } internal bool IsNpc => ((Object)((Component)this).gameObject).name.StartsWith("VM_NpcStall", StringComparison.Ordinal); internal long ShopId { get { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected I4, but got Unknown if (!IsNpc) { return OwnerId; } ZNetView obj = view; int? obj2; if (obj == null) { obj2 = null; } else { ZDO zDO = obj.GetZDO(); obj2 = ((zDO != null) ? new int?(zDO.GetInt("vm_npc_biome", 0)) : ((int?)null)); } int? num = obj2; int num2 = num.GetValueOrDefault(); if (num2 == 0 && WorldGenerator.instance != null) { num2 = (int)WorldGenerator.instance.GetBiome(((Component)this).transform.position); } return NpcMerchant.OwnerForBiome(num2); } } internal ZDOID Id { get { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)view == (Object)null) && view.GetZDO() != null) { return view.GetZDO().m_uid; } return ZDOID.None; } } private void Awake() { piece = ((Component)this).GetComponent<Piece>(); view = ((Component)this).GetComponent<ZNetView>(); } private void Update() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) if (IsNpc && !(Time.unscaledTime < nextNpcPinCheck) && !((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)Minimap.instance == (Object)null)) { nextNpcPinCheck = Time.unscaledTime + 2f; ZNetView obj = view; if (((obj != null) ? obj.GetZDO() : null) != null && !(Utils.DistanceXZ(((Component)Player.m_localPlayer).transform.position, ((Component)this).transform.position) > Mathf.Min(90f, Minimap.instance.m_exploreRadius))) { NpcMapPins.Discover(((Component)this).transform.position, ShopId); } } } public string GetHoverName() { if (!IsNpc) { return "Market Stall"; } return "Edda the Trader"; } public float GetHoverOffset() { return 0f; } public string GetHoverText() { return Localization.instance.Localize((IsNpc ? "Edda the Trader" : "Market Stall") + "\n[<color=yellow><b>$KEY_Use</b></color>] " + (IsNpc ? "Trade with Edda" : "Open market")); } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!hold && !((Object)(object)user != (Object)(object)Player.m_localPlayer)) { ZDOID id = Id; if (!((ZDOID)(ref id)).IsNone()) { if (IsNpc && ShopId == 0L) { ((Character)user).Message((MessageType)2, "The trader is preparing this stall.", 0, (Sprite)null, false); return true; } if (MarketPlugin.UI == null) { MarketPlugin.UI = new MarketUI(); } MarketPlugin.UI.Open(this); return true; } } return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } } internal static class MarketStallModel { private static Shader fallbackShader; internal static void Build(GameObject prefab, Material gameWood) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_03ab: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Unknown result type (might be due to invalid IL or missing references) //IL_04bb: Unknown result type (might be due to invalid IL or missing references) //IL_04e7: Unknown result type (might be due to invalid IL or missing references) //IL_04fb: Unknown result type (might be due to invalid IL or missing references) //IL_0527: Unknown result type (might be due to invalid IL or missing references) //IL_053b: Unknown result type (might be due to invalid IL or missing references) //IL_055d: Unknown result type (might be due to invalid IL or missing references) //IL_0571: Unknown result type (might be due to invalid IL or missing references) //IL_0593: Unknown result type (might be due to invalid IL or missing references) //IL_05a7: Unknown result type (might be due to invalid IL or missing references) //IL_05d8: Unknown result type (might be due to invalid IL or missing references) //IL_05ec: Unknown result type (might be due to invalid IL or missing references) //IL_0623: Unknown result type (might be due to invalid IL or missing references) //IL_0637: Unknown result type (might be due to invalid IL or missing references) //IL_0684: Unknown result type (might be due to invalid IL or missing references) //IL_06a3: Unknown result type (might be due to invalid IL or missing references) //IL_06f0: Unknown result type (might be due to invalid IL or missing references) //IL_0704: Unknown result type (might be due to invalid IL or missing references) //IL_0731: Unknown result type (might be due to invalid IL or missing references) //IL_0745: Unknown result type (might be due to invalid IL or missing references) //IL_0762: Unknown result type (might be due to invalid IL or missing references) //IL_07b2: Unknown result type (might be due to invalid IL or missing references) //IL_07c6: Unknown result type (might be due to invalid IL or missing references) //IL_07f3: Unknown result type (might be due to invalid IL or missing references) //IL_0807: Unknown result type (might be due to invalid IL or missing references) //IL_0829: Unknown result type (might be due to invalid IL or missing references) //IL_083d: Unknown result type (might be due to invalid IL or missing references) //IL_085a: Unknown result type (might be due to invalid IL or missing references) //IL_088b: Unknown result type (might be due to invalid IL or missing references) //IL_089f: Unknown result type (might be due to invalid IL or missing references) //IL_08d0: Unknown result type (might be due to invalid IL or missing references) //IL_08f9: Unknown result type (might be due to invalid IL or missing references) //IL_090d: Unknown result type (might be due to invalid IL or missing references) //IL_092a: Unknown result type (might be due to invalid IL or missing references) //IL_094c: Unknown result type (might be due to invalid IL or missing references) //IL_0960: Unknown result type (might be due to invalid IL or missing references) //IL_0971: Unknown result type (might be due to invalid IL or missing references) //IL_0976: Unknown result type (might be due to invalid IL or missing references) //IL_097d: Unknown result type (might be due to invalid IL or missing references) //IL_098f: Unknown result type (might be due to invalid IL or missing references) //IL_09a5: Unknown result type (might be due to invalid IL or missing references) //IL_09be: Unknown result type (might be due to invalid IL or missing references) //IL_09dd: Unknown result type (might be due to invalid IL or missing references) //IL_09f6: Unknown result type (might be due to invalid IL or missing references) MeshRenderer val = prefab.GetComponentsInChildren<MeshRenderer>(true).FirstOrDefault(); Material val2 = (((Object)(object)gameWood != (Object)null) ? gameWood : (((Object)(object)val == (Object)null) ? null : ((Renderer)val).sharedMaterial)); fallbackShader = (((Object)(object)val2 == (Object)null) ? null : val2.shader); Collider val3 = prefab.GetComponentsInChildren<Collider>(true).FirstOrDefault(); int layer = (((Object)(object)val3 == (Object)null) ? prefab.layer : ((Component)val3).gameObject.layer); MeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<MeshRenderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Renderer)componentsInChildren[i]).enabled = false; } Collider[] componentsInChildren2 = prefab.GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } Material val4 = Wood(val2, new Color(0.49f, 0.34f, 0.22f)); Material val5 = Wood(val2, new Color(0.32f, 0.22f, 0.15f)); Material material = Plain("Stall canvas", new Color(0.66f, 0.48f, 0.29f)); Material val6 = Plain("Stall red canvas", new Color(0.42f, 0.18f, 0.15f)); Material val7 = Plain("Stall rope", new Color(0.65f, 0.55f, 0.37f)); Material material2 = Plain("Stall produce", new Color(0.29f, 0.37f, 0.17f)); Material material3 = Plain("Stall apples", new Color(0.55f, 0.19f, 0.12f)); Material pottery = Plain("Stall pottery", new Color(0.4f, 0.23f, 0.16f)); Material val8 = Plain("Stall linen", new Color(0.61f, 0.54f, 0.4f)); Transform transform = new GameObject("Timber and canvas market stall").transform; transform.SetParent(prefab.transform, false); ((Component)transform).gameObject.layer = prefab.layer; float[] array = new float[2] { -1.55f, 1.55f }; foreach (float num in array) { Block(transform, "Front timber post", new Vector3(num, 1.23f, -0.78f), new Vector3(0.2f, 2.46f, 0.2f), val4); Block(transform, "Back timber post", new Vector3(num, 1.46f, 0.78f), new Vector3(0.2f, 2.92f, 0.2f), val4); Lash(transform, num, -0.78f, 0.68f, val7); Lash(transform, num, -0.78f, 2.28f, val7); Lash(transform, num, 0.78f, 2.67f, val7); } Beam(transform, "Front awning beam", new Vector3(-1.72f, 2.39f, -0.8f), new Vector3(1.72f, 2.39f, -0.8f), 0.14f, 0.14f, val5); Beam(transform, "Back awning beam", new Vector3(-1.7f, 2.96f, 0.78f), new Vector3(1.7f, 2.96f, 0.78f), 0.14f, 0.14f, val5); array = new float[2] { -1.55f, 1.55f }; foreach (float num2 in array) { Beam(transform, "Awning side rail", new Vector3(num2, 2.4f, -0.82f), new Vector3(num2, 2.96f, 0.8f), 0.11f, 0.11f, val4); Beam(transform, "Front diagonal brace", new Vector3(num2, 1.45f, -0.78f), new Vector3(num2 - Mathf.Sign(num2) * 0.52f, 2.34f, -0.78f), 0.11f, 0.11f, val5); } Canopy(transform, "Ochre canvas roof", -0.36f, 0.92f, 2.55f, 3.02f, material); Canopy(transform, "Red canvas roof band", -0.97f, -0.36f, 2.39f, 2.55f, val6); for (int j = 0; j < 7; j++) { Flap(transform, -1.78f + (float)j * 3.56f / 7f, 89f / 175f, val6); } Beam(transform, "Canvas front hem", new Vector3(-1.77f, 2.38f, -0.97f), new Vector3(1.77f, 2.38f, -0.97f), 0.025f, 0.025f, val7); Beam(transform, "Roof stitched seam", new Vector3(0.15f, 2.55f, -0.35f), new Vector3(0.15f, 3.02f, 0.92f), 0.014f, 0.014f, val7); Block(transform, "Rear canvas wall", new Vector3(0f, 1.85f, 0.84f), new Vector3(3.12f, 1.86f, 0.055f), material); Block(transform, "Right canvas side", new Vector3(1.61f, 1.81f, 0.17f), new Vector3(0.055f, 1.75f, 1.2f), material); Block(transform, "Counter top", new Vector3(0f, 0.99f, -0.52f), new Vector3(3.05f, 0.13f, 0.88f), val4); for (int k = 0; k < 8; k++) { Block(transform, "Counter front plank", new Vector3(-1.32f + (float)k * 0.377f, 0.52f, -0.92f), new Vector3(0.35f, 0.72f, 0.09f), (k % 3 == 0) ? val5 : val4); } Beam(transform, "Counter bottom rail", new Vector3(-1.49f, 0.17f, -0.97f), new Vector3(1.49f, 0.17f, -0.97f), 0.1f, 0.12f, val5); array = new float[2] { -1.34f, 1.34f }; foreach (float num3 in array) { Beam(transform, "Counter diagonal", new Vector3(num3, 0.17f, -0.98f), new Vector3(num3 - Mathf.Sign(num3) * 0.56f, 0.89f, -0.98f), 0.09f, 0.09f, val5); } for (int l = 0; l < 2; l++) { float num4 = 1.42f + (float)l * 0.44f; Block(transform, "Merchant shelf", new Vector3(0.83f, num4, 0.44f), new Vector3(1.35f, 0.095f, 0.61f), val4); } Block(transform, "Shelf divider", new Vector3(0.12f, 1.58f, 0.43f), new Vector3(0.11f, 1.28f, 0.68f), val5); Crate(transform, new Vector3(-1.08f, 1.13f, -0.49f), 0.52f, val4, val5); for (int m = 0; m < 5; m++) { Round(transform, "Apple", new Vector3(-1.26f + (float)m * 0.105f, 1.25f + (float)(m % 2) * 0.035f, -0.49f + (float)(m % 2) * 0.1f), new Vector3(0.12f, 0.12f, 0.12f), material3); } Round(transform, "Cabbage", new Vector3(-0.35f, 1.16f, -0.44f), new Vector3(0.29f, 0.24f, 0.29f), material2); Round(transform, "Cabbage", new Vector3(-0.02f, 1.14f, -0.5f), new Vector3(0.25f, 0.22f, 0.25f), material2); Pot(transform, new Vector3(0.63f, 1.09f, -0.5f), pottery); for (int n = 0; n < 3; n++) { Block(transform, "Folded trade cloth", new Vector3(1.15f, 1.12f + (float)n * 0.08f, -0.51f), new Vector3(0.57f, 0.07f, 0.37f), (n == 1) ? val6 : val8); } Crate(transform, new Vector3(1.09f, 1.55f, 0.4f), 0.4f, val4, val5); Round(transform, "Sack of goods", new Vector3(0.52f, 1.58f, 0.42f), new Vector3(0.25f, 0.3f, 0.23f), val8); Pot(transform, new Vector3(0.67f, 1.94f, 0.4f), pottery); Round(transform, "Sack of goods", new Vector3(1.1f, 2.01f, 0.42f), new Vector3(0.25f, 0.28f, 0.23f), val8); GameObject val9 = new GameObject("Market stall interaction hitboxes") { layer = layer }; val9.transform.SetParent(prefab.transform, false); BoxCollider obj = val9.AddComponent<BoxCollider>(); obj.center = new Vector3(0f, 1.13f, -0.76f); obj.size = new Vector3(3.3f, 2.26f, 0.45f); BoxCollider obj2 = val9.AddComponent<BoxCollider>(); obj2.center = new Vector3(0f, 1.02f, 0.8f); obj2.size = new Vector3(3.24f, 2.04f, 0.22f); } internal static void BuildNpc(GameObject prefab) { //IL_0014: 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: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: 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_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) Material material = Plain("Merchant sign cloth", new Color(0.16f, 0.27f, 0.31f)); Material material2 = Plain("Edda's gold trim", new Color(0.76f, 0.53f, 0.22f)); Transform transform = new GameObject("Merchant sign").transform; transform.SetParent(prefab.transform, false); Block(transform, "Indigo stall sign", new Vector3(0f, 2.31f, -1.02f), new Vector3(1.32f, 0.21f, 0.055f), material); float[] array = new float[2] { -0.49f, 0.49f }; foreach (float num in array) { Round(transform, "Gold stud", new Vector3(num, 2.31f, -1.06f), new Vector3(0.07f, 0.07f, 0.035f), material2); } Round(transform, "Merchant emblem", new Vector3(0f, 2.31f, -1.065f), new Vector3(0.17f, 0.17f, 0.035f), material2); } private static Material Wood(Material source, Color tint) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null) { return Plain("Stall timber", tint); } Material val = new Material(source) { name = "Market stall timber" }; if (val.HasProperty("_Color")) { val.color = tint; } return val; } private static Material Plain(string name, Color color) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown Material val = new Material(Shader.Find("Standard") ?? Shader.Find("Diffuse") ?? fallbackShader) { name = name, color = color }; if (val.HasProperty("_Glossiness")) { val.SetFloat("_Glossiness", 0.04f); } return val; } private static Transform Shape(Transform parent, PrimitiveType shape, string name, Vector3 position, Vector3 scale, Material material) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GameObject.CreatePrimitive(shape); ((Object)obj).name = name; obj.layer = ((Component)parent).gameObject.layer; obj.transform.SetParent(parent, false); obj.transform.localPosition = position; obj.transform.localScale = scale; ((Renderer)obj.GetComponent<MeshRenderer>()).sharedMaterial = material; Object.DestroyImmediate((Object)(object)obj.GetComponent<Collider>()); return obj.transform; } private static void Block(Transform parent, string name, Vector3 position, Vector3 scale, Material material) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) Shape(parent, (PrimitiveType)3, name, position, scale, material); } private static void Round(Transform parent, string name, Vector3 position, Vector3 scale, Material material) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) Shape(parent, (PrimitiveType)0, name, position, scale, material); } private static void Beam(Transform parent, string name, Vector3 from, Vector3 to, float width, float depth, Material material) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0016: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) Shape(parent, (PrimitiveType)3, name, (from + to) * 0.5f, new Vector3(width, Vector3.Distance(from, to), depth), material).localRotation = Quaternion.FromToRotation(Vector3.up, to - from); } private static void Lash(Transform parent, float x, float z, float y, Material rope) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < 2; i++) { float num = y + (float)i * 0.045f; Block(parent, "Rope lashing", new Vector3(x, num, z - 0.11f), new Vector3(0.27f, 0.025f, 0.025f), rope); Block(parent, "Rope lashing", new Vector3(x, num, z + 0.11f), new Vector3(0.27f, 0.025f, 0.025f), rope); Block(parent, "Rope lashing", new Vector3(x - 0.11f, num, z), new Vector3(0.025f, 0.025f, 0.27f), rope); Block(parent, "Rope lashing", new Vector3(x + 0.11f, num, z), new Vector3(0.025f, 0.025f, 0.27f), rope); } } private static void Canopy(Transform parent, string name, float frontZ, float backZ, float frontY, float backY, Material material) { //IL_000a: 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) Beam(parent, name, new Vector3(0f, frontY, frontZ), new Vector3(0f, backY, backZ), 3.58f, 0.045f, material); } private static void Flap(Transform parent, float x, float width, Material material) { //IL_0019: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) Block(parent, "Canvas valance", new Vector3(x + width * 0.5f, 2.27f, -0.99f), new Vector3(width - 0.018f, 0.24f, 0.04f), material); Round(parent, "Valance scallop", new Vector3(x + width * 0.5f, 2.15f, -0.99f), new Vector3(width - 0.018f, 0.1f, 0.04f), material); } private static void Crate(Transform parent, Vector3 at, float size, Material timber, Material dark) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) Block(parent, "Produce crate base", at, new Vector3(size, 0.05f, size * 0.7f), dark); float[] array = new float[2] { -1f, 1f }; foreach (float num in array) { Block(parent, "Produce crate side", at + new Vector3(num * size * 0.47f, 0.09f, 0f), new Vector3(0.045f, 0.2f, size * 0.7f), timber); } array = new float[2] { -1f, 1f }; foreach (float num2 in array) { Block(parent, "Produce crate slat", at + new Vector3(0f, 0.09f, num2 * size * 0.32f), new Vector3(size, 0.18f, 0.045f), timber); } } private static void Pot(Transform parent, Vector3 at, Material pottery) { //IL_0007: 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_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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_004e: 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) Shape(parent, (PrimitiveType)2, "Clay pot", at + Vector3.up * 0.11f, new Vector3(0.22f, 0.2f, 0.22f), pottery); Shape(parent, (PrimitiveType)2, "Clay pot rim", at + Vector3.up * 0.23f, new Vector3(0.16f, 0.035f, 0.16f), pottery); } } internal sealed class MarketStore { private const int Format = 1; private readonly string path; private readonly HashSet<Guid> completed = new HashSet<Guid>(); internal readonly List<Listing> Listings = new List<Listing>(); internal readonly List<Offer> Offers = new List<Offer>(); internal readonly List<Claim> Claims = new List<Claim>(); private MarketStore(string file) { path = file; } internal static MarketStore Open(long worldId) { string path = Path.Combine(Paths.ConfigPath, "ValheimMarket"); Directory.CreateDirectory(path); MarketStore marketStore = new MarketStore(Path.Combine(path, worldId + ".market")); if (!File.Exists(marketStore.path)) { return marketStore; } using FileStream input = File.OpenRead(marketStore.path); using BinaryReader binaryReader = new BinaryReader(input); if (binaryReader.ReadInt32() != 1) { throw new InvalidDataException("Unsupported market save format"); } marketStore.Listings.AddRange(MarketCodec.ReadList(binaryReader, Listing.Read)); marketStore.Offers.AddRange(MarketCodec.ReadList(binaryReader, Offer.Read)); marketStore.Claims.AddRange(MarketCodec.ReadList(binaryReader, Claim.Read)); int num = binaryReader.ReadInt32(); if (num < 0 || num > 1000000) { throw new InvalidDataException("Invalid transaction journal"); } for (int i = 0; i < num; i++) { marketStore.completed.Add(MarketCodec.ReadGuid(binaryReader)); } return marketStore; } private void Save() { string sourceFileName = path + ".tmp"; using (FileStream fileStream = new FileStream(sourceFileName, FileMode.Create, FileAccess.Write, FileShare.None)) { using BinaryWriter binaryWriter = new BinaryWriter(fileStream); binaryWriter.Write(1); MarketCodec.WriteList(binaryWriter, Listings, delegate(BinaryWriter x, Listing y) { y.Write(x); }); MarketCodec.WriteList(binaryWriter, Offers, delegate(BinaryWriter x, Offer y) { y.Write(x); }); MarketCodec.WriteList(binaryWriter, Claims, delegate(BinaryWriter x, Claim y) { y.Write(x); }); binaryWriter.Write(completed.Count); foreach (Guid item in completed) { MarketCodec.WriteGuid(binaryWriter, item); } binaryWriter.Flush(); fileStream.Flush(flushToDisk: true); } if (File.Exists(path)) { try { File.Replace(sourceFileName, path, path + ".bak"); return; } catch (PlatformNotSupportedException) { File.Copy(path, path + ".bak", overwrite: true); File.Delete(path); File.Move(sourceFileName, path); return; } } File.Move(sourceFileName, path); } private string Commit(Guid requestId, string result) { completed.Add(requestId); Listings.RemoveAll((Listing x) => !x.Active); Offers.RemoveAll((Offer x) => !x.Active); Save(); return result; } internal bool WasCompleted(Guid requestId) { return completed.Contains(requestId); } internal Listing FindListing(Guid id) { return Listings.FirstOrDefault((Listing x) => x.Id == id && x.Active); } internal Offer FindOffer(Guid id) { return Offers.FirstOrDefault((Offer x) => x.Id == id && x.Active); } internal Claim FindClaim(Guid id) { return Claims.FirstOrDefault((Claim x) => x.Id == id && !x.Collected); } internal string CreateListing(Guid requestId, long seller, string sellerName, ItemBlob item, int price) { if (WasCompleted(requestId)) { return "Already posted"; } item.Validate(); if (price < 1 || price > 1000000) { throw new InvalidDataException("Gold price must be 1–1,000,000"); } if (Listings.Count((Listing x) => x.Active && x.Seller == seller) >= 20) { throw new InvalidDataException("Shop is full (20 listings)"); } Listings.Add(new Listing { Id = Guid.NewGuid(), Seller = seller, SellerName = sellerName, Item = item, GoldPrice = price }); return Commit(requestId, "Listing posted"); } internal string MakeOffer(Guid requestId, Guid listingId, long buyer, string buyerName, ItemBlob item) { if (WasCompleted(requestId)) { return "Offer already posted"; } Listing listing = FindListing(listingId) ?? throw new InvalidDataException("Listing is unavailable"); if (listing.Seller == buyer) { throw new InvalidDataException("You cannot offer on your own listing"); } item.Validate(); if (Offers.Count((Offer x) => x.Active && x.ListingId == listingId) >= 10) { throw new InvalidDataException("This listing has too many offers"); } Offers.Add(new Offer { Id = Guid.NewGuid(), ListingId = listingId, Seller = listing.Seller, Buyer = buyer, BuyerName = buyerName, Item = item }); return Commit(requestId, "Offer sent"); } internal string Buy(Guid requestId, Guid listingId, long buyer, int paidCoins) { if (WasCompleted(requestId)) { return "Purchase already completed"; } Listing listing = FindListing(listingId) ?? throw new InvalidDataException("Listing is unavailable"); if (listing.Seller == buyer) { throw new InvalidDataException("You cannot buy your own listing"); } if (paidCoins != listing.GoldPrice) { throw new InvalidDataException("Price changed"); } listing.Active = false; AddClaim(listing.Seller, buyer, listing.Item); AddCoins(listing.Seller, listing.Seller, paidCoins); ReturnOtherOffers(listing.Id, Guid.Empty); return Commit(requestId, "Purchased. Delivering your item to inventory"); } internal string SellToNpc(Guid requestId, long shopOwner, long seller, ItemBlob item) { if (WasCompleted(requestId)) { return "Already sold"; } int amount = NpcMerchant.Quote(item, shopOwner); AddCoins(shopOwner, seller, amount); return Commit(requestId, "Sold to Edda. Delivering coins to your inventory"); } internal string BuyFromNpc(Guid requestId, long buyer, Listing stock, int paidCoins) { if (WasCompleted(requestId)) { return "Purchase already completed"; } if (stock == null || !NpcMerchant.IsOwner(stock.Seller) || paidCoins != stock.GoldPrice) { throw new InvalidDataException("Edda's stock or price changed"); } stock.Item.Validate(); AddClaim(stock.Seller, buyer, stock.Item); return Commit(requestId, "Purchased. Delivering goods to your inventory"); } internal string AcceptOffer(Guid requestId, Guid offerId, long seller) { if (WasCompleted(requestId)) { return "Offer already accepted"; } Offer offer = FindOffer(offerId) ?? throw new InvalidDataException("Offer is unavailable"); Listing listing = FindListing(offer.ListingId) ?? throw new InvalidDataException("Listing is unavailable"); if (listing.Seller != seller) { throw new InvalidDataException("This is not your listing"); } offer.Active = false; listing.Active = false; AddClaim(seller, offer.Buyer, listing.Item); AddClaim(seller, seller, offer.Item); ReturnOtherOffers(listing.Id, offer.Id); return Commit(requestId, "Offer accepted. Goods are ready to collect"); } internal string RejectOffer(Guid requestId, Guid offerId, long seller) { if (WasCompleted(requestId)) { return "Offer already rejected"; } Offer offer = FindOffer(offerId) ?? throw new InvalidDataException("Offer is unavailable"); if (offer.Seller != seller) { throw new InvalidDataException("This is not your offer to reject"); } offer.Active = false; AddClaim(seller, offer.Buyer, offer.Item); return Commit(requestId, "Offer rejected"); } internal string CancelListing(Guid requestId, Guid listingId, long seller) { if (WasCompleted(requestId)) { return "Listing already canceled"; } Listing listing = FindListing(listingId) ?? throw new InvalidDataException("Listing is unavailable"); if (listing.Seller != seller) { throw new InvalidDataException("This is not your listing"); } listing.Active = false; AddClaim(seller, seller, listing.Item); ReturnOtherOffers(listingId, Guid.Empty); return Commit(requestId, "Listing canceled. Collect your item"); } internal string CancelOffer(Guid requestId, Guid offerId, long buyer) { if (WasCompleted(requestId)) { return "Offer already canceled"; } Offer offer = FindOffer(offerId) ?? throw new InvalidDataException("Offer is unavailable"); if (offer.Buyer != buyer) { throw new InvalidDataException("This is not your offer"); } offer.Active = false; AddClaim(offer.Seller, buyer, offer.Item); return Commit(requestId, "Offer canceled. Collect your item"); } internal void MarkCollected(Guid claimId, long recipient) { Claim claim = FindClaim(claimId); if (claim != null && claim.Recipient == recipient) { claim.Collected = true; Claims.RemoveAll((Claim x) => x.Collected); Save(); } } private void ReturnOtherOffers(Guid listingId, Guid except) { foreach (Offer item in Offers.Where((Offer x) => x.Active && x.ListingId == listingId && x.Id != except)) { item.Active = false; AddClaim(item.Seller, item.Buyer, item.Item); } } private void AddClaim(long shopOwner, long recipient, ItemBlob item) { Claims.Add(new Claim { Id = Guid.NewGuid(), ShopOwner = shopOwner, Recipient = recipient, Item = item }); } private void AddCoins(long shopOwner, long recipient, int amount) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Coins"); if ((Object)(object)itemPrefab == (Object)null) { throw new InvalidDataException("Coin item is unavailable"); } int maxStackSize = itemPrefab.GetComponent<ItemDrop>().m_itemData.m_shared.m_maxStackSize; ItemData val = itemPrefab.GetComponent<ItemDrop>().m_itemData.Clone(); val.m_dropPrefab = itemPrefab; while (amount > 0) { int num = Math.Min(amount, maxStackSize); ItemBlob itemBlob = ItemBlob.FromItem(val, 1); itemBlob.Stack = num; AddClaim(shopOwner, recipient, itemBlob); amount -= num; } } } internal sealed class MarketUI { private enum Page { Browse, Merchant, MyShop, Offers, Collect } private static readonly Color Wood = new Color(0.4f, 0.29f, 0.2f, 0.98f); private static readonly Color Dark = new Color(0.1f, 0.11f, 0.12f, 0.96f); private static readonly Color Line = new Color(0.54f, 0.36f, 0.17f, 1f); private static readonly Color Gold = new Color(0.94f, 0.72f, 0.39f, 1f); private static readonly Color Cream = new Color(0.94f, 0.88f, 0.76f, 1f); private Canvas canvas; private GameObject root; private GameObject ownedEventSystem; private RectTransform panel; private RectTransform body; private readonly Dictionary<Page, Button> tabs = new Dictionary<Page, Button>(); private TextMeshProUGUI status; private TMP_FontAsset font; private TMP_FontAsset titleFont; private Sprite woodSprite; private Sprite insetSprite; private Sprite boxSprite; private Sprite buttonSprite; private Sprite buttonHoverSprite; private Sprite buttonPressedSprite; private Sprite tabSprite; private Sprite tabHoverSprite; private Sprite tabSelectedSprite; private Sprite fieldSprite; private Sprite separatorSprite; private Page page; private MarketStall stall; private MarketSnapshot snapshot; private string loadError; private long selectedOwner; private string search = ""; private ItemData selectedItem; private TMP_InputField priceField; private TMP_InputField quantityField; private CursorLockMode oldLock; private bool oldCursor; private bool opened; private bool waitForMouseRelease; private int closedFrame = -1; private bool rebuildNextFrame; private Guid selectedOfferListing; internal bool IsOpen { get { if (opened) { return (Object)(object)root != (Object)null; } return false; } } internal bool BlocksGameInput { get { if (!IsOpen && !waitForMouseRelease) { return Time.frameCount == closedFrame; } return true; } } internal void Open(MarketStall marketStall) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Expected O, but got Unknown //IL_0267: 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_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_0383: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_0404: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Expected O, but got Unknown //IL_0477: Unknown result type (might be due to invalid IL or missing references) //IL_0635: Unknown result type (might be due to invalid IL or missing references) //IL_0655: Unknown result type (might be due to invalid IL or missing references) //IL_058c: Unknown result type (might be due to invalid IL or missing references) //IL_0585: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)marketStall == (Object)null) { return; } Close(); closedFrame = -1; stall = marketStall; loadError = null; selectedOwner = stall.ShopId; this.page = (stall.IsNpc ? Page.Merchant : Page.Browse); oldLock = Cursor.lockState; oldCursor = Cursor.visible; font = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset x) => ((Object)x).name.IndexOf("Averia", StringComparison.OrdinalIgnoreCase) >= 0)) ?? TMP_Settings.defaultFontAsset; titleFont = ((IEnumerable<TMP_FontAsset>)Resources.FindObjectsOfTypeAll<TMP_FontAsset>()).FirstOrDefault((Func<TMP_FontAsset, bool>)((TMP_FontAsset x) => ((Object)x).name.IndexOf("Norse", StringComparison.OrdinalIgnoreCase) >= 0)) ?? font; Sprite[] sprites = Resources.FindObjectsOfTypeAll<Sprite>(); woodSprite = FindSprite(sprites, "woodpanel_large") ?? FindSprite(sprites, "woodpanel_512x512") ?? FindSprite(sprites, "woodpanel_playerinventory"); insetSprite = FindSprite(sprites, "panel_bkg_128") ?? FindSprite(sprites, "panel_bkg"); boxSprite = FindSprite(sprites, "panel_bkg") ?? insetSprite; buttonSprite = FindSprite(sprites, "button"); buttonHoverSprite = FindSprite(sprites, "button_highlight"); buttonPressedSprite = FindSprite(sprites, "button_pressed"); tabSprite = FindSprite(sprites, "button_tab"); tabHoverSprite = FindSprite(sprites, "button_tab_hover"); tabSelectedSprite = FindSprite(sprites, "button_tab_selected"); fieldSprite = FindSprite(sprites, "text_field"); separatorSprite = FindSprite(sprites, "panel_separator"); root = new GameObject("ValheimMarketUI", new Type[4] { typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster) }); opened = true; canvas = root.GetComponent<Canvas>(); canvas.renderMode = (RenderMode)0; canvas.sortingOrder = 250; CanvasScaler component = root.GetComponent<CanvasScaler>(); component.uiScaleMode = (ScaleMode)1; component.referenceResolution = new Vector2(1920f, 1080f); component.matchWidthOrHeight = 0.5f; if ((Object)(object)EventSystem.current == (Object)null) { ownedEventSystem = new GameObject("ValheimMarketEventSystem", new Type[2] { typeof(EventSystem), typeof(StandaloneInputModule) }); } RectTransform obj = Rect(root.transform, "Backdrop", 0f, 0f, 0f, 0f, stretch: true); obj.anchorMin = Vector2.zero; obj.anchorMax = Vector2.one; obj.offsetMin = Vector2.zero; obj.offsetMax = Vector2.zero; ((Graphic)((Component)obj).gameObject.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.62f); panel = Rect(root.transform, "Market Panel", 0f, 0f, 1250f, 780f); RectTransform obj2 = panel; RectTransform obj3 = panel; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0.5f, 0.5f); obj3.anchorMax = val; obj2.anchorMin = val; panel.pivot = new Vector2(0.5f, 0.5f); panel.anchoredPosi