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 PackAndPlace v0.5.10
BepInEx/plugins/PackAndPlace/ArcByte.PackAndPlace.dll
Decompiled 5 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; 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.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("ArcByte.PackAndPlace")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.5.10.0")] [assembly: AssemblyInformationalVersion("0.5.10")] [assembly: AssemblyProduct("ArcByte.PackAndPlace")] [assembly: AssemblyTitle("ArcByte.PackAndPlace")] [assembly: AssemblyVersion("0.5.10.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 ArcByte.PackAndPlace { internal sealed class AdapterBinding { internal string Id; internal string Key; internal int Version; } internal static class AdapterLayout { internal static int[] Match(IList<AdapterSnapshot> snapshots, IList<AdapterBinding> bindings) { AdapterSnapshot.ValidateAll(snapshots); if (snapshots.Count != bindings.Count) { throw new InvalidDataException("Extension component layout changed or an adapter is missing. Package kept."); } Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal); for (int i = 0; i < bindings.Count; i++) { string key = bindings[i].Id + "|" + bindings[i].Key; if (dictionary.ContainsKey(key)) { throw new InvalidDataException("Ambiguous extension component layout."); } dictionary.Add(key, i); } int[] array = new int[snapshots.Count]; for (int j = 0; j < snapshots.Count; j++) { AdapterSnapshot adapterSnapshot = snapshots[j]; if (!dictionary.TryGetValue(adapterSnapshot.AdapterId + "|" + adapterSnapshot.ComponentKey, out var value) || adapterSnapshot.Version > bindings[value].Version) { throw new InvalidDataException("Missing or incompatible package adapter " + adapterSnapshot.AdapterId + ". Package kept."); } array[j] = value; } return array; } } public sealed class AdapterSnapshot { public string AdapterId = ""; public string ComponentKey = ""; public string Data = ""; public int Version; public float ContentsWeight; public bool Teleportable = true; internal static void ValidateAll(IList<AdapterSnapshot> snapshots) { if (snapshots.Count > 128) { throw new InvalidDataException("Too many extension component snapshots."); } int num = 0; HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); foreach (AdapterSnapshot snapshot in snapshots) { if (snapshot == null || !AdapterIdentity.Valid(snapshot.AdapterId) || snapshot.ComponentKey == null || snapshot.ComponentKey.Length > 1024 || snapshot.ComponentKey.Length == 0 || snapshot.Version < 1 || snapshot.Data == null || snapshot.Data.Length > 262144 || float.IsNaN(snapshot.ContentsWeight) || float.IsInfinity(snapshot.ContentsWeight) || snapshot.ContentsWeight < 0f || snapshot.ContentsWeight > 100000000f || !hashSet.Add(snapshot.AdapterId + "|" + snapshot.ComponentKey)) { throw new InvalidDataException("Invalid or duplicate extension component snapshot."); } try { Convert.FromBase64String(snapshot.Data); } catch (FormatException innerException) { throw new InvalidDataException("Invalid extension payload encoding.", innerException); } num += snapshot.Data.Length; } if (num > 262144) { throw new InvalidDataException("Extension payloads are too large to pack."); } } } internal static class AdapterIdentity { internal static bool Valid(string id) { return !string.IsNullOrEmpty(id) && id.Length <= 160 && id.All((char c) => (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '-' || c == '_'); } } internal sealed class AdapterCatalog<T> { internal sealed class Entry { internal string Id; internal string Component; internal int Version; internal T Adapter; } private readonly List<Entry> entries = new List<Entry>(); private string manifest; internal Entry[] Entries => entries.OrderBy<Entry, string>((Entry e) => e.Id, StringComparer.Ordinal).ToArray(); internal bool Frozen => manifest != null; internal void Add(string id, int version, string component, T adapter) { if (Frozen) { throw new InvalidOperationException("Register package adapters during plugin Awake, before prefab registration or connections."); } if (!AdapterIdentity.Valid(id) || id.StartsWith("arcbyte.", StringComparison.Ordinal) || version < 1 || string.IsNullOrEmpty(component) || component.Length > 1024 || adapter == null) { throw new ArgumentException("Invalid package adapter ID, version or component."); } if (entries.Count >= 128 || entries.Any((Entry e) => e.Id == id || e.Component == component)) { throw new ArgumentException("A package adapter is already registered for that ID or exact component type."); } entries.Add(new Entry { Id = id, Version = version, Component = component, Adapter = adapter }); } internal string Freeze() { if (manifest != null) { return manifest; } using (MemoryStream memoryStream = new MemoryStream()) { using BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true); using SHA256 sHA = SHA256.Create(); Entry[] array = Entries; foreach (Entry entry in array) { binaryWriter.Write(entry.Id); binaryWriter.Write(entry.Version); binaryWriter.Write(entry.Component); } binaryWriter.Flush(); manifest = BitConverter.ToString(sHA.ComputeHash(memoryStream.ToArray())).Replace("-", ""); } return manifest; } } internal sealed class WispSpawnerAdapter : IExtensionAdapter { public string Id => "builtin.wispspawner.cooldown"; public int Version => 1; public Type ComponentType => typeof(WispSpawner); private static ZDO State(MonoBehaviour c) { ZNetView componentInParent = ((Component)c).GetComponentInParent<ZNetView>(); if (!Object.op_Implicit((Object)(object)componentInParent) || !componentInParent.IsValid() || !componentInParent.IsOwner()) { throw new InvalidDataException("Wait for wisplure ownership."); } return componentInParent.GetZDO(); } public string CannotPack(MonoBehaviour c) { State(c); return null; } public byte[] Capture(MonoBehaviour c, PackageCaptureContext context) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown WispSpawner val = (WispSpawner)c; ZDO val2 = State(c); double age = Math.Max(0.0, (ZNet.instance.GetTime() - new DateTime(val2.GetLong(ZDOVars.s_lastSpawn, 0L))).TotalSeconds); return CooldownState.FromAge(val.m_spawnInterval, age).Encode(); } public void ValidateData(int version, byte[] data) { CooldownState.Decode(version, data); } public void ValidateRestore(MonoBehaviour c, int version, byte[] data) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) CooldownState cooldownState = CooldownState.Decode(version, data); State(c); if (((WispSpawner)c).m_spawnInterval != cooldownState.Interval) { throw new InvalidDataException("Wisplure spawn interval changed. Package kept."); } } public void Restore(MonoBehaviour c, int version, byte[] data) { ValidateRestore(c, version, data); CooldownState cooldownState = CooldownState.Decode(version, data); State(c).Set(ZDOVars.s_lastSpawn, ZNet.instance.GetTime().AddSeconds(cooldownState.Remaining - (double)cooldownState.Interval).Ticks); } } internal sealed class MidgardLiftAdapter : IExtensionAdapter { public string Id => "compat.midgardplus.lift"; public int Version => 1; public Type ComponentType { get; } internal MidgardLiftAdapter(Type type) { ComponentType = type; if (((float[])AccessTools.Field(type, "Heights").GetValue(null)).Length != 13 || ((float[])AccessTools.Field(type, "Speeds").GetValue(null)).Length != 5 || AccessTools.Field(type, "_shown") == null || AccessTools.Property(type, "Target") == null) { throw new InvalidOperationException("Midgard lift API changed."); } } private LiftState Read(MonoBehaviour c) { ZDO val = OptionalModAdapters.State(c); LiftState liftState = new LiftState { Height = val.GetInt("MP_lift_h", 3), Speed = val.GetInt("MP_lift_s", 2), Stop = val.GetInt("MP_lift_stop", 0) }; liftState.Validate(); return liftState; } public string CannotPack(MonoBehaviour c) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) Read(c); GameObject val = (GameObject)OptionalModAdapters.Read(c, "_car"); if (!Object.op_Implicit((Object)(object)val) || !(bool)OptionalModAdapters.Read(c, "_placed")) { return "Wait for the lift platform to initialize."; } if (!LiftState.Stationary((float)OptionalModAdapters.Read(c, "_shown"), (float)OptionalModAdapters.Read(c, "Target"))) { return "Stop the lift at its upper or lower endpoint before packing."; } BoxCollider val2 = (BoxCollider)OptionalModAdapters.Read(c, "_box"); if (!Object.op_Implicit((Object)(object)val2)) { return "The lift platform collider is unavailable."; } Bounds bounds = ((Collider)val2).bounds; ((Bounds)(ref bounds)).Expand(new Vector3(0.2f, 1.4f, 0.2f)); if (Character.GetAllCharacters().Any((Character character) => Object.op_Implicit((Object)(object)character) && ((Bounds)(ref bounds)).Intersects((Bounds)(Object.op_Implicit((Object)(object)((Component)character).GetComponent<Collider>()) ? ((Component)character).GetComponent<Collider>().bounds : new Bounds(((Component)character).transform.position, Vector3.one))))) { return "Everyone, including animals, must leave the lift platform before packing."; } if (Physics.OverlapBox(((Bounds)(ref bounds)).center, ((Bounds)(ref bounds)).extents).Any((Collider hit) => Object.op_Implicit((Object)(object)hit) && Object.op_Implicit((Object)(object)hit.attachedRigidbody) && (Object)(object)hit.attachedRigidbody != (Object)(Rigidbody)OptionalModAdapters.Read(c, "_body"))) { return "Remove loose cargo from the lift platform before packing."; } return null; } public byte[] Capture(MonoBehaviour c, PackageCaptureContext context) { string text = CannotPack(c); if (text != null) { throw new InvalidDataException(text); } return Read(c).Encode(); } public void ValidateData(int version, byte[] data) { LiftState.Decode(version, data); } public void ValidateRestore(MonoBehaviour c, int version, byte[] data) { ValidateData(version, data); OptionalModAdapters.State(c); } public void Restore(MonoBehaviour c, int version, byte[] data) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Expected O, but got Unknown //IL_012a: Unknown result type (might be due to invalid IL or missing references) ValidateRestore(c, version, data); LiftState liftState = LiftState.Decode(version, data); ZDO val = OptionalModAdapters.State(c); val.Set("MP_lift_h", liftState.Height); val.Set("MP_lift_s", liftState.Speed); val.Set("MP_lift_stop", liftState.Stop); val.Set("MP_lift_t0", 0L); val.Set("MP_lift_from", 0f); GameObject val2 = (GameObject)OptionalModAdapters.Read(c, "_car"); if (Object.op_Implicit((Object)(object)val2)) { float num = (float)AccessTools.Method(ComponentType, "Estimate", (Type[])null, (Type[])null).Invoke(c, null); AccessTools.Field(ComponentType, "_shown").SetValue(c, num); Vector3 position = (Vector3)AccessTools.Method(ComponentType, "CarPos", (Type[])null, (Type[])null).Invoke(c, new object[1] { num }); val2.transform.position = position; Rigidbody val3 = (Rigidbody)OptionalModAdapters.Read(c, "_body"); if (Object.op_Implicit((Object)(object)val3)) { val3.position = position; } } } } internal sealed class MidgardShrineAdapter : IExtensionAdapter { private readonly Type shrine; public string Id => "compat.midgardplus.hallowshrine"; public int Version => 1; public Type ComponentType { get; } internal MidgardShrineAdapter(Type type) { ComponentType = type; shrine = type.DeclaringType; if (AccessTools.Field(shrine, "_waiting") == null || AccessTools.Field(shrine, "_waitingFor") == null) { throw new InvalidOperationException("Midgard shrine API changed."); } } public string CannotPack(MonoBehaviour c) { //IL_004d: 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) ZDO val = OptionalModAdapters.State(c); if ((bool)AccessTools.Field(shrine, "_waiting").GetValue(null) && (ZDOID)AccessTools.Field(shrine, "_waitingFor").GetValue(null) == val.m_uid) { return "Wait for the Hallow Shrine's offering request to finish."; } if (Player.GetAllPlayers().Any((Player p) => Object.op_Implicit((Object)(object)p) && Vector3.Distance(((Component)p).transform.position, ((Component)c).transform.position) < 3f)) { return "Everyone must step at least 3 metres away from the Hallow Shrine before packing."; } return null; } public byte[] Capture(MonoBehaviour c, PackageCaptureContext context) { string text = CannotPack(c); if (text != null) { throw new InvalidDataException(text); } return new byte[0]; } public void ValidateData(int version, byte[] data) { if (version != 1 || data == null || data.Length != 0) { throw new InvalidDataException("Invalid Hallow Shrine payload."); } } public void ValidateRestore(MonoBehaviour c, int version, byte[] data) { ValidateData(version, data); OptionalModAdapters.State(c); } public void Restore(MonoBehaviour c, int version, byte[] data) { ValidateRestore(c, version, data); } } internal sealed class CooldownState { internal float Interval; internal double Remaining; internal static CooldownState FromAge(float interval, double age) { if (double.IsNaN(age) || double.IsInfinity(age)) { throw new InvalidDataException("Invalid spawn age."); } CooldownState cooldownState = new CooldownState { Interval = interval, Remaining = Math.Max(0.0, (double)interval - Math.Max(0.0, age)) }; cooldownState.Validate(); return cooldownState; } internal void Validate() { if (float.IsNaN(Interval) || float.IsInfinity(Interval) || Interval <= 0f || double.IsNaN(Remaining) || double.IsInfinity(Remaining) || Remaining < 0.0 || Remaining > (double)Interval) { throw new InvalidDataException("Invalid saved spawn cooldown."); } } internal byte[] Encode() { Validate(); using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(Interval); binaryWriter.Write(Remaining); return memoryStream.ToArray(); } internal static CooldownState Decode(int version, byte[] data) { if (version != 1 || data == null || data.Length != 12) { throw new InvalidDataException("Invalid spawn cooldown payload."); } using BinaryReader binaryReader = new BinaryReader(new MemoryStream(data)); CooldownState cooldownState = new CooldownState { Interval = binaryReader.ReadSingle(), Remaining = binaryReader.ReadDouble() }; cooldownState.Validate(); return cooldownState; } } internal sealed class LiftState { internal int Height; internal int Speed; internal int Stop; internal void Validate() { if (Height < 0 || Height >= 13 || Speed < 0 || Speed >= 5 || Stop < 0 || Stop > 1) { throw new InvalidDataException("Invalid saved lift settings."); } } internal byte[] Encode() { Validate(); using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(Height); binaryWriter.Write(Speed); binaryWriter.Write(Stop); return memoryStream.ToArray(); } internal static LiftState Decode(int version, byte[] data) { if (version != 1 || data == null || data.Length != 12) { throw new InvalidDataException("Invalid lift payload."); } using BinaryReader binaryReader = new BinaryReader(new MemoryStream(data)); LiftState liftState = new LiftState { Height = binaryReader.ReadInt32(), Speed = binaryReader.ReadInt32(), Stop = binaryReader.ReadInt32() }; liftState.Validate(); return liftState; } internal static bool Stationary(float shown, float target) { return !float.IsNaN(shown) && !float.IsNaN(target) && !float.IsInfinity(shown) && !float.IsInfinity(target) && Math.Abs(shown - target) < 0.0005f; } } internal sealed class BoatState { internal int Bits; internal int Flags; internal int Store; internal int Tint; internal int Pattern; internal int Fuel; internal float BoostLeft; internal float Skill; internal float Shot; internal float Ram; internal float Horn; internal string Paid = ""; internal string Fit = ""; internal string YardPaid = ""; internal string Planks = ""; internal bool Voyage; internal bool Peaked; internal float Pressure; internal readonly float[] VoyageWait = new float[6]; internal static List<KeyValuePair<string, int>> Ledger(string text) { if (text == null || text.Length > 16384) { throw new InvalidDataException("Boat payment ledger is oversized."); } List<KeyValuePair<string, int>> list = new List<KeyValuePair<string, int>>(); if (text.Length == 0) { return list; } string[] array = text.Split(new char[1] { ';' }); foreach (string text2 in array) { int num = text2.IndexOf(':'); if (list.Count >= 256 || num < 1 || num > 128 || text2.IndexOf(':', num + 1) >= 0 || !int.TryParse(text2.Substring(num + 1), NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result < 1 || result > 1000000) { throw new InvalidDataException("Unsupported boat payment ledger entry."); } string text3 = text2.Substring(0, num); string text4 = text3; foreach (char c in text4) { if (!char.IsLetterOrDigit(c) && c != '_' && c != '-' && c != '.') { throw new InvalidDataException("Invalid boat payment item name."); } } list.Add(new KeyValuePair<string, int>(text3, result)); } return list; } internal void Validate() { if (Bits < 0 || Bits > 8191 || Flags < 0 || Flags > 15 || Store < 0 || Store > 2 || Tint < 0 || Tint > 6 || Pattern < 0 || Pattern > 63 || Fuel < 0 || Fuel > 10) { throw new InvalidDataException("Unsupported boat upgrade state."); } Tuple<float, float>[] array = new Tuple<float, float>[5] { Tuple.Create(BoostLeft, 2700f), Tuple.Create(Skill, 1f), Tuple.Create(Shot, 3f), Tuple.Create(Ram, 3f), Tuple.Create(Horn, 180f) }; foreach (Tuple<float, float> tuple in array) { if (float.IsNaN(tuple.Item1) || float.IsInfinity(tuple.Item1) || tuple.Item1 < 0f || tuple.Item1 > tuple.Item2) { throw new InvalidDataException("Invalid boat cooldown or boost state."); } } Ledger(Paid); Ledger(YardPaid); if (float.IsNaN(Pressure) || float.IsInfinity(Pressure) || Pressure < 0f || Pressure > 100f) { throw new InvalidDataException("Invalid voyage pressure."); } float[] voyageWait = VoyageWait; foreach (float num in voyageWait) { if (float.IsNaN(num) || float.IsInfinity(num) || num < 0f || num > 600f) { throw new InvalidDataException("Invalid voyage event cooldown."); } } if (Fit == null || Fit.Length > 4096 || Planks == null || Planks.Length > 8192) { throw new InvalidDataException("Boat fit or plank state is oversized."); } if (Planks.Length <= 0) { return; } string planks = Planks; foreach (char c in planks) { if (c < 'a' || c > 'u') { throw new InvalidDataException("Invalid boat plank state."); } } } internal byte[] Encode() { Validate(); using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true)); binaryWriter.Write(Bits); binaryWriter.Write(Flags); binaryWriter.Write(Store); binaryWriter.Write(Tint); binaryWriter.Write(Pattern); binaryWriter.Write(Fuel); binaryWriter.Write(BoostLeft); binaryWriter.Write(Skill); binaryWriter.Write(Shot); binaryWriter.Write(Ram); binaryWriter.Write(Horn); binaryWriter.Write(Paid); binaryWriter.Write(Fit); binaryWriter.Write(YardPaid); binaryWriter.Write(Planks); binaryWriter.Write(Voyage); binaryWriter.Write(Peaked); binaryWriter.Write(Pressure); float[] voyageWait = VoyageWait; foreach (float value in voyageWait) { binaryWriter.Write(value); } return memoryStream.ToArray(); } internal static BoatState Decode(int version, byte[] data) { if (version != 1 || data == null || data.Length > 49152) { throw new InvalidDataException("Unsupported boat payload."); } using MemoryStream memoryStream = new MemoryStream(data); using BinaryReader binaryReader = new BinaryReader(memoryStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true)); BoatState boatState = new BoatState { Bits = binaryReader.ReadInt32(), Flags = binaryReader.ReadInt32(), Store = binaryReader.ReadInt32(), Tint = binaryReader.ReadInt32(), Pattern = binaryReader.ReadInt32(), Fuel = binaryReader.ReadInt32(), BoostLeft = binaryReader.ReadSingle(), Skill = binaryReader.ReadSingle(), Shot = binaryReader.ReadSingle(), Ram = binaryReader.ReadSingle(), Horn = binaryReader.ReadSingle(), Paid = binaryReader.ReadString(), Fit = binaryReader.ReadString(), YardPaid = binaryReader.ReadString(), Planks = binaryReader.ReadString() }; byte b = binaryReader.ReadByte(); byte b2 = binaryReader.ReadByte(); if (b > 1 || b2 > 1) { throw new InvalidDataException("Invalid voyage flags."); } boatState.Voyage = b == 1; boatState.Peaked = b2 == 1; boatState.Pressure = binaryReader.ReadSingle(); for (int i = 0; i < boatState.VoyageWait.Length; i++) { boatState.VoyageWait[i] = binaryReader.ReadSingle(); } if (memoryStream.Position != memoryStream.Length) { throw new InvalidDataException("Trailing boat payload data."); } boatState.Validate(); return boatState; } } internal static class BoatComponents { internal static bool Cloth(string type, string assembly, bool onShip) { return onShip && assembly == "MagicaClothV2" && (type == "MagicaCloth2.MagicaCloth" || type == "MagicaCloth2.MagicaCapsuleCollider"); } internal static bool Covered(string type, string assembly) { int result; if (assembly == "MidgardPlus") { switch (type) { default: result = ((type == "MidgardPlus.Content.ShipHullLooks") ? 1 : 0); break; case "MidgardPlus.Content.ShipKitRig": case "MidgardPlus.Content.ShipyardShip": case "MidgardPlus.Content.ShipArmsDeck": case "MidgardPlus.Content.ShipPlankRig": case "MidgardPlus.Content.ShipKitPost": case "MidgardPlus.Content.ShipMount": case "MidgardPlus.Content.SeaVoyage": result = 1; break; } } else { result = 0; } return (byte)result != 0; } } internal static class BoatTransfers { private sealed class Ticket { internal long Owner; internal long Player; internal ZDOID Boat; internal int Kind; internal string Paid; } private const string Request = "AB_PP_BoatOffer_v1"; private const string Reply = "AB_PP_BoatOfferReply_v1"; private static readonly string HarmonyId = "com.arcbytesoftware.valheim.packandplace.boatoffers"; private static Type kit; private static Type yard; private static Type rig; private static Type fitted; private static Type combat; private static readonly TransferTickets<Ticket> tickets = new TransferTickets<Ticket>(); private static readonly TransferReceipts completed = new TransferReceipts(); private static readonly Dictionary<string, Tuple<long, int>> deferred = new Dictionary<string, Tuple<long, int>>(); private static readonly SessionEndpoint<ZRoutedRpc> endpoint = new SessionEndpoint<ZRoutedRpc>(); internal static bool Installed { get; private set; } internal static bool Ready => Installed && endpoint.IsBound(ZRoutedRpc.instance); internal static bool Pending(ZDOID boat) { //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) return tickets.Values.Any((Ticket t) => t.Boat == boat); } internal static void Install() { //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Expected O, but got Unknown //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Expected O, but got Unknown //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Expected O, but got Unknown Assembly a = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly x) => x.GetName().Name == "MidgardPlus"); if (a == null) { return; } try { if (a.GetName().Version != new Version(1, 57, 0, 0)) { throw new InvalidOperationException("Unreviewed Midgard boat RPC version."); } kit = Need("ShipKit"); yard = Need("Shipyard"); rig = Need("ShipKitRig"); fitted = Need("ShipyardShip"); combat = Need("ShipCombat"); MethodInfo methodInfo = AccessTools.Method(kit, "Send", new Type[5] { rig, typeof(int), typeof(int), typeof(string), typeof(float) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(yard, "Send", new Type[6] { typeof(ZNetView), typeof(int), typeof(int), typeof(int), typeof(string), typeof(string) }, (Type[])null); if (methodInfo == null || methodInfo2 == null || AccessTools.Method(kit, "Apply", (Type[])null, (Type[])null) == null || AccessTools.Method(yard, "ApplyRefit", (Type[])null, (Type[])null) == null || AccessTools.Method(kit, "OnRefused", (Type[])null, (Type[])null) == null || AccessTools.Method(yard, "OnReply", (Type[])null, (Type[])null) == null || AccessTools.Method(fitted, "OnRpc", (Type[])null, (Type[])null) == null || AccessTools.Property(yard, "On") == null || AccessTools.Property(combat, "On") == null) { throw new InvalidOperationException("Boat transfer API changed."); } Harmony val = new Harmony(HarmonyId); val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(BoatTransfers), "SendKit", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(BoatTransfers), "SendYard", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Installed = true; } catch (Exception ex) { Shutdown(); Plugin.Log.LogWarning((object)("Boat transfer integration unavailable: " + ex.Message)); } Type Need(string n) { return a.GetType("MidgardPlus.Content." + n, throwOnError: true); } } internal static void Register() { endpoint.Ensure(ZRoutedRpc.instance, Installed, delegate(ZRoutedRpc current) { if (tickets.Count > 0) { Plugin.Log.LogWarning((object)"Leaving a world with unresolved boat offers; no speculative refunds issued."); } tickets.Clear(); completed.Clear(); deferred.Clear(); current.Register<ZPackage>("AB_PP_BoatOffer_v1", (Action<long, ZPackage>)Receive); current.Register<string, int>("AB_PP_BoatOfferReply_v1", (Action<long, string, int>)Result); }); } internal static void Shutdown() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) new Harmony(HarmonyId).UnpatchSelf(); Installed = false; endpoint.Clear(); if (tickets.Count > 0) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)"Boat transfer shutdown with unresolved payments; no speculative timeout refunds were issued."); } } tickets.Clear(); completed.Clear(); deferred.Clear(); } private static bool SendKit(object __0, int __1, int __2, string __3, float __4) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) Send((__0 == null) ? ((ZNetView)null) : ((ZNetView)OptionalModAdapters.Read(__0, "View")), 0, __1, __2, 0, "", __3, __4); return false; } private static bool SendYard(ZNetView __0, int __1, int __2, int __3, string __4, string __5) { if (!Object.op_Implicit((Object)(object)__0)) { Send(null, 1, __1, __2, __3, __4, __5, 0f); return false; } if (!Object.op_Implicit((Object)(object)((Component)__0).GetComponent<Ship>())) { return true; } Send(__0, 1, __1, __2, __3, __4, __5, 0f); return false; } private static void Send(ZNetView view, int kind, int op, int arg, int b, string text, string paid, float skill) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_0106: Expected O, but got Unknown //IL_0110: Unknown result type (might be due to invalid IL or missing references) paid = paid ?? ""; Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { Plugin.Log.LogError((object)"Boat offer has no local payer; refusing transfer."); return; } Ticket ticket = new Ticket { Owner = ((Object.op_Implicit((Object)(object)view) && view.IsValid()) ? view.GetZDO().GetOwner() : 0), Player = localPlayer.GetPlayerID(), Boat = ((Object.op_Implicit((Object)(object)view) && view.IsValid()) ? view.GetZDO().m_uid : ZDOID.None), Kind = kind, Paid = paid }; if (!Ready || ticket.Owner == 0L || tickets.Count >= 128) { Refund(ticket, 0L, 1); return; } string text2 = Guid.NewGuid().ToString("N"); ZPackage val; try { BoatState.Ledger(paid); val = new ZPackage(); val.Write(text2); val.Write(ticket.Boat); val.Write(ticket.Player); val.Write(kind); val.Write(op); val.Write(arg); val.Write(b); val.Write(text ?? ""); val.Write(paid); val.Write(skill); } catch (Exception ex) { Plugin.Log.LogError((object)("Boat offer could not serialize; returning the original payment before dispatch: " + ex)); Refund(ticket, 0L, 1); return; } tickets.Add(text2, ticket.Owner, ticket.Player, ticket); try { ZRoutedRpc.instance.InvokeRoutedRPC(ticket.Owner, "AB_PP_BoatOffer_v1", new object[1] { val }); } catch (Exception ex2) { Plugin.Log.LogError((object)("Boat offer delivery is uncertain; original ticket retained, no speculative duplicate refund: " + ex2)); } } private static void Receive(long sender, ZPackage data) { //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) string text = ""; ZDO zdo = null; uint revision = 0u; try { if (!Ready || data == null || data.Size() > 49152) { return; } text = data.ReadString(); if (text.Length != 32) { return; } string id = sender + ":" + text; if (completed.TryGet(id, out var result)) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "AB_PP_BoatOfferReply_v1", new object[2] { text, result }); return; } ZDOID val = data.ReadZDOID(); long actor = data.ReadLong(); int kind = data.ReadInt(); int op = data.ReadInt(); int arg = data.ReadInt(); int b = data.ReadInt(); string text2 = data.ReadString(); string paid = data.ReadString(); float skill = data.ReadSingle(); if (data.GetPos() != data.Size() || text2.Length > 4096 || float.IsNaN(skill) || float.IsInfinity(skill) || skill < 0f || skill > 1f) { return; } BoatState.Ledger(paid); Player player = ((IEnumerable<Player>)Player.GetAllPlayers()).FirstOrDefault((Func<Player, bool>)((Player p) => Object.op_Implicit((Object)(object)p) && p.GetPlayerID() == actor && ((Character)p).GetOwner() == sender)); GameObject root = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(val) : null); ZNetView view = (Object.op_Implicit((Object)(object)root) ? root.GetComponent<ZNetView>() : null); int num = completed.Resolve(id, delegate { //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Expected O, but got Unknown int result3 = 1; if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)root) || !Object.op_Implicit((Object)(object)root.GetComponent<Ship>()) || !Object.op_Implicit((Object)(object)view) || !view.IsValid() || !view.IsOwner() || view.GetZDO().GetBool(Packing.Locked, false) || view.GetZDO().GetBool("AB_PP_boat_transfer_review", false)) { return result3; } zdo = view.GetZDO(); revision = zdo.DataRevision; if (kind == 0 && op >= 1 && op <= 6) { Component component = root.GetComponent(rig); if (Object.op_Implicit((Object)(object)component)) { result3 = ((!(bool)AccessTools.Method(kit, "Apply", (Type[])null, (Type[])null).Invoke(null, new object[6] { component, zdo, op, arg, paid, skill })) ? 1 : 0); } } else if (kind == 1 && op == 7 && (bool)AccessTools.Property(yard, "On").GetValue(null, null)) { Component component2 = root.GetComponent(fitted); object[] parameters = new object[4] { component2, text2, paid, null }; if (Object.op_Implicit((Object)(object)component2)) { result3 = ((!(bool)AccessTools.Method(yard, "ApplyRefit", (Type[])null, (Type[])null).Invoke(null, parameters)) ? 1 : 0); } } else if (kind == 1 && (op == 8 || op == 9) && (bool)AccessTools.Property(combat, "On").GetValue(null, null)) { Component component3 = root.GetComponent(fitted); if (Object.op_Implicit((Object)(object)component3)) { ZPackage val2 = new ZPackage(); val2.Write(op); val2.Write(arg); val2.Write(b); val2.Write(text2); val2.Write(paid); val2.Write(actor); AccessTools.Method(fitted, "OnRpc", (Type[])null, (Type[])null).Invoke(component3, new object[2] { sender, val2 }); result3 = 0; } } return result3; }); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "AB_PP_BoatOfferReply_v1", new object[2] { text, num }); } catch (Exception ex) { int result2; int num2 = (completed.TryGet(sender + ":" + text, out result2) ? result2 : ((zdo == null || zdo.DataRevision == revision) ? 1 : 2)); if (num2 == 2) { zdo.Set("AB_PP_boat_transfer_review", true); } Plugin.Log.LogError((object)("Boat upgrade transfer failed: " + ex)); if (text.Length == 32) { completed.RememberFailure(sender + ":" + text, num2); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "AB_PP_BoatOfferReply_v1", new object[2] { text, num2 }); } } } private static void Result(long sender, string id, int outcome) { if (!tickets.TryOwner(id, sender, out var payload)) { return; } if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || Player.m_localPlayer.GetPlayerID() != payload.Player) { deferred[id] = Tuple.Create(sender, outcome); return; } deferred.Remove(id); switch (outcome) { case 2: Plugin.Notify(Player.m_localPlayer, "Boat upgrade needs review; see the log. No duplicate refund issued."); return; default: if (outcome != 1) { return; } break; case 0: break; } if (!tickets.TryTake(id, sender, Player.m_localPlayer.GetPlayerID(), out payload)) { return; } try { Refund(payload, sender, outcome); } catch (Exception ex) { Plugin.Log.LogError((object)("Boat refund callback failed; payment ticket is already claimed and will not refund twice: " + ex)); } } internal static void Poll() { if (Plugin.Ready) { Register(); } if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && deferred.Count != 0) { KeyValuePair<string, Tuple<long, int>>[] array = deferred.ToArray(); for (int i = 0; i < array.Length; i++) { KeyValuePair<string, Tuple<long, int>> keyValuePair = array[i]; Result(keyValuePair.Value.Item1, keyValuePair.Key, keyValuePair.Value.Item2); } } } private static void Refund(Ticket ticket, long sender, int outcome) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown ZPackage val = new ZPackage(); if (ticket.Kind == 0) { if (outcome == 1 && ticket.Paid.Length != 0) { val.Write(ticket.Paid); AccessTools.Method(kit, "OnRefused", (Type[])null, (Type[])null).Invoke(null, new object[3] { null, sender, val }); } } else { val.Write((outcome == 1) ? 1 : 2); val.Write((outcome == 1) ? "shipyard_refused" : ""); val.Write((outcome == 1) ? ticket.Paid : ""); AccessTools.Method(yard, "OnReply", (Type[])null, (Type[])null).Invoke(null, new object[2] { sender, val }); } } } [HarmonyPatch(typeof(Hud), "SetupPieceInfo")] internal static class BuildHudPatch { [HarmonyPriority(0)] private static void Postfix(Hud __instance, Piece piece) { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.Ready || !Object.op_Implicit((Object)(object)piece) || !Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return; } ItemData val = Building.Find(Player.m_localPlayer, piece); if (val == null) { return; } GameObject[] requirementItems = __instance.m_requirementItems; foreach (GameObject val2 in requirementItems) { val2.SetActive(false); } if (__instance.m_requirementItems.Length != 0) { GameObject val3 = __instance.m_requirementItems[0]; val3.SetActive(true); Image component = ((Component)val3.transform.Find("res_icon")).GetComponent<Image>(); TMP_Text component2 = ((Component)val3.transform.Find("res_name")).GetComponent<TMP_Text>(); TMP_Text component3 = ((Component)val3.transform.Find("res_amount")).GetComponent<TMP_Text>(); component.sprite = val.GetIcon(); ((Graphic)component).color = Color.white; component2.text = Localization.instance.Localize(val.m_shared.m_name); component3.text = "1"; ((Graphic)component3).color = Color.white; UITooltip component4 = val3.GetComponent<UITooltip>(); if (Object.op_Implicit((Object)(object)component4)) { component4.m_text = val.GetTooltip(-1); component4.m_topic = val.m_shared.m_name; } TMP_Text pieceDescription = __instance.m_pieceDescription; pieceDescription.text += "\n<color=#e8c56a>Uses 1 packed structure. No loose materials or workbench needed.</color>"; } } } internal static class Building { internal sealed class Transaction { internal Player Player; internal Piece Piece; internal ItemData Item; internal PackedState State; internal readonly PackagePlacement<GameObject> Placement = new PackagePlacement<GameObject>(); internal GameObject Spawned => Placement.Spawned; internal bool Committed => Placement.Committed; } internal static ItemData Preferred; internal static Transaction Active; private static readonly BuildCostReceipt Paid = new BuildCostReceipt(); private static readonly HashSet<string> RequirementFailures = new HashSet<string>(); internal static ItemData Find(Player p, Piece piece) { string prefab = Registry.Canonical(((Object)piece).name); PackedState state; return PackageSelection.Find(((Humanoid)p).GetInventory().GetAllItems(), Preferred, (ItemData item) => PackageStacking.CanDeploy(item) && Registry.Read(item, out state) && state.Prefab == prefab); } internal static bool HaveBuildRequirements(Player player, Piece piece, RequirementMode mode) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Ready && (Object)(object)player == (Object)(object)Player.m_localPlayer && Find(player, piece) != null) { return string.IsNullOrEmpty(piece.m_dlc) || DLCMan.instance.IsDLCInstalled(piece.m_dlc); } bool flag = player.HaveRequirements(piece, mode); if (!flag && Plugin.Ready && (Object)(object)player == (Object)(object)Player.m_localPlayer) { ItemData[] array = ((Humanoid)player).GetInventory().GetAllItems().Where(Registry.IsBundle) .ToArray(); if (array.Length != 0) { PackedState state; string text = "Selected " + Registry.Canonical(((Object)piece).name) + "; inventory packages: " + string.Join(", ", array.Select((ItemData item) => Registry.Read(item, out state) ? state.Prefab : ("invalid package (stack " + item.m_stack + ")"))); if (RequirementFailures.Add(text)) { Plugin.Log.LogWarning((object)("Build requirements not met. " + text)); } } } return flag; } internal static bool Begin(Player player, Piece piece, out Transaction transaction) { transaction = null; if (!Plugin.Ready || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return true; } if (Active != null) { return false; } Paid.Clear(); ItemData val = Find(player, piece); if (val == null || !Registry.Read(val, out var state)) { bool flag = player.NoCostCheat() || player.HaveRequirements(piece, (RequirementMode)0); if (!flag) { Plugin.Tell(player, "No matching packed structure or sufficient building materials."); } return flag; } Active = (transaction = new Transaction { Player = player, Piece = piece, Item = val, State = state }); return true; } private static bool HasPayment(Transaction transaction) { PackedState state; return ((Humanoid)transaction.Player).GetInventory().ContainsItem(transaction.Item) && PackageStacking.CanDeploy(transaction.Item) && Registry.Read(transaction.Item, out state) && state.InstanceId == transaction.State.InstanceId && state.Encode() == transaction.State.Encode(); } internal static GameObject Spawn(GameObject prefab, Vector3 position, Quaternion rotation) { //IL_000e: 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_0015: 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_003b: 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) Transaction transaction = Active; if (transaction == null) { return Object.Instantiate<GameObject>(prefab, position, rotation); } if (Registry.Canonical(((Object)prefab).name) != transaction.State.Prefab) { throw new InvalidOperationException("The spawned prefab does not match the selected package."); } return transaction.Placement.Spawn(() => HasPayment(transaction), () => Object.Instantiate<GameObject>(prefab, position, rotation), delegate(GameObject spawned) { Registry.Apply(spawned, transaction.State); }); } internal static void Complete(Transaction transaction, ref bool success) { if (transaction == null) { return; } if (transaction.Placement.Finished) { success = transaction.Committed; return; } try { success = transaction.Placement.Complete(success && Object.op_Implicit((Object)(object)transaction.Spawned), () => HasPayment(transaction), () => ((Humanoid)transaction.Player).GetInventory().RemoveOneItem(transaction.Item), DestroySpawned); if (success) { try { ExtensionAdapters.FinishRestore(transaction.Spawned, committed: true); } catch (Exception ex) { Plugin.Log.LogError((object)("Placement committed; linked tracking cleanup failed: " + ex)); } Paid.Record(transaction.Player, transaction.Piece.m_resources, Time.frameCount); DeploymentInventoryUi.ClearPackageHover(); if (Preferred == transaction.Item && !((Humanoid)transaction.Player).GetInventory().ContainsItem(transaction.Item)) { Preferred = null; } } } finally { if (Active == transaction) { Active = null; } } } internal static void Rollback(Transaction transaction) { transaction?.Placement.Rollback(DestroySpawned); if (Active == transaction) { Active = null; } } private static void DestroySpawned(GameObject spawned) { if (Object.op_Implicit((Object)(object)spawned) && Object.op_Implicit((Object)(object)ZNetScene.instance)) { try { ExtensionAdapters.FinishRestore(spawned, committed: false); } finally { ZNetScene.instance.Destroy(spawned); } } } internal static void ConsumeBuildCost(Player player, Requirement[] resources, int qualityLevel, int itemQuality, int multiplier) { if (!Paid.TryUse(player, resources, Time.frameCount)) { player.ConsumeResources(resources, qualityLevel, itemQuality, multiplier); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ScenePatch { [HarmonyPriority(0)] private static void Postfix(ZNetScene __instance) { if (!Plugin.Ready) { return; } try { Registry.Register(__instance); Packing.EnsureReplies(); BoatTransfers.Register(); } catch (Exception ex) { Plugin.Ready = false; Plugin.DisabledReason = "Prefab registration failed: " + ex.Message; Plugin.Log.LogError((object)("Prefab registration failed; mod disabled. " + ex)); } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class DatabaseAwakePatch { [HarmonyPriority(0)] private static void Postfix() { if (Plugin.Ready && Object.op_Implicit((Object)(object)ZNetScene.instance)) { Registry.Register(ZNetScene.instance); } } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class DatabaseCopyPatch { [HarmonyPriority(0)] private static void Postfix() { if (Plugin.Ready && Object.op_Implicit((Object)(object)ZNetScene.instance)) { Registry.Register(ZNetScene.instance); } } } [HarmonyPatch(typeof(Piece), "Awake")] internal static class PiecePatch { private static void Postfix(Piece __instance) { Packing.Register(__instance); } } [HarmonyPatch(typeof(ZNetView), "Awake")] internal static class PieceNetworkReadyPatch { private static void Postfix(ZNetView __instance) { Piece component = ((Component)__instance).GetComponent<Piece>(); if (Object.op_Implicit((Object)(object)component)) { Packing.Register(component); } } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] internal static class RequirementPatch { [HarmonyPriority(0)] private static void Postfix(Player __instance, Piece piece, RequirementMode mode, ref bool __result) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between Unknown and I4 if (Plugin.Ready && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && (int)mode != 1 && Building.Find(__instance, piece) != null) { __result = string.IsNullOrEmpty(piece.m_dlc) || DLCMan.instance.IsDLCInstalled(piece.m_dlc); } } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] internal static class TryPlacePatch { [HarmonyPriority(0)] private static bool Prefix(Player __instance, Piece piece, out Building.Transaction __state, ref bool __result) { bool flag = Building.Begin(__instance, piece, out __state); if (!flag) { __result = false; } return flag; } [HarmonyPriority(0)] private static void Postfix(Building.Transaction __state, ref bool __result) { Building.Complete(__state, ref __result); } private static Exception Finalizer(Exception __exception, Building.Transaction __state) { if (__exception != null && __state != null) { Building.Rollback(__state); Plugin.Log.LogError((object)("Packed placement encountered an exception. Committed=" + __state.Committed + ". " + __exception)); Plugin.Tell(__state.Player, "Cannot restore this structure or its stored items. Package kept; see BepInEx log for details."); } return __exception; } } [HarmonyPatch(typeof(Player), "PlacePiece")] internal static class SpawnPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = instructions.ToList(); int num = 0; foreach (CodeInstruction item in list) { if (item.operand is MethodInfo methodInfo && methodInfo.DeclaringType == typeof(Object) && methodInfo.Name == "Instantiate" && methodInfo.IsGenericMethod && methodInfo.GetGenericArguments()[0] == typeof(GameObject) && (from p in methodInfo.GetParameters() select p.ParameterType).SequenceEqual(new Type[3] { typeof(GameObject), typeof(Vector3), typeof(Quaternion) })) { item.opcode = OpCodes.Call; item.operand = AccessTools.Method(typeof(Building), "Spawn", (Type[])null, (Type[])null); num++; } } if (num != 1) { throw new InvalidOperationException("Expected exactly one PlacePiece Instantiate call, found " + num); } return list; } } [HarmonyPatch(typeof(Player), "UpdatePlacement")] internal static class CostPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { MethodInfo methodInfo = AccessTools.Method(typeof(Player), "ConsumeResources", (Type[])null, (Type[])null); MethodInfo operand = AccessTools.Method(typeof(Building), "ConsumeBuildCost", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(Player), "HaveRequirements", new Type[2] { typeof(Piece), typeof(RequirementMode) }, (Type[])null); MethodInfo operand2 = AccessTools.Method(typeof(Building), "HaveBuildRequirements", (Type[])null, (Type[])null); List<CodeInstruction> list = instructions.ToList(); int num = 0; int num2 = 0; foreach (CodeInstruction item in list) { if (CodeInstructionExtensions.Calls(item, methodInfo)) { item.opcode = OpCodes.Call; item.operand = operand; num++; } else if (CodeInstructionExtensions.Calls(item, methodInfo2)) { item.opcode = OpCodes.Call; item.operand = operand2; num2++; } } if (num != 1) { throw new InvalidOperationException("Expected exactly one UpdatePlacement build-cost call, found " + num); } if (num2 != 1) { throw new InvalidOperationException("Expected exactly one UpdatePlacement requirement check, found " + num2); } return list; } } [HarmonyPatch(typeof(Humanoid), "DropItem")] internal static class DropPatch { private static bool Prefix(Humanoid __instance, Inventory inventory, ItemData item, int amount, ref bool __result) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown if (!Plugin.Ready || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Registry.IsBundle(item) || !InventoryGui.IsVisible()) { return true; } if (inventory != null && inventory != __instance.GetInventory()) { return true; } if (Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303)) { return true; } __result = amount > 0 && Plugin.BeginPlacement((Player)__instance, inventory ?? __instance.GetInventory(), item); return false; } } [HarmonyPatch(typeof(Humanoid), "UseItem")] internal static class UsePatch { private static bool Prefix(Humanoid __instance, Inventory inventory, ItemData item) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown if (!Plugin.Ready || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Registry.IsBundle(item)) { return true; } if (InventoryGui.IsVisible() && ContentsPanel.InspectRequested()) { ContentsPanel.Open(inventory ?? __instance.GetInventory(), item); return false; } Plugin.BeginPlacement((Player)__instance, inventory ?? __instance.GetInventory(), item); return false; } } [HarmonyPatch(typeof(ItemDrop), "CanPickup")] internal static class PickupPatch { private static bool Prefix(ItemDrop __instance, ref bool __result) { ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && component.IsValid() && component.GetZDO().GetBool(Packing.Staged, false)) { __result = false; return false; } return true; } } [HarmonyPatch(typeof(ItemData), "GetWeight")] internal static class WeightPatch { private static void Postfix(ItemData __instance, int stackOverride, ref float __result) { if (Registry.Read(__instance, out var state)) { __result = state.Weight * (float)((stackOverride < 0) ? __instance.m_stack : stackOverride); } } } [HarmonyPatch(typeof(ItemData), "GetNonStackedWeight")] internal static class SingleWeightPatch { private static void Postfix(ItemData __instance, ref float __result) { if (Registry.Read(__instance, out var state)) { __result = state.Weight; } } } [HarmonyPatch(typeof(Inventory), "IsTeleportable", new Type[] { typeof(bool) })] internal static class TeleportPatch { [HarmonyPriority(800)] private static void Postfix(Inventory __instance, bool allowAllItems, ref bool __result) { PackagePortal.Evaluate(__instance, allowAllItems, ref __result); } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(int) })] internal static class TooltipPatch { private static void Postfix(ItemData __instance, ref string __result) { if (!Registry.IsBundle(__instance)) { return; } if (!Registry.Read(__instance, out var state)) { __result += "\n<color=red>Invalid packed data. Deployment disabled; item kept.</color>"; return; } string text = state.Tag.Replace("<", "").Replace(">", ""); __result = __result + "\n\n<color=#e8c56a>Packed structure</color>\nHealth: " + (state.Health * 100f).ToString("0") + "%"; if (!string.IsNullOrEmpty(text)) { __result = __result + "\nPortal tag: " + text; } __result = __result + "\nPackage weight: " + state.Weight.ToString("0.##") + "\nMaterial weight: " + state.CarriedMaterialWeight.ToString("0.##") + "\nContents weight: " + state.CarriedContentsWeight.ToString("0.##") + "\nStored inventory stacks: " + state.Inventories.Sum((StoredInventory i) => i.ItemCount) + "\nMaterials:"; if (__instance.m_stack > 1) { __result = __result + "\nPackages in stack: " + __instance.m_stack + " | Total weight: " + (state.Weight * (float)__instance.m_stack).ToString("0.##"); } foreach (MaterialCost material in state.Materials) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(material.Prefab); string text2 = (Object.op_Implicit((Object)(object)itemPrefab) ? Localization.instance.Localize(itemPrefab.GetComponent<ItemDrop>().m_itemData.m_shared.m_name) : material.Prefab); __result = __result + "\n " + material.Amount + " x " + text2; } __result += "\nCtrl + right-click: package details and salvage refunds\nDrag out or use: place with hammer\nShift + drag out: drop for trading"; } } internal static class Cargo { internal const string NestedReason = "Cannot pack: this storage contains a packed package. Remove it first; nested packages allow recursive storage and repeated weight reductions."; internal static bool IsPackage(ItemData item) { return Registry.IsBundle(item) || (item?.m_customData.ContainsKey("arcbyte.packandplace.v1") ?? false); } private static object Call(object target, string method, params object[] args) { return AccessTools.Method(target.GetType(), method, args.Select((object a) => a.GetType()).ToArray(), (Type[])null).Invoke(target, args); } private static void AddWeight(PackedState state, ItemData item, float amount) { if (IsPackage(item)) { throw new InvalidDataException("Cannot pack: this storage contains a packed package. Remove it first; nested packages allow recursive storage and repeated weight reductions."); } state.ContentsWeight += item.GetWeight(1) * amount; state.ContentsTeleportable &= item.m_shared.m_teleportable; PackagePortal.Include(state.PortalItems, item, amount, state.SalvageCounts); state.Cheated |= item.m_cheated; } private static ItemData Item(string name) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(name); ItemDrop val = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent<ItemDrop>() : null); if (!Object.op_Implicit((Object)(object)val)) { throw new InvalidDataException("A stored item prefab is unavailable: " + name); } if (IsPackage(val.m_itemData)) { throw new InvalidDataException("Cannot pack: this storage contains a packed package. Remove it first; nested packages allow recursive storage and repeated weight reductions."); } return val.m_itemData; } internal static ItemData StoredTemplate(int hash) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(hash); ItemDrop val = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent<ItemDrop>() : null); if (!Object.op_Implicit((Object)(object)val)) { return null; } ItemData val2 = val.m_itemData.Clone(); val2.m_dropPrefab = itemPrefab; return val2; } internal static void Capture(Piece piece, PackedState state) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown Container[] componentsInChildren = ((Component)piece).GetComponentsInChildren<Container>(true); foreach (Container val in componentsInChildren) { Inventory inventory = val.GetInventory(); foreach (ItemData allItem in inventory.GetAllItems()) { AddWeight(state, allItem, allItem.m_stack); } ZPackage val2 = new ZPackage(); inventory.Save(val2); StoredInventory storedInventory = new StoredInventory { Data = val2.GetBase64(), Width = inventory.GetWidth(), Height = inventory.GetHeight(), ItemCount = inventory.NrOfItems() }; List<ItemData> source = InventorySnapshot.Decode(storedInventory, StoredTemplate, IsPackage); if (!(from val5 in inventory.GetAllItems() select val5.m_stack).SequenceEqual(source.Select((ItemData val5) => val5.m_stack))) { throw new InvalidDataException("A stored stack cannot round-trip through the game's item serializer."); } state.Inventories.Add(storedInventory); } ZDO zDO = ((Component)piece).GetComponent<ZNetView>().GetZDO(); Smelter component = ((Component)piece).GetComponent<Smelter>(); Fermenter component2 = ((Component)piece).GetComponent<Fermenter>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component2)) { throw new InvalidDataException("Multiple machine adapters on one object are unsupported."); } if (Object.op_Implicit((Object)(object)component)) { MachineState obj = new MachineState { Kind = "Smelter", Fuel = (float)Call(component, "GetFuel"), BakeTimer = (float)Call(component, "GetBakeTimer"), Accumulator = (float)Call(component, "GetAccumulator"), Output = zDO.GetString(ZDOVars.s_spawnOre, ""), OutputCount = zDO.GetInt(ZDOVars.s_spawnAmount, 0), CheatedQueued = zDO.GetInt(ZDOVars.s_cheatedQueued, 0), Cheated = zDO.GetInt(ZDOVars.s_cheated, 0) }; MachineState machineState = obj; state.Machine = obj; MachineState machine = machineState; int num = (int)Call(component, "GetQueueSize"); if (num < 0 || num > 4096) { throw new InvalidDataException("Machine queue is too large to pack."); } for (int num2 = 0; num2 < num; num2++) { string text = zDO.GetString(StringExtensionMethods.GetStableHashCode("item" + num2), ""); if (!(bool)Call(component, "IsItemAllowed", text)) { throw new InvalidDataException("Unsupported machine input."); } machine.Queue.Add(text); AddWeight(state, Item(text), 1f); } if (machine.Fuel > 0f) { if (!Object.op_Implicit((Object)(object)component.m_fuelItem)) { throw new InvalidDataException("Machine fuel item is unavailable."); } AddWeight(state, component.m_fuelItem.m_itemData, machine.Fuel); } if (machine.OutputCount > 0) { ItemConversion val3 = ((IEnumerable<ItemConversion>)component.m_conversion).FirstOrDefault((Func<ItemConversion, bool>)((ItemConversion c) => Object.op_Implicit((Object)(object)c.m_from) && ((Object)c.m_from).name == machine.Output)); if (val3 == null || !Object.op_Implicit((Object)(object)val3.m_to)) { throw new InvalidDataException("Unsupported pending machine output."); } AddWeight(state, val3.m_to.m_itemData, machine.OutputCount); } } if (!Object.op_Implicit((Object)(object)component2)) { return; } int content = (int)Call(component2, "GetContent"); state.Machine = new MachineState { Kind = "Fermenter", Content = content, Cheated = zDO.GetInt(ZDOVars.s_cheated, 0), Elapsed = ((content == 0) ? 0.0 : Math.Min(component2.m_fermentationDuration, Math.Max(0.0, (double)Call(component2, "GetFermentationTime")))) }; if (content != 0) { ItemConversion val4 = ((IEnumerable<ItemConversion>)component2.m_conversion).FirstOrDefault((Func<ItemConversion, bool>)((ItemConversion c) => Object.op_Implicit((Object)(object)c.m_from) && StringExtensionMethods.GetStableHashCode(((Object)c.m_from).name) == content)); if (val4 == null) { throw new InvalidDataException("Unsupported fermenter contents."); } AddWeight(state, val4.m_from.m_itemData, 1f); } } internal static void Apply(GameObject placed, PackedState state) { Container[] componentsInChildren = placed.GetComponentsInChildren<Container>(true); if (state.Inventories.Count != 0 && componentsInChildren.Length != state.Inventories.Count) { throw new InvalidDataException("Storage layout has changed. Package kept."); } List<ItemData>[] array = new List<ItemData>[state.Inventories.Count]; for (int i = 0; i < state.Inventories.Count; i++) { StoredInventory saved = state.Inventories[i]; Inventory inventory = componentsInChildren[i].GetInventory(); InventorySnapshot.ValidateDestination(saved, inventory.GetWidth(), inventory.GetHeight()); array[i] = InventorySnapshot.Decode(saved, StoredTemplate, IsPackage); } for (int j = 0; j < array.Length; j++) { Inventory inventory2 = componentsInChildren[j].GetInventory(); InventorySnapshot.Replace(inventory2.GetAllItems(), array[j]); Call(inventory2, "Changed", false, false); Call(componentsInChildren[j], "Save"); } MachineState machine = state.Machine; if (machine == null) { return; } ZDO zDO = placed.GetComponent<ZNetView>().GetZDO(); zDO.Set(ZDOVars.s_cheated, machine.Cheated, false); if (machine.Kind == "Smelter") { Smelter smelter = placed.GetComponent<Smelter>(); if (!Object.op_Implicit((Object)(object)smelter) || machine.Queue.Any((string ore) => !(bool)Call(smelter, "IsItemAllowed", ore))) { throw new InvalidDataException("Machine inputs have changed. Package kept."); } foreach (string item in machine.Queue) { Item(item); Call(smelter, "QueueOre", item, false); } if (machine.Fuel > 0f && !Object.op_Implicit((Object)(object)smelter.m_fuelItem)) { throw new InvalidDataException("Machine fuel has changed."); } if (machine.OutputCount > 0 && !smelter.m_conversion.Any((ItemConversion c) => Object.op_Implicit((Object)(object)c.m_from) && ((Object)c.m_from).name == machine.Output && Object.op_Implicit((Object)(object)c.m_to))) { throw new InvalidDataException("Machine output has changed."); } Call(smelter, "SetFuel", machine.Fuel); Call(smelter, "SetBakeTimer", machine.BakeTimer); Call(smelter, "SetAccumulator", machine.Accumulator); zDO.Set(ZDOVars.s_spawnOre, machine.Output); zDO.Set(ZDOVars.s_spawnAmount, machine.OutputCount, false); zDO.Set(ZDOVars.s_cheatedQueued, machine.CheatedQueued, false); zDO.Set(ZDOVars.s_startTime, ZNet.instance.GetTime().Ticks); } else { Fermenter component = placed.GetComponent<Fermenter>(); if (!Object.op_Implicit((Object)(object)component) || (machine.Content != 0 && !component.m_conversion.Any((ItemConversion c) => Object.op_Implicit((Object)(object)c.m_from) && StringExtensionMethods.GetStableHashCode(((Object)c.m_from).name) == machine.Content))) { throw new InvalidDataException("Fermenter recipe has changed. Package kept."); } zDO.Set(ZDOVars.s_content, machine.Content, false); zDO.Set(ZDOVars.s_startTime, (machine.Content == 0) ? 0 : ZNet.instance.GetTime().AddSeconds(0.0 - machine.Elapsed).Ticks); } } } internal static class CompatibilityAudit { private static string previous; private static string lastError; private static readonly HashSet<string> RuntimeReported = new HashSet<string>(); internal static CompatibilityRow Describe(Piece piece, IEnumerable<string> reasons) { CompatibilityRow compatibilityRow = new CompatibilityRow { Prefab = Registry.Canonical(((Object)piece).name), Name = piece.m_name }; compatibilityRow.Blockers.AddRange(reasons); MonoBehaviour[] componentsInChildren = ((Component)piece).GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val)) { Type type = ((object)val).GetType(); AssemblyName name = type.Assembly.GetName(); compatibilityRow.Components.Add(type.FullName + ", " + name.Name + ", " + name.Version); } } return compatibilityRow; } internal static void Write(IList<CompatibilityRow> rows) { string text = "# PackAndPlace 0.5.10 registered build-piece audit\n# Eligible means component/shape checks passed; ownership, busy state, payload/config and restore checks still apply.\n# Registered extension adapters: " + string.Join(" | ", ExtensionAdapters.DescribeRegistered()) + "\n# Optional integrations: " + CompatibilityText.Cell(string.Join(" | ", OptionalModAdapters.Diagnostics)) + "\n" + CompatibilityText.Format(rows); if (text == previous) { return; } try { string text2 = Path.Combine(Paths.ConfigPath, "ArcByte.PackAndPlace.compatibility.tsv"); Directory.CreateDirectory(Paths.ConfigPath); File.WriteAllText(text2, text); previous = text; Plugin.Log.LogInfo((object)("Packing compatibility audit: " + rows.Count((CompatibilityRow r) => r.Blockers.Count == 0) + " eligible, " + rows.Count((CompatibilityRow r) => r.Blockers.Count > 0) + " blocked build pieces. Full report: " + text2)); } catch (Exception e) { ReportError(e); } } internal static void RuntimeRefusal(Piece piece, string reason) { string text = (Object.op_Implicit((Object)(object)piece) ? Registry.Canonical(((Object)piece).name) : "<missing>"); string item = text + "\t" + reason; if (RuntimeReported.Count >= 512 || !RuntimeReported.Add(item)) { return; } try { string path = Path.Combine(Paths.ConfigPath, "ArcByte.PackAndPlace.runtime-blockers.tsv"); Directory.CreateDirectory(Paths.ConfigPath); if (!File.Exists(path)) { File.WriteAllText(path, "UTC\tPrefab\tReason\n"); } File.AppendAllText(path, DateTime.UtcNow.ToString("O") + "\t" + CompatibilityText.Cell(text) + "\t" + CompatibilityText.Cell(reason) + "\n"); } catch (Exception e) { ReportError(e); } } private static void ReportError(Exception e) { if (!(lastError == e.Message)) { lastError = e.Message; Plugin.Log.LogWarning((object)("Could not write compatibility diagnostics: " + e.Message)); } } } internal sealed class CompatibilityRow { internal string Prefab; internal string Name; internal readonly List<string> Blockers = new List<string>(); internal readonly List<string> Components = new List<string>(); } internal static class CompatibilityText { internal static string Cell(string value) { return (value ?? "").Replace("\t", " ").Replace("\r", " ").Replace("\n", " "); } internal static string Format(IEnumerable<CompatibilityRow> rows) { StringBuilder stringBuilder = new StringBuilder("Prefab\tName\tStatus\tBlocker count\tAll blockers\tComponents (type, assembly, version)\n"); foreach (CompatibilityRow item in rows.OrderBy<CompatibilityRow, string>((CompatibilityRow r) => r.Prefab, StringComparer.Ordinal)) { stringBuilder.Append(Cell(item.Prefab)).Append('\t').Append(Cell(item.Name)) .Append('\t') .Append((item.Blockers.Count == 0) ? "Eligible" : "Blocked") .Append('\t') .Append(item.Blockers.Count) .Append('\t') .Append(Cell(string.Join(" | ", item.Blockers.Distinct()))) .Append('\t') .Append(Cell(string.Join(" | ", item.Components.Distinct().OrderBy<string, string>((string c) => c, StringComparer.Ordinal)))) .Append('\n'); } return stringBuilder.ToString(); } } internal static class ComponentPolicy { private static readonly HashSet<string> Plain = new HashSet<string> { "Piece", "WearNTear", "ZNetView", "Container", "StaticPhysics", "LODGroup", "LodFade", "LodGroup", "MaterialVariation", "RandomRotation", "WindmillPropeller", "Billboard", "Wind", "WindLod", "LightFlicker", "MeshLod", "SnapToGround", "Smelter", "Fermenter", "Vagon", "Switch", "SmokeSpawner", "Windmill", "CraftingStation", "StationExtension", "CookingStation", "Fireplace", "Door", "Sign", "Bed", "PrivateArea", "ItemStand", "ArmorStand", "Beehive", "SapCollector", "Plant", "Turret", "Trap", "Destructible", "Chair" }; private static readonly HashSet<string> Stateful = new HashSet<string> { "Pickable", "Feast", "Incinerator", "Oven", "Sadle", "Tameable", "Character", "TerrainModifier", "TerrainOp" }; private static readonly HashSet<string> Recreated = new HashSet<string> { "RandomPieceRotation", "AutoJumpLedge", "Ledge", "EffectArea", "LightLod", "ZSFX", "GuidePoint", "Demister", "HoverText", "LodFadeInOut", "Barber", "CircleProjector" }; private static readonly HashSet<string> MidgardVisuals = new HashSet<string> { "MidgardPlus.Content.BrightLight", "MidgardPlus.Content.UnderwaterMark", "MidgardPlus.Content.UnderwaterHalo", "MidgardPlus.Content.FxLamp", "MidgardPlus.Content.InstancedLook", "MidgardPlus.Content.EnchantTableGlow", "MidgardPlus.Content.PenMarker", "MidgardPlus.Content.CartRig", "MidgardPlus.Content.VetrBase", "MidgardPlus.Content.VetrSpirit", "MidgardPlus.Content.VetrFlicker", "MidgardPlus.Content.VetrCauldron", "MidgardPlus.Content.PaintTableStand", "MidgardPlus.Content.PortalGlow", "MidgardPlus.Content.VetrWatch" }; internal static string Rejection(string fullName, string assemblyName, bool gameAssembly, bool special) { if (assemblyName == "assembly_valheim" && Recreated.Contains(fullName)) { return null; } if (assemblyName == "assembly_utils" && fullName == "TriggerTracker") { return null; } if (assemblyName == "MidgardPlus" && MidgardVisuals.Contains(fullName)) { return null; } if (fullName == "SoftReferenceableAssets.ReferenceHolder" && assemblyName == "SoftReferenceableAssets") { return null; } if (fullName == "SimpleMeshCombine" && assemblyName == "assembly_simplemeshcombine") { return null; } if (fullName == "MaterialManNotifier" && assemblyName == "assembly_valheim") { return null; } if (fullName == "MidgardPlus.Content.AddedSnapPoint" && assemblyName == "MidgardPlus") { return null; } if (assemblyName == "MidgardPlus" && (fullName == "MidgardPlus.Content.TroughLook" || fullName == "MidgardPlus.Content.CompanionFeederLook")) { return null; } if (fullName == "BaseFood.TrackedStructure" && assemblyName == "BaseFood") { return null; } if (assemblyName == "EpicLoot" && (fullName == "EpicLoot_UnityLib.FeatureStatus3D" || fullName == "EpicLoot_UnityLib.SetRarityColor")) { return null; } if (fullName == "DrakkarLantern.LanterneDeProue" && assemblyName == "DrakkarLantern") { return null; } if (fullName == "RavenwoodCurrency.TableChestInteract" && assemblyName == "RavenwoodCurrency") { return null; } if (fullName == "RavenwoodCurrency.ChestLidAnimation" && assemblyName == "RavenwoodCurrency") { return null; } if (fullName == "SpiritStorage.SpiritStorageContainer" && assemblyName == "SpiritStorage") { return "Spirit Storage's item ledger and transfer protocol need a dedicated adapter; copying only the structure could lose stored items."; } if (fullName == "OdinArchitect.MultiFloorElevator" && assemblyName == "OdinArchitect") { return "This elevator's moving-platform and track relationships need a coordinated structure adapter."; } if (fullName == "PocketTent.TentEntrance" && assemblyName == "PocketTent") { return "The pocket tent's interior/destination links need a coordinated adapter."; } if (fullName == "EverlastingSeedBed.BedBehaviour" && assemblyName == "EverlastingSeedBed") { return "EverlastingSeedBed's saved replanting program needs its own adapter; it is distinct from SeedBed germination."; } if (assemblyName == "Unity.TextMeshPro") { switch (fullName) { default: if (!(fullName == "TMPro.TMP_SubMeshUI")) { break; } goto case "TMPro.TextMeshPro"; case "TMPro.TextMeshPro": case "TMPro.TextMeshProUGUI": case "TMPro.TMP_SubMesh": return null; } } string item = fullName.Substring(fullName.LastIndexOf('.') + 1); if (Stateful.Contains(item)) { return "State preservation is not implemented for component " + fullName + "."; } bool flag = fullName.StartsWith("UnityEngine.", StringComparison.Ordinal); if (!gameAssembly && !flag) { return "Unknown mod component " + fullName + " (" + assemblyName + ")."; } if (!special && !flag && !Plain.Contains(item)) { return "Unsupported component " + fullName + "."; } return null; } } internal sealed class ConfigChangeGate { private string accepted; private string candidate; private float observedAt; internal void Accept(string stamp) { accepted = stamp; candidate = null; } internal bool Observe(string stamp, float now) { if (stamp == null || stamp == accepted) { candidate = null; return false; } if (stamp != candidate) { candidate = stamp; observedAt = now; return false; } return now - observedAt >= 0.25f; } } internal sealed class FoodBarrelAdapter : IExtensionAdapter { private readonly Type category; public string Id => "compat.midgardplus.foodbarrel"; public int Version => 1; public Type ComponentType { get; } internal FoodBarrelAdapter(Type type) { ComponentType = type; category = AccessTools.Field(type, "m_kind")?.FieldType; if (category == null || !category.IsEnum) { throw new InvalidOperationException("Food barrel category API changed."); } } private int Kind(MonoBehaviour c) { return Convert.ToInt32(OptionalModAdapters.Read(c, "m_kind")); } public string CannotPack(MonoBehaviour c) { OptionalModAdapters.State(c); Container component = ((Component)c).GetComponent<Container>(); return (!Object.op_Implicit((Object)(object)component) || component.GetInventory() == null) ? "Food barrel native inventory is unavailable." : (component.IsInUse() ? "Close the food barrel before packing." : null); } public byte[] Capture(MonoBehaviour c, PackageCaptureContext context) { string text = CannotPack(c); if (text != null) { throw new InvalidDataException(text); } byte[] bytes = BitConverter.GetBytes(Kind(c)); ValidateData(1, bytes); return bytes; } public void ValidateData(int version, byte[] data) { if (version != 1 || data == null || data.Length != 4 || !Enum.IsDefined(category, Enum.ToObject(category, BitConverter.ToInt32(data, 0)))) { throw new InvalidDataException("Invalid food barrel category payload."); } } public void ValidateRestore(MonoBehaviour c, int version, byte[] data) { ValidateData(version, data); OptionalModAdapters.State(c); if (!Object.op_Implicit((Object)(object)((Component)c).GetComponent<Container>()) || Kind(c) != BitConverter.ToInt32(data, 0)) { throw new InvalidDataException("Food barrel category or native inventory changed. Package kept."); } } public void Restore(MonoBehaviour c, int version, byte[] data) { ValidateRestore(c, version, data); } } internal sealed class WardrobeAdapter : IExtensionAdapter { private readonly Type wardrobe; public string Id => "compat.midgardplus.wardrobe"; public int Version => 1; public Type ComponentType { get; } internal WardrobeAdapter(Type type) { ComponentType = type; wardrobe = type.Assembly.GetType("MidgardPlus.Content.TransmogWardrobe", throwOnError: true); if (AccessTools.Field(wardrobe, "_spot") == null || AccessTools.Field(wardrobe, "_panel") == null) { throw new InvalidOperationException("Wardrobe UI API changed."); } } public string CannotPack(MonoBehaviour c) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown OptionalModAdapters.State(c); GameObject val = (GameObject)AccessTools.Field(wardrobe, "_panel").GetValue(null); return (Object.op_Implicit((Object)(object)val) && val.activeInHierarchy && AccessTools.Field(wardrobe, "_spot").GetValue(null) == c) ? "Close the wardrobe customization panel before packing." : null; } public byte[] Capture(MonoBehaviour c, PackageCaptureContext context) { string text = CannotPack(c); if (text != null) { throw new InvalidDataException(text); } return new byte[0]; } public void ValidateData(int version, byte[] data) { if (version != 1 || data == null || data.Length != 0) { throw new InvalidDataException("Invalid wardrobe payload."); } } public void ValidateRestore(MonoBehaviour c, int version, byte[] data) { ValidateData(version, data); OptionalModAdapters.State(c); } public void Restore(MonoBehaviour c, int version, byte[] data) { ValidateRestore(c, version, data); } } internal static class ContentsPanel { private sealed class DisplayRow { internal RectTransform Rect; internal Image Background; internal Image Icon; internal TMP_Text Name; internal TMP_Text Detail; internal TMP_Text Amount; internal int Index = -1; } [CompilerGenerated] private static class <>O { public static Func<int, ItemData> <0>__StoredTemplate; public static Func<ItemData, bool> <1>__IsPackage; public static UnityAction <2>__Close; } private static RectTransform root; private static RectTransform viewport; private static RectTransform content; private static ScrollRect scroll; private static TMP_FontAsset font; private static List<PackedContents.Row> entries; private static readonly List<DisplayRow> pool = new List<DisplayRow>(); private static Inventory source; private static ItemData package; private static string encoded; private static int openedStack; private static bool refreshing; private static bool showingRefunds; private static Vector2 screen; private static readonly Color Gold = new Color(0.91f, 0.76f, 0.47f); internal static bool InspectRequested() { return Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305); } internal static void RequestSalvage(Inventory inventory, ItemData item) { PackedState state; string value; if (Plugin.Confirmations.Value) { Open(inventory, item, refunds: true); } else if (Registry.Read(item, out state) && item.m_customData.TryGetValue("arcbyte.packandplace.v1", out value)) { PackageSalvage.Execute(inventory, item, value, Plugin.SalvageMaterialPercent.Value); } } internal static void Open(Inventory inventory, ItemData item, bool refunds = false) { //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_0562: Unknown result type (might be due to invalid IL or missing references) //IL_0567: Unknown result type (might be due to invalid IL or missing references) //IL_0568: Unknown result type (might be due to invalid IL or missing references) //IL_0570: Unknown result type (might be due to invalid IL or missing references) //IL_0572: Unknown result type (might be due to invalid IL or missing references) //IL_0573: Unknown result type (might be due to invalid IL or missing references) //IL_057b: Unknown result type (might be due to invalid IL or missing references) //IL_058f: Unknown result type (might be due to invalid IL or missing references) //IL_05a6: Unknown result type (might be due to invalid IL or missing references) //IL_05d0: Unknown result type (might be due to invalid IL or missing references) //IL_05f7: Unknown result type (might be due to invalid IL or missing references) //IL_0606: Unknown result type (might be due to invalid IL or missing references) //IL_06ce: Unknown result type (might be due to invalid IL or missing references) //IL_075d: Unknown result type (might be due to invalid IL or missing references) //IL_079b: Unknown result type (might be due to invalid IL or missing references) //IL_07ab: Unknown result type (might be due to invalid IL or missing references) //IL_07c5: Unknown result type (might be due to invalid IL or missing references) //IL_07eb: Unknown result type (might be due to invalid IL or missing references) //IL_0830: 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_0854: Unknown result type (might be due to invalid IL or missing references) //IL_086b: Unknown result type (might be due to invalid IL or missing references) //IL_0891: Unknown result type (might be due to invalid IL or missing references) //IL_08d6: Unknown result type (might be due to invalid IL or missing references) //IL_0910: Unknown result type (might be due to invalid IL or missing references) //IL_091f: Unknown result type (might be due to invalid IL or missing references) //IL_0625: Unknown result type (might be due to invalid IL or missing references) //IL_062a: Unknown result type (might be due to invalid IL or missing references) //IL_0630: Expected O, but got Unknown //IL_0989: 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_09c1: 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_0a1d: Unknown result type (might be due to invalid IL or missing references) //IL_0a34: Unknown result type (might be due to invalid IL or missing references) //IL_0a4b: Unknown result type (might be due to invalid IL or missing references) //IL_0a62: Unknown result type (might be due to invalid IL or missing references) //IL_0a8c: Unknown result type (might be due to invalid IL or missing references) //IL_0ab3: Unknown result type (might be due to invalid IL or missing references) //IL_0ac2: Unknown result type (might be due to invalid IL or missing references) //IL_0cb2: Unknown result type (might be due to invalid IL or missing references) //IL_0cc9: Unknown result type (might be due to invalid IL or missing references) //IL_0ce0: Unknown result type (might be due to invalid IL or missing references) //IL_0cf7: Unknown result type (might be due to invalid IL or missing references) //IL_0d14: Unknown result type (might be due to invalid IL or missing references) //IL_0d3b: Unknown result type (might be due to invalid IL or missing references) //IL_0d4a: Unknown result type (might be due to invalid IL or missing references) //IL_0de9: Unknown result type (might be due to invalid IL or missing references) //IL_0df3: Expected O, but got Unknown //IL_0e03: Unknown result type (might be due to invalid IL or missing references) //IL_0e0d: Expected O, but got Unknown InventoryGui instance = InventoryGui.instance; if (!Plugin.Ready || !Object.op_Implicit((Object)(object)instance) || !InventoryGui.IsVisible() || inventory == null || !inventory.ContainsItem(item)) { return; } Close(); if (!Registry.Read(item, out var state)) { Plugin.Tell(Player.m_localPlayer, "This package has invalid data; contents cannot be inspected."); return; } try { Canvas componentInParent = ((Component)instance.m_inventoryRoot).GetComponentInParent<Canvas>(); if (!Object.op_Implicit((Object)(object)componentInParent)) { componentInParent = ((Component)instance).GetComponentInParent<Canvas>(); } if (!Object.op_Implicit((Object)(object)componentInParent)) { throw new InvalidOperationException("Inventory canvas is unavailable."); } font = (Object.op_Implicit((Object)(object)instance.m_containerName) ? instance.m_containerName.font : instance.m_playerName.font); if (!Object.op_Implicit((Object)(object)font)) { throw new InvalidOperationException("Inventory font is unavailable."); } source = inventory; package = item; encoded = item.m_customData["arcbyte.packandplace.v1"]; openedStack = item.m_stack; showingRefunds = refunds; entries = PackedContents.Read(state, Cargo.StoredTemplate, Cargo.IsPackage, (ItemData stored) => Localize(stored.m_shared.m_name)); float returnPercent = Plugin.SalvageMaterialPercent.Value; List<ItemData> list = null; string text = null; try { list = PackageSalvage.Plan(state, returnPercent); } catch (Exception ex) { text = ex.Message; } if (refunds) { entries = ((list != null) ? list.Select((ItemData o) => new PackedContents.Row { Name = Localize(o.m_shared.m_name), Quantity = o.m_stack, Item = o, Detail = "Quality " + o.m_quality + " | Durability " + o.m_durability.ToString("0.##") + " | Variant " + o.m_variant + ((o.m_customData.Count > 0) ? " | Custom item data preserved" : "") }).ToList() : new List<PackedContents.Row> { new PackedContents.Row { Name = "Cannot salvage", Detail = text, Error = true } }); } root = Rect("PackAndPlace_Contents", ((Component)componentInParent).transform); RectTransform obj = root; RectTransform obj2 = root; Vector2 val = (root.pivot = new Vector2(0.5f, 0.5f)); Vector2 anchorMin = (obj2.anchorMax = val); obj.anchorMin = anchorMin; ((Graphic)((Component)root).gameObject.AddComponent<Image>()).color = new Color(0.065f, 0.055f, 0.04f, 0.98f); Outline val4 = ((Component)root).gameObject.AddComponent<Outline>(); ((Shadow)val4).effectColor = Gold; ((Shadow)val4).effectDistance = new Vector2(1f, -1f); Resize(); TMP_Text val5 = Text("Title", (Transform)(object)root, 22); Top(val5.rectTransform, 18f, -14f, -58f, 30f); val5.text = (refunds ? "Salvage refunds: " : "Package details: ") + Localize(item.m_shared.m_name); ((Graphic)val5).color = Gold; TMP_Text val6 = Text("Summary", (Transform)(object)root, 15); Top(val6.rectTransform, 18f, -49f, -18f, 36f); val6.maxVisibleLines = 2; long num = entries.Sum((PackedContents.Row e) => e.Quantity); val6.text = entries.Count((PackedContents.Row e) => e.Quantity > 0) + " stored stacks | " + num.ToString("N0") + " items per package | Package weight " + state.Weight.ToString("0.##") + " | " + item.m_stack + " packages"; if (refunds) { val6.text = "Refund for ONE package: " + num.ToString("N0") + " items | " + returnPercent.ToString("0.##") + "% base materials | full contents"; } RectTransform val7 = Rect("Close", (Transform)(object)root); val = (val7.pivot = Vector2.one); anchorMin = (val7.anchorMax = val); val7.anchorMin = anchorMin; val7.anchoredPosition = new Vector2(-12f, -12f); val7.sizeDelta = new Vector2(34f, 30f); Image val9 = ((Component)val7).gameObject.AddComponent<Image>(); ((Graphic)val9).color = new Color(0.28f, 0.23f, 0.16f); Button val10 = ((Component)val7).gameObject.AddComponent<Button>(); ((Selectable)val10).targetGraphic = (Graphic)(object)val9; Navigation navigation = default(Navigation); ((Navigation)(ref navigation)).mode = (Mode)0; ((Selectable)val10).navigation = navigation; ButtonClickedEvent onClick = val10.onClick; object obj3 = <>O.<2>__Close; if (obj3 == null) { UnityAction val11 = Close; <>O.<2>__Close = val11; obj3 = (object)val11; } ((UnityEvent)onClick).AddListener((UnityAction)obj3); TMP_Text val12 = Text("Label", (Transform)(object)val7, 22); Stretch(val12.rectTransform, 0f, 0f, 0f, 0f); val12.text = "×"; val12.alignment = (TextAlignmentOptions)514; RectTransform val13 = Rect("ContentsList", (Transform)(object)root); Stretch(val13, 14f, 90f, -14f, -94f); ((Graphic)((Component)val13).gameObject.AddComponent<Image>()).color = new Color(0.025f, 0.025f, 0.02f, 0.94f); scroll = ((Component)val13).gameObject.AddComponent<ScrollRect>(); scroll.horizontal = false; scroll.vertical = true; scroll.scrollSensitivity = 28f; scroll.movementType = (MovementType)2; viewport = Rect("Viewport", (Transform)(object)val13); Stretch(viewport, 4f, 4f, -22f, -4f); ((Graphic)((Component)viewport).gameObject.AddComponent<Image>()).color = Color.clear; ((Component)viewport).gameObject.AddComponent<RectMask2D>(); content = Rect("Content", (Transform)(object)viewport); content.anchorMin = new Vector2(0f, 1f); content.anchorMax = Vector2.one; content.pivot = new Vector2(0.5f, 1f); content.sizeDelta = new Vector2(0f, (float)entries.Count * 56f); scroll.viewport = viewport; scroll.content = content; RectTransform val14 = Rect("Scrollbar", (Transform)(object)val13); val14.anchorMin = new Vector2(1f, 0f); val14.anchorMax = Vector2.one; val14.offsetMin = new Vector2(-16f, 4f); val14.offsetMax = new Vector2(-4f, -4f); ((Graphic)((Component)val14).gameObject.AddComponent<Image>()).color = new Color(0.18f, 0.15f, 0.1f); RectTransform val15 = Rect("Handle", (Transform)(object)val14); Stretch(val15, 2f, 2f, -2f, -2f); Image val16 = ((Component)val15).gameObject.AddComponent<Image>(); ((Graphic)val16).color = Gold; Scrollbar val17 = ((Component)val14).gameObject.AddComponent<Scrollbar>(); val17.direction = (Direction)2; val17.handleRect = val15; ((Selectable)val17).targetGraphic = (Graphic)(object)val16; navigation = default(Navigation); ((Navigation)(ref navigation)).mode = (Mode)0; ((Selectable)val17).navigation = navigation; scroll.verticalScrollbar = val17; scroll.verticalScrollbarVisibility = (ScrollbarVisibility)1; ((UnityEvent<Vector2>)(object)scroll.onValueChanged).AddListener((UnityAction<Vector2>)delegate { RefreshRows(); }); TMP_Text val18 = Text("Hint", (Transform)(object)root, 13); val18.rectTransform.anchorMin = Vector2.zero; val18.rectTransform.anchorMax = new Vector2(1f, 0f); val18.rectTransform.offsetMin = new Vector2(18f, 55f); val18.rectTransform.offsetMax = new Vector2(-18f, 77f); val18.text = ((text != null) ? "Salvage unavailable; View refunds explains why." : "Refunds drop nearby. Ctrl + right-click a package to reopen details."); RectTransform val19 = Rect("Salvage", (Transform)(object)root); val19.anchorMin = new Vector2(0.4f, 0f); val19.anchorMax = new Vector2(1f, 0f); val19.offsetMin = new Vector2(4f, 14f); val19.offsetMax = new Vector2(-18f, 48f); Image val20 = ((Component)val19).gameObject.AddComponent<Image>(); ((Graphic)val20).color = new Color(0.28f, 0.23f, 0.16f); Button val21 = ((Component)val19).gameObject.AddComponent<Button>(); ((Selectable)val21).targetGraphic = (Graphic)(object)val20; navigation = default(Navigation); ((Navigation)(ref navigation)).mode = (Mode)0; ((Selectable)val21).navigation = navigation; ((Selectable)val21).interactable = list != null && Object.op_Implicit((Object)(object)Player.m_localPlayer) && inventory == ((Humanoid)Player.m_localPlayer).GetInventory(); TMP_Text val22 = Text("Label", (Transform)(object)val19, 15); Stretch(val22.rectTransform, 4f, 2f, -4f, -2f); val22.alignment = (TextAlignmentOptions)514; val22.enableAutoSizing = true; val22.fontSizeMin = 10f; val22.fontSizeMax = 15f; val22.text = ((!((Selectable)val21).interactable) ? "Salvage unavailable" : ((refunds && Plugin.Confirmations.Value) ? "Confirm salvage 1 package" : "Salvage 1 package")); GameObject val23 = ((IEnumerable<UITooltip>)((Component)instance).GetComponentsInChildren<UITooltip>(true)).FirstOrDefault((Func<UITooltip, bool>)((UITooltip t) => Object.op_Implicit((Object)(object)t.m_tooltipPrefab)))?.m_tooltipPrefab; if (Object.op_Implicit((Object)(object)val23)) { UITooltip val24 = ((Component)val19).gameObject.AddComponent<UITooltip>(); val24.m_tooltipPrefab = val23; val24.m_topic = "Refund for one package"; val24.m_text = ((list == null) ? text : (string.Join("\n", from o in list.Take(12) select o.m_stack.ToString("N0") + " × " + Localize(o.m_shared.m_name)) + ((list.Count > 12) ? "\n… View refunds for the full list." : "") + "\n" + returnPercent.ToString("0.##") + "% base materials; contents in full.")); } RectTransform val25 = Rect("RefundPreview", (Transform)(object)root); val25.anchorMin = Vector2.zero; val25.anchorMax = new Vector2(0.4f, 0f); val25.offsetMin = new Vector2(18f, 14f); val25.offsetMax = new Vector2(-4f, 48f); Image val26 = ((Component)val25).gameObject.AddComponent<Image>(); ((Graphic)val26).color = ((Graphic)val20).color; Button val27 = ((Component)val25).gameObject.AddComponent<Button>(); ((Selectable)val27).targetGraphic = (Graphic)(object)val26; navigation = default(Navigation); ((Navigation)(ref navigation)).mode = (Mode)0; ((Selectable)val27).navigation = navigation; TMP_Text val28 = Text("Label", (Transform)(object)val25, 15); Stretch(val28.rectTransform, 4f, 2f, -4f, -2f); val28.text = (refunds ? "View contents" : "View refunds"); val28.alignment = (TextAlignmentOptions)514; val28.enableAutoSizing = true; val28.fontSizeMin = 10f; val28.fontSizeMax = 15f; ((UnityEvent)val27.onClick).AddListener((UnityAction)delegate { Open(inventory, item, !refunds); }); ((UnityEvent)val21.onClick).AddListener((UnityAction)delegate { if (!refunds && Plugin.Confirmations.Value) { Open(inventory, item, refunds: true); } else { PackageSalvage.Execute(inventory, item, encoded, returnPercent); } }); ((Transform)root).SetAsLastSibling(); UITooltip.HideTooltip(); Canvas.ForceUpdateCanvases(); scroll.verticalNormalizedPosition = 1f; RefreshRows(); } catch (Exception ex2) { Close(); Plugin.Log.LogError((object)("Packed contents preview failed: " + ex2)); Plugin.Tell(Player.m_localPlayer, "Contents preview could not open. See the BepInEx log."); } } internal static void Poll() { if (!Object.op_Implicit((Object)(object)root)) { return; } if (!Plugin.Ready || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || !InventoryGui.IsVisible() || source == null || !source.ContainsItem(package) || !PackageStackPolicy.ValidCount(package.m_stack) || package.m_stack != openedStack || !package.m_customData.TryGetValue("arcbyte.packandplace.v1", out var value) || value != encoded) { Close(); return; } if (screen.x != (float)Screen.width || screen.y != (float)Screen.height) { Resize(); Canvas.ForceUpdateCanvases(); } ((Transform)root).SetAsLastSibling(); RefreshRows(); } internal static void RefreshSettings() { if (Object.op_Implicit((Object)(object)root) && source != null && package != null) { Inventory inventory = source; ItemData item = package; bool refunds = showingRefunds; float verticalNormalizedPosition = (Object.op_Implicit((Object)(object)scroll) ? scroll.verticalNormalizedPosition : 1f); Open(inventory, item, refunds); if (Object.op_Implicit((Object)(object)scroll)) { scroll.verticalNormalizedPosition = verticalNormalizedPosition; } } } private static void Resize() { //IL_000d: 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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: U