Decompiled source of PackAndPlace v0.5.10

BepInEx/plugins/PackAndPlace/ArcByte.PackAndPlace.dll

Decompiled 5 days ago
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