Decompiled source of GuildChest v1.1.1

BepInEx/plugins/GuildChest/GuildChest.Core.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("GuildChest.Core")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1+cf8384c482f04f6c0dbd198ddf18e16e717a54d7")]
[assembly: AssemblyProduct("GuildChest.Core")]
[assembly: AssemblyTitle("GuildChest.Core")]
[assembly: AssemblyVersion("1.1.1.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace GuildChest.Core
{
	public enum AccessResult
	{
		Accepted,
		Busy,
		UnknownChest,
		InvalidSession,
		StaleRevision,
		InvalidSequence,
		AccessDenied,
		InvalidInventory,
		ItemMismatch,
		InvalidDimensions
	}
	public sealed class StoreSnapshot
	{
		public byte[] Inventory { get; }

		public long Revision { get; }

		public StoreSnapshot(byte[] inventory, long revision)
		{
			Inventory = (byte[])inventory.Clone();
			Revision = revision;
		}
	}
	public sealed class Lease
	{
		internal long Sequence;

		internal byte[]? LastPayload;

		public long Peer { get; }

		public string Chest { get; }

		public string Token { get; } = Guid.NewGuid().ToString("N");

		public double ExpiresAt { get; internal set; }

		public Lease(long peer, string chest, double expiresAt)
		{
			Peer = peer;
			Chest = chest;
			ExpiresAt = expiresAt;
		}
	}
	public sealed class SharedStore
	{
		public const double LeaseSeconds = 30.0;

		private readonly HashSet<string> chests = new HashSet<string>(StringComparer.Ordinal);

		private byte[] inventory;

		private long revision;

		private readonly Dictionary<string, byte[]> receipts = new Dictionary<string, byte[]>(StringComparer.Ordinal);

		private readonly Queue<string> receiptOrder = new Queue<string>();

		public Lease? ActiveLease { get; private set; }

		public int ChestCount => chests.Count;

		public SharedStore(byte[] savedInventory, long savedRevision)
		{
			inventory = (byte[])savedInventory.Clone();
			revision = savedRevision;
		}

		public StoreSnapshot Snapshot()
		{
			return new StoreSnapshot(inventory, revision);
		}

		public bool Register(string chest)
		{
			return chests.Add(chest);
		}

		public bool Contains(string chest)
		{
			return chests.Contains(chest);
		}

		public AccessResult Open(long peer, string chest, double now, out Lease? lease)
		{
			Expire(now);
			lease = null;
			if (!chests.Contains(chest))
			{
				return AccessResult.UnknownChest;
			}
			if (ActiveLease != null)
			{
				if (ActiveLease.Peer != peer || ActiveLease.Chest != chest)
				{
					return AccessResult.Busy;
				}
				ActiveLease.ExpiresAt = now + 30.0;
				lease = ActiveLease;
				return AccessResult.Accepted;
			}
			Lease lease2 = (ActiveLease = new Lease(peer, chest, now + 30.0));
			lease = lease2;
			return AccessResult.Accepted;
		}

		public AccessResult Commit(long peer, string token, long expectedRevision, long sequence, byte[] payload, double now)
		{
			if (TryReplay(peer, token, sequence, payload, out var result))
			{
				return result;
			}
			if (!Authorized(peer, token, now))
			{
				return AccessResult.InvalidSession;
			}
			Lease activeLease = ActiveLease;
			if (sequence == activeLease.Sequence && activeLease.LastPayload != null)
			{
				if (!payload.SequenceEqual(activeLease.LastPayload))
				{
					return AccessResult.InvalidSequence;
				}
				return AccessResult.Accepted;
			}
			if (sequence != activeLease.Sequence + 1)
			{
				return AccessResult.InvalidSequence;
			}
			if (expectedRevision != revision)
			{
				return AccessResult.StaleRevision;
			}
			inventory = (byte[])payload.Clone();
			revision++;
			activeLease.Sequence = sequence;
			activeLease.LastPayload = (byte[])payload.Clone();
			activeLease.ExpiresAt = now + 30.0;
			string text = ReceiptKey(peer, token, sequence);
			receipts.Add(text, (byte[])payload.Clone());
			receiptOrder.Enqueue(text);
			while (receiptOrder.Count > 256)
			{
				receipts.Remove(receiptOrder.Dequeue());
			}
			return AccessResult.Accepted;
		}

		private static string ReceiptKey(long peer, string token, long sequence)
		{
			return $"{peer}/{token}/{sequence}";
		}

		public bool TryReplay(long peer, string token, long sequence, byte[] payload, out AccessResult result)
		{
			result = AccessResult.InvalidSession;
			if (!receipts.TryGetValue(ReceiptKey(peer, token, sequence), out byte[] value))
			{
				return false;
			}
			result = ((!value.SequenceEqual(payload)) ? AccessResult.InvalidSequence : AccessResult.Accepted);
			return true;
		}

		public bool Heartbeat(long peer, string token, double now)
		{
			if (!Authorized(peer, token, now))
			{
				return false;
			}
			ActiveLease.ExpiresAt = now + 30.0;
			return true;
		}

		public bool Close(long peer, string token)
		{
			Lease? activeLease = ActiveLease;
			if (activeLease == null || activeLease.Peer != peer || ActiveLease.Token != token)
			{
				return false;
			}
			ActiveLease = null;
			return true;
		}

		public void Disconnect(long peer)
		{
			Lease? activeLease = ActiveLease;
			if (activeLease != null && activeLease.Peer == peer)
			{
				ActiveLease = null;
			}
		}

		public void Expire(double now)
		{
			if (ActiveLease != null && now >= ActiveLease.ExpiresAt)
			{
				ActiveLease = null;
			}
		}

		public bool Authorized(long peer, string token, double now)
		{
			Expire(now);
			Lease? activeLease = ActiveLease;
			if (activeLease != null && activeLease.Peer == peer)
			{
				return ActiveLease.Token == token;
			}
			return false;
		}

		public bool Remove(string chest)
		{
			if (!chests.Remove(chest))
			{
				return false;
			}
			if (ActiveLease?.Chest == chest)
			{
				ActiveLease = null;
			}
			return true;
		}
	}
	public enum TransferPhase
	{
		AwaitingAcknowledgement,
		Accepted,
		Applied,
		Rejected,
		Completed
	}
	public sealed class TransferLifecycle
	{
		public TransferPhase Phase { get; private set; }

		public bool Acknowledge(bool accepted)
		{
			if (Phase != TransferPhase.AwaitingAcknowledgement)
			{
				return false;
			}
			Phase = (accepted ? TransferPhase.Accepted : TransferPhase.Rejected);
			return true;
		}

		public bool TryApply(Action mutation)
		{
			if (Phase != TransferPhase.Accepted)
			{
				return false;
			}
			mutation();
			Phase = TransferPhase.Applied;
			return true;
		}

		public bool Finish()
		{
			if (Phase != TransferPhase.Applied && Phase != TransferPhase.Rejected)
			{
				return false;
			}
			Phase = TransferPhase.Completed;
			return true;
		}
	}
	public sealed class TransferCompletion
	{
		private Action<bool, string>? callback;

		private readonly Action<Exception> logError;

		public bool IsCompleted { get; private set; }

		public TransferCompletion(Action<bool, string>? callback, Action<Exception> logError)
		{
			this.callback = callback;
			this.logError = logError;
		}

		public void Complete(bool accepted, string reason)
		{
			if (IsCompleted)
			{
				return;
			}
			IsCompleted = true;
			Action<bool, string> action = callback;
			callback = null;
			try
			{
				action?.Invoke(accepted, reason);
			}
			catch (Exception obj)
			{
				logError(obj);
			}
		}
	}
}

BepInEx/plugins/GuildChest/GuildChest.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using GuildChest.Core;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("GuildChest")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1+cf8384c482f04f6c0dbd198ddf18e16e717a54d7")]
[assembly: AssemblyProduct("GuildChest")]
[assembly: AssemblyTitle("GuildChest")]
[assembly: AssemblyVersion("1.1.1.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace GuildChest
{
	internal static class AutoStoreAdapter
	{
		private sealed class Bindings
		{
			internal readonly MethodInfo Query;

			internal readonly MethodInfo Store;

			internal readonly MethodInfo Success;

			internal readonly MethodInfo ClearPending;

			internal readonly MethodInfo Ping;

			internal readonly MethodInfo StoreAll;

			internal readonly MethodInfo StoreSingle;

			internal readonly FieldInfo Pings;

			internal readonly Func<float> Range;

			internal readonly (MethodInfo Target, string Prefix)[] Hooks;

			internal Bindings(Type plugin)
			{
				Assembly assembly = plugin.Assembly;
				Type type = StorageBindings.Type(assembly, "AzuAutoStore.Util.Functions");
				Type type2 = StorageBindings.Type(assembly, "AzuAutoStore.Util.Boxes");
				Type type3 = StorageBindings.Type(assembly, "AzuAutoStore.Interfaces.VanillaContainers");
				Type type4 = StorageBindings.Type(assembly, "AzuAutoStore.Interfaces.IContainer");
				ContainerBindings.Validate(type3, crafting: false);
				Query = StorageBindings.NearbyQuery(type2);
				Store = StorageBindings.Method(type, "StoreToContainer", typeof(int), new Type[3]
				{
					type4,
					typeof(ItemData),
					typeof(Inventory)
				});
				Success = StorageBindings.Method(type, "StoreSuccess", typeof(void), new Type[1] { typeof(int) });
				ClearPending = StorageBindings.Method(type, "ClearPendingSends", typeof(void), Type.EmptyTypes);
				Ping = StorageBindings.Method(type, "PingContainer", typeof(void), new Type[1] { typeof(GameObject) });
				StoreAll = StorageBindings.Method(type3, "TryStore", typeof(int), Type.EmptyTypes);
				StoreSingle = StorageBindings.Method(type3, "TryStoreThisItem", typeof(int), new Type[2]
				{
					typeof(ItemData),
					typeof(Inventory)
				});
				Pings = StorageBindings.Field(type2, "ContainersToPing");
				if (!Pings.IsStatic || !typeof(IList).IsAssignableFrom(Pings.FieldType))
				{
					throw new InvalidOperationException("Unsupported AutoStore ping collection.");
				}
				Range = StorageBindings.Setting<float>(plugin, "PlayerRange");
				Hooks = new(MethodInfo, string)[4]
				{
					(Store, "StoreContainer"),
					(StorageBindings.Method(type, "TryStore", typeof(bool), new Type[4]
					{
						typeof(Container),
						typeof(ItemData).MakeByRefType(),
						typeof(bool),
						typeof(bool)
					}), "StoreDirect"),
					(StorageBindings.Method(type, "TryStore", typeof(void), Type.EmptyTypes), "Begin"),
					(StorageBindings.Method(type, "TryStoreThisItem", typeof(void), new Type[2]
					{
						typeof(ItemData),
						typeof(Inventory)
					}), "Begin")
				};
			}
		}

		internal const string PluginId = "Azumatt.AzuAutoStore";

		private static Bindings? bindings;

		private static Bindings Api => bindings ?? throw new InvalidOperationException("AutoStore adapter is unavailable.");

		private static IList Pings => (IList)Api.Pings.GetValue(null);

		internal static float Range => Api.Range();

		internal static void Install(Harmony harmony, Type plugin)
		{
			Bindings bindings = new Bindings(plugin);
			StorageBindings.Patch(harmony, typeof(AutoStoreAdapter), bindings.Hooks);
			AutoStoreAdapter.bindings = bindings;
		}

		internal static List<object> Nearby(Player player)
		{
			return ((IEnumerable)Api.Query.Invoke(null, new object[2] { player, Range })).Cast<object>().ToList();
		}

		internal static int Store(object container, ItemData? item, Inventory? inventory)
		{
			return (int)Api.Store.Invoke(null, new object[3] { container, item, inventory });
		}

		internal static void Success(int count)
		{
			Api.Success.Invoke(null, new object[1] { count });
		}

		internal static void ClearPending()
		{
			Pings.Clear();
			Api.ClearPending.Invoke(null, null);
		}

		private static bool Begin(object[] __args)
		{
			return AutoStoreBatch.Begin(__args);
		}

		private static bool StoreDirect(Container nearbyContainer, ref bool __result)
		{
			if (!Plugin.IsGuild(nearbyContainer) || (Object)(object)nearbyContainer == (Object)(object)InventoryAccess.ScopedChest)
			{
				return true;
			}
			__result = false;
			return false;
		}

		private static bool StoreContainer(object container, ItemData? singleItem, Inventory? inv, ref int __result)
		{
			if (!Plugin.IsGuild(ContainerBindings.ContainerFor(container)))
			{
				return !Client.Pending;
			}
			__result = 0;
			StoreGuild(container, singleItem, inv, null);
			return false;
		}

		internal static bool StoreGuild(object container, ItemData? singleItem, Inventory? inv, Action? completed)
		{
			Container chest = ContainerBindings.ContainerFor(container);
			if (bindings == null || Client.Pending || Client.Opening)
			{
				return false;
			}
			int stored = 0;
			return GuildChestStorage.TryTransfer(chest, delegate(Inventory player, Inventory shared)
			{
				ItemData val = null;
				if (singleItem != null)
				{
					Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory();
					if (inv != inventory || !inventory.ContainsItem(singleItem))
					{
						return;
					}
					val = player.GetItemAt(singleItem.m_gridPos.x, singleItem.m_gridPos.y);
				}
				using (new InventoryAccess.StagingScope(Player.m_localPlayer, chest, player, shared))
				{
					try
					{
						stored = (int)((singleItem == null) ? Api.StoreAll.Invoke(container, null) : Api.StoreSingle.Invoke(container, new object[2] { val, player }));
					}
					finally
					{
						Pings.Remove(container);
					}
				}
			}, delegate(bool accepted, string reason)
			{
				//IL_008d: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (accepted && stored > 0)
					{
						Plugin.Message($"Stored {stored} items in guild storage.");
						if (Object.op_Implicit((Object)(object)chest))
						{
							Api.Ping.Invoke(null, new object[1] { ((Component)chest).gameObject });
							if (Object.op_Implicit((Object)(object)InventoryGui.instance))
							{
								AccessTools.FieldRefAccess<InventoryGui, EffectList>("m_moveItemEffects").Invoke(InventoryGui.instance).Create(((Component)chest).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
							}
						}
					}
					else if (!accepted)
					{
						Plugin.Message("Guild auto-store failed: " + reason);
					}
				}
				finally
				{
					completed?.Invoke();
				}
			});
		}
	}
	internal static class AutoStoreBatch
	{
		private sealed class Batch
		{
			internal Player Player;

			internal Inventory Inventory;

			internal ItemData? Item;

			internal List<object> Destinations;

			internal int Index;

			internal int OrdinaryStored;

			internal bool Waiting;

			internal bool UsedGuild;
		}

		private static Batch? active;

		internal static void Reset()
		{
			active = null;
		}

		private static bool Available(object wrapper, Player player, bool guild)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = ContainerBindings.ObjectFor(wrapper);
			if (!Object.op_Implicit((Object)(object)val) || Vector3.Distance(val.transform.position, ((Component)player).transform.position) > (guild ? Math.Min(AutoStoreAdapter.Range, Plugin.AutomationRange.Value) : AutoStoreAdapter.Range))
			{
				return false;
			}
			ZNetView component = val.GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component) || component.IsValid())
			{
				return PrivateArea.CheckAccess(val.transform.position, 0f, false, true);
			}
			return false;
		}

		internal static bool Begin(object[] __args)
		{
			if (active != null || Client.Pending || Client.Opening)
			{
				return false;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting())
			{
				return true;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			ItemData val = (ItemData)((__args.Length == 0) ? null : /*isinst with value type is only supported in some contexts*/);
			if (__args.Length != 0 && (val == null || __args[1] != inventory || !inventory.ContainsItem(val)))
			{
				return false;
			}
			try
			{
				List<object> list = AutoStoreAdapter.Nearby(localPlayer);
				if (!list.Any((object destination) => Plugin.IsGuild(ContainerBindings.ContainerFor(destination))))
				{
					return true;
				}
				AutoStoreAdapter.ClearPending();
				active = new Batch
				{
					Player = localPlayer,
					Inventory = inventory,
					Item = val,
					Destinations = list
				};
				Tick();
			}
			catch (Exception exception)
			{
				Reset();
				Plugin.Error(exception);
			}
			return false;
		}

		private static void Flush(Batch batch)
		{
			int ordinaryStored = batch.OrdinaryStored;
			batch.OrdinaryStored = 0;
			AutoStoreAdapter.Success(ordinaryStored);
		}

		internal static void Tick()
		{
			Batch batch = active;
			if (batch == null || batch.Waiting || Client.Pending || Client.Opening)
			{
				return;
			}
			try
			{
				if (!Object.op_Implicit((Object)(object)batch.Player) || (Object)(object)batch.Player != (Object)(object)Player.m_localPlayer || ((Character)batch.Player).IsDead() || ((Character)batch.Player).IsTeleporting() || ((Humanoid)batch.Player).GetInventory() != batch.Inventory || (batch.Item != null && !batch.Inventory.ContainsItem(batch.Item)))
				{
					Flush(batch);
					Reset();
					return;
				}
				while (batch.Index < batch.Destinations.Count)
				{
					object obj = batch.Destinations[batch.Index++];
					bool flag = Plugin.IsGuild(ContainerBindings.ContainerFor(obj));
					if ((flag && batch.UsedGuild) || !Available(obj, batch.Player, flag))
					{
						continue;
					}
					if (!flag)
					{
						batch.OrdinaryStored += AutoStoreAdapter.Store(obj, batch.Item, (batch.Item == null) ? null : batch.Inventory);
						if (batch.Item != null && !batch.Inventory.ContainsItem(batch.Item))
						{
							break;
						}
						continue;
					}
					Flush(batch);
					batch.UsedGuild = true;
					batch.Waiting = true;
					if (!AutoStoreAdapter.StoreGuild(obj, batch.Item, (batch.Item == null) ? null : batch.Inventory, delegate
					{
						if (active == batch)
						{
							batch.Waiting = false;
						}
					}))
					{
						batch.Waiting = false;
					}
					return;
				}
				Flush(batch);
				Reset();
			}
			catch (Exception exception)
			{
				Reset();
				AutoStoreAdapter.ClearPending();
				Plugin.Error(exception);
			}
		}
	}
	internal static class BuildingContinuation
	{
		private sealed class Intent
		{
			internal Player Player;

			internal Piece Piece;

			internal ItemData Tool;

			internal Vector3 Position;

			internal Vector3 PlayerPosition;

			internal Quaternion Rotation;

			internal float Started;

			internal bool Ready;
		}

		private static Intent? pending;

		private static bool replaying;

		private static readonly MethodInfo updateGhost = AccessTools.Method(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) }, (Type[])null);

		private static GameObject Ghost(Player player)
		{
			return AccessTools.FieldRefAccess<Player, GameObject>("m_placementGhost").Invoke(player);
		}

		internal static void Reset()
		{
			pending = null;
			replaying = false;
		}

		private static bool MatchesContext(Intent intent)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)intent.Player) && (Object)(object)intent.Player == (Object)(object)Player.m_localPlayer && !((Character)intent.Player).IsDead() && !((Character)intent.Player).IsTeleporting() && ((Character)intent.Player).InPlaceMode() && (Object)(object)intent.Player.GetSelectedPiece() == (Object)(object)intent.Piece && ((Humanoid)intent.Player).RightItem == intent.Tool && Vector3.Distance(((Component)intent.Player).transform.position, intent.PlayerPosition) <= 0.5f)
			{
				return Time.unscaledTime - intent.Started <= 30f;
			}
			return false;
		}

		private static bool Matches(Intent intent)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (!MatchesContext(intent))
			{
				return false;
			}
			GameObject val = Ghost(intent.Player);
			if (Object.op_Implicit((Object)(object)val) && val.activeInHierarchy && Vector3.Distance(val.transform.position, intent.Position) <= 0.1f)
			{
				return Quaternion.Angle(val.transform.rotation, intent.Rotation) <= 1f;
			}
			return false;
		}

		internal static bool TryPlace(Player player, Piece piece)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			if (replaying)
			{
				bool result = pending != null && (Object)(object)pending.Piece == (Object)(object)piece && Matches(pending);
				Reset();
				return result;
			}
			if (pending != null || Client.Pending || Client.Opening)
			{
				return false;
			}
			if (player.NoCostCheat() || ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey()))
			{
				return true;
			}
			GameObject val = Ghost(player);
			ItemData rightItem = ((Humanoid)player).RightItem;
			if (!((Character)player).InPlaceMode() || (Object)(object)player.GetSelectedPiece() != (Object)(object)piece || !Object.op_Implicit((Object)(object)val) || rightItem == null)
			{
				return true;
			}
			updateGhost.Invoke(player, new object[1] { true });
			if ((int)player.GetPlacementStatus() != 0 || !val.activeInHierarchy)
			{
				return true;
			}
			Intent intent = new Intent
			{
				Player = player,
				Piece = piece,
				Tool = rightItem,
				Position = val.transform.position,
				Rotation = val.transform.rotation,
				PlayerPosition = ((Component)player).transform.position,
				Started = Time.unscaledTime
			};
			pending = intent;
			if (MaterialSupply.Supply(piece.m_resources, 0, 1, onlyOne: false, building: true, delegate
			{
				if (pending == intent)
				{
					intent.Ready = true;
				}
			}))
			{
				return false;
			}
			pending = null;
			return true;
		}

		internal static void BeforeUpdate(Player player, bool takeInput)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player != (Object)(object)Player.m_localPlayer || pending == null)
			{
				return;
			}
			if (!takeInput || !MatchesContext(pending) || Hud.IsPieceSelectionVisible())
			{
				Reset();
				return;
			}
			updateGhost.Invoke(player, new object[1] { false });
			if (!Matches(pending) || (int)player.GetPlacementStatus() != 0)
			{
				Reset();
			}
			else if (!pending.Ready)
			{
				if (!Client.Pending && !Client.Opening)
				{
					Reset();
				}
			}
			else if (!Client.Pending && !Client.Opening)
			{
				AccessTools.FieldRefAccess<Player, float>("m_placePressedTime").Invoke(player) = Time.time;
				replaying = true;
			}
		}

		internal static void AfterUpdate(Player player)
		{
			if (!((Object)(object)player != (Object)(object)Player.m_localPlayer) && replaying)
			{
				Reset();
				AccessTools.FieldRefAccess<Player, float>("m_placePressedTime").Invoke(player) = -9999f;
			}
		}
	}
	internal static class ChestAppearance
	{
		internal const string DecorationName = "GuildChestCoins";

		internal static void Apply(GameObject prefab)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Material[] materials = componentsInChildren[i].materials;
				foreach (Material val in materials)
				{
					if (val.HasProperty("_Color"))
					{
						val.color *= new Color(1f, 0.78f, 0.3f, 1f);
					}
				}
			}
			GameObject prefab2 = PrefabManager.Instance.GetPrefab("Coins");
			MeshFilter val2 = (Object.op_Implicit((Object)(object)prefab2) ? ((IEnumerable<MeshFilter>)prefab2.GetComponentsInChildren<MeshFilter>(true)).FirstOrDefault((Func<MeshFilter, bool>)((MeshFilter filter) => Object.op_Implicit((Object)(object)filter.sharedMesh) && ((Object)filter.sharedMesh).name == "coin")) : null);
			MeshRenderer val3 = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent<MeshRenderer>() : null);
			MeshFilter val4 = ((IEnumerable<MeshFilter>)prefab.GetComponentsInChildren<MeshFilter>(true)).FirstOrDefault((Func<MeshFilter, bool>)((MeshFilter filter) => Object.op_Implicit((Object)(object)filter.sharedMesh) && ((Object)filter.sharedMesh).name == "ironchest"));
			Container component = prefab.GetComponent<Container>();
			MeshFilter val5 = (Object.op_Implicit((Object)(object)component.m_closed) ? component.m_closed.GetComponent<MeshFilter>() : null);
			MeshFilter val6 = (Object.op_Implicit((Object)(object)component.m_open) ? component.m_open.GetComponent<MeshFilter>() : null);
			if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)val3) || !val2.sharedMesh.isReadable || !Object.op_Implicit((Object)(object)val4) || !Object.op_Implicit((Object)(object)val5) || !Object.op_Implicit((Object)(object)val6) || !val4.sharedMesh.isReadable || !val5.sharedMesh.isReadable)
			{
				Plugin.LogWarning("Guild chest coin decorations unavailable: expected vanilla coin or chest meshes are missing.");
				return;
			}
			List<CombineInstance> list = new List<CombineInstance>();
			Bounds bounds = val4.sharedMesh.bounds;
			int[] array = new int[2] { -1, 1 };
			foreach (int num in array)
			{
				Quaternion rotation = Quaternion.Euler(90f * (float)num, 0f, 0f);
				float num2 = ((num < 0) ? ((Bounds)(ref bounds)).min.z : ((Bounds)(ref bounds)).max.z);
				AddCoin(list, val2.sharedMesh, val4.sharedMesh, new Vector3(((Bounds)(ref bounds)).center.x, ((Bounds)(ref bounds)).center.y, num2), rotation, 0.46f);
				float[] array2 = new float[2] { -0.55f, 0.55f };
				foreach (float num3 in array2)
				{
					float[] array3 = new float[2] { 0.38f, 0.72f };
					foreach (float num5 in array3)
					{
						AddCoin(list, val2.sharedMesh, val4.sharedMesh, new Vector3(num3, num5, num2), rotation, 0.13f);
					}
				}
			}
			AddDecoration(((Component)val4).transform, Combine("GuildChestCoinSeals", list), val3);
			List<CombineInstance> list2 = new List<CombineInstance>();
			Bounds bounds2 = val5.sharedMesh.bounds;
			for (int num6 = -2; num6 <= 2; num6++)
			{
				AddCoin(list2, val2.sharedMesh, val5.sharedMesh, new Vector3(((Bounds)(ref bounds2)).center.x + (float)num6 * 0.23f, ((Bounds)(ref bounds2)).max.y, ((Bounds)(ref bounds2)).center.z), Quaternion.Euler(0f, (float)num6 * 18f, 0f), (num6 == 0) ? 0.23f : 0.17f);
			}
			Mesh mesh = Combine("GuildChestCoinLid", list2);
			AddDecoration(((Component)val5).transform, mesh, val3);
			AddDecoration(((Component)val6).transform, mesh, val3);
		}

		private static void AddCoin(List<CombineInstance> instances, Mesh coin, Mesh mountingMesh, Vector3 surface, Quaternion rotation, float diameter)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			Bounds bounds = coin.bounds;
			float num = diameter / Mathf.Max(((Bounds)(ref bounds)).size.x, ((Bounds)(ref bounds)).size.z);
			Vector3 val = rotation * Vector3.up;
			surface = FindSurface(mountingMesh, surface, val);
			Vector3 val2 = surface + val * (((Bounds)(ref bounds)).extents.y * num - 0.001f);
			CombineInstance item = default(CombineInstance);
			((CombineInstance)(ref item)).mesh = coin;
			((CombineInstance)(ref item)).transform = Matrix4x4.TRS(val2 - rotation * (((Bounds)(ref bounds)).center * num), rotation, Vector3.one * num);
			instances.Add(item);
		}

		private static Vector3 FindSurface(Mesh mesh, Vector3 surface, Vector3 outward)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = surface + outward;
			Vector3 val2 = -outward;
			Vector3[] vertices = mesh.vertices;
			int[] triangles = mesh.triangles;
			float num = float.PositiveInfinity;
			for (int i = 0; i < triangles.Length; i += 3)
			{
				Vector3 val3 = vertices[triangles[i]];
				Vector3 val4 = vertices[triangles[i + 1]] - val3;
				Vector3 val5 = vertices[triangles[i + 2]] - val3;
				Vector3 val6 = Vector3.Cross(val2, val5);
				float num2 = Vector3.Dot(val4, val6);
				if (Mathf.Abs(num2) < 1E-06f)
				{
					continue;
				}
				Vector3 val7 = val - val3;
				float num3 = Vector3.Dot(val7, val6) / num2;
				if (num3 < 0f || num3 > 1f)
				{
					continue;
				}
				Vector3 val8 = Vector3.Cross(val7, val4);
				float num4 = Vector3.Dot(val2, val8) / num2;
				if (!(num4 < 0f) && !(num3 + num4 > 1f))
				{
					float num5 = Vector3.Dot(val5, val8) / num2;
					if (num5 >= 0f && num5 < num)
					{
						num = num5;
					}
				}
			}
			if (!float.IsPositiveInfinity(num))
			{
				return val + val2 * num;
			}
			return surface;
		}

		private static Mesh Combine(string name, List<CombineInstance> coins)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			Mesh val = new Mesh
			{
				name = name
			};
			val.CombineMeshes(coins.ToArray());
			return val;
		}

		private static void AddDecoration(Transform parent, Mesh mesh, MeshRenderer source)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("GuildChestCoins")
			{
				layer = ((Component)parent).gameObject.layer
			};
			val.transform.SetParent(parent, false);
			val.AddComponent<MeshFilter>().sharedMesh = mesh;
			MeshRenderer obj = val.AddComponent<MeshRenderer>();
			((Renderer)obj).sharedMaterials = ((Renderer)source).sharedMaterials;
			((Renderer)obj).shadowCastingMode = ((Renderer)source).shadowCastingMode;
			((Renderer)obj).receiveShadows = ((Renderer)source).receiveShadows;
		}
	}
	internal enum QuickAction
	{
		None,
		Stack,
		Take,
		Automation
	}
	internal static class Client
	{
		private sealed class OpenRequest
		{
			internal Container Chest;

			internal Player Player;

			internal Inventory Inventory;

			internal ZDOID Id;

			internal long Sequence;

			internal float Started;

			internal QuickAction Action;

			internal Action<Inventory, Inventory>? Transfer;

			internal TransferCompletion? Completion;
		}

		internal sealed class Transaction
		{
			internal readonly Inventory PlayerStage;

			internal readonly List<ItemData> PlayerOriginals;

			internal readonly Dictionary<ItemData, ItemData> Bindings = new Dictionary<ItemData, ItemData>();

			internal readonly Inventory SharedStage;

			internal readonly byte[] PlayerBefore;

			internal byte[] Request = Array.Empty<byte>();

			internal long Sequence;

			internal TransferCompletion? Completed;

			internal readonly TransferLifecycle Lifecycle = new TransferLifecycle();

			internal readonly Player Owner;

			internal readonly Inventory PlayerInventory;

			internal long ReplyRevision;

			internal byte[] ReplyInventory = Array.Empty<byte>();

			internal string ReplyReason = "";

			private List<ItemData> removed = new List<ItemData>();

			private bool notified;

			internal Transaction()
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Expected O, but got Unknown
				Owner = Player.m_localPlayer;
				PlayerInventory = ((Humanoid)Owner).GetInventory();
				Inventory playerInventory = PlayerInventory;
				PlayerBefore = InventoryCodec.Save(playerInventory);
				PlayerOriginals = playerInventory.GetAllItems().ToList();
				PlayerStage = InventoryCodec.Clone(playerInventory);
				SharedStage = InventoryCodec.Clone(View);
				for (int i = 0; i < PlayerOriginals.Count; i++)
				{
					Bindings.Add(PlayerStage.GetAllItems()[i], PlayerOriginals[i]);
				}
			}

			internal void Apply()
			{
				//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
				//IL_0104: Unknown result type (might be due to invalid IL or missing references)
				if (!Object.op_Implicit((Object)(object)Owner) || (Object)(object)Owner != (Object)(object)Player.m_localPlayer || ((Humanoid)Owner).GetInventory() != PlayerInventory)
				{
					throw new InvalidOperationException("The original player inventory is no longer available.");
				}
				List<ItemData> list = ((IEnumerable<ItemData>)PlayerStage.GetAllItems()).Select((Func<ItemData, ItemData>)delegate(ItemData staged)
				{
					if (!Bindings.TryGetValue(staged, out ItemData value2))
					{
						ItemData obj = staged.Clone();
						obj.m_equipped = false;
						return obj;
					}
					return value2;
				}).ToList();
				HashSet<ItemData> remaining = new HashSet<ItemData>(list);
				removed = PlayerOriginals.Where((ItemData item) => !remaining.Contains(item)).ToList();
				List<ItemData> allItems = PlayerInventory.GetAllItems();
				if (allItems.Capacity < list.Count)
				{
					allItems.Capacity = list.Count;
				}
				foreach (ItemData allItem in PlayerStage.GetAllItems())
				{
					if (Bindings.TryGetValue(allItem, out ItemData value))
					{
						value.m_stack = allItem.m_stack;
						value.m_gridPos = allItem.m_gridPos;
					}
				}
				allItems.Clear();
				allItems.AddRange(list);
			}

			internal void Notify()
			{
				if (notified)
				{
					return;
				}
				notified = true;
				foreach (ItemData item in removed)
				{
					Effect(delegate
					{
						((Humanoid)Owner).RemoveEquipAction(item);
					});
					Effect(delegate
					{
						((Humanoid)Owner).UnequipItem(item, false);
					});
				}
				Effect(delegate
				{
					InventoryCodec.Changed(PlayerInventory);
				});
			}
		}

		internal static Container? Chest;

		internal static Inventory? View;

		private static OpenRequest? opening;

		private static long openRequest;

		private static ZDOID chestId;

		private static string token = "";

		private static long revision;

		private static long sequence;

		private static float nextHeartbeat;

		private static float nextRetry;

		private static float lastReply;

		private static bool closeWanted;

		private static bool deferredDeath;

		private static Transaction? transaction;

		private static bool finishing;

		private static bool resetting;

		internal static bool Applying;

		internal static bool Pending => transaction != null;

		internal static bool HasSession => token.Length != 0;

		internal static bool Opening => opening != null;

		internal static Container? CurrentContainer
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)InventoryGui.instance))
				{
					return null;
				}
				return AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer").Invoke(InventoryGui.instance);
			}
		}

		internal static bool GuildUi => Owns(CurrentContainer);

		internal static bool Owns(Container? container)
		{
			if (HasSession && Object.op_Implicit((Object)(object)container))
			{
				return (Object)(object)container == (Object)(object)Chest;
			}
			return false;
		}

		internal static bool Open(Container container, QuickAction action = QuickAction.None)
		{
			return OpenCore(container, action, null, null);
		}

		private static bool OpenCore(Container container, QuickAction action, Action<Inventory, Inventory>? transfer, TransferCompletion? completion)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			if (Pending || Opening || HasSession || finishing || resetting)
			{
				Plugin.Message("The guild inventory is busy.");
				return false;
			}
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead() || !PrivateArea.CheckAccess(((Component)container).transform.position, 0f, true, false))
			{
				return false;
			}
			ZDO zDO = ((Component)container).GetComponent<ZNetView>().GetZDO();
			if (zDO == null)
			{
				return false;
			}
			chestId = zDO.m_uid;
			opening = new OpenRequest
			{
				Chest = container,
				Player = Player.m_localPlayer,
				Inventory = ((Humanoid)Player.m_localPlayer).GetInventory(),
				Id = chestId,
				Sequence = ++openRequest,
				Started = Time.unscaledTime,
				Action = action,
				Transfer = transfer,
				Completion = completion
			};
			lastReply = Time.unscaledTime;
			try
			{
				Send((action == QuickAction.Automation) ? Operation.OpenAutomation : Operation.Open, "", openRequest);
			}
			catch (Exception exception)
			{
				opening = null;
				Plugin.Error(exception);
				return false;
			}
			return true;
		}

		internal static bool Transfer(Container container, Action<Inventory, Inventory> action, Action<bool, string>? completed)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			if (Pending || Opening || finishing || resetting || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead() || ((Character)Player.m_localPlayer).IsTeleporting())
			{
				return false;
			}
			if (HasSession && !Owns(container))
			{
				return false;
			}
			TransferCompletion val = new TransferCompletion(completed, (Action<Exception>)Plugin.Error);
			if (Owns(container))
			{
				StageAutomation(action, val);
				return true;
			}
			return OpenCore(container, QuickAction.Automation, action, val);
		}

		private static void StageAutomation(Action<Inventory, Inventory> action, TransferCompletion completed)
		{
			try
			{
				if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead() || ((Character)Player.m_localPlayer).IsTeleporting())
				{
					throw new InvalidOperationException("The player is no longer available for this transfer.");
				}
				Transaction transaction = new Transaction
				{
					Completed = completed
				};
				action(transaction.PlayerStage, transaction.SharedStage);
				if (!Submit(transaction))
				{
					if (closeWanted)
					{
						Close();
					}
					completed.Complete(true, "No items transferred.");
				}
			}
			catch (Exception ex)
			{
				Plugin.Error(ex);
				if (!Pending)
				{
					if (closeWanted)
					{
						Close();
					}
					completed.Complete(false, ex.Message);
				}
			}
		}

		private static void Send(Operation operation, string sessionToken, long requestSequence, ZDOID? target = null)
		{
			//IL_001f: 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)
			Plugin.RequestRpc.SendPackage(Plugin.ServerId, Protocol.Header(operation, (ZDOID)(((??)target) ?? chestId), sessionToken, requestSequence));
		}

		private static void ReleaseGrant(ZDOID id, string receivedToken)
		{
			//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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (receivedToken.Length != 0 && receivedToken != token && (opening == null || opening.Id != id))
			{
				Effect(delegate
				{
					//IL_000a: Unknown result type (might be due to invalid IL or missing references)
					Send(Operation.Close, receivedToken, 0L, id);
				});
			}
		}

		private static bool Valid(OpenRequest request)
		{
			if (Object.op_Implicit((Object)(object)request.Chest) && Object.op_Implicit((Object)(object)request.Player) && (Object)(object)request.Player == (Object)(object)Player.m_localPlayer && !((Character)request.Player).IsDead() && !((Character)request.Player).IsTeleporting())
			{
				return ((Humanoid)request.Player).GetInventory() == request.Inventory;
			}
			return false;
		}

		private static void CancelOpen(string reason)
		{
			OpenRequest openRequest = opening;
			opening = null;
			if (openRequest != null)
			{
				if (openRequest.Completion != null)
				{
					openRequest.Completion.Complete(false, reason);
				}
				else
				{
					Plugin.Message(reason);
				}
			}
		}

		private static bool Effect(Action action)
		{
			try
			{
				action();
				return true;
			}
			catch (Exception exception)
			{
				Plugin.Error(exception);
				return false;
			}
		}

		internal static IEnumerator Receive(long sender, ZPackage package)
		{
			try
			{
				Handle(sender, package);
			}
			catch (Exception exception)
			{
				Plugin.Error(exception);
				Plugin.Message("Guild Chest could not read the host response.");
			}
			yield break;
		}

		private unsafe static void Handle(long sender, ZPackage package)
		{
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_031d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Invalid comparison between Unknown and I4
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Invalid comparison between Unknown and I4
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || sender != Plugin.ServerId || package.Size() > 1052672)
			{
				return;
			}
			Operation operation = (Operation)package.ReadInt();
			ZDOID val = package.ReadZDOID();
			string text = package.ReadString();
			long num = package.ReadLong();
			AccessResult val2 = (AccessResult)package.ReadInt();
			long replyRevision = package.ReadLong();
			byte[] array = package.ReadByteArray();
			string text2 = ((package.GetPos() < package.Size()) ? package.ReadString() : ((object)(*(AccessResult*)(&val2))/*cast due to .constrained prefix*/).ToString());
			switch (operation)
			{
			case Operation.Peek:
				StoragePreview.ReceiveSnapshot(val, num, val2, replyRevision, array);
				return;
			case Operation.Open:
			case Operation.OpenAutomation:
			{
				if (opening == null || val != opening.Id || num != opening.Sequence || operation != (Operation)((opening.Action == QuickAction.Automation) ? 5 : 0))
				{
					if ((int)val2 == 0)
					{
						ReleaseGrant(val, text);
					}
					return;
				}
				OpenRequest openRequest = opening;
				opening = null;
				if (!Valid(openRequest))
				{
					if ((int)val2 == 0)
					{
						ReleaseGrant(val, text);
					}
					TransferCompletion? completion = openRequest.Completion;
					if (completion != null)
					{
						completion.Complete(false, "The player or guild chest is no longer available.");
					}
					return;
				}
				if ((int)val2 != 0)
				{
					TransferCompletion? completion2 = openRequest.Completion;
					if (completion2 != null)
					{
						completion2.Complete(false, text2);
					}
					Plugin.Message(((int)val2 == 1) ? "Someone is using the guild inventory." : ("Guild Chest: " + text2));
					return;
				}
				Inventory view;
				try
				{
					view = InventoryCodec.Read(array);
				}
				catch (Exception ex)
				{
					ReleaseGrant(val, text);
					Reset();
					TransferCompletion? completion3 = openRequest.Completion;
					if (completion3 != null)
					{
						completion3.Complete(false, ex.Message);
					}
					Plugin.Message("Guild Chest: " + ex.Message);
					return;
				}
				chestId = val;
				Chest = openRequest.Chest;
				token = text;
				sequence = 0L;
				revision = replyRevision;
				View = view;
				lastReply = Time.unscaledTime;
				nextHeartbeat = lastReply + 5f;
				InventoryAccess.Protect(View);
				InventoryAccess.ContainerInventory.Invoke(Chest) = View;
				if (openRequest.Action == QuickAction.Automation)
				{
					closeWanted = true;
					StageAutomation(openRequest.Transfer, openRequest.Completion);
				}
				else if (openRequest.Action == QuickAction.None)
				{
					if (!Effect(delegate
					{
						InventoryGui.instance.Show(Chest, 1);
					}))
					{
						Close();
					}
				}
				else
				{
					closeWanted = true;
					Bulk(openRequest.Action == QuickAction.Take);
				}
				return;
			}
			}
			if (val != chestId || text != token || !HasSession)
			{
				return;
			}
			lastReply = Time.unscaledTime;
			switch (operation)
			{
			case Operation.Commit:
			{
				if (Client.transaction == null || num != Client.transaction.Sequence)
				{
					break;
				}
				Transaction transaction = Client.transaction;
				if (transaction.Lifecycle.Acknowledge((int)val2 == 0))
				{
					transaction.ReplyRevision = replyRevision;
					transaction.ReplyInventory = array;
					transaction.ReplyReason = text2;
					if ((int)val2 != 0)
					{
						Plugin.LogWarning($"Transfer {num} rejected by host: {val2}. {text2}");
					}
					Finish(transaction);
				}
				break;
			}
			case Operation.Heartbeat:
				if ((int)val2 != 0)
				{
					closeWanted = true;
					if (!Pending)
					{
						Close();
					}
				}
				break;
			}
		}

		private static void Finish(Transaction finished)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Invalid comparison between Unknown and I4
			if (finishing || transaction != finished)
			{
				return;
			}
			bool flag = (int)finished.Lifecycle.Phase == 1 || (int)finished.Lifecycle.Phase == 2;
			finishing = true;
			try
			{
				if (flag)
				{
					try
					{
						finished.Lifecycle.TryApply((Action)finished.Apply);
					}
					catch (Exception exception)
					{
						Plugin.Error(exception);
						nextRetry = Time.unscaledTime + 2f;
						return;
					}
					revision = finished.ReplyRevision;
					Applying = true;
					finished.Notify();
					if (!Effect(delegate
					{
						if (View != null)
						{
							InventoryCodec.Replace(View, InventoryCodec.Read(finished.ReplyInventory));
						}
					}))
					{
						closeWanted = true;
					}
					if (!Effect(delegate
					{
						StoragePreview.RefreshSnapshot(finished.ReplyInventory, finished.ReplyRevision);
					}))
					{
						closeWanted = true;
					}
				}
				else
				{
					Effect(delegate
					{
						Plugin.Message("Transfer rejected: " + finished.ReplyReason + " Your items have not moved.");
					});
					closeWanted = true;
				}
				transaction = null;
				Effect(ClearDrag);
				if (deferredDeath && Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					deferredDeath = false;
					Effect(delegate
					{
						((Character)Player.m_localPlayer).OnDeath();
					});
					closeWanted = true;
				}
				if (closeWanted || !Object.op_Implicit((Object)(object)Chest))
				{
					Close();
				}
				finished.Lifecycle.Finish();
			}
			finally
			{
				Applying = false;
				finishing = false;
			}
			TransferCompletion? completed = finished.Completed;
			if (completed != null)
			{
				completed.Complete(flag, finished.ReplyReason);
			}
		}

		internal static void Close()
		{
			if (Pending)
			{
				closeWanted = true;
				return;
			}
			if (HasSession && Object.op_Implicit((Object)(object)ZNet.instance) && ZRoutedRpc.instance != null)
			{
				Effect(delegate
				{
					Send(Operation.Close, token, sequence);
				});
			}
			Reset();
		}

		internal static void Reset()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Invalid comparison between Unknown and I4
			OpenRequest openRequest = opening;
			Transaction transaction = Client.transaction;
			Chest = null;
			opening = null;
			View = null;
			token = "";
			Client.transaction = null;
			closeWanted = false;
			deferredDeath = false;
			resetting = true;
			try
			{
				if (openRequest != null)
				{
					TransferCompletion? completion = openRequest.Completion;
					if (completion != null)
					{
						completion.Complete(false, "The guild inventory session ended before it opened.");
					}
				}
				if (transaction != null)
				{
					TransferCompletion? completed = transaction.Completed;
					if (completed != null)
					{
						completed.Complete((int)transaction.Lifecycle.Phase == 2, "The session ended before transfer completion. A sent transfer may already have been accepted by the host.");
					}
				}
			}
			finally
			{
				resetting = false;
			}
		}

		internal static bool DeferDeath(Player player)
		{
			if ((Object)(object)player != (Object)(object)Player.m_localPlayer || !Pending)
			{
				return false;
			}
			deferredDeath = true;
			closeWanted = true;
			return true;
		}

		internal static void Tick()
		{
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Invalid comparison between Unknown and I4
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Invalid comparison between Unknown and I4
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (opening != null && !Valid(opening))
			{
				CancelOpen("The player or guild chest is no longer available.");
			}
			else if (opening != null && unscaledTime - opening.Started > 30f)
			{
				CancelOpen("Guild Chest host did not respond.");
			}
			if (!HasSession)
			{
				return;
			}
			if (unscaledTime >= nextHeartbeat)
			{
				Effect(delegate
				{
					Send(Operation.Heartbeat, token, sequence);
				});
				nextHeartbeat = unscaledTime + 5f;
			}
			if (Pending)
			{
				if (!(unscaledTime >= nextRetry))
				{
					return;
				}
				Transaction current = transaction;
				nextRetry = unscaledTime + 2f;
				if ((int)current.Lifecycle.Phase == 1 || (int)current.Lifecycle.Phase == 2)
				{
					Finish(current);
					return;
				}
				Effect(delegate
				{
					//IL_0015: Unknown result type (might be due to invalid IL or missing references)
					//IL_001f: Expected O, but got Unknown
					Plugin.RequestRpc.SendPackage(Plugin.ServerId, new ZPackage(current.Request));
				});
			}
			else if (!Object.op_Implicit((Object)(object)Chest) || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead() || unscaledTime - lastReply > 35f || Vector3.Distance(((Component)Chest).transform.position, ((Component)Player.m_localPlayer).transform.position) > 4f)
			{
				Close();
			}
		}

		private static bool Submit(Transaction candidate)
		{
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			foreach (ItemData allItem in candidate.SharedStage.GetAllItems())
			{
				allItem.m_equipped = false;
			}
			byte[] array = InventoryCodec.Save(candidate.SharedStage);
			if (array.SequenceEqual(InventoryCodec.Save(View)))
			{
				Effect(ClearDrag);
				return false;
			}
			byte[] array2 = InventoryCodec.Save(candidate.PlayerStage);
			if (array.Length > 1048576 || array2.Length > 1048576)
			{
				throw new InvalidOperationException("This transfer exceeds the supported inventory size.");
			}
			candidate.Sequence = ++sequence;
			ZPackage val = Protocol.Header(Operation.Commit, chestId, token, candidate.Sequence);
			val.Write(revision);
			val.Write(candidate.PlayerStage.GetWidth());
			val.Write(candidate.PlayerStage.GetHeight());
			val.Write(candidate.PlayerBefore);
			val.Write(array);
			val.Write(array2);
			candidate.Request = val.GetArray();
			transaction = candidate;
			nextRetry = Time.unscaledTime + 2f;
			Effect(ClearDrag);
			Effect(delegate
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_001f: Expected O, but got Unknown
				Plugin.RequestRpc.SendPackage(Plugin.ServerId, new ZPackage(candidate.Request));
			});
			return true;
		}

		internal static void Bulk(bool take)
		{
			if (HasSession && !Pending && Object.op_Implicit((Object)(object)Player.m_localPlayer) && !((Character)Player.m_localPlayer).IsTeleporting())
			{
				Transaction transaction = new Transaction();
				if (take)
				{
					transaction.PlayerStage.MoveAll(transaction.SharedStage);
				}
				else
				{
					transaction.SharedStage.StackAll(transaction.PlayerStage, false);
				}
				if (!Submit(transaction) && closeWanted)
				{
					Close();
				}
			}
		}

		internal static void ClearDrag()
		{
			if (Object.op_Implicit((Object)(object)InventoryGui.instance))
			{
				AccessTools.Method(typeof(InventoryGui), "SetupDragItem", (Type[])null, (Type[])null).Invoke(InventoryGui.instance, new object[3] { null, null, 1 });
			}
		}

		internal static bool Select(InventoryGui gui, InventoryGrid grid, ItemData? item, Vector2i position, Modifier modifier)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Invalid comparison between Unknown and I4
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Invalid comparison between Unknown and I4
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			if (Pending)
			{
				return false;
			}
			if (!GuildUi)
			{
				return true;
			}
			if (((Character)Player.m_localPlayer).IsTeleporting())
			{
				return false;
			}
			Inventory inventory = grid.GetInventory();
			Inventory val = AccessTools.FieldRefAccess<InventoryGui, Inventory>("m_dragInventory").Invoke(gui);
			ItemData val2 = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_dragItem").Invoke(gui);
			bool flag = Object.op_Implicit((Object)(object)AccessTools.FieldRefAccess<InventoryGui, GameObject>("m_dragGo").Invoke(gui));
			if ((int)modifier == 3 && inventory == View)
			{
				Plugin.Message("Move the item into your inventory before dropping it.");
				return false;
			}
			if (flag && (val == View || inventory == View))
			{
				if (val2 == null || !val.ContainsItem(val2))
				{
					ClearDrag();
					return false;
				}
				if (val != inventory && (val2.m_shared.m_questItem || (item != null && item.m_shared.m_questItem)))
				{
					return false;
				}
				Transaction transaction = new Transaction();
				Inventory val3 = ((val == View) ? transaction.SharedStage : transaction.PlayerStage);
				Inventory val4 = ((inventory == View) ? transaction.SharedStage : transaction.PlayerStage);
				ItemData itemAt = val3.GetItemAt(val2.m_gridPos.x, val2.m_gridPos.y);
				int num = AccessTools.FieldRefAccess<InventoryGui, int>("m_dragAmount").Invoke(gui);
				ref Inventory reference = ref AccessTools.FieldRefAccess<InventoryGrid, Inventory>("m_inventory").Invoke(grid);
				Inventory val5 = reference;
				try
				{
					reference = val4;
					grid.DropItem(val3, itemAt, num, position);
				}
				finally
				{
					reference = val5;
				}
				Submit(transaction);
				return false;
			}
			if ((int)modifier == 2 && item != null)
			{
				if (item.m_shared.m_questItem)
				{
					return false;
				}
				Transaction transaction2 = new Transaction();
				Inventory val6 = ((inventory == View) ? transaction2.SharedStage : transaction2.PlayerStage);
				Inventory obj = ((inventory == View) ? transaction2.PlayerStage : transaction2.SharedStage);
				ItemData itemAt2 = val6.GetItemAt(item.m_gridPos.x, item.m_gridPos.y);
				obj.MoveItemToThis(val6, itemAt2);
				Submit(transaction2);
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Container), "Awake")]
	internal static class GuildInventoryRegistrationPatch
	{
		private static void Postfix(Container __instance)
		{
			InventoryAccess.Track(__instance);
		}
	}
	[HarmonyPatch(typeof(Container), "GetInventory")]
	internal static class GuildInventoryAccessPatch
	{
		private static bool Prefix(Container __instance, ref Inventory __result)
		{
			if (!Plugin.IsGuild(__instance))
			{
				return true;
			}
			__result = InventoryAccess.InventoryFor(__instance);
			return false;
		}
	}
	[HarmonyPatch(typeof(ZNetView), "IsOwner")]
	internal static class AutomationOwnerPatch
	{
		private static bool Prefix(ZNetView __instance, ref bool __result)
		{
			if (!Object.op_Implicit((Object)(object)InventoryAccess.ScopedChest) || (Object)(object)((Component)InventoryAccess.ScopedChest).GetComponent<ZNetView>() != (Object)(object)__instance)
			{
				return true;
			}
			__result = true;
			return false;
		}
	}
	[HarmonyPatch]
	internal static class GuildUiInventoryScopePatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			return new string[3] { "Show", "UpdateContainer", "UpdateContainerWeight" }.Select((string name) => AccessTools.Method(typeof(InventoryGui), name, (Type[])null, (Type[])null));
		}

		private static void Prefix(ref bool __state)
		{
			StorageScopes.Enter(StorageScope.Ui, ref __state);
		}

		private static void Finalizer(bool __state)
		{
			StorageScopes.Exit(StorageScope.Ui, __state);
		}
	}
	[HarmonyPatch]
	internal static class CraftyPreviewScopePatch
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name == "HaveRequirements" || methodInfo.Name == "HaveRequirementItems")
				{
					yield return methodInfo;
				}
			}
			yield return AccessTools.Method(typeof(InventoryGui), "SetupRequirement", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(InventoryGui), "SetupRequirementList", (Type[])null, (Type[])null);
			yield return AccessTools.Method(typeof(Hud), "SetupPieceInfo", (Type[])null, (Type[])null);
		}

		[HarmonyPriority(800)]
		private static void Prefix(ref bool __state)
		{
			StorageScopes.Enter(StorageScope.Preview, ref __state);
		}

		private static void Finalizer(bool __state)
		{
			StorageScopes.Exit(StorageScope.Preview, __state);
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
	internal static class GuildCraftingSupplyPatch
	{
		[HarmonyPriority(800)]
		private static bool Prefix(InventoryGui __instance, Player player, ref bool __state)
		{
			if (Client.Pending || Client.Opening)
			{
				return false;
			}
			Recipe recipe = AccessTools.FieldRefAccess<InventoryGui, Recipe>("m_craftRecipe").Invoke(__instance);
			ItemData upgrade = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_craftUpgradeItem").Invoke(__instance);
			bool multi = AccessTools.FieldRefAccess<InventoryGui, bool>("m_multiCrafting").Invoke(__instance);
			int amount = ((!multi) ? 1 : AccessTools.FieldRefAccess<InventoryGui, int>("m_multiCraftAmount").Invoke(__instance));
			CraftingStation station = player.GetCurrentCraftingStation();
			if (Object.op_Implicit((Object)(object)recipe) && !player.NoCostCheat() && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)25) && MaterialSupply.SupplyCrafting(recipe, (upgrade == null) ? 1 : (upgrade.m_quality + 1), amount, delegate
			{
				if (Object.op_Implicit((Object)(object)__instance) && Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && !((Object)(object)player.GetCurrentCraftingStation() != (Object)(object)station) && !((Object)(object)AccessTools.FieldRefAccess<InventoryGui, Recipe>("m_craftRecipe").Invoke(__instance) != (Object)(object)recipe) && AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_craftUpgradeItem").Invoke(__instance) == upgrade && AccessTools.FieldRefAccess<InventoryGui, bool>("m_multiCrafting").Invoke(__instance) == multi && (!multi || AccessTools.FieldRefAccess<InventoryGui, int>("m_multiCraftAmount").Invoke(__instance) == amount))
				{
					AccessTools.Method(typeof(InventoryGui), "DoCrafting", (Type[])null, (Type[])null).Invoke(__instance, new object[1] { player });
				}
			}))
			{
				return false;
			}
			StorageScopes.Enter(StorageScope.Consumption, ref __state);
			return true;
		}

		private static void Finalizer(bool __state)
		{
			StorageScopes.Exit(StorageScope.Consumption, __state);
		}
	}
	[HarmonyPatch(typeof(Player), "TryPlacePiece")]
	internal static class GuildBuildingSupplyPatch
	{
		[HarmonyPriority(800)]
		private static bool Prefix(Player __instance, Piece piece, ref bool __result)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			bool num = BuildingContinuation.TryPlace(__instance, piece);
			if (!num)
			{
				__result = false;
			}
			return num;
		}
	}
	[HarmonyPatch(typeof(Player), "UpdatePlacement")]
	internal static class GuildBuildingResumePatch
	{
		private static void Prefix(Player __instance, bool takeInput)
		{
			BuildingContinuation.BeforeUpdate(__instance, takeInput);
		}

		private static void Finalizer(Player __instance)
		{
			BuildingContinuation.AfterUpdate(__instance);
		}
	}
	[HarmonyPatch(typeof(Player), "ConsumeResources")]
	internal static class GuildConsumptionScopePatch
	{
		private static void Prefix(ref bool __state)
		{
			StorageScopes.Enter(StorageScope.Consumption, ref __state);
		}

		private static void Finalizer(bool __state)
		{
			StorageScopes.Exit(StorageScope.Consumption, __state);
		}
	}
	internal static class GuardedInventoryMethods
	{
		private static readonly HashSet<string> names = new HashSet<string>
		{
			"AddItem", "CanAddItem", "MoveAll", "StackAll", "MoveItemToThis", "RemoveItem", "RemoveOneItem", "RemoveAll", "RemoveUnequipped", "Load",
			"MoveInventoryToGrave", "HaveEmptySlot"
		};

		private static readonly MethodInfo[] methods = (from method in typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
			where names.Contains(method.Name)
			select method).ToArray();

		internal static bool Blocked(Inventory inventory, object[] arguments)
		{
			if (InventoryAccess.Blocked(inventory))
			{
				return true;
			}
			foreach (object obj in arguments)
			{
				Inventory val = (Inventory)((obj is Inventory) ? obj : null);
				if (val != null && InventoryAccess.Blocked(val))
				{
					return true;
				}
			}
			return false;
		}

		internal static IEnumerable<MethodBase> WithReturn(Type result)
		{
			return methods.Where((MethodInfo method) => method.ReturnType == result);
		}
	}
	[HarmonyPatch]
	internal static class GuildInventoryBoolGuard
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			return GuardedInventoryMethods.WithReturn(typeof(bool));
		}

		[HarmonyPriority(800)]
		private static bool Prefix(Inventory __instance, object[] __args, ref bool __result)
		{
			if (!GuardedInventoryMethods.Blocked(__instance, __args))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch]
	internal static class GuildInventoryIntGuard
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			return GuardedInventoryMethods.WithReturn(typeof(int));
		}

		[HarmonyPriority(800)]
		private static bool Prefix(Inventory __instance, object[] __args, ref int __result)
		{
			if (!GuardedInventoryMethods.Blocked(__instance, __args))
			{
				return true;
			}
			__result = 0;
			return false;
		}
	}
	[HarmonyPatch]
	internal static class GuildInventoryItemGuard
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			return GuardedInventoryMethods.WithReturn(typeof(ItemData));
		}

		[HarmonyPriority(800)]
		private static bool Prefix(Inventory __instance, object[] __args, ref ItemData? __result)
		{
			if (!GuardedInventoryMethods.Blocked(__instance, __args))
			{
				return true;
			}
			__result = null;
			return false;
		}
	}
	[HarmonyPatch]
	internal static class GuildInventoryVoidGuard
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			return GuardedInventoryMethods.WithReturn(typeof(void));
		}

		[HarmonyPriority(800)]
		private static bool Prefix(Inventory __instance, object[] __args)
		{
			return !GuardedInventoryMethods.Blocked(__instance, __args);
		}
	}
	internal static class CraftyBoxesAdapter
	{
		private sealed class Bindings
		{
			internal readonly MethodInfo Query;

			internal readonly MethodInfo ShouldPrevent;

			internal readonly MethodInfo CanPull;

			internal readonly MethodInfo Invalidate;

			internal readonly FieldInfo Totals;

			internal readonly FieldInfo ContainersHavingAny;

			internal readonly Func<float> Range;

			internal readonly Func<int> LeaveOne;

			internal readonly (MethodInfo Target, string Prefix)[] Hooks;

			internal Bindings(Type plugin)
			{
				Assembly assembly = plugin.Assembly;
				Type type = StorageBindings.Type(assembly, "AzuCraftyBoxes.Util.Functions.Boxes");
				Type type2 = StorageBindings.Type(assembly, "AzuCraftyBoxes.Util.Functions.MiscFunctions");
				Type type3 = StorageBindings.Type(assembly, "AzuCraftyBoxes.Util.Functions.UiItemBank");
				Type type4 = StorageBindings.Type(assembly, "AzuCraftyBoxes.IContainers.VanillaContainer");
				Type type5 = StorageBindings.Type(assembly, "AzuCraftyBoxes.IContainers.IContainer");
				ContainerBindings.Validate(type4, crafting: true);
				Query = StorageBindings.NearbyQuery(type);
				ShouldPrevent = StorageBindings.Method(type2, "ShouldPrevent", typeof(bool), Type.EmptyTypes);
				CanPull = StorageBindings.Method(type, "CanItemBePulled", typeof(bool), new Type[3]
				{
					typeof(string),
					typeof(string),
					typeof(string)
				});
				Invalidate = StorageBindings.Method(type, "InvalidateCounts", typeof(void), Type.EmptyTypes);
				Totals = StorageBindings.Field(type3, "_totals");
				ContainersHavingAny = StorageBindings.Field(type3, "_containersHavingAny");
				FieldInfo[] array = new FieldInfo[2] { Totals, ContainersHavingAny };
				foreach (FieldInfo fieldInfo in array)
				{
					if (!fieldInfo.IsStatic || !typeof(IDictionary).IsAssignableFrom(fieldInfo.FieldType))
					{
						throw new InvalidOperationException("Unsupported CraftyBoxes UI count cache.");
					}
				}
				Range = StorageBindings.Setting<float>(plugin, "mRange");
				LeaveOne = StorageBindings.Setting<int>(plugin, "leaveOne");
				Hooks = new(MethodInfo, string)[5]
				{
					(StorageBindings.Method(type4, "ItemCount", typeof(int), new Type[1] { typeof(string) }), "Count"),
					(StorageBindings.Method(type4, "GetInventory", typeof(Inventory), Type.EmptyTypes), "GetInventory"),
					(StorageBindings.Method(type4, "ProcessContainerInventory", typeof(int), new Type[3]
					{
						typeof(string),
						typeof(int),
						typeof(int)
					}), "Consume"),
					(StorageBindings.Method(type4, "RemoveItem", typeof(void), new Type[2]
					{
						typeof(string),
						typeof(int)
					}), "Remove"),
					(StorageBindings.Method(type, "MemoUsable", typeof(bool), new Type[1] { typeof(List<>).MakeGenericType(type5) }), "Memo")
				};
			}
		}

		internal const string PluginId = "Azumatt.AzuCraftyBoxes";

		private static Bindings? bindings;

		internal static bool Installed => bindings != null;

		private static Bindings Api => bindings ?? throw new InvalidOperationException("CraftyBoxes adapter is unavailable.");

		internal static bool LeaveOne => Api.LeaveOne() != 0;

		internal static void Install(Harmony harmony, Type plugin)
		{
			Bindings bindings = new Bindings(plugin);
			StorageBindings.Patch(harmony, typeof(CraftyBoxesAdapter), bindings.Hooks);
			CraftyBoxesAdapter.bindings = bindings;
		}

		internal static List<object> Nearby()
		{
			if (!Installed || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || (bool)Api.ShouldPrevent.Invoke(null, null))
			{
				return new List<object>();
			}
			return ((IEnumerable)Api.Query.Invoke(null, new object[2]
			{
				Player.m_localPlayer,
				Api.Range()
			})).Cast<object>().ToList();
		}

		internal static bool Pullable(object wrapper, string prefab)
		{
			MethodInfo canPull = Api.CanPull;
			object[] parameters = new string[3]
			{
				ContainerBindings.PrefabFor(wrapper),
				prefab,
				""
			};
			return (bool)canPull.Invoke(null, parameters);
		}

		internal static void InvalidateCounts()
		{
			if (Installed)
			{
				Api.Invalidate.Invoke(null, null);
				(Api.Totals.GetValue(null) as IDictionary)?.Clear();
				(Api.ContainersHavingAny.GetValue(null) as IDictionary)?.Clear();
			}
		}

		private static bool Count(object __instance, string name, ref int __result)
		{
			Container val = ContainerBindings.ContainerFor(__instance);
			if (!Plugin.IsGuild(val))
			{
				return true;
			}
			Inventory? obj = StoragePreview.For(val);
			__result = ((obj != null) ? obj.CountItems(name, -1, true) : 0);
			return false;
		}

		private static bool GetInventory(object __instance, ref Inventory __result)
		{
			Container val = ContainerBindings.ContainerFor(__instance);
			if (!Plugin.IsGuild(val))
			{
				return true;
			}
			Inventory val2 = StoragePreview.For(val);
			if (val2 == null)
			{
				__result = InventoryAccess.InventoryFor(val);
			}
			else
			{
				__result = InventoryCodec.Clone(val2);
				InventoryAccess.Protect(__result);
			}
			return false;
		}

		private static bool Consume(object __instance, int totalAmount, ref int __result)
		{
			if (!Plugin.IsGuild(ContainerBindings.ContainerFor(__instance)))
			{
				return true;
			}
			__result = totalAmount;
			return false;
		}

		private static bool Remove(object __instance)
		{
			return !Plugin.IsGuild(ContainerBindings.ContainerFor(__instance));
		}

		private static bool Memo(ref bool __result)
		{
			if (StorageScopes.PreviewDepth > 0 && StorageScopes.ConsumptionDepth == 0)
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	public static class GuildChestStorage
	{
		public static bool IsGuildChest(Container container)
		{
			return Plugin.IsGuild(container);
		}

		public static bool TryTransfer(Container chest, Action<Inventory, Inventory> transfer, Action<bool, string>? completed = null)
		{
			if (!Plugin.IsGuild(chest) || transfer == null)
			{
				return false;
			}
			return Client.Transfer(chest, transfer, completed);
		}
	}
	internal static class Host
	{
		private const string ItemsKey = "gc_inventory_v1";

		private const string RevisionKey = "gc_revision";

		internal static SharedStore? Store;

		private static ZDO? state;

		private static ZDOMan? manager;

		private static float nextPeerCheck;

		private static string automationToken = "";

		private static readonly Dictionary<int, float> wardRadii = new Dictionary<int, float>();

		private static readonly HashSet<ZDOID> wards = new HashSet<ZDOID>();

		internal static bool IsServer
		{
			get
			{
				if (Object.op_Implicit((Object)(object)ZNet.instance))
				{
					return ZNet.instance.IsServer();
				}
				return false;
			}
		}

		private static IEnumerable<ZDO> Objects => AccessTools.FieldRefAccess<ZDOMan, Dictionary<ZDOID, ZDO>>("m_objectsByID").Invoke(ZDOMan.instance).Values;

		internal static bool IsState(ZDO zdo)
		{
			return zdo.GetPrefab() == Plugin.StateHash;
		}

		internal static void Initialize()
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Expected O, but got Unknown
			if (!IsServer || ZNet.m_loadError || !Object.op_Implicit((Object)(object)ZNetScene.instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance.GetPrefab("GuildChestWorldState")) || (manager == ZDOMan.instance && Store != null))
			{
				return;
			}
			manager = ZDOMan.instance;
			List<ZDO> list = Objects.Where(IsState).ToList();
			if (list.Count > 1)
			{
				throw new InvalidOperationException("Multiple Guild Chest world state records; refusing to overwrite them.");
			}
			state = list.SingleOrDefault() ?? manager.CreateNewZDO(Vector3.zero, Plugin.StateHash);
			state.Persistent = true;
			state.Type = (ObjectType)2;
			state.SetPrefab(Plugin.StateHash);
			state.SetOwner(ZNet.GetUID());
			int num = state.GetInt("gc_schema", 1);
			if (num != 1)
			{
				throw new InvalidOperationException($"Unsupported Guild Chest save schema {num}.");
			}
			byte[] array = InventoryCodec.Save(InventoryCodec.Empty());
			Store = new SharedStore(state.GetByteArray("gc_inventory_v1", array), state.GetLong("gc_revision", 0L));
			wardRadii.Clear();
			wards.Clear();
			foreach (KeyValuePair<int, GameObject> item in AccessTools.FieldRefAccess<ZNetScene, Dictionary<int, GameObject>>("m_namedPrefabs").Invoke(ZNetScene.instance))
			{
				PrivateArea component = item.Value.GetComponent<PrivateArea>();
				if (Object.op_Implicit((Object)(object)component))
				{
					wardRadii[item.Key] = component.m_radius;
				}
			}
			foreach (ZDO @object in Objects)
			{
				Register(@object);
			}
			Persist();
			Plugin.LogInfo($"Guild Chest authority ready: {Store.ChestCount} chests; Valheim {Version.GetVersionString(false)}.");
		}

		internal static void Persist()
		{
			if (IsServer && Store != null && state != null)
			{
				StoreSnapshot val = Store.Snapshot();
				state.Set("gc_schema", 1);
				state.Set("gc_inventory_v1", val.Inventory);
				state.Set("gc_revision", val.Revision);
			}
		}

		internal static void Register(ZDO zdo)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (IsServer && Store != null)
			{
				if (zdo.GetPrefab() == Plugin.ChestHash)
				{
					Store.Register(((object)Unsafe.As<ZDOID, ZDOID>(ref zdo.m_uid)/*cast due to .constrained prefix*/).ToString());
				}
				if (wardRadii.ContainsKey(zdo.GetPrefab()))
				{
					wards.Add(zdo.m_uid);
				}
			}
		}

		internal static void Destroyed(ZDO zdo)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (IsServer && Store != null && state != null)
			{
				wards.Remove(zdo.m_uid);
				if (zdo.GetPrefab() == Plugin.ChestHash && Store.Remove(((object)Unsafe.As<ZDOID, ZDOID>(ref zdo.m_uid)/*cast due to .constrained prefix*/).ToString()))
				{
					Persist();
				}
			}
		}

		internal static void Tick()
		{
			if (!IsServer)
			{
				return;
			}
			if (manager != ZDOMan.instance)
			{
				Reset();
			}
			else
			{
				if (Store == null)
				{
					return;
				}
				Store.Expire((double)Time.unscaledTime);
				if (!(Time.unscaledTime < nextPeerCheck))
				{
					nextPeerCheck = Time.unscaledTime + 1f;
					Lease activeLease = Store.ActiveLease;
					if (activeLease != null && activeLease.Peer != ZNet.GetUID() && ZNet.instance.GetPeer(activeLease.Peer) == null)
					{
						Store.Disconnect(activeLease.Peer);
					}
				}
			}
		}

		internal static void Reset()
		{
			Store = null;
			state = null;
			manager = null;
			wards.Clear();
			wardRadii.Clear();
			automationToken = "";
		}

		internal static IEnumerator Receive(long sender, ZPackage package)
		{
			try
			{
				Handle(sender, package);
			}
			catch (Exception exception)
			{
				Plugin.Error(exception);
			}
			yield break;
		}

		private unsafe static void Handle(long sender, ZPackage package)
		{
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_039f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a2: Invalid comparison between Unknown and I4
			//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ae: Invalid comparison between Unknown and I4
			//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0410: Unknown result type (might be due to invalid IL or missing references)
			//IL_041d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0424: Expected I4, but got Unknown
			//IL_0442: 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_03e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0382: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			if (!IsServer || Store == null || state == null || package.Size() > 3149824 || (sender != ZNet.GetUID() && ZNet.instance.GetPeer(sender) == null))
			{
				return;
			}
			Operation operation = (Operation)package.ReadInt();
			ZDOID val = package.ReadZDOID();
			string text = package.ReadString();
			long num = package.ReadLong();
			ZDO zDO = ZDOMan.instance.GetZDO(val);
			AccessResult val2 = (AccessResult)3;
			string text2 = text;
			string text3 = "The inventory session is no longer valid. Reopen the chest.";
			try
			{
				switch (operation)
				{
				case Operation.Close:
					val2 = (AccessResult)((!Store.Close(sender, text)) ? 3 : 0);
					break;
				case Operation.Commit:
				{
					long num2 = package.ReadLong();
					int num3 = package.ReadInt();
					int num4 = package.ReadInt();
					byte[] oldPlayer = package.ReadByteArray();
					byte[] array = package.ReadByteArray();
					byte[] newPlayer = package.ReadByteArray();
					AccessResult val4 = default(AccessResult);
					if (Store.TryReplay(sender, text, num, array, ref val4))
					{
						val2 = val4;
						break;
					}
					if (zDO == null || zDO.GetPrefab() != Plugin.ChestHash)
					{
						val2 = (AccessResult)2;
						text3 = "The chest no longer exists on the server.";
						break;
					}
					if (!HasAccess(sender, zDO, text == automationToken))
					{
						val2 = (AccessResult)6;
						text3 = "The server denied access: check your distance and ward permissions.";
						break;
					}
					if (!Store.Authorized(sender, text, (double)Time.unscaledTime) || Store.ActiveLease.Chest != ((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString())
					{
						val2 = (AccessResult)3;
						break;
					}
					if (num3 < 1 || num3 > 16 || num4 < 1 || num4 > 32)
					{
						val2 = (AccessResult)9;
						text3 = $"Unsupported player inventory dimensions: {num3} x {num4}.";
						break;
					}
					if (num2 != Store.Snapshot().Revision)
					{
						val2 = (AccessResult)4;
						text3 = "The shared inventory changed. Reopen the chest.";
						break;
					}
					Inventory oldShared = ReadInventory(Store.Snapshot().Inventory, "stored guild inventory");
					Inventory newShared = ReadInventory(array, "guild inventory after transfer");
					if (InventoryCodec.Conserves(oldShared, oldPlayer, newShared, newPlayer, num3, num4))
					{
						val2 = Store.Commit(sender, text, num2, num, array, (double)Time.unscaledTime);
						if ((int)val2 == 0)
						{
							Persist();
						}
					}
					else
					{
						val2 = (AccessResult)8;
						text3 = "The transfer changes item quantities or types; check inventory mods on client and server.";
					}
					break;
				}
				default:
					if (zDO != null && zDO.GetPrefab() == Plugin.ChestHash && HasAccess(sender, zDO, operation == Operation.Peek || operation == Operation.OpenAutomation || (text == automationToken && text.Length > 0)))
					{
						Store.Register(((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString());
						switch (operation)
						{
						case Operation.Peek:
							val2 = (AccessResult)0;
							break;
						case Operation.Open:
						case Operation.OpenAutomation:
						{
							ReadInventory(Store.Snapshot().Inventory, "stored guild inventory");
							Lease val3 = default(Lease);
							val2 = Store.Open(sender, ((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString(), (double)Time.unscaledTime, ref val3);
							text2 = ((val3 != null) ? val3.Token : null) ?? "";
							if ((int)val2 == 0)
							{
								automationToken = ((operation == Operation.OpenAutomation) ? text2 : "");
							}
							break;
						}
						case Operation.Heartbeat:
						{
							Lease activeLease = Store.ActiveLease;
							if (((activeLease != null) ? activeLease.Chest : null) == ((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString())
							{
								val2 = (AccessResult)((!Store.Heartbeat(sender, text, (double)Time.unscaledTime)) ? 3 : 0);
							}
							break;
						}
						}
					}
					else if (zDO == null || zDO.GetPrefab() != Plugin.ChestHash)
					{
						val2 = (AccessResult)2;
						text3 = "The chest no longer exists on the server.";
					}
					else
					{
						val2 = (AccessResult)6;
						text3 = "The server denied access: check your distance and ward permissions.";
					}
					break;
				}
			}
			catch (Exception ex)
			{
				Plugin.Error(ex);
				val2 = (AccessResult)7;
				text3 = ex.Message;
			}
			if ((int)val2 == 1)
			{
				text3 = "Another player is using the guild inventory.";
			}
			if ((int)val2 == 5)
			{
				text3 = "The transfer request is out of order. Reopen the chest.";
			}
			if ((int)val2 != 0)
			{
				Plugin.LogWarning($"{operation} rejected: {val2}; peer={sender}, chest={val}, request={num}. {text3}");
			}
			StoreSnapshot val5 = Store.Snapshot();
			ZPackage val6 = Protocol.Header(operation, val, text2, num);
			val6.Write((int)val2);
			val6.Write(val5.Revision);
			val6.Write(val5.Inventory);
			val6.Write(((int)val2 == 0) ? "" : text3);
			Plugin.ReplyRpc.SendPackage(sender, val6);
		}

		private static Inventory ReadInventory(byte[] bytes, string context, int width = 8, int height = 4)
		{
			try
			{
				return InventoryCodec.Read(bytes, width, height);
			}
			catch (Exception ex)
			{
				throw new InvalidOperationException("Cannot read " + context + ": " + ex.Message, ex);
			}
		}

		private static bool HasAccess(long sender, ZDO chest, bool automation = false)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			long playerID;
			Vector3 position;
			if (sender == ZNet.GetUID())
			{
				if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					return false;
				}
				playerID = Player.m_localPlayer.GetPlayerID();
				position = ((Component)Player.m_localPlayer).transform.position;
			}
			else
			{
				ZNetPeer peer = ZNet.instance.GetPeer(sender);
				ZDO val = ((peer == null) ? null : ZDOMan.instance.GetZDO(peer.m_characterID));
				if (val == null || val.GetBool(ZDOVars.s_dead, false))
				{
					return false;
				}
				playerID = peer.m_playerID;
				position = val.GetPosition();
			}
			if (Vector3.Distance(position, chest.GetPosition()) > (automation ? Plugin.AutomationRange.Value : 6f))
			{
				return false;
			}
			bool flag = false;
			bool flag2 = false;
			foreach (ZDOID ward in wards)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(ward);
				if (zDO == null || !wardRadii.TryGetValue(zDO.GetPrefab(), out var value) || !zDO.GetBool(ZDOVars.s_enabled, false) || Utils.DistanceXZ(zDO.GetPosition(), chest.GetPosition()) >= value)
				{
					continue;
				}
				flag = true;
				if (zDO.GetLong(ZDOVars.s_creator, 0L) == playerID)
				{
					flag2 = true;
				}
				int num = zDO.GetInt(ZDOVars.s_permitted, 0);
				for (int i = 0; i < num; i++)
				{
					if (zDO.GetLong("pu_id" + i, 0L) == playerID)
					{
						flag2 = true;
					}
				}
			}
			return !flag || flag2;
		}
	}
	internal static class InventoryAccess
	{
		internal sealed class StagingScope : IDisposable
		{
			private readonly Player player;

			private readonly Container chest;

			private readonly Inventory originalPlayer;

			private readonly Inventory originalChest;

			private readonly Container? previousChest;

			private readonly Inventory? previousShared;

			private bool disposed;

			internal StagingScope(Player player, Container chest, Inventory personal, Inventory shared)
			{
				this.player = player;
				this.chest = chest;
				originalPlayer = PlayerInventory.Invoke((Humanoid)(object)player);
				originalChest = ContainerInventory.Invoke(chest);
				previousChest = ScopedChest;
				previousShared = scopedShared;
				PlayerInventory.Invoke((Humanoid)(object)player) = personal;
				ContainerInventory.Invoke(chest) = shared;
				ScopedChest = chest;
				scopedShared = shared;
			}

			public void Dispose()
			{
				if (!disposed)
				{
					disposed = true;
					PlayerInventory.Invoke((Humanoid)(object)player) = originalPlayer;
					ContainerInventory.Invoke(chest) = originalChest;
					ScopedChest = previousChest;
					scopedShared = previousShared;
				}
			}
		}

		private static readonly ConditionalWeakTable<Inventory, object> protectedInventories = new ConditionalWeakTable<Inventory, object>();

		private static readonly object marker = new object();

		internal static readonly FieldRef<Container, Inventory> ContainerInventory = AccessTools.FieldRefAccess<Container, Inventory>("m_inventory");

		private static readonly FieldRef<Humanoid, Inventory> PlayerInventory = AccessTools.FieldRefAccess<Humanoid, Inventory>("m_inventory");

		private static Inventory? scopedShared;

		internal static Container? ScopedChest { get; private set; }

		internal static void Protect(Inventory inventory)
		{
			protectedInventories.GetValue(inventory, (Inventory _) => marker);
		}

		internal static bool Blocked(Inventory inventory)
		{
			if (!protectedInventories.TryGetValue(inventory, out object _))
			{
				if (Client.Pending && !Client.Applying && Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					return inventory == ((Humanoid)Player.m_localPlayer).GetInventory();
				}
				return false;
			}
			return true;
		}

		private static Inventory Unavailable()
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			//IL_0014: Expected O, but got Unknown
			Inventory val = new Inventory("Guild Chest (transaction required)", (Sprite)null, 0, 0);
			Protect(val);
			return val;
		}

		internal static void Track(Container container)
		{
			if (Plugin.IsGuild(container))
			{
				ContainerInventory.Invoke(container) = Unavailable();
			}
		}

		internal static Inventory InventoryFor(Container container)
		{
			if ((Object)(object)container == (Object)(object)ScopedChest)
			{
				return scopedShared;
			}
			if (StorageScopes.UiDepth > 0 && Client.Owns(container))
			{
				return Client.View;
			}
			Inventory val = ContainerInventory.Invoke(container);
			if (val != Client.View && val.GetWidth() == 0)
			{
				return val;
			}
			return Unavailable();
		}
	}
	internal static class InventoryCodec
	{
		private sealed class Entry
		{
			internal int Hash;

			internal ItemData Item;

			internal string UnchangedKey = "";

			internal string QuantityKey => $"{Hash}:{Item.m_quality}:{Item.m_variant}:{Item.m_worldLevel}";
		}

		internal const int MaxBytes = 1048576;

		private static readonly MethodInfo changed = AccessTools.Method(typeof(Inventory), "Changed", new Type[2]
		{
			typeof(bool),
			typeof(bool)
		}, (Type[])null);

		internal static byte[] Save(Inventory inventory)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			inventory.Save(val);
			return val.GetArray();
		}

		internal static Inventory Empty(int width = 8, int height = 4)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			return new Inventory("Guild Chest", (Sprite)null, width, height);
		}

		internal static Inventory Read(byte[] bytes, int width = 8, int height = 4)
		{
			Inventory val = Empty(width, height);
			foreach (Entry item2 in ReadEntries(bytes, width, height))
			{
				ItemData item = item2.Item;
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item2.Hash);
				if (!Object.op_Implicit((Object)(object)itemPrefab) || !Object.op_Implicit((Object)(object)itemPrefab.GetComponent<ItemDrop>()))
				{
					throw new InvalidOperationException($"Missing shared-storage item prefab {item2.Hash}; install the item's mod on both client and server.");
				}
				item.m_dropPrefab = itemPrefab;
				item.m_shared = itemPrefab.GetComponent<ItemDrop>().m_itemData.m_shared;
				if (item.m_stack > item.m_shared.m_maxStackSize)
				{
					throw new InvalidOperationException($"Invalid item {((Object)itemPrefab).name}: stack {item.m_stack} exceeds server maximum {item.m_shared.m_maxStackSize}.");
				}
				val.GetAllItems().Add(item);
			}
			Changed(val);
			return val;
		}

		private static List<Entry> ReadEntries(byte[] bytes, int width, int height)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if (bytes.Length > 1048576)
			{
				throw new InvalidOperationException("Inventory exceeds the supported package size.");
			}
			ZPackage val = new ZPackage(bytes);
			int num = val.ReadInt();
			if (num != 109 && num != 110)
			{
				throw new InvalidOperationException($"Unsupported inventory format {num}; saved data has been retained.");
			}
			int num2 = val.ReadUShort();
			if (num2 > width * height)
			{
				throw new InvalidOperationException("Too many inventory entries.");
			}
			List<Entry> list = new List<Entry>();
			HashSet<int> hashSet = new HashSet<int>();
			for (int i = 0; i < num2; i++)
			{
				int pos = val.GetPos();
				var (num3, val2) = ItemData.Load(val, (Item)num);
				if (val2.m_stack <= 0 || val2.m_quality < 1 || val2.m_gridPos.x < 0 || val2.m_gridPos.x >= width || val2.m_gridPos.y < 0 || val2.m_gridPos.y >= height || !hashSet.Add(val2.m_gridPos.y * width + val2.m_gridPos.x))
				{
					throw new InvalidOperationException($"Invalid item prefab {num3}: stack {val2.m_stack}, quality {val2.m_quality}, slot ({val2.m_gridPos.x}, {val2.m_gridPos.y}) in {width} x {height} inventory, or duplicate slot.");
				}
				byte[] array = new byte[val.GetPos() - pos];
				Array.Copy(bytes, pos, array, 0, array.Length);
				array[4] = 0;
				array[5] = 0;
				list.Add(new Entry
				{
					Hash = num3,
					Item = val2,
					UnchangedKey = Convert.ToBase64String(array)
				});
			}
			if (val.GetPos() != val.Size())
			{
				throw new InvalidOperationException("Unexpected trailing inventory data.");
			}
			return list;
		}

		internal static Inventory Clone(Inventory source)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			//IL_0059: Expected O, but got Unknown
			Inventory val = new Inventory(source.GetName(), source.GetBkg(), source.GetWidth(), source.GetHeight());
			val.GetAllItems().AddRange(from item in source.GetAllItems()
				select item.Clone());
			Changed(val);
			return val;
		}

		internal static void Replace(Inventory target, Inventory source)
		{
			target.GetAllItems().Clear();
			target.GetAllItems().AddRange(from item in source.GetAllItems()
				select item.Clone());
			Changed(target);
		}

		internal static void Changed(Inventory inventory)
		{
			changed.Invoke(inventory, new object[2] { false, false });
		}

		internal static bool Conserves(Inventory oldShared, byte[] oldPlayer, Inventory newShared, byte[] newPlayer, int width, int height)
		{
			List<Entry> list = PlayerEntries(oldPlayer, "player inventory before transfer");
			List<Entry> list2 = PlayerEntries(newPlayer, "player inventory after transfer");
			Dictionary<string, long> dictionary = Count(SharedEntries(oldShared).Concat(list));
			Dictionary<string, long> after = Count(SharedEntries(newShared).Concat(list2));
			if (dictionary.Count != after.Count || !dictionary.All((KeyValuePair<string, long> pair) => after.TryGetValue(pair.Key, out var value) && value == pair.Value))
			{
				return false;
			}
			IOrderedEnumerable<string> first = (from entry in list.Where(MissingPrefab)
				select entry.UnchangedKey).OrderBy<string, string>((string key) => key, StringComparer.Ordinal);
			IOrderedEnumerable<string> second = (from entry in list2.Where(MissingPrefab)
				select entry.UnchangedKey).OrderBy<string, string>((string key) => key, StringComparer.Ordinal);
			return first.SequenceEqual(second);
			static Dictionary<string, long> Count(IEnumerable<Entry> items)
			{
				return (from entry in items
					group entry by entry.QuantityKey).ToDictionary((IGrouping<string, Entry> group) => group.Key, (IGrouping<string, Entry> group) => ((IEnumerable<Entry>)group).Sum((Func<Entry, long>)((Entry entry) => entry.Item.m_stack)));
			}
			static bool MissingPrefab(Entry entry)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(entry.Hash);
				if (Object.op_Implicit((Object)(object)itemPrefab))
				{
					return !Object.op_Implicit((Object)(object)itemPrefab.GetComponent<ItemDrop>());
				}
				return true;
			}
			List<Entry> PlayerEntries(byte[] bytes, string context)
			{
				try
				{
					return ReadEntries(bytes, width, height);
				}
				catch (Exception ex)
				{
					throw new InvalidOperationException("Cannot read " + context + ": " + ex.Message, ex);
				}
			}
			static IEnumerable<Entry> SharedEntries(Inventory inventory)
			{
				return from item in inventory.GetAllItems()
					select new Entry
					{
						Hash = StringExtensionMethods.GetStableHashCode(((Object)item.m_dropPrefab).name),
						Item = item
					};
			}
		}
	}
	internal sealed class MaterialRequest
	{
		internal readonly Requirement[] Requirements;

		internal readonly int Quality;

		internal readonly int Multiplier;

		internal readonly bool OnlyOne;

		internal readonly bool Building;

		internal readonly Recipe? Recipe;

		internal MaterialRequest(Requirement[] requirements, int quality, int multiplier, bool onlyOne, bool building, Recipe? recipe = null)
		{
			Requirements = requirements;
			Quality = quality;
			Multiplier = multiplier;
			OnlyOne = onlyOne;
			Building = building;
			Recipe = recipe;
		}
	}
	internal static class MaterialPlanner
	{
		internal sealed class MaterialNeed
		{
			internal readonly string Name;

			internal readonly int Amount;

			internal readonly int Quality;

			internal MaterialNeed(string name, int amount, int quality = -1)
			{
				Name = name;
				Amount = amount;
				Quality = quality;
			}
		}

		private static int Takeable(int count, bool leaveOne)
		{
			return Math.Max(0, count - (leaveOne ? 1 : 0));
		}

		private static List<MaterialNeed