Decompiled source of Runebourne v0.8.5

plugins/Runebourne.dll

Decompiled 18 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Runebourne.Away;
using Runebourne.Diagnostics;
using Runebourne.Farming;
using Runebourne.General;
using Runebourne.Guide;
using Runebourne.Hauling;
using Runebourne.Mining;
using Runebourne.Planting;
using Runebourne.Progression;
using Runebourne.Serpents;
using Runebourne.Vault;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Runebourne")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Runebourne")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("0.8.5")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.8.5.0")]
namespace Runebourne
{
	[BepInPlugin("com.yohanb.runebourne", "Runebourne", "0.8.5")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal class Runebourne : BaseUnityPlugin
	{
		public const string PluginGUID = "com.yohanb.runebourne";

		public const string PluginName = "Runebourne";

		public const string PluginVersion = "0.8.5";

		public static CustomLocalization Localization = LocalizationManager.Instance.GetLocalization();

		private void Awake()
		{
			Logger.LogInfo((object)"Runebourne has loaded");
			FarmPostRegistration.Start();
			FarmSpiritRegistration.Start();
			SpiritDamage.Start();
			FarmUpgradeRegistration.Start();
			DeerRegistration.Start();
			FarmTrough.Start();
			FarmAnimalSounds.Start();
			CenterMessageWrap.Start();
			FarmAnimalDrawing.Start();
			FarmHerdCollisions.Start();
			FarmHerdCalm.Start();
			FieldRune.Start();
			LightningRune.Start();
			SerpentDepot.Start();
			VaultRegistration.Start();
			SerpentCartography.Initialize();
			SerpentPatches.Start();
			SerpentLure.StartPatches();
			SerpentCargoPanel.StartPatches();
			SerpentRecovery.Start();
			PlantingRegistration.Start();
			BerryRegistration.Start();
			HaulerRegistration.Start();
			GeneralPatches.Start();
			GeneralRegistration.Start();
			HaulerInput.Start();
			PlantHarvestPatches.Start();
			PlantGrowth.StartPatches();
			ContainerInputTiming.Start();
			PlantTreePatches.Start();
			PlantStorage.BlocksUnlink = PlantWork.BlocksUnlink;
			FarmCommandWand.Start();
			WandBuildMode.Start();
			LecternRegistration.Start();
			ReevesBoardRegistration.Start();
			FarmRecoveryRecord.StartRegistration();
			FarmHarvestPatches.Start();
			FarmInventoryPanel.StartPatches();
			HaulerCargoPanel.StartPatches();
			GeneralCargoPanel.StartPatches();
			MiningRegistration.Start();
			RenewalRune.Start();
			MiningCargoPanel.StartPatches();
			MiningPatches.Start();
			VaultPatches.Start();
			PostWork.EnableGate = MiningPost.WorkGate;
			((Component)this).gameObject.AddComponent<MiningNetwork>();
			((Component)this).gameObject.AddComponent<MiningMapRing>();
			((Component)this).gameObject.AddComponent<WorkerWatchReport>();
			((Component)this).gameObject.AddComponent<WorkerWatchMap>();
			((Component)this).gameObject.AddComponent<HaulerMap>();
			((Component)this).gameObject.AddComponent<FarmHarvestNetwork>();
			((Component)this).gameObject.AddComponent<RuntimePerformance>();
			((Component)this).gameObject.AddComponent<HaulerNetwork>();
			((Component)this).gameObject.AddComponent<GeneralNetwork>();
			((Component)this).gameObject.AddComponent<ProgressionNetwork>();
			((Component)this).gameObject.AddComponent<ContentGate>();
			((Component)this).gameObject.AddComponent<SerpentNetwork>();
			((Component)this).gameObject.AddComponent<SerpentCatalogue>();
			((Component)this).gameObject.AddComponent<SerpentFleet>();
			((Component)this).gameObject.AddComponent<WorkerDirectory>();
			((Component)this).gameObject.AddComponent<SerpentMap>();
			((Component)this).gameObject.AddComponent<SerpentActivity>();
			((Component)this).gameObject.AddComponent<MiningActivity>();
			((Component)this).gameObject.AddComponent<HaulerActivity>();
			AwayWork.Bind(((BaseUnityPlugin)this).Config);
			((Component)this).gameObject.AddComponent<AwayWork>();
			((Component)this).gameObject.AddComponent<SerpentTravel>();
			((Component)this).gameObject.AddComponent<SerpentHover>();
			((Component)this).gameObject.AddComponent<SerpentLure>();
			SerpentBody.OpenPanel = SerpentPanel.Open;
			SerpentBody.WandUsed = SerpentSelection.UseMounted;
			SerpentBody.CanBoard = delegate(ZDO z)
			{
				SerpentState serpentState = SerpentRecord.Read(z);
				return serpentState != null && serpentState.TravelMode == SerpentState.Mode.Passenger && !serpentState.HasCargo && !serpentState.Pending && !serpentState.Dead;
			};
			SerpentNetwork.Tamed = SerpentVisual.Strike;
			((Component)this).gameObject.AddComponent<HaulerFilterButton>();
			((Component)this).gameObject.AddComponent<VaultWindow>();
			((Component)this).gameObject.AddComponent<WorkerSelectionVisual>();
			((Component)this).gameObject.AddComponent<WandAreaPreview>();
			((Component)this).gameObject.AddComponent<FarmStorageNetwork>();
			((Component)this).gameObject.AddComponent<FarmSpiritNetwork>();
			((Component)this).gameObject.AddComponent<FarmSettingsNetwork>();
			((Component)this).gameObject.AddComponent<PlantingSettingsNetwork>();
			((Component)this).gameObject.AddComponent<FarmCensusNetwork>();
			((Component)this).gameObject.AddComponent<FarmBreedingNetwork>();
			FarmBreedingPatches.Start();
			FarmAnimalTiming.StartPatches();
			FarmAttachment.StartPatches();
			HaulerAttachment.StartPatches();
			HaulerRelay.StartPatches();
			PostSpacing.StartPatches();
			MiningAttachment.StartPatches();
			FarmStarFood.StartPatches();
			FarmBoarVisuals.StartPatches();
			((Component)this).gameObject.AddComponent<FarmStarFood>();
			TestFieldTerrain.Start();
			ProgressionRecord.StartRegistration();
			ProgressionPatches.Start();
			ContentGate.StartPatches();
			PieceManager.OnPiecesRegistered += WorkGates.LogMissing;
			DevConsole.Start(((BaseUnityPlugin)this).Config);
		}

		private void OnDestroy()
		{
			FarmPostRegistration.Stop();
			ProgressionRecord.StopRegistration();
			ProgressionPatches.Stop();
			ContentGate.StopPatches();
			PieceManager.OnPiecesRegistered -= WorkGates.LogMissing;
			FarmSpiritRegistration.Stop();
			SpiritDamage.Stop();
			FarmUpgradeRegistration.Stop();
			DeerRegistration.Stop();
			FarmTrough.Stop();
			FarmAnimalSounds.Stop();
			CenterMessageWrap.Stop();
			FarmAnimalDrawing.Stop();
			FarmHerdCollisions.Stop();
			FarmHerdCalm.Stop();
			FieldRune.Stop();
			LightningRune.Stop();
			SerpentDepot.Stop();
			VaultRegistration.Stop();
			SerpentCartography.Shutdown();
			SerpentPatches.Stop();
			SerpentLure.StopPatches();
			SerpentCargoPanel.StopPatches();
			SerpentRecovery.Stop();
			SerpentSelection.Cancel();
			SerpentPanel.Close();
			SerpentDepotPanel.Close();
			SerpentBody.OpenPanel = null;
			SerpentBody.WandUsed = null;
			SerpentBody.CanBoard = null;
			SerpentNetwork.Tamed = null;
			PlantingRegistration.Stop();
			BerryRegistration.Stop();
			HaulerRegistration.Stop();
			GeneralRegistration.Stop();
			GeneralPatches.Stop();
			GeneralSelection.Cancel();
			HaulerInput.Stop();
			HaulerSelection.Cancel();
			PlantHarvestPatches.Stop();
			PlantGrowth.StopPatches();
			ContainerInputTiming.Stop();
			PlantTreePatches.Stop();
			PlantStorage.BlocksUnlink = null;
			FarmCommandWand.Stop();
			WandBuildMode.Stop();
			LecternRegistration.Stop();
			LecternWindow.Close();
			ReevesBoardRegistration.Stop();
			ReevesBoardWindow.Close();
			FarmRecoveryRecord.StopRegistration();
			FarmHarvestPatches.Stop();
			FarmInventoryPanel.StopPatches();
			HaulerCargoPanel.StopPatches();
			GeneralCargoPanel.StopPatches();
			MiningRegistration.Stop();
			RenewalRune.Stop();
			MiningCargoPanel.StopPatches();
			MiningPatches.Stop();
			VaultPatches.Stop();
			MiningExcavation.Unregister();
			MiningSelection.Cancel();
			MiningPanel.Close();
			PostWork.EnableGate = null;
			FarmBreedingPatches.Stop();
			FarmAnimalTiming.StopPatches();
			FarmAttachment.StopPatches();
			HaulerAttachment.StopPatches();
			HaulerRelay.StopPatches();
			PostSpacing.StopPatches();
			MiningAttachment.StopPatches();
			FarmStarFood.StopPatches();
			FarmBoarVisuals.StopPatches();
			DevConsole.Stop();
			TestFieldTerrain.Stop();
		}
	}
}
namespace Runebourne.Vault
{
	internal sealed class VaultChest : MonoBehaviour
	{
		internal const string IdentityKey = "runebourne.vault.identity.v1";

		internal const string ItemKey = "runebourne.vault.item.v1";

		internal const string LevelKey = "runebourne.vault.level.v1";

		internal const string StoredKey = "runebourne.vault.stored.v1";

		internal const string CapacityKey = "runebourne.vault.capacity.v1";

		private const string ClearRpc = "Runebourne_VaultClear";

		internal static readonly List<VaultChest> Loaded = new List<VaultChest>();

		private readonly Guid settler = Guid.NewGuid();

		private ZNetView view;

		private Container chest;

		private float nextCapacity;

		private float nextNudge;

		internal Container Chest => chest;

