Decompiled source of ProvisioningCache v0.3.10

BepInEx/plugins/ProvisioningCache/ProvisioningCache.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using ProvisioningCache.Core;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ProvisioningCache")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.10.0")]
[assembly: AssemblyInformationalVersion("0.3.10")]
[assembly: AssemblyProduct("ProvisioningCache")]
[assembly: AssemblyTitle("ProvisioningCache")]
[assembly: AssemblyVersion("0.3.10.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ProvisioningCache
{
	internal sealed class CacheAccounts
	{
		internal const string OwnerKey = "pc.account.owner";

		internal const string LinkKey = "pc.mp.account";

		internal const string LedgerKey = "pc.mp.collections";

		internal const string RevisionKey = "pc.mp.revision";

		private readonly ZDOMan world;

		private readonly Dictionary<long, ZDO> records = new Dictionary<long, ZDO>();

		internal IEnumerable<ZDO> Records => records.Values;

		internal CacheAccounts(ZDOMan world)
		{
			this.world = world;
		}

		internal ZDO Find(long owner)
		{
			if (!records.TryGetValue(owner, out var value))
			{
				return null;
			}
			return value;
		}

		internal void Load(List<ZDO> accounts)
		{
			records.Clear();
			foreach (ZDO item in from z in accounts
				orderby ((ZDOID)(ref z.m_uid)).UserID, ((ZDOID)(ref z.m_uid)).ID
				select z)
			{
				long num = item.GetLong("pc.account.owner", 0L);
				if (num != 0L)
				{
					if (records.ContainsKey(num))
					{
						Plugin.Instance.ReportError("Duplicate cache account preserved for player " + num);
						continue;
					}
					item.SetOwner(ZNet.GetUID());
					item.Persistent = true;
					records.Add(num, item);
				}
			}
		}

		internal ZDO GetOrCreate(long owner, ZDO piece)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			if (records.TryGetValue(owner, out var value))
			{
				return value;
			}
			string text = piece.GetString("pc.mp.state", "");
			CacheState state = ((text.Length == 0) ? new CacheState
			{
				LastWorldSeconds = ZNet.instance.GetTimeSeconds()
			} : StateCodec.Decode(text));
			CollectionLedger ledger = CollectionLedger.Decode(piece.GetString("pc.mp.collections", ""), state);
			value = world.CreateNewZDO(Vector3.zero, StringExtensionMethods.GetStableHashCode("pc_cache_account"));
			value.SetPrefab(StringExtensionMethods.GetStableHashCode("pc_cache_account"));
			value.Persistent = true;
			value.SetType((ObjectType)2);
			value.SetOwner(ZNet.GetUID());
			if (text.Length > 0)
			{
				CopyPieceMetadata(piece, value);
			}
			value.Set("pc.account.owner", owner);
			RememberPiece(value, piece.m_uid);
			Save(value, state, ledger);
			records.Add(owner, value);
			return value;
		}

		internal void Attach(ZDO account, ZDO piece)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			CacheState state = StateCodec.Decode(account.GetString("pc.mp.state", ""));
			CacheOwner.Remember(account, piece);
			CacheBinding.Attach(state, ((ZDOID)(ref piece.m_uid)).UserID, ((ZDOID)(ref piece.m_uid)).ID, ZNet.instance.GetTimeSeconds());
			RememberPiece(account, piece.m_uid);
			Save(account, state);
		}

		internal void Pause(ZDO account)
		{
			CacheState state = StateCodec.Decode(account.GetString("pc.mp.state", ""));
			CacheBinding.Pause(state, ZNet.instance.GetTimeSeconds());
			Save(account, state);
		}

		internal void Advance(ZDO account, CacheState state)
		{
			if (BoundPiece(account, state) != null)
			{
				Production.Advance(state, ZNet.instance.GetTimeSeconds(), active: true);
			}
			else
			{
				CacheBinding.Pause(state, ZNet.instance.GetTimeSeconds());
			}
		}

		internal ZDO FindForPiece(ZDOID id)
		{
			//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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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)
			ZDO zDO = world.GetZDO(id);
			if (zDO != null && zDO.GetPrefab() == StringExtensionMethods.GetStableHashCode("pc_provisioning_cache") && records.TryGetValue(zDO.GetLong("creator", 0L), out var value) && zDO.GetZDOID("pc.mp.account") == value.m_uid && value.GetInt(PieceKey(id), 0) == 1)
			{
				return value;
			}
			return ((IEnumerable<ZDO>)records.Values).FirstOrDefault((Func<ZDO, bool>)((ZDO record) => record.GetInt(PieceKey(id), 0) == 1));
		}

		internal void Save(ZDO account, CacheState state, CollectionLedger ledger = null)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			string text = StateCodec.Encode(state);
			long num = account.GetLong("pc.mp.revision", 0L) + 1;
			account.SetOwner(ZNet.GetUID());
			account.Set("pc.mp.state", text);
			if (ledger != null)
			{
				account.Set("pc.mp.collections", ledger.Encode());
			}
			account.Set("pc.mp.revision", num);
			ZDO val = BoundPiece(account, state);
			if (val != null)
			{
				val.SetOwner(ZNet.GetUID());
				val.Set("pc.mp.account", account.m_uid);
				val.Set("pc.mp.state", text);
				val.Set("pc.mp.revision", num);
				val.Set("pc.mp.used", account.GetInt("pc.mp.used", 0));
			}
		}

		private ZDO BoundPiece(ZDO account, CacheState state)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (state.BoundUser == 0L || state.BoundId == 0)
			{
				return null;
			}
			ZDO zDO = world.GetZDO(new ZDOID(state.BoundUser, state.BoundId));
			if (zDO == null || zDO.GetPrefab() != StringExtensionMethods.GetStableHashCode("pc_provisioning_cache") || zDO.GetLong("creator", 0L) != account.GetLong("pc.account.owner", 0L))
			{
				return null;
			}
			return zDO;
		}

		private static string PieceKey(ZDOID id)
		{
			return "pc.account.piece." + ((ZDOID)(ref id)).UserID + "." + ((ZDOID)(ref id)).ID;
		}

		private static void RememberPiece(ZDO account, ZDOID id)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			account.Set(PieceKey(id), 1);
		}

		private static void CopyPieceMetadata(ZDO source, ZDO target)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			List<KeyValuePair<int, float>> list = default(List<KeyValuePair<int, float>>);
			List<KeyValuePair<int, Vector3>> list2 = default(List<KeyValuePair<int, Vector3>>);
			List<KeyValuePair<int, Quaternion>> list3 = default(List<KeyValuePair<int, Quaternion>>);
			List<KeyValuePair<int, int>> list4 = default(List<KeyValuePair<int, int>>);
			List<KeyValuePair<int, long>> list5 = default(List<KeyValuePair<int, long>>);
			List<KeyValuePair<int, string>> list6 = default(List<KeyValuePair<int, string>>);
			List<KeyValuePair<int, byte[]>> list7 = default(List<KeyValuePair<int, byte[]>>);
			ZDOConnection val = default(ZDOConnection);
			ZDOExtraData.GetData(source.m_uid, ref list, ref list2, ref list3, ref list4, ref list5, ref list6, ref list7, ref val);
			if (list4 != null)
			{
				foreach (KeyValuePair<int, int> item in list4)
				{
					target.Set(item.Key, item.Value, false);
				}
			}
			if (list5 != null)
			{
				foreach (KeyValuePair<int, long> item2 in list5)
				{
					target.Set(item2.Key, item2.Value);
				}
			}
			if (list6 == null)
			{
				return;
			}
			foreach (KeyValuePair<int, string> item3 in list6)
			{
				target.Set(item3.Key, item3.Value);
			}
		}
	}
	internal sealed class CacheCommand : ConsoleCommand
	{
		private readonly bool admin;

		public override string Name
		{
			get
			{
				if (!admin)
				{
					return "cache";
				}
				return "cache_admin";
			}
		}

		public override string Help
		{
			get
			{
				if (!admin)
				{
					return "Open your own placed Provisioning Cache from anywhere.";
				}
				return "Open another player's cache: cache_admin <player name or character ID>. No arguments lists cache owners. Server admins only.";
			}
		}

		internal CacheCommand(bool admin)
		{
			this.admin = admin;
		}

		public override void Run(string[] args)
		{
			((ConsoleCommand)this).Run(args, (Terminal)(object)Console.instance);
		}

		public override void Run(string[] args, Terminal context)
		{
			if (!admin && args.Length != 0)
			{
				if (context != null)
				{
					context.AddString("Usage: cache");
				}
				return;
			}
			string text = Plugin.Instance.Network.OpenRemote(admin, string.Join(" ", args), context);
			if (text.Length > 0 && context != null)
			{
				context.AddString(text);
			}
		}

		internal static void Register()
		{
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new CacheCommand(admin: false));
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new CacheCommand(admin: true));
		}
	}
	internal static class CacheInventory
	{
		internal static ItemData CreateItem(string id)
		{
			GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(id) : null);
			ItemData val2 = ((!Object.op_Implicit((Object)(object)val)) ? null : val.GetComponent<ItemDrop>()?.m_itemData);
			if (val2 == null)
			{
				return null;
			}
			ItemData obj = val2.Clone();
			obj.m_dropPrefab = val;
			obj.m_stack = 1;
			obj.m_worldLevel = (byte)Game.m_worldLevel;
			return obj;
		}

		internal static bool TryAddOne(string id)
		{
			ItemData val = CreateItem(id);
			Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory();
			if (val != null && inventory.CanAddItem(val, 1))
			{
				return inventory.AddItem(val);
			}
			return false;
		}

		internal static void ShowPickups(Dictionary<string, int> received)
		{
			foreach (KeyValuePair<string, int> item in received)
			{
				ItemData val = CreateItem(item.Key);
				if (val != null)
				{
					((Character)Player.m_localPlayer).ShowPickupMessage(val, item.Value);
				}
			}
		}
	}
	internal static class CacheModel
	{
		private static Mesh mesh;

		private static Material woodMaterial;

		internal static void Apply(GameObject cache)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Expected O, but got Unknown
			//IL_037a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0381: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_03be: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03dd: 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)
			GameObject prefab = PrefabManager.Instance.GetPrefab("wood_pole");
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				throw new InvalidOperationException("Valheim wood pole prefab is unavailable.");
			}
			WearNTear component = prefab.GetComponent<WearNTear>();
			Material val = ((Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_new)) ? component.m_new : prefab).GetComponentsInChildren<MeshRenderer>(true).SelectMany((MeshRenderer renderer) => ((Renderer)renderer).sharedMaterials).FirstOrDefault((Func<Material, bool>)((Material candidate) => Object.op_Implicit((Object)(object)candidate)));
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Valheim wood material is unavailable.");
			}
			if (!Object.op_Implicit((Object)(object)woodMaterial))
			{
				woodMaterial = new Material(val)
				{
					name = "ProvisionCacheWood",
					mainTextureScale = Vector2.one,
					mainTextureOffset = Vector2.zero
				};
			}
			val = woodMaterial;
			if (!Object.op_Implicit((Object)(object)mesh))
			{
				mesh = ReadMesh(Assembly.GetExecutingAssembly().GetManifestResourceStream("ProvisioningCache.Model"));
			}
			BoxCollider[] array = (from c in cache.GetComponentsInChildren<BoxCollider>(true)
				where !((Collider)c).isTrigger
				select c).ToArray();
			Bounds val2 = default(Bounds);
			bool flag = false;
			BoxCollider[] array2 = array;
			foreach (BoxCollider val3 in array2)
			{
				Matrix4x4 val4 = cache.transform.worldToLocalMatrix * ((Component)val3).transform.localToWorldMatrix;
				for (int num2 = 0; num2 < 8; num2++)
				{
					Vector3 val5 = ((Matrix4x4)(ref val4)).MultiplyPoint3x4(val3.center + Vector3.Scale(val3.size * 0.5f, new Vector3((float)(((num2 & 1) != 0) ? 1 : (-1)), (float)(((num2 & 2) != 0) ? 1 : (-1)), (float)(((num2 & 4) != 0) ? 1 : (-1)))));
					if (!flag)
					{
						((Bounds)(ref val2))..ctor(val5, Vector3.zero);
						flag = true;
					}
					else
					{
						((Bounds)(ref val2)).Encapsulate(val5);
					}
				}
			}
			float num3 = (flag ? Mathf.Max(((Bounds)(ref val2)).size.x, ((Bounds)(ref val2)).size.z) : 1f);
			if (num3 <= 0f)
			{
				num3 = 1f;
			}
			LODGroup[] componentsInChildren = cache.GetComponentsInChildren<LODGroup>(true);
			for (int num = 0; num < componentsInChildren.Length; num++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[num]);
			}
			Animator[] componentsInChildren2 = cache.GetComponentsInChildren<Animator>(true);
			for (int num = 0; num < componentsInChildren2.Length; num++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren2[num]);
			}
			Animation[] componentsInChildren3 = cache.GetComponentsInChildren<Animation>(true);
			for (int num = 0; num < componentsInChildren3.Length; num++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren3[num]);
			}
			Renderer[] componentsInChildren4 = cache.GetComponentsInChildren<Renderer>(true);
			for (int num = 0; num < componentsInChildren4.Length; num++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren4[num]);
			}
			MeshFilter[] componentsInChildren5 = cache.GetComponentsInChildren<MeshFilter>(true);
			for (int num = 0; num < componentsInChildren5.Length; num++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren5[num]);
			}
			Collider[] componentsInChildren6 = cache.GetComponentsInChildren<Collider>(true);
			for (int num = 0; num < componentsInChildren6.Length; num++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren6[num]);
			}
			GameObject val6 = new GameObject("ProvisionCacheModel", new Type[2]
			{
				typeof(MeshFilter),
				typeof(MeshRenderer)
			});
			val6.layer = cache.layer;
			val6.transform.SetParent(cache.transform, false);
			val6.transform.localScale = Vector3.one * num3;
			val6.GetComponent<MeshFilter>().sharedMesh = mesh;
			((Renderer)val6.GetComponent<MeshRenderer>()).sharedMaterial = val;
			BoxCollider obj = cache.AddComponent<BoxCollider>();
			Bounds bounds = mesh.bounds;
			obj.center = ((Bounds)(ref bounds)).center * num3;
			bounds = mesh.bounds;
			obj.size = ((Bounds)(ref bounds)).size * num3;
			WearNTear component2 = cache.GetComponent<WearNTear>();
			component2.m_new = (component2.m_worn = (component2.m_broken = val6));
			Plugin.Instance.ReportModel("Custom cache model: " + mesh.vertexCount + " vertices; Valheim material " + ((Object)val).name);
		}

		internal static Mesh ReadMesh(Stream stream)
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: 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_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Expected O, but got Unknown
			using (stream)
			{
				if (stream == null)
				{
					throw new InvalidDataException("Embedded cache model is missing.");
				}
				using BinaryReader binaryReader = new BinaryReader(stream);
				if (binaryReader.ReadInt32() != 827147088)
				{
					throw new InvalidDataException("Invalid cache model header.");
				}
				int num = binaryReader.ReadInt32();
				int num2 = binaryReader.ReadInt32();
				if (num <= 0 || num2 <= 0 || num2 % 3 != 0 || stream.Length != 12 + (long)num * 32L + (long)num2 * 4L)
				{
					throw new InvalidDataException("Invalid cache model data.");
				}
				Vector3[] array = (Vector3[])(object)new Vector3[num];
				Vector3[] array2 = (Vector3[])(object)new Vector3[num];
				Vector2[] array3 = (Vector2[])(object)new Vector2[num];
				Color[] array4 = (Color[])(object)new Color[num];
				int[] array5 = new int[num2];
				for (int i = 0; i < num; i++)
				{
					array[i] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
					array2[i] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
					array3[i] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
					array4[i] = Color.white;
				}
				for (int j = 0; j < num2; j++)
				{
					array5[j] = binaryReader.ReadInt32();
					if (array5[j] < 0 || array5[j] >= num)
					{
						throw new InvalidDataException("Invalid cache model triangle.");
					}
				}
				Mesh val = new Mesh
				{
					name = "ProvisionCache",
					indexFormat = (IndexFormat)(num > 65535),
					vertices = array,
					normals = array2,
					uv = array3,
					colors = array4,
					triangles = array5
				};
				val.RecalculateBounds();
				val.RecalculateTangents();
				val.UploadMeshData(true);
				return val;
			}
		}
	}
	public sealed class CacheModelScale : MonoBehaviour
	{
		public Vector3 BaseScale = Vector3.one;

		private void Awake()
		{
			ApplyScale();
		}

		private void LateUpdate()
		{
			ApplyScale();
		}

		internal void ApplyScale()
		{
			//IL_000e: 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_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)Plugin.Instance))
			{
				Vector3 val = BaseScale * Plugin.Instance.ModelScale;
				if (((Component)this).transform.localScale != val)
				{
					((Component)this).transform.localScale = val;
				}
			}
		}
	}
	internal static class CacheOwner
	{
		internal const string NameKey = "pc.account.ownerName";

		internal static string OnlineName(long owner)
		{
			//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_005f: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			if (owner == 0L)
			{
				return "";
			}
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)localPlayer) && localPlayer.GetPlayerID() == owner)
			{
				return localPlayer.GetPlayerName();
			}
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || ZDOMan.instance == null)
			{
				return "";
			}
			foreach (PlayerInfo player in ZNet.instance.GetPlayerList())
			{
				ZDO zDO = ZDOMan.instance.GetZDO(player.m_characterID);
				if (zDO != null && zDO.GetLong(ZDOVars.s_playerID, 0L) == owner)
				{
					return player.m_name;
				}
			}
			return "";
		}

		internal static void Remember(ZDO account, ZDO piece)
		{
			string text = OnlineName(account.GetLong("pc.account.owner", 0L));
			if (string.IsNullOrWhiteSpace(text))
			{
				text = piece.GetString("pc.account.ownerName", "");
			}
			if (string.IsNullOrWhiteSpace(text))
			{
				text = account.GetString("pc.account.ownerName", "");
			}
			if (!string.IsNullOrWhiteSpace(text))
			{
				account.Set("pc.account.ownerName", text);
				piece.Set("pc.account.ownerName", text);
			}
		}

		internal static string Name(ZDO piece)
		{
			if (piece == null)
			{
				return "Unknown owner";
			}
			string text = piece.GetString("pc.account.ownerName", "");
			if (string.IsNullOrWhiteSpace(text))
			{
				text = OnlineName(piece.GetLong("pc.account.owner", piece.GetLong("creator", 0L)));
			}
			if (string.IsNullOrWhiteSpace(text))
			{
				return "Unknown owner";
			}
			text = text.Replace('<', '‹').Replace('>', '›').Replace('\r', ' ')
				.Replace('\n', ' ')
				.Trim();
			if (text.Length <= 64)
			{
				return text;
			}
			return text.Substring(0, 61) + "…";
		}
	}
	[HarmonyPatch(typeof(Player), "TryPlacePiece")]
	internal static class CachePlacement
	{
		private static bool Prefix(Player __instance, Piece piece, ref bool __result)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)piece) || !Object.op_Implicit((Object)(object)((Component)piece).GetComponent<CacheInteractable>()) || !MultiplayerCache.HasPlacedCache(__instance.GetPlayerID()))
			{
				return true;
			}
			((Character)__instance).Message((MessageType)2, "You already have a Provisioning Cache. Remove it before building another.", 0, (Sprite)null, false);
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
	internal static class CachePlacementScale
	{
		internal static void Prefix(GameObject ___m_placementGhost)
		{
			if (Object.op_Implicit((Object)(object)___m_placementGhost))
			{
				CacheModelScale component = ___m_placementGhost.GetComponent<CacheModelScale>();
				if (Object.op_Implicit((Object)(object)component))
				{
					component.ApplyScale();
				}
			}
		}
	}
	internal static class CacheScrollList
	{
		internal const float RowWidth = 822f;

		internal static ScrollRect Create(Transform parent, float y, float height, float contentHeight)
		{
			//IL_0026: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: 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_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			Image obj = Image(parent, "Inset list border", 24f, y, 852f, height, new Color(0.38f, 0.34f, 0.26f, 0.8f));
			Image(((Component)obj).transform, "Inset list", 1f, 1f, 850f, height - 2f, new Color(0.055f, 0.06f, 0.05f, 0.98f));
			Image val = Image(((Component)obj).transform, "Viewport", 6f, 6f, 822f, height - 12f, Color.clear);
			((Graphic)val).raycastTarget = true;
			((Component)val).gameObject.AddComponent<RectMask2D>();
			RectTransform content = Rect(((Component)val).transform, "Scrollable rows", 0f, 0f, 822f, Mathf.Max(height - 12f, contentHeight));
			Image obj2 = Image(((Component)obj).transform, "Scroll track", 834f, 8f, 12f, height - 16f, new Color(0.18f, 0.19f, 0.16f));
			((Graphic)obj2).raycastTarget = true;
			Image val2 = Image((Transform)(object)Rect(((Component)obj2).transform, "Sliding area", 2f, 2f, 8f, height - 20f), "Scroll thumb", 0f, 0f, 8f, height - 20f, Color.white);
			((Graphic)val2).rectTransform.anchorMin = Vector2.zero;
			((Graphic)val2).rectTransform.anchorMax = Vector2.one;
			RectTransform rectTransform = ((Graphic)val2).rectTransform;
			Vector2 offsetMin = (((Graphic)val2).rectTransform.offsetMax = Vector2.zero);
			rectTransform.offsetMin = offsetMin;
			((Graphic)val2).raycastTarget = true;
			Scrollbar val3 = ((Component)obj2).gameObject.AddComponent<Scrollbar>();
			val3.handleRect = ((Graphic)val2).rectTransform;
			((Selectable)val3).targetGraphic = (Graphic)(object)val2;
			val3.direction = (Direction)2;
			ColorBlock colors = ((Selectable)val3).colors;
			((ColorBlock)(ref colors)).normalColor = new Color(0.58f, 0.48f, 0.32f);
			((ColorBlock)(ref colors)).highlightedColor = new Color(0.94f, 0.73f, 0.36f);
			((ColorBlock)(ref colors)).pressedColor = new Color(1f, 0.81f, 0.45f);
			((ColorBlock)(ref colors)).selectedColor = new Color(0.68f, 0.56f, 0.36f);
			((ColorBlock)(ref colors)).disabledColor = new Color(0.38f, 0.35f, 0.27f);
			((ColorBlock)(ref colors)).colorMultiplier = 1f;
			((ColorBlock)(ref colors)).fadeDuration = 0.1f;
			((Selectable)val3).colors = colors;
			((Selectable)val3).interactable = contentHeight > height - 12f;
			ScrollRect obj3 = ((Component)obj).gameObject.AddComponent<ScrollRect>();
			obj3.viewport = ((Graphic)val).rectTransform;
			obj3.content = content;
			obj3.horizontal = false;
			obj3.vertical = true;
			obj3.movementType = (MovementType)2;
			obj3.inertia = false;
			obj3.scrollSensitivity = 630f;
			obj3.verticalScrollbar = val3;
			obj3.verticalScrollbarVisibility = (ScrollbarVisibility)0;
			return obj3;
		}

		private static RectTransform Rect(Transform parent, string name, float x, float y, float width, float height)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = new GameObject(name, new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0f, 1f);
			component.pivot = val;
			Vector2 anchorMin = (component.anchorMax = val);
			component.anchorMin = anchorMin;
			component.anchoredPosition = new Vector2(x, 0f - y);
			component.sizeDelta = new Vector2(width, height);
			return component;
		}

		private static Image Image(Transform parent, string name, float x, float y, float width, float height, Color color)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			Image obj = ((Component)Rect(parent, name, x, y, width, height)).gameObject.AddComponent<Image>();
			((Graphic)obj).color = color;
			((Graphic)obj).raycastTarget = false;
			return obj;
		}
	}
	internal sealed class CacheSession
	{
		private MultiplayerCache Network => Plugin.Instance.Network;

		private Player LocalPlayer => Player.m_localPlayer;

		internal CacheState State => Network.Snapshot;

		internal bool CanManage
		{
			get
			{
				if (!Network.IsOwner)
				{
					return Network.AdminOverride;
				}
				return true;
			}
		}

		internal bool IsOwner => Network.IsOwner;

		internal bool AdminOverride => Network.AdminOverride;

		internal string OwnerName => Network.OwnerName;

		internal bool Busy => Network.Busy;

		internal static bool Supported
		{
			get
			{
				if (Object.op_Implicit((Object)(object)ZNet.instance))
				{
					return ZDOMan.instance != null;
				}
				return false;
			}
		}

		internal int Coins => Count("Coins");

		internal bool Bind(ZDO cache, out string error)
		{
			return Network.Select(cache, out error);
		}

		internal void Tick()
		{
			Network.Refresh();
		}

		private static GameObject Item(string id)
		{
			if (!Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				return null;
			}
			return ObjectDB.instance.GetItemPrefab(id);
		}

		private static string SharedName(string id)
		{
			GameObject obj = Item(id);
			if (obj == null)
			{
				return null;
			}
			return obj.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_name;
		}

		internal int Count(string id)
		{
			string text = SharedName(id);
			if (!Object.op_Implicit((Object)(object)LocalPlayer) || text == null)
			{
				return 0;
			}
			return ((Humanoid)LocalPlayer).GetInventory().CountItems(text, -1, true);
		}

		internal string Reason(Offer offer)
		{
			if (CanManage)
			{
				if (!Busy)
				{
					return Upgrades.BlockReason(State, offer, Coins, (string boss) => Object.op_Implicit((Object)(object)ZoneSystem.instance) && ZoneSystem.instance.GetGlobalKey(boss), Count);
				}
				return "Waiting for the server…";
			}
			return "Only the owner can upgrade.";
		}

		internal string Purchase(string id)
		{
			if (!Supported || State == null || !Object.op_Implicit((Object)(object)LocalPlayer))
			{
				return "Cache unavailable.";
			}
			Tick();
			Offer offer = Upgrades.Offers(State).Find((Offer o) => o.Id == id);
			if (offer == null)
			{
				return "Upgrade already purchased.";
			}
			string text = Reason(offer);
			if (text.Length > 0)
			{
				return text;
			}
			string result = Network.Send("purchase", id);
			if (!Network.Busy)
			{
				return result;
			}
			Inventory inventory = ((Humanoid)LocalPlayer).GetInventory();
			inventory.RemoveItem(SharedName("Coins"), offer.Coins, -1, true);
			if (offer.SampleCount > 0)
			{
				inventory.RemoveItem(SharedName(offer.Sample), offer.SampleCount, -1, true);
			}
			return result;
		}

		internal string Allocate(IReadOnlyDictionary<string, int> draft)
		{
			if (!Supported || State == null)
			{
				return "Cache unavailable.";
			}
			if (!CanManage)
			{
				return "Only the owner can change allocation.";
			}
			return Network.Send("allocate", "", new Dictionary<string, int>(draft));
		}

		internal string Collect()
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			if (!Supported || State == null || !Object.op_Implicit((Object)(object)LocalPlayer))
			{
				return "Cache unavailable.";
			}
			if (Busy)
			{
				return "Waiting for the server…";
			}
			Tick();
			Inventory inventory = ((Humanoid)LocalPlayer).GetInventory();
			Inventory val = new Inventory("Cache collection preview", (Sprite)null, inventory.GetWidth(), inventory.GetHeight());
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				val.GetAllItems().Add(allItem.Clone());
			}
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			Resource[] resources = Catalog.Resources;
			foreach (Resource resource in resources)
			{
				ItemData val2 = CacheInventory.CreateItem(resource.Id);
				if (val2 == null)
				{
					continue;
				}
				int j;
				for (j = 0; j < State.Resources[resource.Id].Stored && j < 100000; j++)
				{
					ItemData val3 = val2.Clone();
					if (!val.CanAddItem(val3, 1) || !val.AddItem(val3))
					{
						break;
					}
				}
				if (j > 0)
				{
					dictionary.Add(resource.Id, j);
				}
			}
			if (dictionary.Count != 0)
			{
				return Network.Send("collect", "", dictionary);
			}
			return "No items fit in your inventory, or the cache is empty.";
		}
	}
	internal sealed class CacheWindow
	{
		private enum Tab
		{
			Production,
			Upgrades,
			Licenses
		}

		private const float Width = 900f;

		private const float Height = 740f;

		private const float ProductionRowStep = 76f;

		private const float PurchaseRowStep = 86f;

		private const float TierHeadingStep = 34f;

		private static readonly Vector2 TopLeft = new Vector2(0f, 1f);

		private static readonly Color Ink = new Color(0.95f, 0.92f, 0.83f);

		private static readonly Color Muted = new Color(0.77f, 0.75f, 0.69f);

		private static readonly Color Gold = new Color(0.94f, 0.73f, 0.36f);

		private static readonly Color Green = new Color(0.66f, 0.81f, 0.6f);

		private static readonly Color Inset = new Color(0.075f, 0.085f, 0.075f, 0.94f);

		private GameObject panel;

		private GameObject content;

		private CacheInteractable target;

		private Text subtitle;

		private Text ownerLabel;

		private Text wallet;

		private Text speed;

		private Text storage;

		private Text status;

		private Text total;

		private Text draftHint;

		private Button apply;

		private Button collect;

		private Text tierCostLabel;

		private Image storageBar;

		private readonly Button[] tabs = (Button[])(object)new Button[3];

		private readonly Image[] tabUnderlines = (Image[])(object)new Image[3];

		private readonly Dictionary<string, int> draft = new Dictionary<string, int>();

		private readonly Dictionary<string, Text> liveRows = new Dictionary<string, Text>();

		private readonly Dictionary<string, Image> progressBars = new Dictionary<string, Image>();

		private readonly Dictionary<string, Image> activityMarks = new Dictionary<string, Image>();

		private readonly Dictionary<string, Button> increaseButtons = new Dictionary<string, Button>();

		private readonly List<Tuple<Button, Offer>> purchaseButtons = new List<Tuple<Button, Offer>>();

		private Tab currentTab;

		private bool inputBlocked;

		private ScrollRect listScroll;

		private Tab scrollTab;

		private readonly Dictionary<Tab, float> scrollOffsets = new Dictionary<Tab, float>();

		private float nextRefresh;

		private CacheSession Session => Plugin.Instance.Session;

		private CacheState State => Session.State;

		private bool HasDraft
		{
			get
			{
				if (State != null)
				{
					return draft.Any((KeyValuePair<string, int> p) => p.Value != State.Resources[p.Key].Percent);
				}
				return false;
			}
		}

		internal bool IsOpen => Object.op_Implicit((Object)(object)panel);

		internal void Open(CacheInteractable cache)
		{
			//IL_0034: 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_0048: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bb: Unknown result type (might be due to invalid IL or missing references)
			Close();
			if (!Object.op_Implicit((Object)(object)GUIManager.CustomGUIFront))
			{
				return;
			}
			target = cache;
			panel = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 900f, 740f, false);
			Surface(panel.transform, "Tint", 12f, 12f, 876f, 716f, new Color(0.1f, 0.09f, 0.07f, 0.87f));
			Label(panel.transform, "Provisioning Cache", 28f, 23f, 650f, 36f, 28, Ink, bold: true, (TextAnchor)3);
			subtitle = Label(panel.transform, "", 30f, 62f, 430f, 24f, 17, Gold, bold: false, (TextAnchor)3);
			ownerLabel = Label(panel.transform, "", 474f, 66f, 396f, 24f, 17, Ink, bold: false, (TextAnchor)5);
			ownerLabel.supportRichText = false;
			ownerLabel.horizontalOverflow = (HorizontalWrapMode)1;
			ownerLabel.resizeTextForBestFit = true;
			ownerLabel.resizeTextMinSize = 12;
			ownerLabel.resizeTextMaxSize = 17;
			Button(panel.transform, "Close", 786f, 27f, 86f, Close);
			Surface(panel.transform, "Summary", 24f, 98f, 852f, 60f, Inset);
			Label(panel.transform, "COINS", 40f, 103f, 165f, 18f, 13, Muted, bold: false, (TextAnchor)3);
			wallet = Label(panel.transform, "", 40f, 123f, 165f, 29f, 23, Gold, bold: false, (TextAnchor)3);
			Surface(panel.transform, "Divider", 220f, 110f, 1f, 36f, new Color(1f, 1f, 1f, 0.12f));
			Label(panel.transform, "PRODUCTION SPEED", 242f, 103f, 210f, 18f, 13, Muted, bold: false, (TextAnchor)3);
			speed = Label(panel.transform, "", 242f, 123f, 210f, 29f, 23, null, bold: false, (TextAnchor)3);
			Surface(panel.transform, "Divider", 470f, 110f, 1f, 36f, new Color(1f, 1f, 1f, 0.12f));
			Label(panel.transform, "STORAGE", 492f, 102f, 350f, 18f, 13, Muted, bold: false, (TextAnchor)3);
			storage = Label(panel.transform, "", 492f, 121f, 362f, 24f, 17, null, bold: false, (TextAnchor)3);
			storageBar = ProgressBar(panel.transform, 492f, 148f, 360f, 4f);
			for (int i = 0; i < tabs.Length; i++)
			{
				Tab tab = (Tab)i;
				float x = 28 + i * 177;
				tabs[i] = Button(panel.transform, (tab == Tab.Licenses) ? "Resources" : tab.ToString(), x, 171f, 165f, delegate
				{
					SwitchTab(tab);
				});
				tabUnderlines[i] = Surface(panel.transform, "Active " + tab.ToString() + " tab", x, 212f, 165f, 3f, Gold);
			}
			status = Label(panel.transform, "Esc to close", 30f, 706f, 840f, 24f, 14, Muted, bold: false, (TextAnchor)3);
			draft.Clear();
			foreach (KeyValuePair<string, ResourceState> resource in State.Resources)
			{
				draft[resource.Key] = resource.Value.Percent;
			}
			currentTab = Tab.Production;
			BuildContent();
			Refresh();
			ScaleToScreen();
			GUIManager.BlockInput(true);
			inputBlocked = true;
		}

		internal void NetworkChanged(string message, bool resetDraft)
		{
			if (!Object.op_Implicit((Object)(object)panel) || State == null)
			{
				return;
			}
			if (resetDraft)
			{
				draft.Clear();
				foreach (KeyValuePair<string, ResourceState> resource in State.Resources)
				{
					draft[resource.Key] = resource.Value.Percent;
				}
				BuildContent();
			}
			Refresh();
			Notify(message);
		}

		internal void Close()
		{
			if (Object.op_Implicit((Object)(object)panel))
			{
				Object.Destroy((Object)(object)panel);
			}
			panel = null;
			content = null;
			target = null;
			listScroll = null;
			scrollOffsets.Clear();
			tierCostLabel = null;
			liveRows.Clear();
			progressBars.Clear();
			activityMarks.Clear();
			increaseButtons.Clear();
			purchaseButtons.Clear();
			if (inputBlocked)
			{
				GUIManager.BlockInput(false);
			}
			inputBlocked = false;
		}

		internal void Update()
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)panel))
			{
				if (inputBlocked)
				{
					Close();
				}
				return;
			}
			bool remote = Plugin.Instance.Network.Remote;
			if ((!remote && !Object.op_Implicit((Object)(object)target)) || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead() || !CacheSession.Supported || State == null || !Object.op_Implicit((Object)(object)GUIManager.CustomGUIFront) || (!remote && (Vector3.Distance(((Component)Player.m_localPlayer).transform.position, ((Component)target).transform.position) > 5f || !PrivateArea.CheckAccess(((Component)target).transform.position, 0f, false, false))))
			{
				Close();
				return;
			}
			if (Input.GetKeyDown((KeyCode)27))
			{
				Close();
				return;
			}
			ScaleToScreen();
			if (Time.unscaledTime >= nextRefresh)
			{
				nextRefresh = Time.unscaledTime + 0.25f;
				Refresh();
			}
			RefreshProgress();
		}

		private void ScaleToScreen()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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)
			Rect rect = GUIManager.CustomGUIFront.GetComponent<RectTransform>().rect;
			panel.transform.localScale = Vector3.one * Mathf.Min(1f, Mathf.Min(((Rect)(ref rect)).width / 924f, ((Rect)(ref rect)).height / 764f));
		}

		private void SwitchTab(Tab tab)
		{
			currentTab = tab;
			BuildContent();
			Refresh();
		}

		private void BuildContent()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: 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_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)listScroll))
			{
				scrollOffsets[scrollTab] = listScroll.content.anchoredPosition.y;
			}
			listScroll = null;
			if (Object.op_Implicit((Object)(object)content))
			{
				content.SetActive(false);
				Object.Destroy((Object)(object)content);
			}
			content = new GameObject("CacheContent", new Type[1] { typeof(RectTransform) });
			RectTransform component = content.GetComponent<RectTransform>();
			((Transform)component).SetParent(panel.transform, false);
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			Vector2 offsetMin = (component.offsetMax = Vector2.zero);
			component.offsetMin = offsetMin;
			liveRows.Clear();
			progressBars.Clear();
			activityMarks.Clear();
			increaseButtons.Clear();
			purchaseButtons.Clear();
			total = null;
			draftHint = null;
			apply = null;
			collect = null;
			tierCostLabel = null;
			for (int i = 0; i < tabs.Length; i++)
			{
				bool flag = currentTab == (Tab)i;
				((Component)tabUnderlines[i]).gameObject.SetActive(flag);
				TintButton(tabs[i], flag);
			}
			if (currentTab == Tab.Production)
			{
				BuildProduction();
			}
			else
			{
				BuildPurchases();
			}
			if (Object.op_Implicit((Object)(object)listScroll))
			{
				Canvas.ForceUpdateCanvases();
				Rect rect = listScroll.content.rect;
				float height = ((Rect)(ref rect)).height;
				rect = listScroll.viewport.rect;
				float num = Mathf.Max(0f, height - ((Rect)(ref rect)).height);
				listScroll.content.anchoredPosition = new Vector2(0f, Mathf.Clamp(scrollOffsets.TryGetValue(currentTab, out var value) ? value : 0f, 0f, num));
				listScroll.StopMovement();
			}
		}

		private void BuildProduction()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: 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_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0541: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Unknown result type (might be due to invalid IL or missing references)
			List<Resource> list = (from resource in Catalog.Resources
				where State.Resources[resource.Id].Unlocked
				orderby State.Resources[resource.Id].Percent > 0 descending, 60.0 * State.Speed * (double)State.Resources[resource.Id].Percent / (100.0 * resource.Work) descending
				select resource).ToList();
			Label(content.transform, "RESOURCE / NEXT ITEM", 102f, 222f, 330f, 20f, 13, Muted, bold: false, (TextAnchor)3);
			Label(content.transform, "ALLOCATION", 504f, 222f, 170f, 20f, 13, Muted, bold: false, (TextAnchor)4);
			Label(content.transform, "READY", 753f, 222f, 76f, 20f, 13, Muted, bold: false, (TextAnchor)4);
			Transform val = CreateList(246f, 394f, list.Count, 76f);
			int num = 0;
			foreach (Resource r in list)
			{
				float num2 = (float)num++ * 76f;
				Surface(val, r.Name + " row", 0f, num2, 822f, 70f, Inset);
				activityMarks[r.Id] = Surface(val, "Activity", 0f, num2 + 8f, 3f, 54f, Gold);
				ItemIcon(val, r.Id, 14f, num2 + 14f, 42f);
				Label(val, r.Name, 72f, num2 + 5f, 345f, 25f, 20, Ink, bold: true, (TextAnchor)3);
				liveRows[r.Id] = Label(val, "", 72f, num2 + 31f, 340f, 23f, 16, Muted, bold: false, (TextAnchor)3);
				progressBars[r.Id] = ProgressBar(val, 72f, num2 + 62f, 325f, 4f);
				if (State.AllocationUnlocked)
				{
					GameObject val2 = GUIManager.Instance.CreateInputField(val, TopLeft, TopLeft, new Vector2(546f, 0f - num2 - 35f), (ContentType)2, "0", 19, 70f, 38f);
					InputField input = val2.GetComponent<InputField>();
					input.characterLimit = 3;
					input.textComponent.alignment = (TextAnchor)4;
					input.SetTextWithoutNotify(draft[r.Id].ToString());
					((UnityEvent<string>)(object)input.onValueChanged).AddListener((UnityAction<string>)delegate(string value)
					{
						draft[r.Id] = (int.TryParse(value, out var result) ? result : (-1));
						UpdateTotal();
					});
					Button(val, "−", 460f, num2 + 15f, 42f, delegate
					{
						input.text = Math.Max(0, draft[r.Id] - 5).ToString();
					});
					increaseButtons[r.Id] = Button(val, "+", 602f, num2 + 15f, 42f, delegate
					{
						input.text = Math.Min(100, draft[r.Id] + 5).ToString();
					});
					Label(val, "%", 655f, num2 + 20f, 25f, 27f, 17, Muted, bold: false, (TextAnchor)3);
				}
				else
				{
					Button(val, "Produce only", 460f, num2 + 15f, 205f, delegate
					{
						foreach (string item in draft.Keys.ToList())
						{
							draft[item] = ((item == r.Id) ? Math.Min(100, State.MaxAllocation) : 0);
						}
						Notify(Session.Allocate(draft));
						BuildContent();
						Refresh();
					});
				}
				liveRows[r.Id + "_stock"] = Label(val, "", 723f, num2 + 15f, 76f, 40f, 26, Ink, bold: true, (TextAnchor)4);
			}
			ListFooter(list.Count, "resources");
			Surface(content.transform, "Allocation footer", 24f, 658f, 852f, 40f, Inset);
			total = Label(content.transform, "", 40f, 662f, 378f, 20f, 16, null, bold: false, (TextAnchor)3);
			draftHint = Label(content.transform, "", 40f, 680f, 378f, 18f, 12, Muted, bold: false, (TextAnchor)3);
			if (State.AllocationUnlocked)
			{
				apply = Button(content.transform, "Apply changes", 468f, 658f, 202f, delegate
				{
					Notify(Session.Allocate(draft));
					BuildContent();
					Refresh();
				});
			}
			collect = Button(content.transform, "Collect all", 690f, 658f, 170f, delegate
			{
				Notify(Session.Collect());
				Refresh();
			});
			TintButton(collect, prominent: true);
			UpdateTotal();
		}

		private void BuildPurchases()
		{
			//IL_00f8: 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_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			bool licenses = currentTab == Tab.Licenses;
			List<Offer> list = (from o in Upgrades.Offers(State)
				where Catalog.Find(o.Id) != null == licenses
				orderby o.Tier, (Session.Reason(o).Length != 0) ? 1 : 0
				select o).ToList();
			Offer offer = (licenses ? null : list.Find((Offer o) => o.Id == "tier"));
			if (offer != null)
			{
				list.Remove(offer);
			}
			Label(content.transform, licenses ? "RESOURCE LICENSES" : ((offer != null) ? "NEXT CACHE TIER" : "CACHE UPGRADES"), 30f, 222f, 810f, 20f, 13, (offer != null) ? Gold : Muted, bold: false, (TextAnchor)3);
			if (offer != null)
			{
				PurchaseRow(content.transform, offer, 246f, prominent: true);
			}
			float height = ((offer != null) ? 302 : 394);
			int headings = (licenses ? list.Select((Offer o) => o.Tier).Distinct().Count() : 0);
			Transform parent = CreateList((offer != null) ? 338 : 246, height, list.Count, 86f, headings);
			float num = 0f;
			int num2 = -1;
			foreach (Offer item in list)
			{
				if (licenses && item.Tier != num2)
				{
					Label(parent, "TIER " + item.Tier, 14f, num + 4f, 110f, 23f, 15, Muted, bold: true, (TextAnchor)3);
					Surface(parent, "Tier divider", 124f, num + 16f, 682f, 1f, new Color(Muted.r, Muted.g, Muted.b, 0.22f));
					num += 34f;
					num2 = item.Tier;
				}
				PurchaseRow(parent, item, num);
				num += 86f;
			}
			if (list.Count == 0)
			{
				Label(parent, licenses ? "All resource licenses purchased." : "All available rank upgrades purchased.", 16f, 24f, 790f, 60f, 22, Gold, bold: false, (TextAnchor)3);
			}
			ListFooter(list.Count, licenses ? "licenses" : "rank upgrades");
			Label(content.transform, licenses ? "Unlock resources with Coins and five samples from your inventory." : "Upgrades use Coins from your inventory.", 30f, 669f, 835f, 27f, 15, Muted, bold: false, (TextAnchor)3);
		}

		private void PurchaseRow(Transform parent, Offer offer, float y, bool prominent = false)
		{
			//IL_00e4: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			float num = (prominent ? 24 : 0);
			if (prominent)
			{
				Surface(parent, "Cache tier border", num, y, 852f, 80f, new Color(Gold.r, Gold.g, Gold.b, 0.7f));
				Surface(parent, "Cache tier inset", num + 2f, y + 2f, 848f, 76f, new Color(0.14f, 0.12f, 0.075f, 0.98f));
				Surface(parent, "Cache tier accent", num, y, 4f, 80f, Gold);
			}
			else
			{
				Surface(parent, offer.Name + " row", num, y, 822f, 80f, Inset);
			}
			object obj;
			if (!prominent)
			{
				obj = null;
			}
			else if (!Object.op_Implicit((Object)(object)target))
			{
				GameObject prefab = PrefabManager.Instance.GetPrefab("pc_provisioning_cache");
				obj = ((prefab != null) ? prefab.GetComponent<Piece>() : null);
			}
			else
			{
				obj = ((Component)target).GetComponent<Piece>();
			}
			Piece val = (Piece)obj;
			if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.m_icon))
			{
				Image obj2 = Surface(parent, "Cache tier icon", num + 14f, y + 19f, 42f, 42f, Color.white);
				obj2.sprite = val.m_icon;
				obj2.preserveAspect = true;
			}
			else
			{
				string prefab2 = ((offer.Sample.Length > 0) ? offer.Sample : ((offer.Id == "storage") ? "Wood" : "Hammer"));
				ItemIcon(parent, prefab2, num + 14f, y + 19f, 42f);
			}
			Label(parent, offer.Name, num + 72f, y + 4f, 550f, 25f, 19, prominent ? Gold : Ink, bold: true, (TextAnchor)3);
			liveRows[offer.Id + "_detail"] = Label(parent, "", num + 72f, y + 32f, 550f, 22f, 16, Muted, bold: false, (TextAnchor)3);
			liveRows[offer.Id] = Label(parent, "", num + 72f, y + 56f, 550f, 21f, 15, null, bold: false, (TextAnchor)3);
			Action action = delegate
			{
				Notify(Session.Purchase(offer.Id));
				BuildContent();
				Refresh();
			};
			Button item = (prominent ? TierButton(parent, offer, y, action) : Button(parent, offer.Coins + " Coins", 648f, y + 20f, 158f, action));
			purchaseButtons.Add(Tuple.Create<Button, Offer>(item, offer));
		}

		private Button TierButton(Transform parent, Offer offer, float y, Action purchase)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			tierCostLabel = Label(parent, offer.Coins + " Coins", 702f, y + 6f, 158f, 22f, 16, Gold, bold: true, (TextAnchor)4);
			return Button(parent, "Upgrade Tier", 702f, y + 32f, 158f, purchase);
		}

		private Transform CreateList(float y, float height, int count, float rowStep, int headings = 0)
		{
			float contentHeight = Mathf.Max(0f, (float)count * rowStep + (float)headings * 34f - 6f);
			listScroll = CacheScrollList.Create(content.transform, y, height, contentHeight);
			scrollTab = currentTab;
			return (Transform)(object)listScroll.content;
		}

		private void ListFooter(int count, string noun)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = listScroll.content.rect;
			float height = ((Rect)(ref rect)).height;
			rect = listScroll.viewport.rect;
			if (height > ((Rect)(ref rect)).height)
			{
				Label(content.transform, "Mouse wheel to scroll", 30f, 641f, 460f, 16f, 13, Muted, bold: false, (TextAnchor)3);
			}
			Label(content.transform, count + " " + noun, 664f, 641f, 200f, 16f, 13, Muted, bold: false, (TextAnchor)5);
		}

		private void Notify(string message)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			status.text = message;
			((Graphic)status).color = Gold;
		}

		private void UpdateTotal()
		{
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)total))
			{
				return;
			}
			foreach (KeyValuePair<string, Button> increaseButton in increaseButtons)
			{
				((Selectable)increaseButton.Value).interactable = draft[increaseButton.Key] < 100;
				TintButton(increaseButton.Value, prominent: false);
			}
			int num = draft.Values.Sum();
			bool flag = num <= State.MaxAllocation && draft.Values.All((int v) => v >= 0 && v <= 100);
			total.text = (State.AllocationUnlocked ? ("Allocated " + num + "% / " + State.MaxAllocation + "%") : (num + "% / " + State.MaxAllocation + "% · Single resource"));
			((Graphic)total).color = (Color)(flag ? Ink : new Color(0.97f, 0.64f, 0.46f));
			draftHint.text = ((!State.AllocationUnlocked) ? "Upgrade Allocation to split your production." : ((!flag) ? ("Each resource ≤100%; total ≤" + State.MaxAllocation + "%.") : (HasDraft ? "Unsaved changes · apply when ready" : ("Saved · " + (State.MaxAllocation - num) + "% unassigned"))));
			((Graphic)draftHint).color = ((flag && !HasDraft) ? Green : Muted);
			if (Object.op_Implicit((Object)(object)apply))
			{
				((Selectable)apply).interactable = Session.CanManage && !Session.Busy && flag && HasDraft;
				TintButton(apply, flag && HasDraft);
			}
		}

		private void Refresh()
		{
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_04fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0548: Unknown result type (might be due to invalid IL or missing references)
			//IL_0541: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: 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)
			//IL_0578: Unknown result type (might be due to invalid IL or missing references)
			//IL_0571: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)panel) || State == null)
			{
				return;
			}
			subtitle.text = Catalog.TierNames[State.Tier - 1] + " Cache  ·  Tier " + State.Tier;
			ownerLabel.text = "Owner: " + Session.OwnerName + (Session.AdminOverride ? " (Admin)" : (Session.IsOwner ? " (You)" : ""));
			wallet.text = Session.Coins.ToString("N0");
			speed.text = State.Speed.ToString("0.##") + "×";
			bool flag = State.UsedWork >= State.Capacity - 0.0001;
			storage.text = Mathf.Clamp((float)(State.UsedWork / State.Capacity * 100.0), 0f, 100f).ToString("0.#") + "% full" + (flag ? " · FULL" : "");
			((Graphic)storage).color = (flag ? Gold : Ink);
			((Graphic)storageBar).rectTransform.anchorMax = new Vector2(Mathf.Clamp01((float)(State.UsedWork / State.Capacity)), 1f);
			((Graphic)storageBar).color = Gold;
			if (currentTab != Tab.Production)
			{
				foreach (Tuple<Button, Offer> purchaseButton in purchaseButtons)
				{
					Offer item = purchaseButton.Item2;
					string text = Session.Reason(item);
					bool flag2 = text.Length == 0;
					((Selectable)purchaseButton.Item1).interactable = flag2;
					if (item.Id == "tier")
					{
						TintButton(purchaseButton.Item1, flag2);
						((Graphic)tierCostLabel).color = (flag2 ? Gold : Muted);
					}
					else
					{
						TintButton(purchaseButton.Item1, flag2);
					}
					Text obj = liveRows[item.Id];
					obj.text = ((text.Length == 0) ? "Ready to purchase" : text);
					((Graphic)obj).color = ((text.Length == 0) ? Green : Gold);
					Resource resource = Catalog.Find(item.Sample);
					liveRows[item.Id + "_detail"].text = ((resource != null) ? ((60.0 * State.Speed / resource.Work).ToString("0.##") + "/hr at 100% · Samples " + Session.Count(item.Sample) + "/" + item.SampleCount) : ((item.Id == "tier") ? "Unlock the next resource tier · +10% total allocation." : ((item.Id == "max_allocation") ? (State.MaxAllocation + "% → " + (State.MaxAllocation + 5) + "% total allocation") : item.Description)));
				}
			}
			else
			{
				Resource[] resources = Catalog.Resources;
				foreach (Resource resource2 in resources)
				{
					if (liveRows.TryGetValue(resource2.Id, out var value))
					{
						ResourceState resourceState = State.Resources[resource2.Id];
						double num = State.Speed * (double)resourceState.Percent / 100.0;
						value.text = ((num <= 0.0) ? "Idle" : ((60.0 * num / resource2.Work).ToString("0.##") + "/hr · " + resourceState.Percent + "% active" + (flag ? " · Full" : "")));
						((Graphic)value).color = (Color)((num > 0.0) ? Muted : new Color(0.6f, 0.61f, 0.57f));
						Text obj2 = liveRows[resource2.Id + "_stock"];
						obj2.text = resourceState.Stored.ToString("N0");
						((Graphic)obj2).color = ((resourceState.Stored > 0) ? Gold : Muted);
						((Graphic)activityMarks[resource2.Id]).color = ((num > 0.0) ? Gold : Color.clear);
					}
				}
				if (Object.op_Implicit((Object)(object)collect))
				{
					((Selectable)collect).interactable = !Session.Busy && State.Resources.Values.Any((ResourceState r) => r.Stored > 0);
				}
				UpdateTotal();
			}
			RefreshProgress();
		}

		private void RefreshProgress()
		{
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			if (State == null || currentTab != Tab.Production || !Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return;
			}
			double num = Math.Max(0.0, ZNet.instance.GetTimeSeconds() - State.LastWorldSeconds);
			double num2 = ((State.AssignedMultiplier == 0.0) ? 0.0 : Math.Min(num / 60.0 * State.Speed, Math.Max(0.0, State.Capacity - State.UsedWork) / State.AssignedMultiplier));
			foreach (KeyValuePair<string, Image> progressBar in progressBars)
			{
				ResourceState resourceState = State.Resources[progressBar.Key];
				float num3 = Mathf.Clamp01((float)((resourceState.Progress + num2 * (double)resourceState.Percent / 100.0) / Catalog.Find(progressBar.Key).Work));
				((Graphic)progressBar.Value).rectTransform.anchorMax = new Vector2(num3, 1f);
				((Graphic)progressBar.Value).color = (Color)((resourceState.Percent > 0) ? Gold : new Color(0.39f, 0.41f, 0.37f));
			}
		}

		private static Image Surface(Transform parent, string name, float x, float y, float width, float height, Color color)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_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)
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			Vector2 val2 = (component.pivot = TopLeft);
			Vector2 anchorMin = (component.anchorMax = val2);
			component.anchorMin = anchorMin;
			component.anchoredPosition = new Vector2(x, 0f - y);
			component.sizeDelta = new Vector2(width, height);
			Image component2 = val.GetComponent<Image>();
			((Graphic)component2).color = color;
			((Graphic)component2).raycastTarget = false;
			return component2;
		}

		private static Image ProgressBar(Transform parent, float x, float y, float width, float height)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_0089: 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)
			Image val = Surface(((Component)Surface(parent, "Progress track", x, y, width, height, new Color(0.25f, 0.26f, 0.23f))).transform, "Progress", 0f, 0f, 0f, 0f, Gold);
			((Graphic)val).rectTransform.anchorMin = Vector2.zero;
			((Graphic)val).rectTransform.anchorMax = new Vector2(0f, 1f);
			RectTransform rectTransform = ((Graphic)val).rectTransform;
			Vector2 offsetMin = (((Graphic)val).rectTransform.offsetMax = Vector2.zero);
			rectTransform.offsetMin = offsetMin;
			return val;
		}

		private static void ItemIcon(Transform parent, string prefab, float x, float y, float size)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			object obj;
			if (!Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				obj = null;
			}
			else
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefab);
				obj = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			}
			ItemDrop val = (ItemDrop)obj;
			if (Object.op_Implicit((Object)(object)val))
			{
				Sprite icon = val.m_itemData.GetIcon();
				if (Object.op_Implicit((Object)(object)icon))
				{
					Image obj2 = Surface(parent, prefab + " icon", x, y, size, size, Color.white);
					obj2.sprite = icon;
					obj2.preserveAspect = true;
				}
			}
		}

		private static Text Label(Transform parent, string text, float x, float y, float width, float height, int size, Color? color = null, bool bold = false, TextAnchor alignment = (TextAnchor)3)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			Text component = GUIManager.Instance.CreateText(text, parent, TopLeft, TopLeft, new Vector2(x + width / 2f, 0f - y - height / 2f), bold ? GUIManager.Instance.AveriaSerifBold : GUIManager.Instance.AveriaSerif, size, (Color)(((??)color) ?? Ink), false, Color.black, width, height, false).GetComponent<Text>();
			component.alignment = alignment;
			((Graphic)component).raycastTarget = false;
			component.horizontalOverflow = (HorizontalWrapMode)0;
			return component;
		}

		private static Button Button(Transform parent, string label, float x, float y, float width, Action action)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_005e: Expected O, but got Unknown
			Button component = GUIManager.Instance.CreateButton(label, parent, TopLeft, TopLeft, new Vector2(x + width / 2f, 0f - y - 20f), width, 40f).GetComponent<Button>();
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				action();
			});
			TintButton(component, prominent: false);
			return component;
		}

		private static void TintButton(Button button, bool prominent)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Text componentInChildren = ((Component)button).GetComponentInChildren<Text>();
			if (Object.op_Implicit((Object)(object)componentInChildren))
			{
				((Graphic)componentInChildren).color = ((!((Selectable)button).interactable) ? Muted : (prominent ? Gold : Ink));
				componentInChildren.fontSize = 17;
			}
			ColorBlock colors = ((Selectable)button).colors;
			((ColorBlock)(ref colors)).normalColor = (prominent ? new Color(1f, 0.94f, 0.8f) : new Color(0.78f, 0.8f, 0.76f));
			((ColorBlock)(ref colors)).highlightedColor = Color.white;
			((ColorBlock)(ref colors)).disabledColor = new Color(0.52f, 0.54f, 0.5f, 0.8f);
			((Selectable)button).colors = colors;
		}
	}
	internal sealed class MultiplayerCache
	{
		private sealed class Command
		{
			internal long World;

			internal long Nonce;

			internal ZDOID Cache;

			internal string Action;

			internal string Argument;

			internal CacheAccess Access;

			internal int Tier;

			internal int Speed;

			internal int Storage;

			internal int Allocation;

			internal Dictionary<string, int> Counts = new Dictionary<string, int>();

			internal ZPackage Encode()
			{
				//IL_0000: 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_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: 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)
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_006d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: 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_0091: Unknown result type (might be due to invalid IL or missing references)
				//IL_009d: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: Expected O, but got Unknown
				//IL_00aa: Expected O, but got Unknown
				ZPackage val = new ZPackage();
				string text = ((Access == CacheAccess.AdminRemote) ? "admin_" : ((Access == CacheAccess.OwnerRemote) ? "remote_" : ""));
				val.Write(World);
				val.Write(Cache);
				val.Write(Nonce);
				val.Write(text + Action);
				val.Write(Argument);
				val.Write(Tier);
				val.Write(Speed);
				val.Write(Storage);
				val.Write(Allocation);
				WriteCounts(val, Counts);
				return val;
			}

			internal static Command Read(ZPackage p)
			{
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				Command command = new Command
				{
					World = p.ReadLong(),
					Cache = p.ReadZDOID(),
					Nonce = p.ReadLong(),
					Action = p.ReadString(),
					Argument = p.ReadString(),
					Tier = p.ReadInt(),
					Speed = p.ReadInt(),
					Storage = p.ReadInt(),
					Allocation = p.ReadInt(),
					Counts = ReadCounts(p)
				};
				if (command.Nonce <= 0 || command.Argument.Length > 32768 || command.Action.Length > 32)
				{
					throw new InvalidDataException("Invalid cache request.");
				}
				if (command.Action.StartsWith("admin_", StringComparison.Ordinal))
				{
					command.Access = CacheAccess.AdminRemote;
					command.Action = command.Action.Substring(6);
				}
				else if (command.Action.StartsWith("remote_", StringComparison.Ordinal))
				{
					command.Access = CacheAccess.OwnerRemote;
					command.Action = command.Action.Substring(7);
				}
				return command;
			}
		}

		internal const string StateKey = "pc.mp.state";

		private const string RequestRpc = "PC_Request_v2";

		private const string ReplyRpc = "PC_Reply_v2";

		private const string PlacementRpc = "PC_PlacementRejected";

		internal const string DuplicateMessage = "You already have a Provisioning Cache. Remove it before building another.";

		private ZRoutedRpc registered;

		private ZDOMan world;

		private readonly List<ZDO> caches = new List<ZDO>();

		private readonly List<ZDO> accountRecords = new List<ZDO>();

		private readonly Dictionary<long, ZDO> owners = new Dictionary<long, ZDO>();

		private CacheAccounts accounts;

		private int scan;

		private int accountScan;

		private bool scannedCaches;

		private bool scannedAccounts;

		private bool ready;

		private float nextScan;

		private float retry;

		private float nextRefund;

		internal bool Busy;

		internal ZDOID Selected;

		internal CacheState Snapshot;

		private long snapshotRevision;

		private long requestId;

		private string pending = "";

		private Player escrowPlayer;

		private const string RemoteRequestRpc = "PC_RemoteOpen";

		private const string RemoteReplyRpc = "PC_RemoteSnapshot";

		private CacheAccess selectedAccess;

		private long remoteOwner;

		private long remoteRequest;

		private string remoteOwnerName = "";

		private bool remoteAwaiting;

		private bool remoteOpening;

		private float nextRemoteSnapshot;

		private float remoteTimeout;

		private Terminal remoteTerminal;

		private static string WorldKey => ZNet.instance.GetWorldUID().ToString();

		private static string EscrowKey => "pc.mp.pending.v1." + WorldKey;

		private static string DeliveryKey => "pc.mp.delivery.v1." + WorldKey;

		private static string RefundKey => "pc.mp.refund.v1." + WorldKey;

		private static long ServerId
		{
			get
			{
				if (!ZNet.instance.IsServer())
				{
					return ZNet.instance.GetServerPeer()?.m_uid ?? 0;
				}
				return ZNet.GetUID();
			}
		}

		internal bool IsOwner
		{
			get
			{
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					long? obj2;
					if (!Remote)
					{
						ZDOMan obj = world;
						if (obj == null)
						{
							obj2 = null;
						}
						else
						{
							ZDO zDO = obj.GetZDO(Selected);
							obj2 = ((zDO != null) ? new long?(zDO.GetLong("creator", 0L)) : ((long?)null));
						}
					}
					else
					{
						obj2 = remoteOwner;
					}
					return obj2 == Player.m_localPlayer.GetPlayerID();
				}
				return false;
			}
		}

		internal string OwnerName
		{
			get
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				if (!Remote)
				{
					ZDOMan obj = world;
					return CacheOwner.Name((obj != null) ? obj.GetZDO(Selected) : null);
				}
				return remoteOwnerName;
			}
		}

		internal bool Remote => selectedAccess != CacheAccess.Nearby;

		internal bool AdminOverride => selectedAccess == CacheAccess.AdminRemote;

		internal void Update()
		{
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_039c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a2: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || ZRoutedRpc.instance == null || ZDOMan.instance == null)
			{
				registered = null;
				world = null;
				ready = false;
				return;
			}
			if (registered != ZRoutedRpc.instance)
			{
				registered = ZRoutedRpc.instance;
				registered.Register<ZPackage>("PC_Request_v2", (Action<long, ZPackage>)Request);
				registered.Register<ZPackage>("PC_Reply_v2", (Action<long, ZPackage>)Reply);
				registered.Register<string>("PC_PlacementRejected", (Action<long, string>)PlacementRejected);
				registered.Register<ZPackage>("PC_RemoteOpen", (Action<long, ZPackage>)RemoteRequest);
				registered.Register<ZPackage>("PC_RemoteSnapshot", (Action<long, ZPackage>)RemoteReply);
			}
			if (world != ZDOMan.instance)
			{
				world = ZDOMan.instance;
				accounts = new CacheAccounts(world);
				caches.Clear();
				accountRecords.Clear();
				owners.Clear();
				scan = (accountScan = 0);
				scannedCaches = (scannedAccounts = (ready = false));
				nextScan = 0f;
				Snapshot = null;
				Selected = ZDOID.None;
				snapshotRevision = 0L;
				pending = "";
				Busy = false;
				escrowPlayer = null;
				ResetRemote();
			}
			if (ZNet.instance.IsServer() && Object.op_Implicit((Object)(object)ObjectDB.instance) && Time.unscaledTime >= nextScan)
			{
				if (!scannedCaches)
				{
					if (scan == 0)
					{
						caches.Clear();
					}
					scannedCaches = world.GetAllZDOsWithPrefabIterative("pc_provisioning_cache", caches, ref scan);
				}
				if (!scannedAccounts)
				{
					if (accountScan == 0)
					{
						accountRecords.Clear();
					}
					scannedAccounts = world.GetAllZDOsWithPrefabIterative("pc_cache_account", accountRecords, ref accountScan);
				}
				if (scannedCaches && scannedAccounts)
				{
					Reconcile();
					ready = true;
					scan = (accountScan = 0);
					scannedCaches = (scannedAccounts = false);
					nextScan = Time.unscaledTime + 2f;
				}
			}
			Player localPlayer = Player.m_localPlayer;
			UpdateRemote();
			if (Object.op_Implicit((Object)(object)localPlayer) && (Object)(object)escrowPlayer != (Object)(object)localPlayer)
			{
				escrowPlayer = localPlayer;
				pending = (localPlayer.m_customData.TryGetValue(EscrowKey, out var value) ? value : "");
				Busy = pending.Length > 0;
				retry = 0f;
			}
			if (Object.op_Implicit((Object)(object)localPlayer) && !((Character)localPlayer).IsDead() && Object.op_Implicit((Object)(object)ObjectDB.instance) && Time.unscaledTime >= nextRefund)
			{
				nextRefund = Time.unscaledTime + 1f;
				FlushRefunds();
			}
			if (!Object.op_Implicit((Object)(object)localPlayer) || !Busy || pending.Length <= 0 || ServerId == 0L || !(Time.unscaledTime >= retry))
			{
				return;
			}
			retry = Time.unscaledTime + 3f;
			try
			{
				registered.InvokeRoutedRPC(ServerId, "PC_Request_v2", new object[1] { (object)new ZPackage(Convert.FromBase64String(pending)) });
			}
			catch (Exception ex)
			{
				Plugin.Instance.ReportError("Cache request retry: " + ex.Message);
			}
		}

		private void Reconcile()
		{
			accounts.Load(accountRecords);
			owners.Clear();
			foreach (ZDO item in from z in caches
				orderby z.GetString("pc.mp.state", "").Length > 0 descending, ((ZDOID)(ref z.m_uid)).UserID, ((ZDOID)(ref z.m_uid)).ID
				select z)
			{
				long num = item.GetLong("creator", 0L);
				if (num == 0L)
				{
					continue;
				}
				if (owners.ContainsKey(num))
				{
					item.SetOwner(ZNet.GetUID());
					item.Set("pc.mp.duplicate", true);
					try
					{
						DropBuildRefund(item, "Wood", 20);
						DropBuildRefund(item, "Stone", 10);
						world.DestroyZDO(item);
						NotifyPlacementRejected(num);
					}
					catch (Exception ex)
					{
						Plugin.Instance.ReportError("Duplicate cache refund will retry: " + ex.Message);
					}
				}
				else
				{
					owners.Add(num, item);
					try
					{
						accounts.Attach(accounts.GetOrCreate(num, item), item);
					}
					catch (Exception ex2)
					{
						Plugin.Instance.ReportError("Cache data preserved: " + ex2.Message);
					}
				}
			}
			foreach (ZDO item2 in accounts.Records.Where((ZDO a) => !owners.ContainsKey(a.GetLong("pc.account.owner", 0L))))
			{
				try
				{
					accounts.Pause(item2);
				}
				catch (Exception ex3)
				{
					Plugin.Instance.ReportError("Unplaced cache account preserved: " + ex3.Message);
				}
			}
		}

		internal bool Select(ZDO z, out string error)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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)
			if (z.GetBool("pc.mp.duplicate", false))
			{
				error = "You already have a Provisioning Cache. Remove it before building another. Building materials are being returned beside it.";
				return false;
			}
			ResetRemote();
			Selected = z.m_uid;
			snapshotRevision = z.GetLong("pc.mp.revision", 0L);
			string text = z.GetString("pc.mp.state", "");
			if (text.Length == 0 || z.GetZDOID("pc.mp.account") == ZDOID.None)
			{
				error = "Server is registering this cache. Try again shortly.";
				return false;
			}
			try
			{
				Snapshot = StateCodec.Decode(text);
			}
			catch (Exception ex)
			{
				error = "Cache data could not be read.";
				Plugin.Instance.ReportError(ex.ToString());
				return false;
			}
			if (IsOwner && !Busy && z.GetInt("pc.mp.used", 0) == 0)
			{
				Send("initialize", "");
			}
			error = "";
			return true;
		}

		internal void Refresh()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (Busy || world == null)
			{
				return;
			}
			if (Remote)
			{
				RefreshRemote();
				return;
			}
			ZDO zDO = world.GetZDO(Selected);
			if (zDO == null)
			{
				Snapshot = null;
				return;
			}
			string text = zDO.GetString("pc.mp.state", "");
			long num = zDO.GetLong("pc.mp.revision", 0L);
			if (num < snapshotRevision || text.Length == 0)
			{
				return;
			}
			try
			{
				Snapshot = StateCodec.Decode(text);
				snapshotRevision = num;
			}
			catch (Exception ex)
			{
				Plugin.Instance.ReportError("Cache snapshot: " + ex.Message);
			}
		}

		internal string Send(string action, string argument, Dictionary<string, int> counts = null)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if (Busy)
			{
				return "Waiting for the server…";
			}
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || Snapshot == null)
			{
				return "Cache unavailable.";
			}
			requestId = Math.Max(DateTime.UtcNow.Ticks, requestId + 1);
			SetPending(new Command
			{
				World = ZNet.instance.GetWorldUID(),
				Cache = Selected,
				Nonce = requestId,
				Action = action,
				Argument = argument,
				Access = selectedAccess,
				Tier = Snapshot.Tier,
				Speed = Snapshot.SpeedRank,
				Storage = Snapshot.StorageRank,
				Allocation = Snapshot.AllocationRank,
				Counts = (counts ?? new Dictionary<string, int>())
			});
			return "Waiting for the server…";
		}

		private void SetPending(Command command)
		{
			pending = Convert.ToBase64String(command.Encode().GetArray());
			Busy = true;
			retry = 0f;
			Player.m_localPlayer.m_customData[EscrowKey] = pending;
		}

		private void Request(long sender, ZPackage p)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bc: Unknown result type (might be due to invalid IL or missing references)
			if (!ZNet.instance.IsServer() || !ready)
			{
				return;
			}
			try
			{
				Command command = Command.Read(p);
				if (command.World != ZNet.instance.GetWorldUID() || !GetActor(sender, out var playerId, out var playerZdo, out var isAdmin))
				{
					return;
				}
				ZDO zDO = world.GetZDO(command.Cache);
				ZDO val = accounts.FindForPiece(command.Cache);
				if (val == null)
				{
					Respond(sender, command, null, "Cache is unavailable; pending payments will be returned.");
					return;
				}
				CacheState cacheState = StateCodec.Decode(val.GetString("pc.mp.state", ""));
				CollectionLedger collectionLedger = CollectionLedger.Decode(val.GetString("pc.mp.collections", ""), cacheState);
				CollectionReservation collectionReservation = collectionLedger.Find(playerId);
				if (command.Action == "collect_ack")
				{
					if (collectionReservation == null || collectionReservation.Request != command.Nonce)
					{
						Respond(sender, command, val, "Collection receipt not found.");
						return;
					}
					accounts.Advance(val, cacheState);
					collectionLedger.Acknowledge(cacheState, playerId, command.Nonce, command.Counts);
					accounts.Save(val, cacheState, collectionLedger);
					Record(val, playerId, command, CollectionMessage(collectionReservation), paid: false);
					Respond(sender, command, val, CollectionMessage(collectionReservation));
					return;
				}
				if (command.Action == "collect" && collectionReservation?.Request == command.Nonce)
				{
					Respond(sender, command, val, collectionReservation.Complete ? CollectionMessage(collectionReservation) : "Adding items to inventory…", paid: false, collectionReservation.Complete ? null : collectionReservation.Granted);
					return;
				}
				string text = "pc.receipt." + playerId;
				long num = val.GetLong(text, 0L);
				if (!NetworkPolicy.IsNewRequest(command.Nonce, num))
				{
					Respond(sender, command, val, (command.Nonce == num) ? val.GetString(text + ".result", "") : "Stale request rejected.", command.Nonce == num && val.GetInt(text + ".paid", 0) == 1);
					return;
				}
				if (zDO == null || zDO.GetPrefab() != StringExtensionMethods.GetStableHashCode("pc_provisioning_cache"))
				{
					Record(val, playerId, command, "Cache was removed; progress is preserved. Pending payments will be returned.", paid: false);
					Respond(sender, command, val, "Cache was removed; progress is preserved. Pending payments will be returned.");
					return;
				}
				long num2 = val.GetLong("pc.account.owner", 0L);
				string error = NetworkPolicy.Authorize(playerId, num2, (playerZdo == null) ? double.PositiveInfinity : ((double)Vector3.Distance(playerZdo.GetPosition(), zDO.GetPosition())), command.Action, command.Access, isAdmin);
				if (val.GetInt("pc.mp.used", 0) == 0 && playerId != num2 && !(command.Access == CacheAccess.AdminRemote && isAdmin))
				{
					error = "The owner must open this cache before visitors can collect.";
				}
				if (!owners.TryGetValue(num2, out var value) || value.m_uid != command.Cache)
				{
					error = "Only one cache per player is allowed.";
				}
				bool flag = error.Length == 0;
				bool paid = false;
				accounts.Advance(val, cacheState);
				if (flag && command.Action == "collect")
				{
					Dictionary<string, int> wanted = command.Counts.Where((KeyValuePair<string, int> pair) => Object.op_Implicit((Object)(object)ObjectDB.instance.GetItemPrefab(pair.Key))).ToDictionary((KeyValuePair<string, int> pair) => pair.Key, (KeyValuePair<string, int> pair) => pair.Value);
					collectionReservation = collectionLedger.Reserve(cacheState, playerId, command.Nonce, wanted);
					if (playerId == num2 || command.Access == CacheAccess.AdminRemote)
					{
						val.Set("pc.mp.used", 1);
					}
					accounts.Save(val, cacheState, collectionLedger);
					if (collectionReservation.Complete)
					{
						Record(val, playerId, command, CollectionMessage(collectionReservation), paid: false);
					}
					Respond(sender, command, val, collectionReservation.Complete ? CollectionMessage(collectionReservation) : "Adding items to inventory…", paid: false, collectionReservation.Complete ? null : collectionReservation.Granted);
					return;
				}
				if (flag && command.Action == "initialize")
				{
					error = "Cache ready. Visitors can now collect.";
				}
				else if (flag && command.Action == "allocate")
				{
					Production.Allocate(cacheState, command.Counts, out error);
				}
				else if (flag && command.Action == "purchase")
				{
					Offer offer = Upgrades.Offers(cacheState).Find((Offer o) => o.Id == command.Argument);
					error = ((offer == null) ? "Already purchased." : ((!NetworkPolicy.QuoteMatches(cacheState, command.Tier, command.Speed, command.Storage, command.Allocation)) ? "Upgrade changed; try again." : Upgrades.BlockReason(cacheState, offer, int.MaxValue, (string key) => ZoneSystem.instance.GetGlobalKey(key), (string _) => int.MaxValue)));
					if (error.Length == 0)
					{
						Upgrades.Apply(cacheState, offer);
						paid = true;
						error = offer.Name + " purchased.";
					}
				}
				if (flag && (playerId == num2 || command.Access == CacheAccess.AdminRemote))
				{
					val.Set("pc.mp.used", 1);
				}
				accounts.Save(val, cacheState);
				Record(val, playerId, command, error, paid);
				Respond(sender, command, val, error, paid);
			}
			catch (Exception ex)
			{
				Plugin.Instance.ReportError("Cache server request failed: " + ex);
			}
		}

		private static string CollectionMessage(CollectionReservation receipt)
		{
			int num = receipt.Accepted.Values.Sum();
			return "Collected " + num + " items." + ((num < receipt.Granted.Values.Sum()) ? " Remaining items stayed in the cache." : "");
		}

		private static void Record(ZDO z, long player, Command command, string message, bool paid)
		{
			string text = "pc.receipt." + player;
			if (command.Nonce >= z.GetLong(text, 0L))
			{
				z.Set(text, command.Nonce);
				z.Set(text + ".result", message);
				z.Set(text + ".paid", paid ? 1 : 0);
			}
		}

		private void Respond(long sender, Command command, ZDO z, string message, bool paid = false, Dictionary<string, int> grant = null)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			ZPackage val = new ZPackage();
			val.Write(command.Nonce);
			val.Write(command.Cache);
			val.Write(((z != null) ? z.GetString("pc.mp.state", "") : null) ?? "");
			val.Write(message);
			val.Write(paid);
			val.Write((z != null) ? z.GetLong("pc.mp.revision", 0L) : 0);
			val.Write(grant != null);
			WriteCounts(val, grant);
			registered.InvokeRoutedRPC(sender, "PC_Reply_v2", new object[1] { val });
		}

		private void Reply(long sender, ZPackage p)
		{
			//IL_0026: 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_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//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_00a4: 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)
			if (sender != ServerId || !Busy || !Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				return;
			}
			try
			{
				long num = p.ReadLong();
				ZDOID val = p.ReadZDOID();
				string text = p.ReadString();
				string text2 = p.ReadString();
				bool flag = p.ReadBool();
				long num2 = p.ReadLong();
				bool flag2 = p.ReadBool();
				Dictionary<string, int> granted = ReadCounts(p);
				Command command = Command.Read(new ZPackage(Convert.FromBase64String(pending)));
				if (command.Nonce != num || command.Cache != val)
				{
					return;
				}
				CacheState cacheState = ((text.Length > 0) ? StateCodec.Decode(text) : null);
				bool flag3 = val == Selected || (cacheState != null && cacheState.BoundUser == ((ZDOID)(ref Selected)).UserID && cacheState.BoundId == ((ZDOID)(ref Selected)).ID);
				if (flag3 && cacheState != null && num2 >= snapshotRevision)
				{
					Snapshot = cacheState;
					snapshotRevision = num2;
				}
				if (flag2)
				{
					if (!(command.Action != "collect") || !(command.Action != "collect_ack"))
					{
						ReceiveGrant(command, granted);
					}
					return;
				}
				if (command.Action == "purchase" && !flag)
				{
					QueueRefund(command);
				}
				Busy = false;
				pending = "";
				Player.m_localPlayer.m_customData.Remove(EscrowKey);
				if (command.Action == "collect" || command.Action == "collect_ack")
				{
					Player.m_localPlayer.m_customData.Remove(DeliveryKey);
				}
				if (flag3)
				{
					Plugin.Instance.Window.NetworkChanged(text2, command.Action != "collect" && command.Action != "collect_ack");
				}
				((Character)Player.m_localPlayer).Message((MessageType)2, text2, 0, (Sprite)null, false);
			}
			catch (Exception ex)
			{
				Plugin.Instance.ReportError("Cache reply preserved for retry: " + ex);
			}
		}

		private void ReceiveGrant(Command command, Dictionary<string, int> granted)
		{
			Player player = Player.m_localPlayer;
			if (((Character)player).IsDead())
			{
				return;
			}
			CollectionDelivery delivery;
			if (player.m_customData.TryGetValue(DeliveryKey, out var value))
			{
				delivery = CollectionDelivery.Decode(value);
				if (delivery.Request != command.Nonce || !delivery.Matches(granted))
				{
					throw new InvalidDataException("Collection grant changed.");
				}
			}
			else
			{
				delivery = new CollectionDelivery
				{
					Request = command.Nonce
				};
				foreach (KeyValuePair<string, int> item in granted)
				{
					delivery.Granted.Add(item.Key, item.Value);
				}
				player.m_customData[DeliveryKey] = delivery.Encode();
			}
			Dictionary<string, int> received = new Dictionary<string, int>();
			delivery.Deliver(delegate(string id)
			{
				if (!CacheInventory.TryAddOne(id))
				{
					return false;
				}
				received[id] = ((!received.TryGetValue(id, out var value2)) ? 1 : (value2 + 1));
				return true;
			}, delegate
			{
				player.m_customData[DeliveryKey] = delivery.Encode();
			});
			command.Action = "collect_ack";
			command.Argument = "";
			command.Counts = new Dictionary<string, int>(delivery.Accepted);
			SetPending(command);
			CacheInventory.ShowPickups(received);
		}

		private static void QueueRefund(Command command)
		{
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			Dictionary<string, string> customData = Player.m_localPlayer.m_customData;
			string value;
			long result;
			long num = ((customData.TryGetValue(RefundKey + ".last", out value) && long.TryParse(value, out result)) ? result : 0);
			checked
			{
				if (command.Nonce > num)
				{
					Offer offer = Upgrades.Offers(new CacheState
					{
						Tier = command.Tier,
						SpeedRank = command.Speed,
						StorageRank = command.Storage,
						AllocationRank = command.Allocation
					}).Find((Offer o) => o.Id == command.Argument);
					if (offer == null)
					{
						throw new InvalidDataException("Cannot reconstruct upgrade refund.");
					}
					string value2;
					Dictionary<string, int> dictionary = (customData.TryGetValue(RefundKey, out value2) ? ReadCounts(new ZPackage(Convert.FromBase64String(value2)), refunds: true) : new Dictionary<string, int>());
					dictionary["Coins"] = (dictionary.TryGetValue("Coins", out var value3) ? value3 : 0) + offer.Coins;
					if (offer.SampleCount > 0)
					{
						dictionary[offer.Sample] = (dictionary.TryGetValue(offer.Sample, out var value4) ? value4 : 0) + offer.SampleCount;
					}
					StoreRefunds(dictionary);
					customData[RefundKey + ".last"] = command.Nonce.ToString();
				}
			}
		}

		private static void Store