		internal ZDO Zdo
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)view) || !view.IsValid())
				{
					return null;
				}
				return view.GetZDO();
			}
		}

		internal string Item
		{
			get
			{
				ZDO zdo = Zdo;
				return ((zdo != null) ? zdo.GetString("runebourne.vault.item.v1", "") : null) ?? "";
			}
		}

		internal int ItemLevel
		{
			get
			{
				ZDO zdo = Zdo;
				if (zdo == null)
				{
					return 0;
				}
				return zdo.GetInt("runebourne.vault.level.v1", 0);
			}
		}

		internal long Stored
		{
			get
			{
				long val = 0L;
				ZDO zdo = Zdo;
				return Math.Max(val, (zdo != null) ? zdo.GetLong("runebourne.vault.stored.v1", 0L) : 0);
			}
		}

		internal int CapacityStacks
		{
			get
			{
				ZDO zdo = Zdo;
				if (zdo == null)
				{
					return VaultRules.LevelStacks[0];
				}
				return zdo.GetInt("runebourne.vault.capacity.v1", VaultRules.LevelStacks[0]);
			}
		}

		internal string Identity
		{
			get
			{
				ZDO zdo = Zdo;
				return ((zdo != null) ? zdo.GetString("runebourne.vault.identity.v1", "") : null) ?? "";
			}
		}

		internal GameObject ItemPrefab
		{
			get
			{
				if (Item.Length <= 0 || !Object.op_Implicit((Object)(object)ObjectDB.instance))
				{
					return null;
				}
				return ObjectDB.instance.GetItemPrefab(Item);
			}
		}

		internal int StackSize
		{
			get
			{
				GameObject itemPrefab = ItemPrefab;
				if (!Object.op_Implicit((Object)(object)itemPrefab))
				{
					return 1;
				}
				return Math.Max(1, itemPrefab.GetComponent<ItemDrop>().m_itemData.m_shared.m_maxStackSize);
			}
		}

		private long SlotAmount
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)chest) || chest.GetInventory() == null)
				{
					return 0L;
				}
				return ((IEnumerable<ItemData>)chest.GetInventory().GetAllItems()).Sum((Func<ItemData, long>)((ItemData i) => i.m_stack));
			}
		}

		internal long Total => SlotAmount + Stored;

		internal static VaultChest For(Container container)
		{
			if (!Object.op_Implicit((Object)(object)container))
			{
				return null;
			}
			return ((Component)container).GetComponent<VaultChest>();
		}

		internal static VaultChest For(Inventory inventory)
		{
			if (inventory == null)
			{
				return null;
			}
			foreach (VaultChest item in Loaded)
			{
				if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)item.chest) && item.chest.GetInventory() == inventory)
				{
					return item;
				}
			}
			return null;
		}

		private void Awake()
		{
			view = ((Component)this).GetComponent<ZNetView>();
			chest = ((Component)this).GetComponent<Container>();
			if (Object.op_Implicit((Object)(object)view) && view.IsValid() && !view.m_ghost && Object.op_Implicit((Object)(object)chest))
			{
				view.Register("Runebourne_VaultClear", (Action<long>)RpcClear);
				Loaded.Add(this);
				((MonoBehaviour)this).InvokeRepeating("Settle", 1f, 1f);
			}
		}

		private void OnDestroy()
		{
			((MonoBehaviour)this).CancelInvoke();
			Loaded.Remove(this);
		}

		internal bool Matches(ItemData item)
		{
			if (item != null && Object.op_Implicit((Object)(object)item.m_dropPrefab))
			{
				return VaultRules.Matches(((Object)item.m_dropPrefab).name, item.m_worldLevel, item.m_quality, item.m_customData?.Count ?? 0, Item, ItemLevel);
			}
			return false;
		}

		internal string ItemName()
		{
			GameObject itemPrefab = ItemPrefab;
			if (!Object.op_Implicit((Object)(object)itemPrefab) || Localization.instance == null)
			{
				return Item;
			}
			return Localization.instance.Localize(itemPrefab.GetComponent<ItemDrop>().m_itemData.m_shared.m_name);
		}

		internal string Title()
		{
			return VaultRules.Title((Item.Length > 0) ? ItemName() : null, Total, CapacityStacks, StackSize);
		}

		internal string WindowLine()
		{
			return VaultRules.WindowLine((Item.Length > 0) ? ItemName() : null, Total, CapacityStacks, StackSize);
		}

		internal void Nudge()
		{
			Inventory val = (Object.op_Implicit((Object)(object)chest) ? chest.GetInventory() : null);
			if (val != null && !(Time.time < nextNudge) && Item.Length != 0 && (val.GetItemAt(0, 0)?.m_stack ?? 0) < Math.Min(StackSize, Total))
			{
				nextNudge = Time.time + 0.2f;
				Settle();
			}
		}

		internal bool MayPut(ItemData item, out string refusal)
		{
			refusal = null;
			ZDO zdo = Zdo;
			if (zdo == null || item == null || !Object.op_Implicit((Object)(object)item.m_dropPrefab))
			{
				refusal = "The Deephold isn't ready; open it again";
				return false;
			}
			if (!VaultRules.Qualifies(item.m_shared.m_maxStackSize, item.m_quality, item.m_customData?.Count ?? 0))
			{
				refusal = "A Deephold holds only plain stackable items";
				return false;
			}
			if (Item.Length == 0)
			{
				if (!view.IsOwner())
				{
					refusal = "Open the Deephold again";
					return false;
				}
				if (!VaultRules.Empty(chest.GetInventory().NrOfItems(), Stored))
				{
					refusal = "Empty the Deephold first";
					return false;
				}
				zdo.Set("runebourne.vault.item.v1", ((Object)item.m_dropPrefab).name);
				zdo.Set("runebourne.vault.level.v1", item.m_worldLevel);
				return true;
			}
			if (!Matches(item))
			{
				refusal = "This Deephold holds only " + ItemName();
				return false;
			}
			int stackSize = StackSize;
			int capacityStacks = CapacityStacks;
			if (!VaultRules.Accepts(itemSet: true, Total, VaultRules.Capacity(capacityStacks, stackSize), Stored, VaultRules.StoreLimit(capacityStacks, stackSize)))
			{
				refusal = "This Deephold is full";
				return false;
			}
			return true;
		}

		private unsafe void Settle()
		{
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			ZDO zdo = Zdo;
			Inventory val = (Object.op_Implicit((Object)(object)chest) ? chest.GetInventory() : null);
			if (zdo == null || !view.IsOwner() || val == null)
			{
				return;
			}
			if (zdo.GetString("runebourne.vault.identity.v1", "").Length == 0)
			{
				zdo.Set("runebourne.vault.identity.v1", Guid.NewGuid().ToString("N"));
			}
			if (Time.time >= nextCapacity)
			{
				nextCapacity = Time.time + 2f;
				RefreshCapacity(zdo);
			}
			if (WorkerResources.Prepared(zdo) || Dragging())
			{
				return;
			}
			GameObject itemPrefab = ItemPrefab;
			bool flag = Item.Length > 0 && Object.op_Implicit((Object)(object)itemPrefab);
			if (Item.Length == 0 && Stored == 0L && VaultFill.Adopt(val.GetAllItems(), out var prefab, out var level))
			{
				zdo.Set("runebourne.vault.item.v1", prefab);
				zdo.Set("runebourne.vault.level.v1", level);
				itemPrefab = ItemPrefab;
				flag = Item.Length > 0 && Object.op_Implicit((Object)(object)itemPrefab);
			}
			if (flag)
			{
				if (val.GetAllItems().Any((ItemData i) => !Matches(i)))
				{
					WriteFilter(zdo, accepts: false);
					return;
				}
				int[] array = new int[24];
				foreach (ItemData allItem in val.GetAllItems())
				{
					int num = allItem.m_gridPos.y * 8 + allItem.m_gridPos.x;
					if (allItem.m_gridPos.x < 0 || allItem.m_gridPos.x >= 8 || num < 0 || num >= 24 || array[num] != 0)
					{
						return;
					}
					array[num] = allItem.m_stack;
				}
				int stackSize = StackSize;
				long stored = Stored;
				int[] array2;
				long newStore;
				try
				{
					array2 = VaultRules.Layout(array, stored, stackSize, VaultRules.StoreLimit(CapacityStacks, stackSize), out newStore);
				}
				catch (Exception ex) when (ex is ArgumentException || ex is InvalidOperationException)
				{
					ZDOID uid = zdo.m_uid;
					Logger.LogWarning((object)("Deephold " + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString() + " not settled: " + ex.Message));
					WriteFilter(zdo, accepts: false);
					return;
				}
				if (newStore != stored || !array2.SequenceEqual(array))
				{
					Apply(zdo, val, itemPrefab, array, array2, stored, newStore);
				}
			}
			int capacityStacks = CapacityStacks;
			int stackSize2 = StackSize;
			WriteFilter(zdo, VaultRules.Accepts(flag, Total, VaultRules.Capacity(capacityStacks, stackSize2), Stored, VaultRules.StoreLimit(capacityStacks, stackSize2)));
		}

		private bool Dragging()
		{
			InventoryGui instance = InventoryGui.instance;
			if (Object.op_Implicit((Object)(object)instance) && (Object)(object)instance.m_currentContainer == (Object)(object)chest)
			{
				if (instance.m_dragItem == null)
				{
					return instance.m_splitItem != null;
				}
				return true;
			}
			return false;
		}

		private unsafe void Apply(ZDO zdo, Inventory inventory, GameObject prefab, int[] slots, int[] target, long stored, long store)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			if (((IEnumerable<int>)slots).Sum((Func<int, long>)((int n) => n)) + stored != ((IEnumerable<int>)target).Sum((Func<int, long>)((int n) => n)) + store)
			{
				ZDOID uid = zdo.m_uid;
				Logger.LogError((object)("Deephold " + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString() + " settle would change its total; nothing written"));
				return;
			}
			Dictionary<int, ItemData> dictionary = new Dictionary<int, ItemData>();
			for (int num = 0; num < 24; num++)
			{
				if (target[num] > 0 && inventory.GetItemAt(num % 8, num / 8) == null)
				{
					dictionary[num] = NewStack(prefab, target[num], num % 8, num / 8);
				}
			}
			Guid operation = Guid.NewGuid();
			if (!WorkerResources.TryAcquire(zdo, settler, operation, ZNet.instance.GetTime().Ticks + 50000000))
			{
				return;
			}
			FarmHarvestWork.Mutating.Add(chest);
			try
			{
				List<ItemData> allItems = inventory.GetAllItems();
				for (int num2 = 0; num2 < 24; num2++)
				{
					ItemData itemAt = inventory.GetItemAt(num2 % 8, num2 / 8);
					if (target[num2] == 0)
					{
						if (itemAt != null)
						{
							allItems.Remove(itemAt);
						}
					}
					else if (itemAt != null)
					{
						itemAt.m_stack = target[num2];
					}
					else
					{
						allItems.Add(dictionary[num2]);
					}
				}
				zdo.Set("runebourne.vault.stored.v1", store);
			}
			finally
			{
				FarmHarvestWork.Mutating.Remove(chest);
				WorkerResources.Release(zdo, settler, operation);
			}
			inventory.Changed(false, false);
			chest.Save();
		}

		private ItemData NewStack(GameObject prefab, int amount, int x, int y)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			ItemData obj = prefab.GetComponent<ItemDrop>().m_itemData.Clone();
			obj.m_dropPrefab = prefab;
			obj.m_stack = amount;
			obj.m_worldLevel = ItemLevel;
			obj.m_gridPos = new Vector2i(x, y);
			return obj;
		}

		private void WriteFilter(ZDO zdo, bool accepts)
		{
			HaulerFilter haulerFilter = VaultRules.Filter(Item, accepts);
			HaulerFilter haulerFilter2 = HaulerFilter.Read(zdo.GetByteArray("runebourne.chest.hauler.filter.v1", (byte[])null));
			if (haulerFilter2 == null || !haulerFilter2.SameRules(haulerFilter))
			{
				haulerFilter.Revision = ((haulerFilter2 == null || haulerFilter2.Revision == long.MaxValue) ? 1 : (haulerFilter2.Revision + 1));
				zdo.Set("runebourne.chest.hauler.filter.v1", haulerFilter.Serialize());
			}
		}

		private void RefreshCapacity(ZDO zdo)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			string identity = zdo.GetString("runebourne.vault.identity.v1", "");
			if (identity.Length == 0)
			{
				return;
			}
			List<int> list = new List<int>();
			List<ZDO> list2 = new List<ZDO>();
			for (int i = 0; i < VaultRegistration.UpgradeNames.Length; i++)
			{
				if (FarmCensus.CollectPrefab(((Component)this).transform.position, 5f, StringExtensionMethods.GetStableHashCode(VaultRegistration.UpgradeNames[i]), list2) != FarmCensus.State.Ready)
				{
					return;
				}
				if (list2.Any((ZDO r) => r != null && r.IsValid() && r.GetString("runebourne.vault.upgrade.vault.v1", "") == identity))
				{
					list.Add(i + 1);
				}
			}
			int num = VaultRules.CapacityStacks(VaultRules.BestLevel(list));
			if (zdo.GetInt("runebourne.vault.capacity.v1", VaultRules.LevelStacks[0]) != num)
			{
				zdo.Set("runebourne.vault.capacity.v1", num);
			}
		}

		internal void RequestClear()
		{
			if (Zdo != null)
			{
				view.InvokeRPC("Runebourne_VaultClear", Array.Empty<object>());
			}
		}

		private void RpcClear(long sender)
		{
			ZDO zdo = Zdo;
			if (zdo != null && view.IsOwner() && Object.op_Implicit((Object)(object)chest) && VaultRules.Empty(chest.GetInventory().NrOfItems(), Stored))
			{
				zdo.Set("runebourne.vault.item.v1", "");
				zdo.Set("runebourne.vault.level.v1", 0);
				WriteFilter(zdo, accepts: false);
			}
		}
	}
	internal static class VaultFill
	{
		internal static bool Open(ZDO z, Inventory inventory)
		{
			if (VaultHint.Unset(z) && inventory != null && inventory.NrOfItems() == 0)
			{
				return z.GetLong("runebourne.vault.stored.v1", 0L) <= 0;
			}
			return false;
		}

		internal static bool Qualifies(ItemData item)
		{
			if (item != null && Object.op_Implicit((Object)(object)item.m_dropPrefab) && item.m_shared != null)
			{
				return VaultRules.Qualifies(item.m_shared.m_maxStackSize, item.m_quality, item.m_customData?.Count ?? 0);
			}
			return false;
		}

		internal static HaulerFilter Filter(ZDO z, Inventory inventory, IEnumerable<ItemData> items)
		{
			if (!Open(z, inventory))
			{
				return WorkerChestFilter.Read(z);
			}
			ItemData val = items.FirstOrDefault((Func<ItemData, bool>)Qualifies);
			HaulerFilter haulerFilter = new HaulerFilter
			{
				SelectedOnly = true
			};
			if (val != null)
			{
				haulerFilter.Items.Add(((Object)val.m_dropPrefab).name);
			}
			return haulerFilter;
		}

		internal static bool Adopt(IList<ItemData> items, out string prefab, out int level)
		{
			prefab = null;
			level = 0;
			if (items == null || items.Count == 0 || !items.All(Qualifies))
			{
				return false;
			}
			string name = ((Object)items[0].m_dropPrefab).name;
			int world = items[0].m_worldLevel;
			if (items.Any((ItemData i) => ((Object)i.m_dropPrefab).name != name || i.m_worldLevel != world))
			{
				return false;
			}
			prefab = name;
			level = world;
			return true;
		}
	}
	internal static class VaultHint
	{
		internal const string NoItem = "The Deephold has no item yet. Put one in to choose it.";

		internal const string WandNote = "Workers skip this Deephold until it has an item. Put one in to choose it.";

		internal const string Row = "No item yet: put one in to choose it";

		private static int prefab;

		private static int Prefab
		{
			get
			{
				if (prefab == 0)
				{
					return prefab = StringExtensionMethods.GetStableHashCode("Runebourne_Vault");
				}
				return prefab;
			}
		}

		internal static bool Unset(ZDO zdo)
		{
			if (zdo != null && zdo.IsValid() && zdo.GetPrefab() == Prefab)
			{
				return zdo.GetString("runebourne.vault.item.v1", "").Length == 0;
			}
			return false;
		}

		internal static bool Unset(Container chest)
		{
			ZNetView val = (Object.op_Implicit((Object)(object)chest) ? ((Component)chest).GetComponent<ZNetView>() : null);
			if (Object.op_Implicit((Object)(object)val) && val.IsValid())
			{
				return Unset(val.GetZDO());
			}
			return false;
		}

		internal static bool Deephold(int linkPrefab)
		{
			return linkPrefab == Prefab;
		}

		internal static string Explain(string status, int unset, int tried)
		{
			if (unset > 0)
			{
				if (unset < tried)
				{
					return Join(status, "The Deephold has no item yet. Put one in to choose it.");
				}
				return "The Deephold has no item yet. Put one in to choose it.";
			}
			return status;
		}

		internal static string Join(string status, string hint)
		{
			return status.TrimEnd('.', ' ') + ". " + hint;
		}

		internal static bool Means(string status, string key)
		{
			if (!(status == key) && !(status == "The Deephold has no item yet. Put one in to choose it."))
			{
				return status == Join(key, "The Deephold has no item yet. Put one in to choose it.");
			}
			return true;
		}

		internal static void Wand(Container chest)
		{
			if (Unset(chest) && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				((Character)Player.m_localPlayer).Message((MessageType)1, "Workers skip this Deephold until it has an item. Put one in to choose it.", 0, (Sprite)null, false);
			}
		}
	}
	internal static class VaultPatches
	{
		private static Harmony patches;

		private static bool removing;

		internal static void Start()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			//IL_0146: 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_0168: Expected O, but got Unknown
			//IL_0168: Expected O, but got Unknown
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Expected O, but got Unknown
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Expected O, but got Unknown
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Expected O, but got Unknown
			//IL_022a: Expected O, but got Unknown
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Expected O, but got Unknown
			Stop();
			patches = new Harmony("com.yohanb.runebourne.vault");
			patches.Patch((MethodBase)AccessTools.Method(typeof(InventoryGrid), "DropItem", (Type[])null, (Type[])null), new HarmonyMethod(typeof(VaultPatches), "Drop", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			patches.Patch((MethodBase)AccessTools.Method(typeof(Inventory), "MoveItemToThis", new Type[2]
			{
				typeof(Inventory),
				typeof(ItemData)
			}, (Type[])null), new HarmonyMethod(typeof(VaultPatches), "Move", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			patches.Patch((MethodBase)AccessTools.Method(typeof(Inventory), "StackAll", (Type[])null, (Type[])null), new HarmonyMethod(typeof(VaultPatches), "StackAll", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			patches.Patch((MethodBase)AccessTools.Method(typeof(Container), "CanBeRemoved", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(VaultPatches), "Removable", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			patches.Patch((MethodBase)AccessTools.Method(typeof(Player), "RemovePiece", (Type[])null, (Type[])null), new HarmonyMethod(typeof(VaultPatches), "BeginRemove", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(VaultPatches), "EndRemove", (Type[])null), (HarmonyMethod)null);
			patches.Patch((MethodBase)AccessTools.Method(typeof(WearNTear), "ApplyDamage", (Type[])null, (Type[])null), new HarmonyMethod(typeof(VaultPatches), "Undamaged", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			patches.Patch((MethodBase)AccessTools.Method(typeof(Container), "GetHoverText", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(VaultPatches), "Hover", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			patches.Patch((MethodBase)AccessTools.Method(typeof(InventoryGui), "UpdateContainer", (Type[])null, (Type[])null), new HarmonyMethod(typeof(VaultPatches), "WindowReset", (Type[])null), new HarmonyMethod(typeof(VaultPatches), "WindowTitle", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			patches.Patch((MethodBase)AccessTools.Method(typeof(Player), "TryPlacePiece", (Type[])null, (Type[])null), new HarmonyMethod(typeof(VaultPatches), "Place", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		internal static void Stop()
		{
			Harmony obj = patches;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			patches = null;
			removing = false;
		}

		private static bool Drop(InventoryGrid __instance, Inventory fromInventory, ItemData item, int amount, Vector2i pos, ref bool __result)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_0095: 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)
			Inventory inventory = __instance.GetInventory();
			if (inventory == null || fromInventory == null || inventory == fromInventory || item == null)
			{
				return true;
			}
			VaultChest vaultChest = VaultChest.For(inventory);
			VaultChest vaultChest2 = VaultChest.For(fromInventory);
			if (!Object.op_Implicit((Object)(object)vaultChest) && !Object.op_Implicit((Object)(object)vaultChest2))
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)vaultChest))
			{
				__result = false;
				if (!vaultChest.MayPut(item, out var refusal))
				{
					FarmCommandWand.Say(refusal);
					return false;
				}
				Vector2i val = ((inventory.GetItemAt(pos.x, pos.y) == null) ? pos : inventory.FindEmptySlot(false));
				if (val.x < 0)
				{
					FarmCommandWand.Say("The Deephold is still storing. Try again in a moment.");
					return false;
				}
				__result = inventory.MoveItemToThis(fromInventory, item, amount, val.x, val.y);
				return false;
			}
			ItemData itemAt = inventory.GetItemAt(pos.x, pos.y);
			if (itemAt != null && itemAt != item && item.m_stack == amount && (itemAt.m_shared.m_name != item.m_shared.m_name || (item.m_shared.m_maxQuality > 1 && itemAt.m_quality != item.m_quality) || itemAt.m_shared.m_maxStackSize == 1))
			{
				__result = false;
				FarmCommandWand.Say("Drop it on an empty slot: a Deephold can't swap items");
				return false;
			}
			return true;
		}

		private static bool Move(Inventory __instance, Inventory fromInventory, ItemData item)
		{
			if (__instance == fromInventory)
			{
				return true;
			}
			VaultChest vaultChest = VaultChest.For(__instance);
			if (!Object.op_Implicit((Object)(object)vaultChest) || vaultChest.MayPut(item, out var refusal))
			{
				return true;
			}
			FarmCommandWand.Say(refusal);
			return false;
		}

		private static bool StackAll(Inventory __instance, Inventory fromInventory, bool message, ref int __result)
		{
			VaultChest vaultChest = VaultChest.For(__instance);
			if (!Object.op_Implicit((Object)(object)vaultChest))
			{
				return true;
			}
			__result = 0;
			string refusal = null;
			if (vaultChest.Item.Length > 0)
			{
				foreach (ItemData item in fromInventory.GetAllItems().ToList())
				{
					if (vaultChest.Matches(item) && (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !((Humanoid)Player.m_localPlayer).IsItemEquiped(item)))
					{
						if (!vaultChest.MayPut(item, out refusal))
						{
							break;
						}
						int stack = item.m_stack;
						if (__instance.AddItem(item))
						{
							fromInventory.RemoveItem(item);
							__result += stack;
						}
						else
						{
							__result += stack - item.m_stack;
						}
					}
				}
			}
			if (message && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, (__result > 0) ? ("$msg_stackall " + __result) : (refusal ?? "$msg_stackall_none"), 0, (Sprite)null, false);
			}
			__instance.Changed(false, false);
			fromInventory.Changed(false, false);
			return false;
		}

		private static void Removable(Container __instance, ref bool __result)
		{
			VaultChest vaultChest = VaultChest.For(__instance);
			if (Object.op_Implicit((Object)(object)vaultChest) && !VaultRules.Empty(__instance.GetInventory().NrOfItems(), vaultChest.Stored))
			{
				__result = false;
				if (removing && Object.op_Implicit((Object)(object)Player.m_localPlayer))
				{
					((Character)Player.m_localPlayer).Message((MessageType)1, "Empty the Deephold first: it still holds " + vaultChest.Total.ToString("N0"), 0, (Sprite)null, false);
				}
			}
		}

		private static void BeginRemove()
		{
			removing = true;
		}

		private static Exception EndRemove(Exception __exception)
		{
			removing = false;
			return __exception;
		}

		private static bool Undamaged(WearNTear __instance, ref bool __result)
		{
			if (!Object.op_Implicit((Object)(object)__instance) || (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<VaultChest>()) && !Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<VaultUpgrade>())))
			{
				return true;
			}
			__result = false;
			return false;
		}

		private static void Hover(Container __instance, ref string __result)
		{
			VaultChest vaultChest = VaultChest.For(__instance);
			if (Object.op_Implicit((Object)(object)vaultChest) && !string.IsNullOrEmpty(__result))
			{
				int num = __result.IndexOf('\n');
				__result = vaultChest.Title() + ((num >= 0) ? __result.Substring(num) : "");
			}
		}

		private static void WindowReset(InventoryGui __instance)
		{
			if (!Object.op_Implicit((Object)(object)VaultChest.For(__instance.m_currentContainer)))
			{
				VaultWindow.Unshape(__instance.m_containerGrid);
			}
		}

		private static void WindowTitle(InventoryGui __instance)
		{
			VaultChest vaultChest = VaultChest.For(__instance.m_currentContainer);
			if (Object.op_Implicit((Object)(object)vaultChest) && Object.op_Implicit((Object)(object)__instance.m_container) && ((Component)__instance.m_container).gameObject.activeInHierarchy)
			{
				if (Object.op_Implicit((Object)(object)__instance.m_containerName))
				{
					__instance.m_containerName.text = VaultRules.WindowTitle();
				}
				VaultWindow.Shape(__instance.m_containerGrid, vaultChest);
			}
		}

		private static bool Place(Player __instance, Piece __0, ref bool __result)
		{
			//IL_0034: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			VaultUpgrade vaultUpgrade = (Object.op_Implicit((Object)(object)__0) ? ((Component)__0).GetComponent<VaultUpgrade>() : null);
			if (!Object.op_Implicit((Object)(object)vaultUpgrade))
			{
				return true;
			}
			GameObject placementGhost = __instance.m_placementGhost;
			VaultChest vaultChest = (Object.op_Implicit((Object)(object)placementGhost) ? VaultUpgrade.Nearest(placementGhost.transform.position) : null);
			if (Object.op_Implicit((Object)(object)vaultChest) && (vaultChest.Identity.Length == 0 || !VaultUpgrade.Duplicate(vaultChest.Identity, vaultUpgrade.Level, ((Component)vaultChest).transform.position, ZDOID.None)))
			{
				return true;
			}
			__result = false;
			FarmCommandWand.Say(Object.op_Implicit((Object)(object)vaultChest) ? ("This Deephold already has a " + vaultUpgrade.GetHoverName()) : "Build it within 5 m of a Deephold");
			return false;
		}
	}
	internal static class VaultRegistration
	{
		internal const string VaultName = "Runebourne_Vault";

		internal static readonly string[] UpgradeNames = new string[3] { "Runebourne_VaultUpgrade1", "Runebourne_VaultUpgrade2", "Runebourne_VaultUpgrade3" };

		internal static readonly string[] UpgradeTitles = new string[3] { "Silverdeep Stone", "Tarflame Pillar", "Svelgr Frame" };

		internal static readonly (string Item, int Amount)[] VaultCost = new(string, int)[4]
		{
			("FineWood", 10),
			("ElderBark", 10),
			("Iron", 6),
			("SurtlingCore", 2)
		};

		internal static readonly (string Item, int Amount)[][] UpgradeCosts = new(string, int)[3][]
		{
			new(string, int)[3]
			{
				("Stone", 15),
				("Silver", 6),
				("Crystal", 3)
			},
			new(string, int)[3]
			{
				("FineWood", 10),
				("BlackMetal", 8),
				("Tar", 5)
			},
			new(string, int)[4]
			{
				("BlackMarble", 10),
				("YggdrasilWood", 10),
				("Eitr", 6),
				("BlackCore", 1)
			}
		};

		internal static string UpgradeEffect(int level)
		{
			if (level < 3)
			{
				return VaultRules.LevelStacks[level] + " stacks";
			}
			return "unlimited";
		}

		internal static void Start()
		{
			PrefabManager.OnVanillaPrefabsAvailable += Register;
		}

		internal static void Stop()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= Register;
		}

		private static RequirementConfig[] Requirements((string Item, int Amount)[] cost)
		{
			return Array.ConvertAll(cost, (Converter<(string, int), RequirementConfig>)(((string Item, int Amount) c) => new RequirementConfig(c.Item, c.Amount, 0, true)));
		}

		private static void Register()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_0068: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= Register;
			CustomPiece val = new CustomPiece("Runebourne_Vault", "piece_chest", new PieceConfig
			{
				Name = "Deephold",
				Description = "Holds 75 stacks of one item, more with upgrades within 5 m. The first item put in picks it. Can't be damaged; empty it to remove it.",
				PieceTable = "Runebourne_WandPieces",
				Category = "Runebourne",
				Enabled = true,
				Requirements = Requirements(VaultCost)
			});
			Container component = val.PiecePrefab.GetComponent<Container>();
			component.m_name = "Deephold";
			component.m_width = 8;
			component.m_height = 3;
			val.PiecePrefab.AddComponent<VaultChest>();
			BlenderPieceVisual.Install(val.PiecePrefab, BlenderPieceVisual.Deephold);
			if (!PieceManager.Instance.AddPiece(val))
			{
				throw new InvalidOperationException("Deephold registration failed");
			}
			for (int i = 0; i < UpgradeNames.Length; i++)
			{
				CustomPiece val2 = new CustomPiece(UpgradeNames[i], "stone_pillar", new PieceConfig
				{
					Name = UpgradeTitles[i],
					Description = "A Deephold within 5 m holds " + UpgradeEffect(i + 1) + ". One per Deephold.",
					PieceTable = "Runebourne_WandPieces",
					Category = "Runebourne",
					Enabled = true,
					Requirements = Requirements(UpgradeCosts[i])
				});
				val2.PiecePrefab.AddComponent<VaultUpgrade>().Level = i + 1;
				BlenderPieceVisual.Install(val2.PiecePrefab, BlenderPieceVisual.DeepholdUpgrades[i]);
				if (!PieceManager.Instance.AddPiece(val2))
				{
					throw new InvalidOperationException(UpgradeTitles[i] + " registration failed");
				}
			}
		}
	}
	internal static class VaultRules
	{
		internal const string Name = "Deephold";

		internal const int Width = 8;

		internal const int Height = 3;

		internal const int Slots = 24;

		internal const int TopSlots = 8;

		internal const int Unlimited = 0;

		internal const float Reach = 5f;

		internal static readonly int[] LevelStacks = new int[4] { 75, 200, 500, 0 };

		internal static int CapacityStacks(int level)
		{
			if (level < 0 || level >= LevelStacks.Length)
			{
				return LevelStacks[0];
			}
			return LevelStacks[level];
		}

		internal static int BestLevel(IEnumerable<int> levels)
		{
			return levels?.Where((int l) => l >= 1 && l < LevelStacks.Length).DefaultIfEmpty(0).Max() ?? 0;
		}

		internal static long Capacity(int stacks, int stackSize)
		{
			if (stacks != 0)
			{
				return (long)stacks * (long)Math.Max(1, stackSize);
			}
			return long.MaxValue;
		}

		internal static long StoreLimit(int stacks, int stackSize)
		{
			if (stacks != 0)
			{
				return Math.Max(0L, (long)(stacks - 24) * (long)Math.Max(1, stackSize));
			}
			return long.MaxValue;
		}

		internal static int[] Layout(int[] slots, long store, int stackSize, long storeLimit, out long newStore)
		{
			if (slots == null || slots.Length != 24 || stackSize < 1 || store < 0)
			{
				throw new ArgumentException("Bad vault layout input");
			}
			long num = 0L;
			long num2 = 0L;
			for (int i = 0; i < 24; i++)
			{
				if (slots[i] < 0)
				{
					throw new ArgumentException("Negative vault slot");
				}
				if (i < 8)
				{
					num += slots[i];
				}
				else
				{
					num2 += slots[i];
				}
			}
			long num3 = Math.Max(0L, 8L * (long)stackSize - num);
			long num4 = Math.Min(num3, num2);
			num2 -= num4;
			num += num4;
			long num5 = Math.Min(num3 - num4, store);
			store -= num5;
			num += num5;
			long num6 = ((storeLimit == long.MaxValue) ? num2 : Math.Max(0L, Math.Min(num2, storeLimit - store)));
			num2 -= num6;
			store += num6;
			int[] array = new int[24];
			Pack(array, 0, 8, num, stackSize);
			Pack(array, 8, 16, num2, stackSize);
			newStore = store;
			return array;
		}

		private static void Pack(int[] slots, int start, int count, long amount, int stackSize)
		{
			for (int i = 0; i < count; i++)
			{
				if (amount <= 0)
				{
					break;
				}
				amount -= (slots[start + i] = (int)Math.Min(stackSize, amount));
			}
			if (amount > 0)
			{
				throw new InvalidOperationException("Vault slots overflow");
			}
		}

		internal static bool Accepts(bool itemSet, long total, long capacity, long store, long storeLimit)
		{
			if (itemSet && total >= 0 && store >= 0 && total < capacity)
			{
				return store <= storeLimit;
			}
			return false;
		}

		internal static bool Qualifies(int maxStack, int quality, int customData)
		{
			if (maxStack > 1 && quality <= 1)
			{
				return customData == 0;
			}
			return false;
		}

		internal static bool Matches(string prefab, int worldLevel, int quality, int customData, string item, int itemLevel)
		{
			if (!string.IsNullOrEmpty(item) && prefab == item && worldLevel == itemLevel && quality <= 1)
			{
				return customData == 0;
			}
			return false;
		}

		internal static bool Empty(int slotItems, long store)
		{
			if (slotItems == 0)
			{
				return store == 0;
			}
			return false;
		}

		internal static string Title(string itemName, long total, int stacks, int stackSize)
		{
			if (string.IsNullOrEmpty(itemName))
			{
				return "Deephold · empty, put an item in to choose it";
			}
			string text = total.ToString("N0", CultureInfo.InvariantCulture);
			if (stacks == 0)
			{
				return "Deephold · " + itemName + " " + text + " (unlimited)";
			}
			long num = Capacity(stacks, stackSize);
			return "Deephold · " + itemName + " " + text + " / " + num.ToString("N0", CultureInfo.InvariantCulture) + ((total > num) ? " · over capacity" : ((total == num) ? " · full" : ""));
		}

		internal static string WindowTitle()
		{
			return "Deephold";
		}

		internal static string WindowLine(string itemName, long total, int stacks, int stackSize)
		{
			if (string.IsNullOrEmpty(itemName))
			{
				return "Empty. Put an item in to choose what it holds.";
			}
			string text = total.ToString("N0", CultureInfo.InvariantCulture);
			if (stacks == 0)
			{
				return itemName + " · " + text + " · no limit";
			}
			long num = Capacity(stacks, stackSize);
			return itemName + " · " + text + " / " + num.ToString("N0", CultureInfo.InvariantCulture) + ((total > num) ? " · over capacity" : ((total == num) ? " · full" : ""));
		}

		internal static string SlotCount(long total)
		{
			if (total >= 100000)
			{
				if (total >= 1000000)
				{
					if (total >= 10000000)
					{
						return (total / 1000000).ToString(CultureInfo.InvariantCulture) + "M";
					}
					return ((double)(total / 100000) / 10.0).ToString("0.0", CultureInfo.InvariantCulture) + "M";
				}
				return (total / 1000).ToString(CultureInfo.InvariantCulture) + "k";
			}
			return total.ToString("N0", CultureInfo.InvariantCulture);
		}

		internal static HaulerFilter Filter(string item, bool accepts)
		{
			HaulerFilter haulerFilter = new HaulerFilter
			{
				SelectedOnly = true
			};
			if (accepts && !string.IsNullOrEmpty(item))
			{
				haulerFilter.Items.Add(item);
			}
			return haulerFilter;
		}
	}
	internal sealed class VaultUpgrade : MonoBehaviour, Hoverable
	{
		internal const string BindingKey = "runebourne.vault.upgrade.vault.v1";

		[SerializeField]
		internal int Level;

		private ZNetView view;

		internal static readonly List<VaultUpgrade> Loaded = new List<VaultUpgrade>();

		internal static readonly Color Color = new Color(1f, 0.72f, 0.25f, 1f);

		private void Awake()
		{
			view = ((Component)this).GetComponent<ZNetView>();
			Loaded.Add(this);
		}

		private void Start()
		{
			((MonoBehaviour)this).InvokeRepeating("Bind", 0.3f, 2f);
		}

		private void OnDestroy()
		{
			((MonoBehaviour)this).CancelInvoke();
			Loaded.Remove(this);
		}

		private void Bind()
		{
			//IL_0090: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)view) || !view.IsValid() || !view.IsOwner() || view.m_ghost || Level < 1 || Level > VaultRegistration.UpgradeNames.Length)
			{
				return;
			}
			ZDO zDO = view.GetZDO();
			if (zDO.GetString("runebourne.vault.upgrade.vault.v1", "").Length > 0)
			{
				return;
			}
			Piece component = ((Component)this).GetComponent<Piece>();
			if (!Object.op_Implicit((Object)(object)component) || component.GetCreator() == 0L)
			{
				return;
			}
			VaultChest vaultChest = Nearest(((Component)this).transform.position);
			if (!Object.op_Implicit((Object)(object)vaultChest))
			{
				Reject();
				return;
			}
			string identity = vaultChest.Identity;
			if (identity.Length != 0)
			{
				if (Duplicate(identity, Level, ((Component)vaultChest).transform.position, zDO.m_uid))
				{
					Reject();
				}
				else
				{
					zDO.Set("runebourne.vault.upgrade.vault.v1", identity);
				}
			}
		}

		private void Reject()
		{
			WearNTear component = ((Component)this).GetComponent<WearNTear>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.Destroy((HitData)null, false);
			}
		}

		internal VaultChest BoundVault()
		{
			string bound = ((Object.op_Implicit((Object)(object)view) && view.IsValid() && !view.m_ghost) ? view.GetZDO().GetString("runebourne.vault.upgrade.vault.v1", "") : "");
			if (bound.Length != 0)
			{
				return VaultChest.Loaded.FirstOrDefault((VaultChest v) => Object.op_Implicit((Object)(object)v) && v.Identity == bound);
			}
			return null;
		}

		internal static Transform[] VisualTargets(VaultChest vault, VaultUpgrade ghost)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			List<Transform> list = (from u in Loaded
				where Object.op_Implicit((Object)(object)u) && ((Behaviour)u).isActiveAndEnabled && (Object)(object)u.BoundVault() == (Object)(object)vault
				select ((Component)u).transform).ToList();
			if (Object.op_Implicit((Object)(object)ghost) && ((Component)ghost).gameObject.activeInHierarchy && (Object)(object)Nearest(((Component)ghost).transform.position) == (Object)(object)vault)
			{
				list.Add(((Component)ghost).transform);
			}
			return list.Distinct().Take(4).ToArray();
		}

		internal static VaultChest Nearest(Vector3 position)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			VaultChest vaultChest = null;
			float num = 25f;
			foreach (VaultChest item in VaultChest.Loaded)
			{
				if (Object.op_Implicit((Object)(object)item) && item.Zdo != null)
				{
					Vector3 val = ((Component)item).transform.position - position;
					float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
					if (!(sqrMagnitude > num) && (sqrMagnitude != num || !Object.op_Implicit((Object)(object)vaultChest) || string.CompareOrdinal(item.Identity, vaultChest.Identity) < 0))
					{
						num = sqrMagnitude;
						vaultChest = item;
					}
				}
			}
			return vaultChest;
		}

		internal static bool Duplicate(string identity, int level, Vector3 near, ZDOID except)
		{
			//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_001a: Unknown result type (might be due to invalid IL or missing references)
			List<ZDO> list = new List<ZDO>();
			if (FarmCensus.CollectPrefab(near, 5f, StringExtensionMethods.GetStableHashCode(VaultRegistration.UpgradeNames[level - 1]), list) != FarmCensus.State.Ready)
			{
				return true;
			}
			return list.Any((ZDO z) => z != null && z.IsValid() && z.m_uid != except && z.GetString("runebourne.vault.upgrade.vault.v1", "") == identity);
		}

		public string GetHoverName()
		{
			if (Level < 1 || Level > VaultRegistration.UpgradeTitles.Length)
			{
				return "Deephold upgrade";
			}
			return VaultRegistration.UpgradeTitles[Level - 1];
		}

		public float GetHoverOffset()
		{
			return 0f;
		}

		public string GetHoverText()
		{
			string text = GetHoverName() + "\nA Deephold within 5 m holds " + VaultRegistration.UpgradeEffect(Level) + ".";
			string bound = ((Object.op_Implicit((Object)(object)view) && view.IsValid()) ? view.GetZDO().GetString("runebourne.vault.upgrade.vault.v1", "") : "");
			if (bound.Length == 0)
			{
				return text + "\nNot connected — build it within 5 m of a Deephold";
			}
			bool flag = VaultChest.Loaded.Any(delegate(VaultChest v)
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				if (Object.op_Implicit((Object)(object)v) && v.Identity == bound)
				{
					Vector3 val = ((Component)v).transform.position - ((Component)this).transform.position;
					return ((Vector3)(ref val)).sqrMagnitude <= 25f;
				}
				return false;
			});
			return text + (flag ? "" : "\nIts Deephold is gone; remove this to get the materials back");
		}
	}
	internal sealed class VaultWindow : MonoBehaviour
	{
		private Button clear;

		private float next;

		private static InventoryGrid shaped;

		private static Text line;

		private void Update()
		{
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: 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)
			if (Time.unscaledTime < next || GUIManager.IsHeadless())
			{
				return;
			}
			next = Time.unscaledTime + 0.25f;
			InventoryGui instance = InventoryGui.instance;
			VaultChest vaultChest = (Object.op_Implicit((Object)(object)instance) ? VaultChest.For(instance.m_currentContainer) : null);
			if (!Object.op_Implicit((Object)(object)vaultChest) || !Object.op_Implicit((Object)(object)instance.m_container) || !((Component)instance.m_container).gameObject.activeInHierarchy || vaultChest.Item.Length <= 0 || vaultChest.Total != 0)
			{
				if (Object.op_Implicit((Object)(object)clear))
				{
					((Component)clear).gameObject.SetActive(false);
				}
				return;
			}
			if (!Object.op_Implicit((Object)(object)clear) || (Object)(object)((Component)clear).transform.parent != (Object)(object)instance.m_container)
			{
				if (Object.op_Implicit((Object)(object)clear))
				{
					Object.Destroy((Object)(object)((Component)clear).gameObject);
				}
				clear = HaulerUI.Button((Transform)(object)instance.m_container, "Clear item", 0f, -30f, 220f, Clear);
				RectTransform val = (RectTransform)((Component)clear).transform;
				Vector2 val2 = default(Vector2);
				((Vector2)(ref val2))..ctor(0.5f, 0f);
				val.anchorMax = val2;
				val.anchorMin = val2;
				val.anchoredPosition = new Vector2(0f, -28f);
			}
			((Component)clear).gameObject.SetActive(true);
		}

		private void Clear()
		{
			InventoryGui instance = InventoryGui.instance;
			VaultChest vaultChest = (Object.op_Implicit((Object)(object)instance) ? VaultChest.For(instance.m_currentContainer) : null);
			if (Object.op_Implicit((Object)(object)vaultChest))
			{
				if (vaultChest.Total != 0L)
				{
					FarmCommandWand.Say("Empty the Deephold first");
					return;
				}
				vaultChest.RequestClear();
				FarmCommandWand.Say("Deephold cleared: put an item in to choose a new one");
			}
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)clear))
			{
				Object.Destroy((Object)(object)((Component)clear).gameObject);
			}
		}

		internal static void Shape(InventoryGrid grid, VaultChest vault)
		{
			//IL_004a: 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_0054: 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_007b: 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_0182: 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_018c: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)grid) || grid.m_width != 8 || grid.m_height != 3 || grid.m_elements.Count != 24)
			{
				return;
			}
			shaped = grid;
			InventoryElement val = grid.m_elements[0];
			float elementSpace = grid.m_elementSpace;
			Rect rect = ((RectTransform)((Component)grid).transform).rect;
			float num = ((Rect)(ref rect)).width / 2f - grid.GetWidgetSize().x / 2f;
			((RectTransform)((Component)val).transform).anchoredPosition = new Vector2(num + 7f * elementSpace / 2f, 0f - elementSpace);
			for (int i = 1; i < grid.m_elements.Count; i++)
			{
				if (((Component)grid.m_elements[i]).gameObject.activeSelf)
				{
					((Component)grid.m_elements[i]).gameObject.SetActive(false);
				}
			}
			if (vault.Chest.GetInventory().GetItemAt(0, 0) != null && Object.op_Implicit((Object)(object)val.m_amount))
			{
				((Behaviour)val.m_amount).enabled = true;
				val.m_amount.text = VaultRules.SlotCount(vault.Total);
			}
			if (!Object.op_Implicit((Object)(object)line) || (Object)(object)((Component)line).transform.parent != (Object)(object)((Component)val).transform)
			{
				if (Object.op_Implicit((Object)(object)line))
				{
					Object.Destroy((Object)(object)((Component)line).gameObject);
				}
				Transform transform = ((Component)val).transform;
				rect = ((RectTransform)((Component)val).transform).rect;
				line = HaulerUI.Label(transform, "", 0f, (0f - ((Rect)(ref rect)).height) / 2f - 24f, 520f);
				line.alignment = (TextAnchor)4;
			}
			line.text = vault.WindowLine();
			vault.Nudge();
		}

		internal static void Unshape(InventoryGrid grid)
		{
			if (Object.op_Implicit((Object)(object)shaped) && !((Object)(object)shaped != (Object)(object)grid))
			{
				shaped = null;
				grid.m_width = 0;
				if (Object.op_Implicit((Object)(object)line))
				{
					Object.Destroy((Object)(object)((Component)line).gameObject);
				}
			}
		}
	}
}
namespace Runebourne.Serpents
{
	internal static class LightningRune
	{
		internal const string Name = "RunebourneLightningRune";

		private static Harmony patches;

		internal static void Start()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable += Register;
			patches = new Harmony("com.yohanb.runebourne.lightning.rune");
			patches.Patch((MethodBase)AccessTools.Method(typeof(Humanoid), "UseItem", new Type[3]
			{
				typeof(Inventory),
				typeof(ItemData),
				typeof(bool)
			}, (Type[])null), new HarmonyMethod(typeof(LightningRune), "Use", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		internal static void Stop()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= Register;
			Harmony obj = patches;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			patches = null;
		}

		private static void Register()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			PrefabManager.OnVanillaPrefabsAvailable -= Register;
			ItemConfig val = new ItemConfig();
			val.Name = "Lightning rune";
			val.Description = "Tames a wild sea serpent below 10% health within 50 m. Use it with the command wand equipped. Half of tries work; each uses a rune.";
			val.CraftingStation = "forge";
			val.MinStationLevel = 1;
			val.Amount = 1;
			val.Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
			{
				new RequirementConfig("Stone", 5, 0, true),
				new RequirementConfig("Iron", 1, 0, true),
				new RequirementConfig("GreydwarfEye", 3, 0, true)
			};
			CustomItem val2 = new CustomItem("RunebourneLightningRune", "BoneFragments", val);
			ItemData itemData = val2.ItemPrefab.GetComponent<ItemDrop>().m_itemData;
			itemData.m_shared.m_itemType = (ItemType)1;
			itemData.m_shared.m_maxStackSize = 10;
			itemData.m_shared.m_weight = 0.2f;
			RunicItemVisual.Install(val2.ItemPrefab, BlenderPieceVisual.LightningRune);
			if (!ItemManager.Instance.AddItem(val2))
			{
				throw new InvalidOperationException("Lightning rune registration failed");
			}
		}

		private static bool Use(Humanoid __instance, Inventory inventory, ItemData item, bool fromInventoryGui)
		{
			if ((Object)(object)item?.m_dropPrefab == (Object)null || ((Object)item.m_dropPrefab).name != "RunebourneLightningRune")
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || (Object)(object)__instance != (Object)(object)localPlayer || ((Character)localPlayer).IsDead())
			{
				return false;
			}
			if (!FarmCommandWand.IsWand(((Humanoid)localPlayer).GetRightItem()))
			{
				FarmCommandWand.Say("Equip the command wand first, then use the lightning rune.");
				return false;
			}
			Inventory inventory2 = ((Humanoid)localPlayer).GetInventory();
			if ((inventory != null && inventory != inventory2) || !inventory2.GetAllItems().Contains(item) || item.m_stack < 1)
			{
				return false;
			}
			if (!Object.op_Implicit((Object)(object)SerpentNetwork.Instance))
			{
				FarmCommandWand.Say("Serpent taming isn't ready yet. Try again in a moment.");
				return false;
			}
			SerpentNetwork.Instance.Request(new SerpentNetwork.Command
			{
				Action = SerpentNetwork.Action.Tame,
				X = item.m_gridPos.x,
				Y = item.m_gridPos.y,
				Data = FarmWorkerInventory.Signature(item)
			});
			return false;
		}
	}
	internal sealed class SerpentActivity : MonoBehaviour
	{
		private sealed class Lease
		{
			internal Guid Key;

			internal ZDOID Subject;

			internal float Touched;

			internal bool Retain;

			internal bool Granted;

			internal bool Free;

			internal readonly HashSet<Vector2s> Sectors = new HashSet<Vector2s>();

			internal readonly HashSet<ZDOID> Records = new HashSet<ZDOID>();
		}

		internal const int SectorBudget = 32;

		internal const double SoftBudgetMs = 2.0;

		internal static SerpentActivity Instance;

		private readonly Dictionary<Guid, Lease> leases = new Dictionary<Guid, Lease>();

		private readonly Dictionary<Vector2s, int> sectors = new Dictionary<Vector2s, int>();

		private readonly Dictionary<Vector2s, int> budgeted = new Dictionary<Vector2s, int>();

		private readonly HashSet<Vector2s> residents = new HashSet<Vector2s>();

		private readonly Queue<Lease> waiting = new Queue<Lease>();

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

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

		private readonly HashSet<ZDOID> terrainIds = new HashSet<ZDOID>();

		private readonly Dictionary<Vector2s, List<ZDO>> terrainWitnesses = new Dictionary<Vector2s, List<ZDO>>();

		private readonly Dictionary<Vector2s, float> terrainAt = new Dictionary<Vector2s, float>();

		private readonly Stopwatch timer = new Stopwatch();

		private Harmony harmony;

		private ZNet world;

		private int cursor;

		internal double NativeMilliseconds { get; private set; }

		internal int ActiveSectors => BudgetCount();

		internal int FreeSectors => sectors.Keys.Count((Vector2s s) => !budgeted.ContainsKey(s));

		private void Awake()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			Instance = this;
			harmony = new Harmony("com.yohanb.runebourne.serpentactivity");
			harmony.Patch((MethodBase)AccessTools.Method(typeof(ZNetScene), "RemoveObjects", (Type[])null, (Type[])null), new HarmonyMethod(typeof(SerpentActivity), "KeepRequested", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
			Clear();
		}

		private void Clear()
		{
			leases.Clear();
			sectors.Clear();
			budgeted.Clear();
			residents.Clear();
			waiting.Clear();
			retained.Clear();
			terrainIds.Clear();
			terrainWitnesses.Clear();
			terrainAt.Clear();
			cursor = 0;
		}

		internal bool Acquire(Guid key, ZDOID subject, Vector3 anchor, IEnumerable<ZDO> objects, bool retain, IEnumerable<Vector2s> sectors = null, bool budgeted = true)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			if (key == Guid.Empty || !SerpentRoute.Point(anchor))
			{
				return false;
			}
			if (!leases.TryGetValue(key, out var value))
			{
				value = new Lease
				{
					Key = key,
					Subject = subject,
					Free = !budgeted
				};
				value.Sectors.Add(ZoneSystem.GetZone(anchor));
				leases.Add(key, value);
				if (value.Free)
				{
					Grant(value);
				}
				else
				{
					waiting.Enqueue(value);
				}
			}
			value.Touched = Time.unscaledTime;
			value.Retain = retain;
			foreach (ZDO @object in objects)
			{
				if (@object != null && @object.IsValid())
				{
					Reserve(value, @object.GetSector());
					value.Records.Add(@object.m_uid);
				}
			}
			if (sectors != null)
			{
				foreach (Vector2s sector in sectors)
				{
					Reserve(value, sector);
				}
			}
			return Ready(key);
		}

		private void Reserve(Lease lease, Vector2s sector)
		{
			//IL_0006: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (lease.Sectors.Contains(sector))
			{
				return;
			}
			if (lease.Free)
			{
				lease.Sectors.Add(sector);
				if (lease.Granted)
				{
					Count(sectors, sector, 1);
				}
				return;
			}
			if (lease.Granted)
			{
				Unreserve(lease);
				waiting.Enqueue(lease);
			}
			lease.Sectors.Add(sector);
		}

		private static void Count(Dictionary<Vector2s, int> counts, Vector2s sector, int change)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			counts.TryGetValue(sector, out var value);
			value += change;
			if (value <= 0)
			{
				counts.Remove(sector);
			}
			else
			{
				counts[sector] = value;
			}
		}

		private void Grant(Lease lease)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			lease.Granted = true;
			foreach (Vector2s sector in lease.Sectors)
			{
				Count(sectors, sector, 1);
				if (!lease.Free)
				{
					Count(budgeted, sector, 1);
				}
			}
		}

		internal bool Ready(Guid key)
		{
			return Check(key, explain: false) == null;
		}

		internal string Blocker(Guid key)
		{
			return Check(key, explain: true);
		}

		private string Check(Guid key, bool explain)
		{
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: 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_0252: 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_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0316: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: 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_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			if (!leases.TryGetValue(key, out var value))
			{
				if (!explain)
				{
					return "";
				}
				return "no lease";
			}
			if (!value.Granted)
			{
				if (!explain)
				{
					return "";
				}
				return "waiting its turn: " + (waiting.ToList().IndexOf(value) + 1) + " of " + waiting.Count + " in the queue, " + BudgetCount() + " of " + 32 + " zones in use, needs " + value.Sectors.Count;
			}
			if (!Object.op_Implicit((Object)(object)ZoneSystem.instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				if (!explain)
				{
					return "";
				}
				return "world not ready";
			}
			foreach (Vector2s sector in value.Sectors)
			{
				if (Ungenerated(sector))
				{
					continue;
				}
				object obj;
				if (!explain)
				{
					obj = null;
				}
				else
				{
					short x = sector.x;
					string text = x.ToString();
					x = sector.y;
					obj = "zone " + text + "," + x;
				}
				string text2 = (string)obj;
				if (!ZoneSystem.instance.IsZoneLoaded(sector))
				{
					return explain ? (text2 + (ZoneSystem.instance.m_zones.ContainsKey(sector) ? " still loading its objects" : " not loaded")) : "";
				}
				if (!terrainWitnesses.TryGetValue(sector, out var value2))
				{
					return explain ? (text2 + " ground edits not scanned yet") : "";
				}
				foreach (ZDO item in value2)
				{
					if (item.IsValid() && !ZNetScene.instance.HaveInstance(item))
					{
						return explain ? (text2 + " ground edit not created yet") : "";
					}
				}
			}
			foreach (ZDOID record in value.Records)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(record);
				if (zDO != null && zDO.IsValid() && !ZNetScene.instance.HaveInstance(zDO))
				{
					if (!explain)
					{
						return "";
					}
					GameObject prefab = ZNetScene.instance.GetPrefab(zDO.GetPrefab());
					string[] obj2 = new string[9]
					{
						"not created: ",
						Object.op_Implicit((Object)(object)prefab) ? ((Object)prefab).name : ("prefab " + zDO.GetPrefab()),
						" at ",
						null,
						null,
						null,
						null,
						null,
						null
					};
					Vector3 position = zDO.GetPosition();
					obj2[3] = ((Vector3)(ref position)).ToString("0");
					obj2[4] = " (zone ";
					obj2[5] = zDO.GetSector().x.ToString();
					obj2[6] = ",";
					obj2[7] = zDO.GetSector().y.ToString();
					obj2[8] = (ZoneSystem.instance.IsZoneLoaded(zDO.GetSector()) ? " loaded)" : " not loaded)");
					return string.Concat(obj2);
				}
			}
			return null;
		}

		internal void Release(Guid key)
		{
			if (leases.TryGetValue(key, out var value) && !value.Retain)
			{
				Unreserve(value);
				leases.Remove(key);
			}
		}

		internal void Settle(Guid key)
		{
			if (leases.TryGetValue(key, out var value))
			{
				value.Retain = false;
			}
			Release(key);
		}

		private void Unreserve(Lease lease)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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)
			if (!lease.Granted)
			{
				return;
			}
			foreach (Vector2s sector in lease.Sectors)
			{
				Count(sectors, sector, -1);
				if (!lease.Free)
				{
					Count(budgeted, sector, -1);
				}
			}
			lease.Granted = false;
		}

		internal static bool Fits(int active, int additional)
		{
			if (active >= 0 && additional >= 0)
			{
				return active + additional <= 32;
			}
			return false;
		}

		private int BudgetCount()
		{
			return budgeted.Count + residents.Count((Vector2s s) => !sectors.ContainsKey(s));
		}

		internal bool GrantNext()
		{
			while (waiting.Count > 0)
			{
				Lease lease = waiting.Peek();
				if (!leases.TryGetValue(lease.Key, out var value) || value != lease || lease.Granted)
				{
					waiting.Dequeue();
					continue;
				}
				int additional = lease.Sectors.Count((Vector2s s) => !budgeted.ContainsKey(s) && (!residents.Contains(s) || sectors.ContainsKey(s)));
				if (!Fits(BudgetCount(), additional))
				{
					return false;
				}
				waiting.Dequeue();
				Grant(lease);
				return true;
			}
			return false;
		}

		private void Update()
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: 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_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: 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)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_0340: Unknown result type (might be due to invalid IL or missing references)
			//IL_053e: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_0472: Unknown result type (might be due to invalid IL or missing references)
			//IL_0477: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			//IL_056e: Unknown result type (might be due to invalid IL or missing references)
			//IL_051d: Unknown result type (might be due to invalid IL or missing references)
			//IL_052c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)world != (Object)(object)ZNet.instance)
			{
				Clear();
				world = ZNet.instance;
			}
			if (!Object.op_Implicit((Object)(object)world) || !world.IsServer() || !Object.op_Implicit((Object)(object)ZoneSystem.instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance) || ZDOMan.instance == null)
			{
				return;
			}
			timer.Restart();
			NativeMilliseconds = 0.0;
			Vector2s[] array = residents.ToArray();
			foreach (Vector2s val in array)
			{
				if (!ZoneSystem.instance.m_zones.TryGetValue(val, out var value))
				{
					residents.Remove(val);
					terrainAt.Remove(val);
					terrainWitnesses.Remove(val);
				}
				else if (!sectors.ContainsKey(val) && !PlayerArea(ZoneSystem.GetZonePos(val)))
				{
					value.m_ttl = Mathf.Max(value.m_ttl, ZoneSystem.instance.m_zoneTTL + 1f);
				}
			}
			KeyValuePair<Guid, Lease>[] array2 = leases.ToArray();
			for (int i = 0; i < array2.Length; i++)
			{
				KeyValuePair<Guid, Lease> keyValuePair = array2[i];
				Lease value2 = keyValuePair.Value;
				if (ZDOMan.instance.GetZDO(value2.Subject) == null || (!value2.Retain && Time.unscaledTime - value2.Touched > 3f))
				{
					value2.Retain = false;
					Release(keyValuePair.Key);
				}
			}
			while (timer.Elapsed.TotalMilliseconds < 2.0 && GrantNext())
			{
			}
			Vector2s[] array3 = sectors.Keys.ToArray();
			bool flag = false;
			for (int j = 0; j < array3.Length; j++)
			{
				if (!(timer.Elapsed.TotalMilliseconds - NativeMilliseconds < 2.0))
				{
					break;
				}
				Vector2s val2 = array3[(cursor + j) % array3.Length];
				if (ZoneSystem.instance.m_zones.TryGetValue(val2, out var value3))
				{
					value3.m_ttl = 0f;
				}
				else if (!flag && ZoneSystem.instance.IsZoneGenerated(val2))
				{
					double totalMilliseconds = timer.Elapsed.TotalMilliseconds;
					ZoneSystem.instance.PokeLocalZone(val2);
					NativeMilliseconds += timer.Elapsed.TotalMilliseconds - totalMilliseconds;
					flag = true;
					if (ZoneSystem.instance.m_zones.ContainsKey(val2))
					{
						residents.Add(val2);
					}
				}
			}
			if (array3.Length != 0)
			{
				cursor = (cursor + 1) % array3.Length;
			}
			retained.Clear();
			terrainIds.Clear();
			foreach (Lease value6 in leases.Values)
			{
				if (!value6.Granted)
				{
					continue;
				}
				foreach (ZDOID record in value6.Records)
				{
					ZDO zDO = ZDOMan.instance.GetZDO(record);
					if (zDO != null && zDO.IsValid())
					{
						if (zDO.GetOwner() != ZNet.GetUID() && !PlayerArea(zDO.GetPosition()))
						{
							zDO.SetOwner(ZNet.GetUID());
							ZDOMan.instance.ForceSendZDO(zDO.m_uid);
						}
						retained.Add(zDO);
					}
				}
			}
			bool flag2 = false;
			array = array3;
			foreach (Vector2s val3 in array)
			{
				if (!ZoneSystem.instance.IsZoneLoaded(val3))
				{
					continue;
				}
				if (!flag2 && timer.Elapsed.TotalMilliseconds - NativeMilliseconds < 2.0 && (!terrainAt.TryGetValue(val3, out var value4) || Time.unscaledTime - value4 > 5f))
				{
					flag2 = true;
					terrain.Clear();
					double totalMilliseconds2 = timer.Elapsed.TotalMilliseconds;
					ZDOMan.instance.FindSectorObjects(val3, new SimulationDistance(0, 0, false), terrain, (List<ZDO>)null);
					NativeMilliseconds += timer.Elapsed.TotalMilliseconds - totalMilliseconds2;
					List<ZDO> list = new List<ZDO>();
					foreach (ZDO item in terrain)
					{
						GameObject prefab = ZNetScene.instance.GetPrefab(item.GetPrefab());
						if (Object.op_Implicit((Object)(object)prefab) && Object.op_Implicit((Object)(object)prefab.GetComponent<TerrainComp>()))
						{
							list.Add(item);
						}
					}
					terrainWitnesses[val3] = list;
					terrainAt[val3] = Time.unscaledTime;
				}
				if (!terrainWitnesses.TryGetValue(val3, out var value5))
				{
					continue;
				}
				foreach (ZDO item2 in value5)
				{
					if (item2.IsValid() && terrainIds.Add(item2.m_uid))
					{
						retained.Add(item2);
					}
				}
			}
			for (int k = 0; k < retained.Count; k++)
			{
				ZDO val4 = retained[(cursor + k) % retained.Count];
				if (ZoneSystem.instance.IsZoneLoaded(val4.GetSector()) && !ZNetScene.instance.HaveInstance(val4))
				{
					double totalMilliseconds3 = timer.Elapsed.TotalMilliseconds;
					ZNetScene.instance.CreateObject(val4);
					NativeMilliseconds += timer.Elapsed.TotalMilliseconds - totalMilliseconds3;
					break;
				}
			}
			timer.Stop();
		}

		private static void KeepRequested(List<ZDO> currentNearObjects)
		{
			if (!Object.op_Implicit((Object)(object)Instance) || !Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer())
			{
				return;
			}
			foreach (ZDO item in Instance.retained)
			{
				if (item != null && item.IsValid())
				{
					currentNearObjects.Add(item);
				}
			}
			AwayWork.Instance?.Keep(currentNearObjects);
		}

		internal static bool Ungenerated(Vector2s zone)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer() && Object.op_Implicit((Object)(object)ZoneSystem.instance))
			{
				return !ZoneSystem.instance.IsZoneGenerated(zone);
			}
			return false;
		}

		internal static bool Ungenerated(Vector3 point)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return Ungenerated(ZoneSystem.GetZone(point));
		}

		internal static bool PlayerArea(Vector3 point)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || !Object.op_Implicit((Object)(object)ZoneSystem.instance))
			{
				return true;
			}
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && ZNetScene.InActiveArea(point, ZNet.instance.GetReferencePosition()))
			{
				return true;
			}
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				if (peer.IsReady() && peer.m_characterID != ZDOID.None && ZNetScene.InActiveArea(point, peer.GetRefPos()))
				{
					return true;
				}
			}
			return false;
		}
	}
	internal sealed class SerpentBody : MonoBehaviour, Interactable, Hoverable
	{
		internal sealed class HeightTrail
		{
			private readonly float[] times;

			private readonly float[] heights;

			private int count;

			private int next;

			internal int Count => count;

			internal HeightTrail(int size)
			{
				times = new float[Mathf.Max(2, size)];
				heights = new float[times.Length];
			}

			internal void Push(float time, float height)
			{
				if (float.IsNaN(time) || float.IsInfinity(time) || float.IsNaN(height) || float.IsInfinity(height))
				{
					return;
				}
				int num = (next - 1 + times.Length) % times.Length;
				if (count > 0 && time <= times[num])
				{
					heights[num] = height;
					return;
				}
				times[next] = time;
				heights[next] = height;
				next = (next + 1) % times.Length;
				if (count < times.Length)
				{
					count++;
				}
			}

			internal float At(float time, float nowTime, float nowHeight)
			{
				if (count == 0 || float.IsNaN(time) || time >= nowTime)
				{
					return nowHeight;
				}
				int num = (next - 1 + times.Length) % times.Length;
				float num2 = times[num];
				float num3 = heights[num];
				if (time >= num2)
				{
					if (!(nowTime - num2 > 1E-05f))
					{
						return nowHeight;
					}
					return Mathf.Lerp(num3, nowHeight, (time - num2) / (nowTime - num2));
				}
				for (int i = 1; i < count; i++)
				{
					int num4 = (num - i + times.Length) % times.Length;
					float num5 = times[num4];
					float num6 = heights[num4];
					if (time >= num5)
					{
						if (!(num2 - num5 > 1E-05f))
						{
							return num3;
						}
						return Mathf.Lerp(num6, num3, (time - num5) / (num2 - num5));
					}
					num2 = num5;
					num3 = num6;
				}
				return num3;
			}
		}

		internal const string Marker = "rb_serpent_tamed";

		private const string BoardRpc = "Runebourne.Serpent.Board.v1";

		private const string ReplyRpc = "Runebourne.Serpent.Seat.v1";

		private const string ReleaseRpc = "Runebourne.Serpent.Leave.v1";

		private const string ControlRpc = "Runebourne.Serpent.Control.v1";

		private const string DriverKey = "rb_serpent_driver";

		private const string PassengerKey = "rb_serpent_passenger";

		private const float SeatRange = 12f;

		private const float LeaseSeconds = 5f;

		internal const float HealDelay = 20f;

		internal const float HealPerSecond = 0.02f;

		private const float LungeForce = 60f;

		private const float LungeCooldown = 1.2f;

		internal const float SeatHeight = 0.65f;

		internal const float BobSlot = 14f;

		internal const float BobSkip = 0.3f;

		internal const float BobMinLift = 0.75f;

		internal const float BobMaxLift = 1f;

		internal const float BobMinHold = 1f;

		internal const float BobMaxHold = 3f;

		internal const float BobRise = 1.2f;

		internal const float LeapApex = 1.5f;

		internal const float LeapDuration = 1.4f;

		internal const float LeapMaxSpeed = 25f;

		internal const float JumpCooldown = 2.5f;

		internal const float JumpWindow = 1.6f;

		internal const float TeleportDistance = 5f;

		internal const float SwimSpeed = 10f;

		internal const float RideSpeed = 17.5f;

		internal const float WaveMinSpeed = 3f;

		internal const float WavePitchMax = 35f;

		private static readonly int SerpentPrefab = StringExtensionMethods.GetStableHashCode("Serpent");

		private static readonly int PlayerPrefab = StringExtensionMethods.GetStableHashCode("Player");

		internal static readonly List<SerpentBody> Loaded = new List<SerpentBody>();

		internal static Func<ZDO, bool> CanBoard;

		internal static Action<SerpentBody> OpenPanel;

		internal static Action<SerpentBody> WandUsed;

		private MonsterAI ai;

		private readonly float[] heartbeat = new float[2];

		private Vector3 direction;

		private float controlTime;

		private float maintenance;

		private float requestUntil;

		private bool requestedPassenger;

		private bool ownerReady;

		private string requestToken;

		private long observedOwner;

		private long observedStrike;

		private float nextVisual;

		private Vector3 idleAnchor;

		private Vector3 shoreProbePosition;

		private Vector3 shoreProbeDirection;

		private float nextShoreProbe;

		private float shoreMessage;

		private float lastHealth = -1f;

		private float healAfter;

		private float lastRegen;

		private float nextLunge;

		private float slowSince;

		private float restDepth = -1f;

		private float bobPhase;

		private int bobSeed;

		private bool jumpRequested;

		private float nextJump;

		private float leapStart;

		private float leapUntil;

		private float leapFrom;

		private float leapTop;

		private Transform visual;

		private Vector3 visualRestPos;

		private Quaternion visualRestRot = Quaternion.identity;

		private Vector3 stepPos;

		private Quaternion stepRot = Quaternion.identity;

		private bool stepKnown;

		private bool smoothable;

		private readonly HeightTrail trail = new HeightTrail(320);

		private Transform[] spine;

		private float[] spineOffset;

		private Vector3[] boneWorldPos;

		private Vector3[] baseLocalPos;

		private Vector3[] writtenLocalPos;

		private Quaternion[] boneWorldRot;

		private Quaternion[] baseLocalRot;

		private Quaternion[] writtenLocalRot;

		private bool[] baseKnown;

		private GameObject[] travelHarness = Array.Empty<GameObject>();

		private GameObject[] cargoHarness = Array.Empty<GameObject>();

		private const float HoverSeconds = 1f;

		private string hoverText;

		private float hoverAt;

		internal ZNetView View { get; private set; }

		internal Character Character { get; private set; }

		internal bool HasRiders
		{
			get
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_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)
				if (!(Rider(passenger: false) != ZDOID.None))
				{
					return Rider(passenger: true) != ZDOID.None;
				}
				return true;
			}
		}

		internal long DriverPlayer
		{
			get
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				ZDOMan instance = ZDOMan.instance;
				long? obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					ZDO zDO = instance.GetZDO(Rider(passenger: false));
					obj = ((zDO != null) ? new long?(zDO.GetLong(ZDOVars.s_playerID, 0L)) : ((long?)null));
				}
				long? num = obj;
				return num.GetValueOrDefault();
			}
		}

		internal SerpentMount Driver { get; private set; }

		internal SerpentMount Passenger { get; private set; }

		internal bool ShoreBlocked { get; private set; }

		internal bool ShoreUnloaded { get; private set; }

		internal bool InWaterForRoute()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return SerpentDepot.WaterPosition(((Component)this).transform.position);
		}

		internal static bool Marked(ZDO record)
		{
			if (record != null && record.GetPrefab() == SerpentPrefab)
			{
				return record.GetBool("rb_serpent_tamed", false);
			}
			return false;
		}

		internal static SerpentBody Ensure(Character character)
		{
			if (!Object.op_Implicit((Object)(object)character))
			{
				return null;
			}
			SerpentBody component = ((Component)character).GetComponent<SerpentBody>();
			if (Object.op_Implicit((Object)(object)component))
			{
				return component;
			}
			ZNetView component2 = ((Component)character).GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component2) || !Marked(component2.GetZDO()))
			{
				return null;
			}
			return ((Component)character).gameObject.AddComponent<SerpentBody>();
		}

		private void Awake()
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: 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_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: 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_0173: Invalid comparison between Unknown and I4
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			Character = ((Component)this).GetComponent<Character>();
			View = ((Component)this).GetComponent<ZNetView>();
			ai = ((Component)this).GetComponent<MonsterAI>();
			if (!Object.op_Implicit((Object)(object)Character) || !Object.op_Implicit((Object)(object)View) || !Marked(View.GetZDO()))
			{
				((Behaviour)this).enabled = false;
				return;
			}
			Driver = CreateSeat(passenger: false, new Vector3(0.6f, 0.65f, -1.4f));
			Passenger = CreateSeat(passenger: true, new Vector3(-0.6f, 0.65f, -3.15f));
			restDepth = Character.m_swimDepth;
			bobSeed = ((object)Unsafe.As<ZDOID, ZDOID>(ref View.GetZDO().m_uid)/*cast due to .constrained prefix*/).GetHashCode();
			bobPhase = (float)Mathf.Abs(bobSeed % 1000) / 1000f * 14f;
			visual = (Object.op_Implicit((Object)(object)Character.GetVisual()) ? Character.GetVisual().transform : ((Component)this).transform.Find("Visual"));
			if (Object.op_Implicit((Object)(object)visual))
			{
				visualRestPos = visual.localPosition;
				visualRestRot = visual.localRotation;
			}
			smoothable = Object.op_Implicit((Object)(object)visual) && (int)Character.m_groundTilt == 0;
			SkinnedMeshRenderer componentInChildren = ((Component)this).GetComponentInChildren<SkinnedMeshRenderer>(true);
			if (Object.op_Implicit((Object)(object)componentInChildren) && componentInChildren.bones != null)
			{
				Transform[] array = componentInChildren.bones.Where((Transform b) => Object.op_Implicit((Object)(object)b)).Distinct().OrderBy(Depth)
					.ToArray();
				float snout = ((array.Length != 0) ? array.Max((Transform b) => ((Component)this).transform.InverseTransformPoint(b.position).z) : 0f);
				spine = array;
				spineOffset = array.Select((Transform b) => Mathf.Max(0f, snout - ((Component)this).transform.InverseTransformPoint(b.position).z)).ToArray();
				boneWorldPos = (Vector3[])(object)new Vector3[array.Length];
				boneWorldRot = (Quaternion[])(object)new Quaternion[array.Length];
			}
			View.Register<ZDOID, long, bool, string>("Runebourne.Serpent.Board.v1", (Method<ZDOID, long, bool, string>)Board);
			View.Register<bool, bool, string>("Runebourne.Serpent.Seat.v1", (Action<long, bool, bool, string>)Reply);
			View.Register<ZDOID>("Runebourne.Serpent.Leave.v1", (Action<long, ZDOID>)Release);
			View.Register<ZDOID, Vector3>("Runebourne.Serpent.Control.v1", (Action<long, ZDOID, Vector3>)Control);
			idleAnchor = ((Component)this).transform.position;
			Loaded.Add(this);
			healAfter = Time.time + 20f;
			lastRegen = Time.time;
			SerpentTravel.Watch(View.GetZDO());
			SerpentVisual.Apply(((Component)this).gameObject, out travelHarness, out cargoHarness);
			ShowHarness();
		}

		private void ShowHarness()
		{
			bool flag = View.GetZDO().GetBool("rb_serpent_cargo", false);
			GameObject[] array = travelHarness;
			foreach (GameObject val in array)
			{
				if (Object.op_Implicit((Object)(object)val) && val.activeSelf == flag)
				{
					val.SetActive(!flag);
				}
			}
			array = cargoHarness;
			foreach (GameObject val2 in array)
			{
				if (Object.op_Implicit((Object)(object)val2) && val2.activeSelf != flag)
				{
					val2.SetActive(flag);
				}
			}
		}

		private SerpentMount CreateSeat(bool passenger, Vector3 position)
		{
			//IL_000f: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(passenger ? "Runebourne passenger seat" : "Runebourne driver seat");
			val.transform.SetParent(((Component)this).transform, false);
			val.transform.localPosition = position;
			SerpentVisual.MountAtRest(val.transform, ((Component)this).gameObject, position);
			SerpentMount serpentMount = val.AddComponent<SerpentMount>();
			serpentMount.Body = this;
			serpentMount.Passenger = passenger;
			return serpentMount;
		}

		internal ZDOID Rider(bool passenger)
		{
			//IL_001a: 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)
			if (!Object.op_Implicit((Object)(object)View) || !View.IsValid())
			{
				return ZDOID.None;
			}
			return View.GetZDO().GetZDOID(passenger ? "rb_serpent_passenger" : "rb_serpent_driver");
		}

		private void SetRider(bool passenger, ZDOID id)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			View.GetZDO().Set(passenger ? "rb_serpent_passenger" : "rb_serpent_driver", id);
			heartbeat[passenger ? 1u : 0u] = Time.unscaledTime;
			if (!passenger)
			{
				direction = Vector3.zero;
				jumpRequested = false;
				idleAnchor = ((Component)this).transform.position;
				if (Object.op_Implicit((Object)(object)ai) && id == ZDOID.None)
				{
					((BaseAI)ai).SetPatrolPoint();
				}
			}
		}

		internal static bool ActorWitness(ZDO actor, long sender, long player, Vector3 seat, float range)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (actor != null && sender != 0L && actor.GetOwner() == sender && actor.GetPrefab() == PlayerPrefab && player != 0L && actor.GetLong(ZDOVars.s_playerID, 0L) == player)
			{
				Vector3 val = actor.GetPosition() - seat;
				return ((Vector3)(ref val)).sqrMagnitude <= range * range;
			}
			return false;
		}

		private Player Actor(long sender, ZDOID id, long player, bool passenger, bool ward)
		{
			//IL_000c: 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_005e: 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)
			ZDOMan instance = ZDOMan.instance;
			ZDO actor = ((instance != null) ? instance.GetZDO(id) : null);
			SerpentMount serpentMount = (passenger ? Passenger : Driver);
			if (!Object.op_Implicit((Object)(object)serpentMount) || !ActorWitness(actor, sender, player, ((Component)serpentMount).transform.position, 12f))
			{
				return null;
			}
			GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(id) : null);
			Player val2 = (Object.op_Implicit((Object)