Decompiled source of Hearthfolk v1.0.0

Hearthfolk.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Hearthfolk.Jobs;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Splatform;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: AssemblyCompany("Hearthfolk")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Hearthfolk")]
[assembly: AssemblyTitle("Hearthfolk")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Hearthfolk
{
	[HarmonyPatch(typeof(WearNTear), "ApplyDamage")]
	internal static class BaseDamageDefensePatch
	{
		[HarmonyPostfix]
		private static void Postfix(WearNTear __instance, float damage, HitData hitData, bool __result)
		{
			if (__result && !(damage <= 0f) && hitData != null)
			{
				ExilesHearth.ReportBaseDamage(__instance, hitData.GetAttacker());
			}
		}
	}
	[HarmonyPatch(typeof(Chair), "Interact")]
	internal static class ChairInteractPatch
	{
		private static bool Prefix(Chair __instance, Humanoid human, bool hold, ref bool __result)
		{
			if (hold || !SettlerController.IsSeatReserved(__instance))
			{
				return true;
			}
			Player val = (Player)(object)((human is Player) ? human : null);
			if (val != null && (Object)(object)val == (Object)(object)Player.m_localPlayer)
			{
				((Character)val).Message((MessageType)2, "$msg_blocked", 0, (Sprite)null);
			}
			__result = false;
			return false;
		}
	}
	internal sealed class ChestSortPanel : MonoBehaviour
	{
		private sealed class ItemChoice
		{
			internal string SharedName;

			internal string DisplayName;

			internal Sprite Icon;
		}

		private const float PanelWidth = 620f;

		private const float PanelHeight = 690f;

		private const float MaxUseDistance = 10f;

		private static ChestSortPanel _instance;

		private Container _container;

		private Rect _rect;

		private Vector2 _scroll;

		private string _search = string.Empty;

		private bool _wasConfigured;

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

		private List<ItemChoice> _choices = new List<ItemChoice>();

		internal static void Toggle(Container container)
		{
			if ((Object)(object)_instance == (Object)null)
			{
				GameObject val = (((Object)(object)HearthfolkPlugin.Instance != (Object)null) ? ((Component)HearthfolkPlugin.Instance).gameObject : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				_instance = val.AddComponent<ChestSortPanel>();
			}
			if ((Object)(object)_instance._container == (Object)(object)container)
			{
				_instance.Close();
			}
			else
			{
				_instance.Open(container);
			}
		}

		private void Open(Container container)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && ChestSortRules.CanConfigure(container, localPlayer.GetPlayerID()))
			{
				_container = container;
				_wasConfigured = ChestSortRules.IsConfigured(container);
				_selected = ChestSortRules.ReadItems(container);
				_choices = BuildChoices(container, _selected);
				_search = string.Empty;
				_scroll = Vector2.zero;
				_rect = new Rect(((float)Screen.width - 620f) / 2f, ((float)Screen.height - 690f) / 2f, 620f, 690f);
				GUIManager.BlockInput(true);
			}
		}

		private void Close()
		{
			_container = null;
			GUIManager.BlockInput(false);
		}

		private void OnDestroy()
		{
			if ((Object)(object)_container != (Object)null)
			{
				GUIManager.BlockInput(false);
			}
		}

		private void Update()
		{
			//IL_0044: 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)
			if (!((Object)(object)_container == (Object)null))
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer == (Object)null || (Object)(object)_container == (Object)null || !((Component)_container).gameObject.activeInHierarchy || Vector3.Distance(((Component)localPlayer).transform.position, ((Component)_container).transform.position) > 10f || Input.GetKeyDown((KeyCode)27))
				{
					Close();
					return;
				}
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
		}

		private void OnGUI()
		{
			//IL_0026: 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_0050: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_container == (Object)null))
			{
				GUISkin skin = GUI.skin;
				GUI.skin = HfGuiSkin.Get();
				_rect = GUILayout.Window(((Object)this).GetInstanceID(), _rect, new WindowFunction(DrawWindow), Localization.instance.Localize("$hf_chest_sort_title"), Array.Empty<GUILayoutOption>());
				GUI.skin = skin;
			}
		}

		private void DrawWindow(int id)
		{
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_container == (Object)null)
			{
				return;
			}
			GUILayout.Space(4f);
			DrawIntakeStorageSection();
			GUILayout.Space(8f);
			GUILayout.Label(Localization.instance.Localize(_wasConfigured ? "$hf_chest_sort_mode_explicit" : "$hf_chest_sort_mode_auto"), Array.Empty<GUILayoutOption>());
			GUILayout.Label(Localization.instance.Localize("$hf_chest_sort_desc"), Array.Empty<GUILayoutOption>());
			GUILayout.Space(5f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(Localization.instance.Localize("$hf_chest_sort_search"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
			_search = GUILayout.TextField(_search ?? string.Empty, Array.Empty<GUILayoutOption>());
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button(Localization.instance.Localize("$hf_chest_sort_select_present"), Array.Empty<GUILayoutOption>()))
			{
				SelectPresentMaterials();
			}
			if (GUILayout.Button(Localization.instance.Localize("$hf_chest_sort_clear"), Array.Empty<GUILayoutOption>()))
			{
				_selected.Clear();
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(5f);
			_scroll = GUILayout.BeginScrollView(_scroll, GUI.skin.box);
			List<ItemChoice> list = _choices.Where(MatchesSearch).ToList();
			for (int i = 0; i < list.Count; i += 2)
			{
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				DrawChoice(list[i]);
				if (i + 1 < list.Count)
				{
					DrawChoice(list[i + 1]);
				}
				else
				{
					GUILayout.FlexibleSpace();
				}
				GUILayout.EndHorizontal();
			}
			if (list.Count == 0)
			{
				GUILayout.Label(Localization.instance.Localize("$hf_chest_sort_no_items"), Array.Empty<GUILayoutOption>());
			}
			GUILayout.EndScrollView();
			GUILayout.Space(6f);
			GUILayout.Label(string.Format(Localization.instance.Localize("$hf_chest_sort_selected"), _selected.Count), Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button(Localization.instance.Localize("$hf_chest_sort_save"), Array.Empty<GUILayoutOption>()))
			{
				ChestSortRules.RequestSet(_container, _selected, configured: true);
				Player localPlayer = Player.m_localPlayer;
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)2, "$hf_chest_sort_saved", 0, (Sprite)null);
				}
				Close();
			}
			if (GUILayout.Button(Localization.instance.Localize("$hf_chest_sort_use_auto"), Array.Empty<GUILayoutOption>()))
			{
				ChestSortRules.RequestSet(_container, Array.Empty<string>(), configured: false);
				Player localPlayer2 = Player.m_localPlayer;
				if (localPlayer2 != null)
				{
					((Character)localPlayer2).Message((MessageType)2, "$hf_chest_sort_auto_restored", 0, (Sprite)null);
				}
				Close();
			}
			if (GUILayout.Button(Localization.instance.Localize("$hf_panel_close"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) }))
			{
				Close();
			}
			GUILayout.EndHorizontal();
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 20f));
		}

		private void DrawIntakeStorageSection()
		{
			Player localPlayer = Player.m_localPlayer;
			long ownerId = (((Object)(object)localPlayer != (Object)null) ? localPlayer.GetPlayerID() : 0);
			ExilesHearth exilesHearth = ExilesHearth.IntakeCandidateFor(_container, ownerId);
			GUILayout.BeginVertical(GUI.skin.box, Array.Empty<GUILayoutOption>());
			GUILayout.Label(Localization.instance.Localize("$hf_chest_intake_section"), HfGuiSkin.CardTitle, Array.Empty<GUILayoutOption>());
			GUILayout.Label(Localization.instance.Localize("$hf_chest_intake_desc"), HfGuiSkin.MutedLabel, Array.Empty<GUILayoutOption>());
			if ((Object)(object)exilesHearth == (Object)null)
			{
				GUILayout.Label(Localization.instance.Localize("$hf_chest_intake_no_hearth"), Array.Empty<GUILayoutOption>());
				GUILayout.EndVertical();
				return;
			}
			IntakeRoles intakeRoles = exilesHearth.IntakeRolesFor(_container);
			bool flag = intakeRoles != IntakeRoles.None;
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(Localization.instance.Localize(flag ? "$hf_chest_intake_current" : "$hf_chest_intake_available"), Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			if (GUILayout.Button(Localization.instance.Localize("$hf_chest_intake_all"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }))
			{
				exilesHearth.RequestSetIntakeStorageRoles(_container, IntakeRoles.All);
				if (localPlayer != null)
				{
					((Character)localPlayer).Message((MessageType)2, "$hf_chest_intake_saved", 0, (Sprite)null);
				}
			}
			if (flag && GUILayout.Button(Localization.instance.Localize("$hf_chest_intake_remove"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(120f) }))
			{
				exilesHearth.RequestSetIntakeStorageRoles(_container, IntakeRoles.None);
			}
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			DrawIntakeRoleToggle(exilesHearth, intakeRoles, IntakeRoles.Lumberjack, "$hf_role_lumberjack");
			DrawIntakeRoleToggle(exilesHearth, intakeRoles, IntakeRoles.Miner, "$hf_role_miner");
			DrawIntakeRoleToggle(exilesHearth, intakeRoles, IntakeRoles.Farmer, "$hf_role_farmer");
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			GUILayout.EndVertical();
		}

		private void DrawIntakeRoleToggle(ExilesHearth hearth, IntakeRoles roles, IntakeRoles role, string labelKey)
		{
			//IL_0007: 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)
			bool flag = (roles & role) != 0;
			Color contentColor = GUI.contentColor;
			if (!flag)
			{
				GUI.contentColor = new Color(0.55f, 0.5f, 0.42f);
			}
			if (GUILayout.Button((flag ? "✓ " : "— ") + Localization.instance.Localize(labelKey), Array.Empty<GUILayoutOption>()))
			{
				hearth.RequestSetIntakeStorageRoles(_container, flag ? (roles & ~role) : (roles | role));
			}
			GUI.contentColor = contentColor;
		}

		private void DrawChoice(ItemChoice choice)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Invalid comparison between Unknown and I4
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			bool flag = _selected.Contains(choice.SharedName);
			Color backgroundColor = GUI.backgroundColor;
			Color contentColor = GUI.contentColor;
			if (flag)
			{
				GUI.backgroundColor = new Color(2.4f, 2f, 1.1f);
				GUI.contentColor = new Color(1f, 0.85f, 0.45f);
			}
			if (GUILayout.Button((flag ? "✓ " : string.Empty) + choice.DisplayName, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(275f),
				GUILayout.Height(42f)
			}))
			{
				if (flag)
				{
					_selected.Remove(choice.SharedName);
				}
				else
				{
					_selected.Add(choice.SharedName);
				}
			}
			Rect lastRect = GUILayoutUtility.GetLastRect();
			if ((Object)(object)choice.Icon != (Object)null && (Object)(object)choice.Icon.texture != (Object)null && (int)Event.current.type == 7)
			{
				Rect textureRect = choice.Icon.textureRect;
				Texture2D texture = choice.Icon.texture;
				Rect val = default(Rect);
				((Rect)(ref val))..ctor(((Rect)(ref textureRect)).x / (float)((Texture)texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)texture).height, ((Rect)(ref textureRect)).width / (float)((Texture)texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)texture).height);
				GUI.DrawTextureWithTexCoords(new Rect(((Rect)(ref lastRect)).x + 6f, ((Rect)(ref lastRect)).y + 5f, 32f, 32f), (Texture)(object)texture, val, true);
			}
			GUI.backgroundColor = backgroundColor;
			GUI.contentColor = contentColor;
		}

		private bool MatchesSearch(ItemChoice choice)
		{
			if (!string.IsNullOrWhiteSpace(_search) && choice.DisplayName.IndexOf(_search, StringComparison.OrdinalIgnoreCase) < 0)
			{
				return choice.SharedName.IndexOf(_search, StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private void SelectPresentMaterials()
		{
			Container container = _container;
			Inventory val = ((container != null) ? container.GetInventory() : null);
			if (val == null)
			{
				return;
			}
			foreach (ItemData allItem in val.GetAllItems())
			{
				if (ChestSortRules.IsSortable(allItem))
				{
					_selected.Add(allItem.m_shared.m_name);
				}
			}
		}

		private static List<ItemChoice> BuildChoices(Container container, HashSet<string> selected)
		{
			HashSet<string> hashSet = new HashSet<string>(selected, StringComparer.Ordinal);
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				hashSet.UnionWith(localPlayer.m_knownMaterial);
			}
			Inventory inventory = container.GetInventory();
			if (inventory != null)
			{
				hashSet.UnionWith(from item in inventory.GetAllItems()
					where item != null
					select item.m_shared.m_name);
			}
			List<ItemChoice> list = new List<ItemChoice>();
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return list;
			}
			foreach (GameObject item in ObjectDB.instance.m_items)
			{
				ItemData val = ((item != null) ? item.GetComponent<ItemDrop>() : null)?.m_itemData;
				if (ChestSortRules.IsSortable(val) && hashSet.Contains(val.m_shared.m_name))
				{
					list.Add(new ItemChoice
					{
						SharedName = val.m_shared.m_name,
						DisplayName = Localization.instance.Localize(val.m_shared.m_name),
						Icon = val.GetIcon()
					});
				}
			}
			return (from choice in list
				group choice by choice.SharedName into @group
				select @group.First() into choice
				orderby choice.DisplayName
				select choice).ToList();
		}
	}
	internal static class ChestSortRules
	{
		private const char Separator = '|';

		internal static void Register(Container container)
		{
			ZNetView val = container?.m_nview;
			if (!((Object)(object)val == (Object)null) && val.IsValid() && !(container is SettlerInventory))
			{
				val.Register<long, string>("hf_SetChestSort", (Action<long, long, string>)delegate(long sender, long requesterId, string payload)
				{
					Receive(container, requesterId, payload);
				});
			}
		}

		internal static bool IsConfigured(Container container)
		{
			if (TryGetZdo(container, out var zdo))
			{
				return zdo.GetBool("hf_sort_configured", false);
			}
			return false;
		}

		internal static HashSet<string> ReadItems(Container container)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			if (!TryGetZdo(container, out var zdo))
			{
				return hashSet;
			}
			string[] array = zdo.GetString("hf_sort_items", string.Empty).Split(new char[1] { '|' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string item in array)
			{
				hashSet.Add(item);
			}
			return hashSet;
		}

		internal static bool Accepts(Container container, string sharedName)
		{
			if ((Object)(object)container == (Object)null || string.IsNullOrEmpty(sharedName))
			{
				return false;
			}
			if (IsConfigured(container))
			{
				return ReadItems(container).Contains(sharedName);
			}
			Inventory inventory = container.GetInventory();
			if (inventory != null)
			{
				return inventory.GetAllItems().Any((ItemData item) => item != null && item.m_shared.m_name == sharedName);
			}
			return false;
		}

		internal static bool IsSortable(ItemData item)
		{
			//IL_0020: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Invalid comparison between Unknown and I4
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Invalid comparison between Unknown and I4
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Invalid comparison between Unknown and I4
			if (item == null || item.m_shared == null || item.m_shared.m_questItem)
			{
				return false;
			}
			ItemType itemType = item.m_shared.m_itemType;
			if (itemType - 1 <= 1 || (int)itemType == 13 || (int)itemType == 21)
			{
				return true;
			}
			return false;
		}

		internal static void RequestSet(Container container, IEnumerable<string> items, bool configured)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && CanConfigure(container, localPlayer.GetPlayerID()))
			{
				string text = (configured ? ("1|" + string.Join('|'.ToString(), from name in items.Where((string name) => !string.IsNullOrEmpty(name) && name.IndexOf('|') < 0).Distinct()
					orderby name
					select name)) : "0");
				container.m_nview.InvokeRPC("hf_SetChestSort", new object[2]
				{
					localPlayer.GetPlayerID(),
					text
				});
			}
		}

		internal static bool IsStationaryPlayerChest(Container container)
		{
			if ((Object)(object)container == (Object)null || container is SettlerInventory || !((Component)container).gameObject.activeInHierarchy || (Object)(object)container.m_nview == (Object)null || !container.m_nview.IsValid() || (Object)(object)container.m_wagon != (Object)null || (Object)(object)((Component)container).GetComponentInParent<Ship>() != (Object)null || (Object)(object)((Component)container).GetComponentInParent<Vagon>() != (Object)null)
			{
				return false;
			}
			Piece val = ((Component)container).GetComponent<Piece>() ?? ((Component)container).GetComponentInParent<Piece>();
			if ((Object)(object)val != (Object)null)
			{
				return val.IsPlacedByPlayer();
			}
			return false;
		}

		internal static bool CanConfigure(Container container, long playerId)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (playerId != 0L && IsStationaryPlayerChest(container) && !ContainerInUse(container) && container.CheckAccess(playerId))
			{
				return PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false);
			}
			return false;
		}

		private static void Receive(Container container, long requesterId, string payload)
		{
			if (!((Object)(object)container == (Object)null) && !((Object)(object)container.m_nview == (Object)null) && container.m_nview.IsValid() && container.m_nview.IsOwner() && requesterId != 0L && IsStationaryPlayerChest(container) && container.CheckAccess(requesterId) && !string.IsNullOrEmpty(payload))
			{
				bool flag = payload.StartsWith("1|", StringComparison.Ordinal);
				string text = ((flag && payload.Length > 2) ? payload.Substring(2) : string.Empty);
				ZDO zDO = container.m_nview.GetZDO();
				zDO.Set("hf_sort_configured", flag);
				zDO.Set("hf_sort_items", text);
				Diagnostics.Log($"Hearthfolk[sorting]: chest={((Object)((Component)container).gameObject).name} configured={flag} items={text}");
			}
		}

		private static bool TryGetZdo(Container container, out ZDO zdo)
		{
			zdo = null;
			if ((Object)(object)container == (Object)null || (Object)(object)container.m_nview == (Object)null || !container.m_nview.IsValid())
			{
				return false;
			}
			zdo = container.m_nview.GetZDO();
			return zdo != null;
		}

		private static bool ContainerInUse(Container container)
		{
			if (!container.IsInUse())
			{
				return container.m_nview.GetZDO().GetInt(ZDOVars.s_inUse, 0) == 1;
			}
			return true;
		}
	}
	internal sealed class ChopTarget
	{
		private readonly TreeBase _tree;

		private readonly TreeLog _log;

		internal bool IsLog => (Object)(object)_log != (Object)null;

		internal GameObject GameObject
		{
			get
			{
				if (!((Object)(object)_tree != (Object)null))
				{
					if (!((Object)(object)_log != (Object)null))
					{
						return null;
					}
					return ((Component)_log).gameObject;
				}
				return ((Component)_tree).gameObject;
			}
		}

		internal int InstanceId
		{
			get
			{
				if (!((Object)(object)GameObject != (Object)null))
				{
					return 0;
				}
				return ((Object)GameObject).GetInstanceID();
			}
		}

		internal Vector3 Center => GameObject.transform.position;

		internal int MinToolTier
		{
			get
			{
				if (!((Object)(object)_tree != (Object)null))
				{
					if (!((Object)(object)_log != (Object)null))
					{
						return 0;
					}
					return _log.m_minToolTier;
				}
				return _tree.m_minToolTier;
			}
		}

		internal ChopTarget(TreeBase tree)
		{
			_tree = tree;
		}

		internal ChopTarget(TreeLog log)
		{
			_log = log;
		}

		internal bool IsValid()
		{
			GameObject gameObject = GameObject;
			if ((Object)(object)gameObject != (Object)null)
			{
				return gameObject.activeInHierarchy;
			}
			return false;
		}

		internal Vector3 ClosestPoint(Vector3 from)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			GameObject gameObject = GameObject;
			if ((Object)(object)gameObject == (Object)null)
			{
				return from;
			}
			Collider componentInChildren = gameObject.GetComponentInChildren<Collider>();
			if ((Object)(object)componentInChildren == (Object)null)
			{
				return gameObject.transform.position;
			}
			MeshCollider val = (MeshCollider)(object)((componentInChildren is MeshCollider) ? componentInChildren : null);
			if ((Object)(object)val != (Object)null && !val.convex)
			{
				return componentInChildren.ClosestPointOnBounds(from);
			}
			return componentInChildren.ClosestPoint(from);
		}

		internal float ReadHealth()
		{
			ZNetView val = (((Object)(object)_tree != (Object)null) ? _tree.m_nview : (((Object)(object)_log != (Object)null) ? _log.m_nview : null));
			float num = (((Object)(object)_tree != (Object)null) ? _tree.m_health : (((Object)(object)_log != (Object)null) ? _log.m_health : 0f));
			if (!((Object)(object)val != (Object)null) || !val.IsValid())
			{
				return num;
			}
			return val.GetZDO().GetFloat(ZDOVars.s_health, num);
		}

		internal void Damage(HitData hit)
		{
			if ((Object)(object)_tree != (Object)null)
			{
				_tree.Damage(hit);
				return;
			}
			TreeLog log = _log;
			if (log != null)
			{
				log.Damage(hit);
			}
		}
	}
	internal static class CivilPathPlanner
	{
		private readonly struct HeapEntry
		{
			internal readonly int Node;

			internal readonly float Score;

			internal HeapEntry(int node, float score)
			{
				Node = node;
				Score = score;
			}
		}

		private sealed class MinHeap
		{
			private readonly List<HeapEntry> _items = new List<HeapEntry>();

			internal int Count => _items.Count;

			internal void Push(HeapEntry entry)
			{
				_items.Add(entry);
				int num = _items.Count - 1;
				while (num > 0)
				{
					int num2 = (num - 1) / 2;
					if (_items[num2].Score <= entry.Score)
					{
						break;
					}
					_items[num] = _items[num2];
					num = num2;
				}
				_items[num] = entry;
			}

			internal HeapEntry Pop()
			{
				HeapEntry result = _items[0];
				HeapEntry value = _items[_items.Count - 1];
				_items.RemoveAt(_items.Count - 1);
				if (_items.Count == 0)
				{
					return result;
				}
				int num = 0;
				while (true)
				{
					int num2 = num * 2 + 1;
					if (num2 >= _items.Count)
					{
						break;
					}
					int num3 = num2 + 1;
					int num4 = ((num3 < _items.Count && _items[num3].Score < _items[num2].Score) ? num3 : num2);
					if (_items[num4].Score >= value.Score)
					{
						break;
					}
					_items[num] = _items[num4];
					num = num4;
				}
				_items[num] = value;
				return result;
			}
		}

		private const float BaseCellSize = 0.82f;

		private const float BodyRadius = 0.34f;

		private const float MaxStepHeight = 0.85f;

		private const int MaxExpandedNodes = 4000;

		private static readonly int ObstacleMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "terrain" });

		internal static bool TryBuildPath(Vector3 start, Vector3 goal, Transform mover, string actor, out List<Vector3> waypoints)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0490: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			//IL_04da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0503: Unknown result type (might be due to invalid IL or missing references)
			//IL_0508: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0410: Unknown result type (might be due to invalid IL or missing references)
			//IL_0415: Unknown result type (might be due to invalid IL or missing references)
			waypoints = null;
			float num = Utils.DistanceXZ(start, goal);
			if (num < 1.25f)
			{
				waypoints = new List<Vector3> { goal };
				return true;
			}
			float num2 = Mathf.Clamp(num * 0.58f, 8f, 24f);
			float num3 = Mathf.Min(start.x, goal.x) - num2;
			float num4 = Mathf.Max(start.x, goal.x) + num2;
			float num5 = Mathf.Min(start.z, goal.z) - num2;
			float num6 = Mathf.Max(start.z, goal.z) + num2;
			float num7 = 0.82f;
			int num8 = Mathf.CeilToInt((num4 - num3) / num7) + 1;
			int num9 = Mathf.CeilToInt((num6 - num5) / num7) + 1;
			int num10 = num8 * num9;
			if (num10 > 11000)
			{
				num7 *= Mathf.Sqrt((float)num10 / 11000f);
				num8 = Mathf.CeilToInt((num4 - num3) / num7) + 1;
				num9 = Mathf.CeilToInt((num6 - num5) / num7) + 1;
				num10 = num8 * num9;
			}
			bool[] array = new bool[num10];
			bool[] array2 = new bool[num10];
			bool[] array3 = new bool[num10];
			float[] array4 = new float[num10];
			float[] array5 = new float[num10];
			int[] array6 = new int[num10];
			for (int i = 0; i < num10; i++)
			{
				array5[i] = float.MaxValue;
				array6[i] = -1;
			}
			int num11 = Mathf.Clamp(Mathf.RoundToInt((start.x - num3) / num7), 0, num8 - 1);
			int num12 = Mathf.Clamp(Mathf.RoundToInt((start.z - num5) / num7), 0, num9 - 1) * num8 + num11;
			array[num12] = true;
			array2[num12] = true;
			array4[num12] = start.y;
			array5[num12] = 0f;
			MinHeap minHeap = new MinHeap();
			minHeap.Push(new HeapEntry(num12, num));
			int num13 = 0;
			int num14 = -1;
			Vector2Int[] array7 = (Vector2Int[])(object)new Vector2Int[8]
			{
				new Vector2Int(1, 0),
				new Vector2Int(-1, 0),
				new Vector2Int(0, 1),
				new Vector2Int(0, -1),
				new Vector2Int(1, 1),
				new Vector2Int(1, -1),
				new Vector2Int(-1, 1),
				new Vector2Int(-1, -1)
			};
			while (minHeap.Count > 0 && num13 < 4000)
			{
				int node = minHeap.Pop().Node;
				if (array3[node])
				{
					continue;
				}
				array3[node] = true;
				num13++;
				int num15 = node % num8;
				int num16 = node / num8;
				Vector3 val = GridPoint(num15, num16, num3, num5, num7, array4[node]);
				if (Utils.DistanceXZ(val, goal) <= num7 * 1.5f && SegmentClear(val, goal, mover, num7))
				{
					num14 = node;
					break;
				}
				Vector2Int[] array8 = array7;
				for (int j = 0; j < array8.Length; j++)
				{
					Vector2Int val2 = array8[j];
					int num17 = num15 + ((Vector2Int)(ref val2)).x;
					int num18 = num16 + ((Vector2Int)(ref val2)).y;
					if (num17 < 0 || num17 >= num8 || num18 < 0 || num18 >= num9)
					{
						continue;
					}
					int num19 = num18 * num8 + num17;
					if (array3[num19])
					{
						continue;
					}
					float expectedHeight = array4[node];
					if (!EvaluateNode(num19, num17, num18, num3, num5, num7, expectedHeight, mover, array, array2, array4))
					{
						continue;
					}
					if (((Vector2Int)(ref val2)).x != 0 && ((Vector2Int)(ref val2)).y != 0)
					{
						int node2 = num16 * num8 + num17;
						int node3 = num18 * num8 + num15;
						if (!EvaluateNode(node2, num17, num16, num3, num5, num7, expectedHeight, mover, array, array2, array4) || !EvaluateNode(node3, num15, num18, num3, num5, num7, expectedHeight, mover, array, array2, array4))
						{
							continue;
						}
					}
					float num20 = ((((Vector2Int)(ref val2)).x != 0 && ((Vector2Int)(ref val2)).y != 0) ? (num7 * 1.414214f) : num7);
					float num21 = Mathf.Abs(array4[num19] - array4[node]) * 1.5f;
					float num22 = array5[node] + num20 + num21;
					if (!(num22 >= array5[num19]))
					{
						array5[num19] = num22;
						array6[num19] = node;
						float num23 = Utils.DistanceXZ(GridPoint(num17, num18, num3, num5, num7, array4[num19]), goal);
						minHeap.Push(new HeapEntry(num19, num22 + num23));
					}
				}
			}
			if (num14 < 0)
			{
				Diagnostics.Navigation("Hearthfolk[planner]: " + actor + " no physical route " + $"({num:0.0}m, expanded={num13})");
				return false;
			}
			List<Vector3> list = new List<Vector3> { goal };
			int num24 = num14;
			while (num24 >= 0 && num24 != num12)
			{
				int x = num24 % num8;
				int z = num24 / num8;
				list.Add(GridPoint(x, z, num3, num5, num7, array4[num24]));
				num24 = array6[num24];
			}
			list.Add(start);
			list.Reverse();
			waypoints = Smooth(list, mover, num7);
			if (waypoints.Count > 0 && Utils.DistanceXZ(waypoints[0], start) < 0.65f)
			{
				waypoints.RemoveAt(0);
			}
			Diagnostics.Navigation("Hearthfolk[planner]: " + actor + " physical route " + $"{num:0.0}m " + $"with {waypoints.Count} waypoint(s), expanded={num13}");
			return waypoints.Count > 0;
		}

		internal static bool TryProjectWalkPoint(Vector3 desired, Transform mover, out Vector3 point)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_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)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: 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_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			Vector3[] obj = new Vector3[9]
			{
				Vector3.zero,
				Vector3.forward,
				Vector3.back,
				Vector3.right,
				Vector3.left,
				default(Vector3),
				default(Vector3),
				default(Vector3),
				default(Vector3)
			};
			Vector3 val = new Vector3(1f, 0f, 1f);
			obj[5] = ((Vector3)(ref val)).normalized;
			val = new Vector3(1f, 0f, -1f);
			obj[6] = ((Vector3)(ref val)).normalized;
			val = new Vector3(-1f, 0f, 1f);
			obj[7] = ((Vector3)(ref val)).normalized;
			val = new Vector3(-1f, 0f, -1f);
			obj[8] = ((Vector3)(ref val)).normalized;
			Vector3[] array = (Vector3[])(object)obj;
			float[] array2 = new float[4] { 0f, 0.45f, 0.85f, 1.25f };
			foreach (float num in array2)
			{
				Vector3[] array3 = array;
				foreach (Vector3 val2 in array3)
				{
					if (num == 0f && val2 != Vector3.zero)
					{
						continue;
					}
					Vector3 val3 = desired + val2 * num;
					if (TryGround(val3, desired.y, out var height) && !(Mathf.Abs(height - desired.y) > 2.5f))
					{
						point = new Vector3(val3.x, height, val3.z);
						if (HasBodyClearance(point, mover))
						{
							return true;
						}
					}
				}
			}
			point = desired;
			return false;
		}

		private static bool EvaluateNode(int node, int x, int z, float minX, float minZ, float cellSize, float expectedHeight, Transform mover, bool[] evaluated, bool[] walkable, float[] heights)
		{
			//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_005f: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			if (evaluated[node])
			{
				if (walkable[node])
				{
					return Mathf.Abs(heights[node] - expectedHeight) <= 0.85f;
				}
				return false;
			}
			evaluated[node] = true;
			Vector3 val = GridPoint(x, z, minX, minZ, cellSize, expectedHeight);
			if (!TryGround(val, expectedHeight, out var height))
			{
				return false;
			}
			heights[node] = height;
			walkable[node] = Mathf.Abs(height - expectedHeight) <= 0.85f && HasBodyClearance(new Vector3(val.x, height, val.z), mover);
			return walkable[node];
		}

		private static Vector3 GridPoint(int x, int z, float minX, float minZ, float cellSize, float y)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(minX + (float)x * cellSize, y, minZ + (float)z * cellSize);
		}

		private static bool TryGround(Vector3 point, float expectedHeight, out float height)
		{
			//IL_0007: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			height = 0f;
			RaycastHit[] array = Physics.RaycastAll(new Vector3(point.x, expectedHeight + 2.2f, point.z), Vector3.down, 4.8f, ObstacleMask, (QueryTriggerInteraction)1);
			float num = float.MaxValue;
			bool flag = false;
			RaycastHit[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				RaycastHit val = array2[i];
				if (!((Object)(object)((RaycastHit)(ref val)).collider == (Object)null) && !((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Character>() != (Object)null) && !(Vector3.Dot(((RaycastHit)(ref val)).normal, Vector3.up) < 0.55f))
				{
					float num2 = Mathf.Abs(((RaycastHit)(ref val)).point.y - expectedHeight);
					if (!(num2 >= num))
					{
						height = ((RaycastHit)(ref val)).point.y;
						num = num2;
						flag = true;
					}
				}
			}
			if (flag)
			{
				return true;
			}
			if ((Object)(object)ZoneSystem.instance != (Object)null)
			{
				return ZoneSystem.instance.GetGroundHeight(point, ref height);
			}
			return false;
		}

		private static bool HasBodyClearance(Vector3 ground, Transform mover)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_002a: 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_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ground + Vector3.up * 0.48f;
			Vector3 val2 = ground + Vector3.up * 1.55f;
			Collider[] array = Physics.OverlapCapsule(val, val2, 0.34f, ObstacleMask, (QueryTriggerInteraction)1);
			foreach (Collider val3 in array)
			{
				if (!((Object)(object)val3 == (Object)null) && (!((Object)(object)mover != (Object)null) || !((Component)val3).transform.IsChildOf(mover)) && !((Object)(object)((Component)val3).GetComponentInParent<Character>() != (Object)null) && !((Object)(object)((Component)val3).GetComponentInParent<Heightmap>() != (Object)null))
				{
					Bounds bounds = val3.bounds;
					if (!(((Bounds)(ref bounds)).max.y <= ground.y + 0.28f))
					{
						return false;
					}
				}
			}
			return true;
		}

		private static bool SegmentClear(Vector3 from, Vector3 to, Transform mover, float cellSize)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: 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)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			float num = Utils.DistanceXZ(from, to);
			int num2 = Mathf.Max(1, Mathf.CeilToInt(num / (cellSize * 0.62f)));
			float num3 = from.y;
			for (int i = 1; i <= num2; i++)
			{
				float num4 = (float)i / (float)num2;
				Vector3 val = Vector3.Lerp(from, to, num4);
				if (!TryGround(val, num3, out var height) || Mathf.Abs(height - num3) > 0.85f || !HasBodyClearance(new Vector3(val.x, height, val.z), mover))
				{
					return false;
				}
				num3 = height;
			}
			return true;
		}

		private static List<Vector3> Smooth(IReadOnlyList<Vector3> raw, Transform mover, float cellSize)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>();
			int num = 0;
			list.Add(raw[0]);
			while (num < raw.Count - 1)
			{
				int num2 = num + 1;
				for (int num3 = raw.Count - 1; num3 > num + 1; num3--)
				{
					if (SegmentClear(raw[num], raw[num3], mover, cellSize))
					{
						num2 = num3;
						break;
					}
				}
				list.Add(raw[num2]);
				num = num2;
			}
			return list;
		}

		internal static float PathLength(IReadOnlyList<Vector3> path, Vector3 start)
		{
			//IL_0006: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: 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)
			float num = 0f;
			Vector3 val = start;
			foreach (Vector3 item in path)
			{
				num += Utils.DistanceXZ(val, item);
				val = item;
			}
			return num;
		}
	}
	[HarmonyPatch(typeof(Container), "Awake")]
	internal static class ContainerAwakePatch
	{
		[HarmonyPostfix]
		private static void Postfix(Container __instance)
		{
			ChestSortRules.Register(__instance);
		}
	}
	[HarmonyPatch(typeof(Container), "Interact")]
	internal static class ContainerInteractPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(Container __instance, Humanoid character, bool hold, ref bool __result)
		{
			Player val = (Player)(object)((character is Player) ? character : null);
			if (hold || (Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer || !ControlHeld() || !ChestSortRules.CanConfigure(__instance, val.GetPlayerID()))
			{
				return true;
			}
			ChestSortPanel.Toggle(__instance);
			__result = true;
			return false;
		}

		private static bool ControlHeld()
		{
			if (!Input.GetKey((KeyCode)306))
			{
				return Input.GetKey((KeyCode)305);
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Container), "GetHoverText")]
	internal static class ContainerHoverPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Container __instance, ref string __result)
		{
			if ((Object)(object)Player.m_localPlayer != (Object)null && ChestSortRules.IsStationaryPlayerChest(__instance))
			{
				__result = __result + "\n" + Localization.instance.Localize("$hf_chest_sort_hover");
			}
		}
	}
	internal static class Diagnostics
	{
		internal static bool Enabled
		{
			get
			{
				if (HfConfig.DebugLog != null)
				{
					return HfConfig.DebugLog.Value;
				}
				return false;
			}
		}

		internal static void Log(string message)
		{
			if (Enabled)
			{
				Logger.LogInfo((object)message);
			}
		}

		internal static void Navigation(string message)
		{
			Logger.LogInfo((object)message);
		}
	}
	internal static class DormantSettlerRegistry
	{
		internal sealed class Record
		{
			internal readonly ZDO Zdo;

			internal ZDOID Id
			{
				get
				{
					//IL_0014: 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)
					if (Zdo == null)
					{
						return ZDOID.None;
					}
					return Zdo.m_uid;
				}
			}

			internal string Name
			{
				get
				{
					if (Zdo == null)
					{
						return Localization.instance.Localize("$hf_settler");
					}
					return Zdo.GetString("hf_name", Localization.instance.Localize("$hf_settler"));
				}
			}

			internal SettlerRole Role
			{
				get
				{
					if (Zdo == null)
					{
						return SettlerRole.Idle;
					}
					return (SettlerRole)Zdo.GetInt("hf_role", 0);
				}
			}

			internal long RespawnAt
			{
				get
				{
					if (Zdo == null)
					{
						return 0L;
					}
					return Zdo.GetLong("hf_respawn_at", 0L);
				}
			}

			internal string StatusText => SettlerController.FormatRespawnStatus(RespawnAt);

			internal Record(ZDO zdo)
			{
				Zdo = zdo;
			}
		}

		private const float RefreshInterval = 0.75f;

		private static readonly List<ZDO> Cached = new List<ZDO>();

		private static float _nextRefresh;

		internal static List<Record> ForHearth(ExilesHearth hearth, IEnumerable<ZDOID> instantiatedIds)
		{
			if ((Object)(object)hearth == (Object)null)
			{
				return new List<Record>();
			}
			Refresh();
			HashSet<ZDOID> liveIds = new HashSet<ZDOID>(instantiatedIds);
			return (from zdo in Cached
				where zdo.GetBool("hf_respawning", false) && BelongsTo(zdo, hearth) && !liveIds.Contains(zdo.m_uid)
				select new Record(zdo)).OrderBy<Record, string>((Record record) => record.Name, StringComparer.CurrentCultureIgnoreCase).ToList();
		}

		internal static void WakeExpired(ExilesHearth hearth)
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: 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_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: 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_0131: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)hearth == (Object)null || !hearth.IsNetworkOwner || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			Refresh();
			long now = DateTime.UtcNow.Ticks;
			int num = 0;
			foreach (ZDO item in Cached.Where((ZDO zdo) => zdo.GetBool("hf_respawning", false) && BelongsTo(zdo, hearth) && zdo.GetLong("hf_respawn_at", 0L) <= now))
			{
				if (!((Object)(object)ZNetScene.instance.FindInstance(item.m_uid) != (Object)null))
				{
					if (!item.HasOwner())
					{
						item.SetOwner(ZDOMan.GetSessionID());
					}
					if (item.IsOwner())
					{
						Vector3 position = ((Component)hearth).transform.position + ((Component)hearth).transform.right * (2.2f + (float)num * 0.65f) + Vector3.up * 0.5f;
						item.SetPosition(position);
						num++;
						Diagnostics.Log($"Hearthfolk[respawn]: waking unloaded settler ZDO {item.m_uid}");
					}
				}
			}
		}

		internal static void RecallDisconnectedFollowers(ExilesHearth hearth)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: 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_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)hearth == (Object)null || !hearth.IsNetworkOwner || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			Refresh();
			int num = 0;
			foreach (ZDO item in Cached.Where((ZDO zdo) => BelongsTo(zdo, hearth) && zdo.GetInt("hf_role", 0) == 5 && zdo.GetInt("hf_follower_mode", 0) == 1 && zdo.GetLong("hf_follower_target", 0L) != 0))
			{
				long num2 = item.GetLong("hf_follower_target", 0L);
				if (SettlerController.IsPlayerConnected(num2) || (Object)(object)ZNetScene.instance.FindInstance(item.m_uid) != (Object)null)
				{
					continue;
				}
				Vector3 vec = item.GetVec3("hf_home", ((Component)hearth).transform.position);
				if (!(Vector3.Distance(item.GetPosition(), vec) <= 6f) || !(item.GetString("hf_status", string.Empty) == "$hf_status_follower_waiting_for_player"))
				{
					if (!item.HasOwner())
					{
						item.SetOwner(ZDOMan.GetSessionID());
					}
					if (item.IsOwner())
					{
						Vector3 position = vec + ((Component)hearth).transform.right * (2.2f + (float)num * 0.65f) + Vector3.up * 0.5f;
						item.Set("hf_status", "$hf_status_follower_waiting_for_player");
						item.SetPosition(position);
						num++;
						Diagnostics.Log($"Hearthfolk[follower]: recalled unloaded settler ZDO {item.m_uid} " + $"while preserving player {num2}");
					}
				}
			}
		}

		private static bool BelongsTo(ZDO zdo, ExilesHearth hearth)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (zdo == null || !zdo.IsValid())
			{
				return false;
			}
			long num = zdo.GetLong("hf_owner", 0L);
			if (num != 0L && hearth.OwnerId != 0L && num != hearth.OwnerId)
			{
				return false;
			}
			return Vector3.Distance(zdo.GetVec3("hf_home", zdo.GetPosition()), ((Component)hearth).transform.position) <= 6f;
		}

		private static void Refresh()
		{
			if (!(Time.unscaledTime < _nextRefresh) && ZDOMan.instance != null)
			{
				_nextRefresh = Time.unscaledTime + 0.75f;
				List<ZDO> list = new List<ZDO>();
				int num = 0;
				bool flag = false;
				int num2 = 0;
				while (!flag && num2++ < 2048)
				{
					flag = ZDOMan.instance.GetAllZDOsWithPrefabIterative("hf_settler", list, ref num);
				}
				Cached.Clear();
				Cached.AddRange(from zdo in list
					where zdo != null && zdo.IsValid()
					group zdo by zdo.m_uid into @group
					select @group.First());
			}
		}
	}
	internal sealed class ExilesHearth : MonoBehaviour, Interactable, Hoverable
	{
		private sealed class SavedRouteEntry
		{
			internal ZDOID Id;

			internal Vector3 Position;

			internal string Prefab;

			internal long Creator;
		}

		internal static readonly List<ExilesHearth> Instances = new List<ExilesHearth>();

		private static readonly string[] SettlerNames = new string[12]
		{
			"Astrid", "Birger", "Eira", "Freydis", "Gorm", "Hakon", "Ingrid", "Kari", "Leif", "Runa",
			"Sigrid", "Torsten"
		};

		private ZNetView _nview;

		private Piece _piece;

		private float _nextDormantSettlerCheck;

		private List<Door> _availableGatewayCache;

		private float _availableGatewayCacheAt;

		private List<Container> _intakeStorageCache;

		private float _intakeStorageCacheUntil;

		internal ZDOID PersistentId
		{
			get
			{
				//IL_001b: 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)
				if (!((Object)(object)_nview != (Object)null) || !_nview.IsValid())
				{
					return ZDOID.None;
				}
				return _nview.GetZDO().m_uid;
			}
		}

		internal bool IsNetworkOwner
		{
			get
			{
				if ((Object)(object)_nview != (Object)null && _nview.IsValid())
				{
					return _nview.IsOwner();
				}
				return false;
			}
		}

		internal long OwnerId
		{
			get
			{
				if (!((Object)(object)_piece != (Object)null))
				{
					return 0L;
				}
				return _piece.GetCreator();
			}
		}

		internal bool AlertActive
		{
			get
			{
				if ((Object)(object)_nview != (Object)null && _nview.IsValid())
				{
					return _nview.GetZDO().GetBool("hf_settlement_alert", false);
				}
				return false;
			}
		}

		internal bool RaidActive => RaidAt(((Component)this).transform.position);

		internal bool DefenseThreatActive
		{
			get
			{
				if ((Object)(object)_nview != (Object)null && _nview.IsValid())
				{
					return _nview.GetZDO().GetLong("hf_defense_threat_until", 0L) > DateTime.UtcNow.Ticks;
				}
				return false;
			}
		}

		internal List<Vector3> PatrolRoute => PatrolPoint.RouteFor(this);

		internal int PatrolPointCount => PatrolRoute.Count;

		internal int AvailablePatrolPointCount => PatrolPoint.PointsFor(this).Count;

		internal List<PatrolPoint> AvailablePatrolPoints => PatrolPoint.PointsFor(this);

		internal bool PatrolRouteConfigured
		{
			get
			{
				if ((Object)(object)_nview != (Object)null && _nview.IsValid())
				{
					return _nview.GetZDO().GetBool("hf_patrol_route_configured", false);
				}
				return false;
			}
		}

		internal List<ZDOID> SavedPatrolRoute => ResolveSavedRoute("hf_patrol_route", "hf_patrol_route_identity", PatrolPoint.PointsFor(this).Select(PatrolRouteEntry), "patrol");

		internal List<ZDOID> CurrentPatrolRouteIds => PatrolPoint.RouteIdsFor(this);

		internal bool GatewayDoorsConfigured
		{
			get
			{
				if (!((Object)(object)_nview != (Object)null) || !_nview.IsValid() || !_nview.GetZDO().GetBool("hf_gateway_doors_configured", false))
				{
					return TaggedGatewayDoors().Count > 0;
				}
				return true;
			}
		}

		internal List<ZDOID> SavedGatewayDoorIds
		{
			get
			{
				List<ZDOID> list = ResolveSavedRoute("hf_gateway_doors", "hf_gateway_doors_identity", AvailableGatewayDoors.Select(GatewayRouteEntry), "gateway");
				List<Door> list2 = TaggedGatewayDoors();
				if (list.Count > 0)
				{
					if (list2.Count == 0 && (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner())
					{
						PersistGatewayMarkers(AvailableGatewayDoors, list);
					}
					return list;
				}
				if (list2.Count == 0)
				{
					return list;
				}
				List<ZDOID> list3 = list2.Select((Door door) => door.m_nview.GetZDO().m_uid).Distinct().Take(32)
					.ToList();
				if ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner())
				{
					ZDO zDO = _nview.GetZDO();
					zDO.Set("hf_gateway_doors", EncodePatrolRoute(list3));
					StoreRouteIdentity(zDO, "hf_gateway_doors_identity", list3, list2.Select(GatewayRouteEntry));
					zDO.Set("hf_gateway_doors_configured", true);
					Logger.LogInfo((object)$"Hearthfolk[gateway]: restored {list3.Count} entrance(s) from their door markers.");
				}
				return list3;
			}
		}

		internal List<Door> AvailableGatewayDoors
		{
			get
			{
				if (_availableGatewayCache == null || Time.time >= _availableGatewayCacheAt)
				{
					_availableGatewayCache = FindAvailableGatewayDoors();
					_availableGatewayCacheAt = Time.time + 1f;
				}
				return _availableGatewayCache;
			}
		}

		internal int AvailableGatewayDoorCount => AvailableGatewayDoors.Count;

		internal List<Door> ConfiguredGatewayDoors
		{
			get
			{
				Dictionary<ZDOID, Door> byId = AvailableGatewayDoors.Where((Door door) => (Object)(object)door?.m_nview != (Object)null && door.m_nview.IsValid()).ToDictionary((Door door) => door.m_nview.GetZDO().m_uid);
				return (from id in SavedGatewayDoorIds.Where(byId.ContainsKey)
					select byId[id]).ToList();
			}
		}

		internal ZDOID IntakeStorageId
		{
			get
			{
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				Container? obj = ResolveIntakeStorages().FirstOrDefault();
				ZDOID? obj2;
				if (obj == null)
				{
					obj2 = null;
				}
				else
				{
					ZNetView nview = obj.m_nview;
					obj2 = ((nview != null) ? new ZDOID?(nview.GetZDO().m_uid) : ((ZDOID?)null));
				}
				return (ZDOID)(((??)obj2) ?? ZDOID.None);
			}
		}

		internal bool HasIntakeStorage => ResolveIntakeStorages().Count > 0;

		internal int RecruitCost => Mathf.Max(0, HfConfig.RecruitCoins.Value);

		private void Awake()
		{
			_nview = ((Component)this).GetComponent<ZNetView>();
			_piece = ((Component)this).GetComponent<Piece>();
			if ((Object)(object)_nview != (Object)null && _nview.IsValid())
			{
				_nview.Register<long>("hf_ToggleSettlementAlert", (Action<long, long>)RPC_ToggleAlert);
				_nview.Register("hf_SignalDefenseThreat", (Action<long>)RPC_SignalDefenseThreat);
				_nview.Register<long, int, string>("hf_SetPatrolRoute", (Action<long, long, int, string>)RPC_SetPatrolRoute);
				_nview.Register<long, ZDOID>("hf_SetIntakeStorage", (Action<long, long, ZDOID>)RPC_SetIntakeStorage);
				_nview.Register<long, ZDOID, int>("hf_SetIntakeStorageRoles", (Action<long, long, ZDOID, int>)RPC_SetIntakeStorageRoles);
				_nview.Register<long, int, string>("hf_SetGatewayDoors", (Action<long, long, int, string>)RPC_SetGatewayDoors);
			}
			if (!Instances.Contains(this))
			{
				Instances.Add(this);
			}
		}

		private void OnDestroy()
		{
			Instances.Remove(this);
		}

		private void Update()
		{
			if (!(Time.time < _nextDormantSettlerCheck))
			{
				_nextDormantSettlerCheck = Time.time + 1f;
				DormantSettlerRegistry.WakeExpired(this);
				DormantSettlerRegistry.RecallDisconnectedFollowers(this);
			}
		}

		public string GetHoverName()
		{
			return Localization.instance.Localize("$piece_hf_hearth");
		}

		public string GetHoverText()
		{
			return Localization.instance.Localize("$piece_hf_hearth\n[<color=yellow><b>$KEY_Use</b></color>] $hf_manage");
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (!hold)
			{
				Player val = (Player)(object)((user is Player) ? user : null);
				if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
				{
					if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
					{
						return false;
					}
					long num = (((Object)(object)_piece != (Object)null) ? _piece.GetCreator() : 0);
					if (num != 0L && num != val.GetPlayerID())
					{
						((Character)val).Message((MessageType)2, "$msg_cantopen", 0, (Sprite)null);
						return true;
					}
					HearthPanel.Toggle(this);
					return true;
				}
			}
			return false;
		}

		internal void RequestToggleAlert()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && (Object)(object)_nview != (Object)null && _nview.IsValid())
			{
				_nview.InvokeRPC("hf_ToggleSettlementAlert", new object[1] { localPlayer.GetPlayerID() });
			}
		}

		private void RPC_ToggleAlert(long sender, long requesterId)
		{
			if (_nview.IsOwner() && (OwnerId == 0L || OwnerId == requesterId))
			{
				ZDO zDO = _nview.GetZDO();
				zDO.Set("hf_settlement_alert", !zDO.GetBool("hf_settlement_alert", false));
			}
		}

		internal void RequestSetPatrolRoute(IList<ZDOID> route)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)_nview == (Object)null) && _nview.IsValid())
			{
				_nview.InvokeRPC("hf_SetPatrolRoute", new object[3]
				{
					localPlayer.GetPlayerID(),
					1,
					EncodePatrolRoute(route)
				});
			}
		}

		internal void RequestAutomaticPatrolRoute()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)_nview == (Object)null) && _nview.IsValid())
			{
				_nview.InvokeRPC("hf_SetPatrolRoute", new object[3]
				{
					localPlayer.GetPlayerID(),
					0,
					string.Empty
				});
			}
		}

		private void RPC_SetPatrolRoute(long sender, long requesterId, int configured, string encodedRoute)
		{
			if (!_nview.IsOwner() || (OwnerId != 0L && OwnerId != requesterId))
			{
				return;
			}
			ZDO zDO = _nview.GetZDO();
			if (configured == 0)
			{
				zDO.Set("hf_patrol_route_configured", false);
				zDO.Set("hf_patrol_route", string.Empty);
				zDO.Set("hf_patrol_route_identity", string.Empty);
				return;
			}
			List<PatrolPoint> source = PatrolPoint.PointsFor(this);
			HashSet<ZDOID> validIds = new HashSet<ZDOID>(source.Select((PatrolPoint point) => point.PersistentId));
			List<ZDOID> list = (from id in DecodePatrolRoute(encodedRoute)
				where id != ZDOID.None && validIds.Contains(id)
				select id).Distinct().Take(64).ToList();
			zDO.Set("hf_patrol_route", EncodePatrolRoute(list));
			StoreRouteIdentity(zDO, "hf_patrol_route_identity", list, source.Select(PatrolRouteEntry));
			zDO.Set("hf_patrol_route_configured", true);
			Diagnostics.Log($"Hearthfolk[patrol]: saved {list.Count} persistent route point(s).");
		}

		internal void RequestSetGatewayDoors(IList<ZDOID> doors)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)_nview == (Object)null) && _nview.IsValid())
			{
				_nview.InvokeRPC("hf_SetGatewayDoors", new object[3]
				{
					localPlayer.GetPlayerID(),
					1,
					EncodePatrolRoute(doors)
				});
			}
		}

		internal void RequestAutomaticGatewayDoors()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)_nview == (Object)null) && _nview.IsValid())
			{
				_nview.InvokeRPC("hf_SetGatewayDoors", new object[3]
				{
					localPlayer.GetPlayerID(),
					0,
					string.Empty
				});
			}
		}

		private void RPC_SetGatewayDoors(long sender, long requesterId, int configured, string encodedDoors)
		{
			if (!_nview.IsOwner() || (OwnerId != 0L && OwnerId != requesterId))
			{
				return;
			}
			ZDO zDO = _nview.GetZDO();
			if (configured == 0)
			{
				ClearGatewayMarkers(AvailableGatewayDoors);
				zDO.Set("hf_gateway_doors_configured", false);
				zDO.Set("hf_gateway_doors", string.Empty);
				zDO.Set("hf_gateway_doors_identity", string.Empty);
				return;
			}
			List<Door> availableGatewayDoors = AvailableGatewayDoors;
			HashSet<ZDOID> validIds = new HashSet<ZDOID>(from door in availableGatewayDoors
				where (Object)(object)door?.m_nview != (Object)null && door.m_nview.IsValid()
				select door.m_nview.GetZDO().m_uid);
			List<ZDOID> list = (from id in DecodePatrolRoute(encodedDoors)
				where id != ZDOID.None && validIds.Contains(id)
				select id).Distinct().Take(32).ToList();
			if (list.Count != 0)
			{
				zDO.Set("hf_gateway_doors", EncodePatrolRoute(list));
				StoreRouteIdentity(zDO, "hf_gateway_doors_identity", list, availableGatewayDoors.Select(GatewayRouteEntry));
				zDO.Set("hf_gateway_doors_configured", true);
				PersistGatewayMarkers(availableGatewayDoors, list);
				Logger.LogInfo((object)$"Hearthfolk[gateway]: saved {list.Count} persistent entrance(s).");
			}
		}

		private List<Door> TaggedGatewayDoors()
		{
			return AvailableGatewayDoors.Where(GatewayMarkerMatches).ToList();
		}

		private bool GatewayMarkerMatches(Door door)
		{
			//IL_0058: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)door?.m_nview == (Object)null || !door.m_nview.IsValid())
			{
				return false;
			}
			ZDO zDO = door.m_nview.GetZDO();
			if (zDO.GetBool("hf_gateway_marker", false) && zDO.GetLong("hf_gateway_creator", 0L) == OwnerId)
			{
				return Vector3.Distance(zDO.GetVec3("hf_gateway_hearth", Vector3.zero), ((Component)this).transform.position) <= 0.75f;
			}
			return false;
		}

		private void PersistGatewayMarkers(IEnumerable<Door> available, ICollection<ZDOID> selected)
		{
			//IL_004f: 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_00cf: Unknown result type (might be due to invalid IL or missing references)
			HashSet<ZDOID> hashSet = new HashSet<ZDOID>(selected);
			foreach (Door item in available)
			{
				if ((Object)(object)item?.m_nview == (Object)null || !item.m_nview.IsValid())
				{
					continue;
				}
				ZDO zDO = item.m_nview.GetZDO();
				bool flag = hashSet.Contains(zDO.m_uid);
				if (flag || GatewayMarkerMatches(item))
				{
					if (!item.m_nview.IsOwner())
					{
						item.m_nview.ClaimOwnership();
					}
					if (!item.m_nview.IsOwner())
					{
						Logger.LogWarning((object)("Hearthfolk[gateway]: could not persist marker on " + ((Object)item).name + "; door is owned by another peer."));
						continue;
					}
					zDO = item.m_nview.GetZDO();
					zDO.Set("hf_gateway_marker", flag);
					zDO.Set("hf_gateway_hearth", flag ? ((Component)this).transform.position : Vector3.zero);
					zDO.Set("hf_gateway_creator", flag ? OwnerId : 0);
				}
			}
		}

		private void ClearGatewayMarkers(IEnumerable<Door> available)
		{
			PersistGatewayMarkers(available, new List<ZDOID>());
		}

		internal List<Container> ResolveIntakeStorages(Component self = null)
		{
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				return new List<Container>();
			}
			if (_intakeStorageCache == null || Time.time >= _intakeStorageCacheUntil)
			{
				_intakeStorageCache = (from container in SceneObjectCache.Get<Container>(1f)
					where (Object)(object)container != (Object)null && (Object)(object)container.m_nview != (Object)null && container.m_nview.IsValid() && ChestSortRules.IsStationaryPlayerChest(container) && container.m_nview.GetZDO().GetZDOID("hf_intake_hearth") == PersistentId && container.m_nview.GetZDO().GetInt("hf_intake_roles", 0) != 0
					select container).ToList();
				Container val = StorageLink.Resolve(_nview.GetZDO(), (Component)(object)this);
				if ((Object)(object)val != (Object)null && !_intakeStorageCache.Contains(val))
				{
					_intakeStorageCache.Add(val);
				}
				_intakeStorageCacheUntil = Time.time + 1f;
			}
			Vector3 origin = (((Object)(object)self != (Object)null) ? self.transform.position : ((Component)this).transform.position);
			return (from container in _intakeStorageCache
				where (Object)(object)container != (Object)null && ((Component)container).gameObject.activeInHierarchy
				orderby Vector3.Distance(origin, ((Component)container).transform.position)
				select container).ToList();
		}

		internal Container ResolveIntakeStorage(Component self = null)
		{
			SettlerController settlerController = self as SettlerController;
			IntakeRoles required = (((Object)(object)settlerController != (Object)null) ? IntakeRoleFor(settlerController.CurrentRole) : IntakeRoles.All);
			List<Container> source = ResolveIntakeStorages(self);
			if ((Object)(object)settlerController != (Object)null && settlerController.CurrentRole == SettlerRole.Caretaker)
			{
				return source.FirstOrDefault();
			}
			return ((IEnumerable<Container>)source).FirstOrDefault((Func<Container, bool>)((Container container) => (IntakeRolesFor(container) & required) != 0));
		}

		internal bool HasIntakeStorageFor(SettlerRole role)
		{
			if (role == SettlerRole.Caretaker)
			{
				return HasIntakeStorage;
			}
			IntakeRoles required = IntakeRoleFor(role);
			if (required != IntakeRoles.None)
			{
				return ResolveIntakeStorages().Any((Container container) => (IntakeRolesFor(container) & required) != 0);
			}
			return false;
		}

		internal IntakeRoles IntakeRolesFor(Container container)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)container?.m_nview == (Object)null || !container.m_nview.IsValid())
			{
				return IntakeRoles.None;
			}
			ZDO zDO = container.m_nview.GetZDO();
			if (zDO.GetZDOID("hf_intake_hearth") == PersistentId)
			{
				return (IntakeRoles)(zDO.GetInt("hf_intake_roles", 0) & 7);
			}
			if (!(StorageLink.GetId(_nview.GetZDO()) == zDO.m_uid))
			{
				return IntakeRoles.None;
			}
			return IntakeRoles.All;
		}

		internal void RequestSetIntakeStorage(Container container)
		{
			RequestSetIntakeStorageRoles(container, IntakeRoles.All);
		}

		internal void RequestSetIntakeStorageRoles(Container container, IntakeRoles roles)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)container?.m_nview == (Object)null) && container.m_nview.IsValid() && !((Object)(object)_nview == (Object)null) && _nview.IsValid() && !((Object)(object)IntakeCandidateFor(container, localPlayer.GetPlayerID()) != (Object)(object)this))
			{
				_nview.InvokeRPC("hf_SetIntakeStorageRoles", new object[3]
				{
					localPlayer.GetPlayerID(),
					container.m_nview.GetZDO().m_uid,
					(int)(roles & IntakeRoles.All)
				});
			}
		}

		private void RPC_SetIntakeStorage(long sender, long requesterId, ZDOID containerId)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner() && requesterId != 0L && (OwnerId == 0L || OwnerId == requesterId) && !((Object)(object)ZNetScene.instance == (Object)null))
			{
				GameObject val = ZNetScene.instance.FindInstance(containerId);
				Container val2 = (((Object)(object)val != (Object)null) ? (val.GetComponent<Container>() ?? val.GetComponentInChildren<Container>(true)) : null);
				if (ChestSortRules.IsStationaryPlayerChest(val2) && val2.CheckAccess(requesterId) && !((Object)(object)IntakeHearthWithinRange(val2, requesterId) != (Object)(object)this))
				{
					SetIntakeStorageRoles(val2, IntakeRoles.All);
				}
			}
		}

		private void RPC_SetIntakeStorageRoles(long sender, long requesterId, ZDOID containerId, int requestedRoles)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner() && requesterId != 0L && (OwnerId == 0L || OwnerId == requesterId) && !((Object)(object)ZNetScene.instance == (Object)null))
			{
				GameObject val = ZNetScene.instance.FindInstance(containerId);
				Container val2 = (((Object)(object)val != (Object)null) ? (val.GetComponent<Container>() ?? val.GetComponentInChildren<Container>(true)) : null);
				if (ChestSortRules.IsStationaryPlayerChest(val2) && val2.CheckAccess(requesterId) && !((Object)(object)IntakeHearthWithinRange(val2, requesterId) != (Object)(object)this))
				{
					SetIntakeStorageRoles(val2, (IntakeRoles)(requestedRoles & 7));
				}
			}
		}

		private void SetIntakeStorageRoles(Container container, IntakeRoles roles)
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)container?.m_nview == (Object)null) && container.m_nview.IsValid())
			{
				Container val = StorageLink.Resolve(_nview.GetZDO(), (Component)(object)this);
				if ((Object)(object)val?.m_nview != (Object)null && val.m_nview.IsValid() && (Object)(object)val != (Object)(object)container)
				{
					SetPhysicalIntakeRoles(val, IntakeRoles.All);
				}
				StorageLink.Clear(_nview.GetZDO());
				SetPhysicalIntakeRoles(container, roles);
				_intakeStorageCache = null;
				_intakeStorageCacheUntil = 0f;
				Diagnostics.Log($"Hearthfolk[storage]: intake chest {container.m_nview.GetZDO().m_uid} roles={(int)roles} hearth={PersistentId}");
			}
		}

		private void SetPhysicalIntakeRoles(Container container, IntakeRoles roles)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if (!container.m_nview.IsOwner())
			{
				container.m_nview.ClaimOwnership();
			}
			ZDO zDO = container.m_nview.GetZDO();
			if (roles == IntakeRoles.None)
			{
				if (zDO.GetZDOID("hf_intake_hearth") == PersistentId)
				{
					zDO.Set("hf_intake_hearth", ZDOID.None);
					zDO.Set("hf_intake_roles", 0);
				}
			}
			else
			{
				zDO.Set("hf_intake_hearth", PersistentId);
				zDO.Set("hf_intake_roles", (int)(roles & IntakeRoles.All));
			}
		}

		private static IntakeRoles IntakeRoleFor(SettlerRole role)
		{
			return role switch
			{
				SettlerRole.Lumberjack => IntakeRoles.Lumberjack, 
				SettlerRole.Miner => IntakeRoles.Miner, 
				SettlerRole.Farmer => IntakeRoles.Farmer, 
				_ => IntakeRoles.None, 
			};
		}

		private List<ZDOID> ResolveSavedRoute(string routeKey, string identityKey, IEnumerable<SavedRouteEntry> available, string label)
		{
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				return new List<ZDOID>();
			}
			ZDO zDO = _nview.GetZDO();
			List<ZDOID> list = DecodePatrolRoute(zDO.GetString(routeKey, string.Empty));
			if (list.Count == 0)
			{
				return list;
			}
			List<SavedRouteEntry> source = (from entry in available
				where entry != null && entry.Id != ZDOID.None
				group entry by entry.Id into @group
				select @group.First()).ToList();
			Dictionary<ZDOID, SavedRouteEntry> dictionary = source.ToDictionary((SavedRouteEntry entry) => entry.Id);
			Dictionary<ZDOID, SavedRouteEntry> dictionary2 = (from entry in DecodeRouteIdentity(zDO.GetString(identityKey, string.Empty))
				where entry != null && entry.Id != ZDOID.None
				group entry by entry.Id).ToDictionary((IGrouping<ZDOID, SavedRouteEntry> group) => group.Key, (IGrouping<ZDOID, SavedRouteEntry> group) => group.First());
			HashSet<ZDOID> used = new HashSet<ZDOID>();
			List<SavedRouteEntry> list2 = new List<SavedRouteEntry>();
			bool flag = false;
			foreach (ZDOID item in list)
			{
				SavedRouteEntry identity;
				if (dictionary.TryGetValue(item, out var value) && used.Add(value.Id))
				{
					list2.Add(value);
				}
				else if (dictionary2.TryGetValue(item, out identity) && !string.IsNullOrEmpty(identity.Prefab))
				{
					SavedRouteEntry savedRouteEntry = (from candidate in source
						where !used.Contains(candidate.Id) && candidate.Creator == identity.Creator && string.Equals(candidate.Prefab, identity.Prefab, StringComparison.Ordinal) && Vector3.Distance(candidate.Position, identity.Position) <= 0.85f
						orderby Vector3.Distance(candidate.Position, identity.Position)
						select candidate).FirstOrDefault();
					if (savedRouteEntry != null)
					{
						used.Add(savedRouteEntry.Id);
						list2.Add(savedRouteEntry);
						flag = true;
					}
				}
			}
			if (list2.Count == list.Count && _nview.IsOwner())
			{
				List<ZDOID> list3 = list2.Select((SavedRouteEntry entry) => entry.Id).ToList();
				if (flag || !list.SequenceEqual(list3))
				{
					zDO.Set(routeKey, EncodePatrolRoute(list3));
				}
				zDO.Set(identityKey, EncodeRouteIdentity(list2));
				if (flag)
				{
					Diagnostics.Log($"Hearthfolk[{label}]: restored {list2.Count} saved selection(s) after ZDO identity changed.");
				}
			}
			return list2.Select((SavedRouteEntry entry) => entry.Id).ToList();
		}

		private static void StoreRouteIdentity(ZDO zdo, string identityKey, IEnumerable<ZDOID> route, IEnumerable<SavedRouteEntry> available)
		{
			Dictionary<ZDOID, SavedRouteEntry> candidates = (from entry in available
				where entry != null && entry.Id != ZDOID.None
				group entry by entry.Id).ToDictionary((IGrouping<ZDOID, SavedRouteEntry> group) => group.Key, (IGrouping<ZDOID, SavedRouteEntry> group) => group.First());
			List<SavedRouteEntry> entries = (from id in route.Where(candidates.ContainsKey)
				select candidates[id]).ToList();
			zdo.Set(identityKey, EncodeRouteIdentity(entries));
		}

		private static SavedRouteEntry PatrolRouteEntry(PatrolPoint point)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)point == (Object)null)
			{
				return null;
			}
			Piece val = ((Component)point).GetComponent<Piece>() ?? ((Component)point).GetComponentInParent<Piece>();
			return new SavedRouteEntry
			{
				Id = point.PersistentId,
				Position = point.Position,
				Prefab = MaterialFilters.PrefabName(((Object)(object)val != (Object)null) ? ((Component)val).gameObject : ((Component)point).gameObject),
				Creator = (((Object)(object)val != (Object)null) ? val.GetCreator() : 0)
			};
		}

		private static SavedRouteEntry GatewayRouteEntry(Door door)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)door?.m_nview == (Object)null || !door.m_nview.IsValid())
			{
				return null;
			}
			Piece val = ((Component)door).GetComponent<Piece>() ?? ((Component)door).GetComponentInParent<Piece>();
			return new SavedRouteEntry
			{
				Id = door.m_nview.GetZDO().m_uid,
				Position = ((Component)door).transform.position,
				Prefab = MaterialFilters.PrefabName(((Object)(object)val != (Object)null) ? ((Component)val).gameObject : ((Component)door).gameObject),
				Creator = (((Object)(object)val != (Object)null) ? val.GetCreator() : 0)
			};
		}

		private static string EncodeRouteIdentity(IEnumerable<SavedRouteEntry> entries)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			List<SavedRouteEntry> list = entries?.Where((SavedRouteEntry entry) => entry != null).Take(64).ToList() ?? new List<SavedRouteEntry>();
			ZPackage val = new ZPackage();
			val.Write(1);
			val.Write(list.Count);
			foreach (SavedRouteEntry item in list)
			{
				val.Write(item.Id);
				val.Write(item.Position.x);
				val.Write(item.Position.y);
				val.Write(item.Position.z);
				val.Write(item.Prefab ?? string.Empty);
				val.Write(item.Creator);
			}
			return val.GetBase64();
		}

		private static List<SavedRouteEntry> DecodeRouteIdentity(string encoded)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			List<SavedRouteEntry> list = new List<SavedRouteEntry>();
			if (string.IsNullOrEmpty(encoded))
			{
				return list;
			}
			try
			{
				ZPackage val = new ZPackage(encoded);
				if (val.ReadInt() != 1)
				{
					return list;
				}
				int num = Mathf.Clamp(val.ReadInt(), 0, 64);
				for (int i = 0; i < num; i++)
				{
					list.Add(new SavedRouteEntry
					{
						Id = val.ReadZDOID(),
						Position = new Vector3(val.ReadSingle(), val.ReadSingle(), val.ReadSingle()),
						Prefab = val.ReadString(),
						Creator = val.ReadLong()
					});
				}
			}
			catch (Exception ex)
			{
				Diagnostics.Log("Hearthfolk[routing]: invalid saved identity: " + ex.Message);
				list.Clear();
			}
			return list;
		}

		internal static string EncodePatrolRoute(IEnumerable<ZDOID> route)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			List<ZDOID> list = route?.Where((ZDOID id) => id != ZDOID.None).Distinct().Take(64)
				.ToList() ?? new List<ZDOID>();
			ZPackage val = new ZPackage();
			val.Write(list.Count);
			foreach (ZDOID item in list)
			{
				val.Write(item);
			}
			return val.GetBase64();
		}

		internal static List<ZDOID> DecodePatrolRoute(string encoded)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_002c: 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_0033: 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_0042: 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)
			List<ZDOID> list = new List<ZDOID>();
			if (string.IsNullOrEmpty(encoded))
			{
				return list;
			}
			try
			{
				ZPackage val = new ZPackage(encoded);
				int num = Mathf.Clamp(val.ReadInt(), 0, 64);
				for (int i = 0; i < num; i++)
				{
					ZDOID val2 = val.ReadZDOID();
					if (val2 != ZDOID.None && !list.Contains(val2))
					{
						list.Add(val2);
					}
				}
			}
			catch (Exception ex)
			{
				Diagnostics.Log("Hearthfolk[patrol]: invalid saved route: " + ex.Message);
			}
			return list;
		}

		internal static bool AlertAt(Vector3 home, long ownerId)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			ExilesHearth exilesHearth = FindFor(home, ownerId);
			if ((Object)(object)exilesHearth != (Object)null)
			{
				return exilesHearth.AlertActive;
			}
			return false;
		}

		internal static bool DefenseThreatAt(Vector3 home, long ownerId)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			ExilesHearth exilesHearth = FindFor(home, ownerId);
			if ((Object)(object)exilesHearth != (Object)null)
			{
				return exilesHearth.DefenseThreatActive;
			}
			return false;
		}

		internal static void ReportSettlerAttack(Vector3 home, long ownerId, Character attacker)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (IsActualAttacker(attacker))
			{
				FindFor(home, ownerId)?.SignalDefenseThreat();
			}
		}

		internal static void ReportBaseDamage(WearNTear target, Character attacker)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)target == (Object)null) && !((Object)(object)target.m_piece == (Object)null) && target.m_piece.GetCreator() != 0L && IsActualAttacker(attacker))
			{
				ExilesHearth exilesHearth = NearestTo(((Component)target).transform.position, 0L);
				float num = Mathf.Max(18f, (HfConfig.WorkRadius != null) ? HfConfig.WorkRadius.Value : 30f);
				if ((Object)(object)exilesHearth != (Object)null && Utils.DistanceXZ(((Component)exilesHearth).transform.position, ((Component)target).transform.position) <= num)
				{
					exilesHearth.SignalDefenseThreat();
				}
			}
		}

		private static bool IsActualAttacker(Character attacker)
		{
			if ((Object)(object)attacker != (Object)null && !attacker.IsDead() && !attacker.IsTamed() && !(attacker is Player))
			{
				return (Object)(object)((Component)attacker).GetComponent<SettlerController>() == (Object)null;
			}
			return false;
		}

		private void SignalDefenseThreat()
		{
			if (!((Object)(object)_nview == (Object)null) && _nview.IsValid())
			{
				_nview.InvokeRPC("hf_SignalDefenseThreat", Array.Empty<object>());
			}
		}

		private void RPC_SignalDefenseThreat(long sender)
		{
			if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner())
			{
				_nview.GetZDO().Set("hf_defense_threat_until", DateTime.UtcNow.AddSeconds(12.0).Ticks);
				Diagnostics.Log("Hearthfolk[defense]: settlement is under attack");
			}
		}

		internal static bool RaidAt(Vector3 position)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)RandEventSystem.instance == (Object)null || position.y > 3000f)
			{
				return false;
			}
			RandomEvent currentRandomEvent = RandEventSystem.instance.GetCurrentRandomEvent();
			if (currentRandomEvent != null)
			{
				return Utils.DistanceXZ(position, currentRandomEvent.m_pos) < currentRandomEvent.m_eventRange;
			}
			return false;
		}

		internal static ExilesHearth FindFor(Vector3 home, long ownerId)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			return (from hearth in Instances
				where (Object)(object)hearth != (Object)null && (Object)(object)hearth._nview != (Object)null && hearth._nview.IsValid() && (ownerId == 0L || hearth.OwnerId == 0L || hearth.OwnerId == ownerId) && Vector3.Distance(((Component)hearth).transform.position, home) <= 6f
				orderby Vector3.Distance(((Component)hearth).transform.position, home)
				select hearth).FirstOrDefault();
		}

		internal static ExilesHearth NearestTo(Vector3 point, long ownerId)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			return (from hearth in Instances
				where (Object)(object)hearth != (Object)null && (Object)(object)hearth._nview != (Object)null && hearth._nview.IsValid() && (ownerId == 0L || hearth.OwnerId == 0L || hearth.OwnerId == ownerId)
				orderby Vector3.Distance(((Component)hearth).transform.position, point)
				select hearth).FirstOrDefault();
		}

		internal static ExilesHearth IntakeCandidateFor(Container container, long ownerId)
		{
			if (!ChestSortRules.CanConfigure(container, ownerId))
			{
				return null;
			}
			return IntakeHearthWithinRange(container, ownerId);
		}

		private static ExilesHearth IntakeHearthWithinRange(Container container, long ownerId)
		{
			//IL_0011: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)container == (Object)null)
			{
				return null;
			}
			ExilesHearth exilesHearth = NearestTo(((Component)container).transform.position, ownerId);
			float num = Mathf.Max(20f, (HfConfig.WorkRadius != null) ? HfConfig.WorkRadius.Value : 30f);
			if (!((Object)(object)exilesHearth != (Object)null) || !(Vector3.Distance(((Component)exilesHearth).transform.position, ((Component)container).transform.position) <= num))
			{
				return null;
			}
			return exilesHearth;
		}

		private List<Door> FindAvailableGatewayDoors()
		{
			float radius = Mathf.Max(20f, (HfConfig.WorkRadius != null) ? (HfConfig.WorkRadius.Value + 10f) : 40f);
			return (from door in SceneObjectCache.Get<Door>(1f).Where(delegate(Door door)
				{
					//IL_002f: 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)(object)door == (Object)null || (Object)(object)door.m_nview == (Object)null || !door.m_nview.IsValid() || Vector3.Distance(((Component)this).transform.position, ((Component)door).transform.position) > radius)
					{
						return false;
					}
					Piece val = ((Component)door).GetComponent<Piece>() ?? ((Component)door).GetComponentInParent<Piece>();
					long num = (((Object)(object)val != (Object)null) ? val.GetCreator() : 0);
					return (Object)(object)val != (Object)null && val.IsPlacedByPlayer() && (OwnerId == 0L || num == 0L || num == OwnerId);
				})
				group door by door.m_nview.GetZDO().m_uid into @group
				select @group.First() into door
				orderby Vector3.Distance(((Component)this).transform.position, ((Component)door).transform.position)
				select door).ToList();
		}

		internal void Recruit(Player player)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)_nview == (Object)null || !_nview.IsValid())
			{
				return;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			int recruitCost = RecruitCost;
			if (inventory.CountItems("$item_coins", -1, true) < recruitCost)
			{
				Message(player, "$hf_need_coins", recruitCost);
				return;
			}
			GameObject prefab = PrefabManager.Instance.GetPrefab("hf_settler");
			if ((Object)(object)prefab == (Object)null)
			{
				((Character)player).Message((MessageType)2, "$hf_prefab_missing", 0, (Sprite)null);
				return;
			}
			Vector3 val = ((Component)this).transform.position + ((Component)this).transform.forward * 2.2f + Vector3.up * 0.2f;
			GameObject val2 = Object.Instantiate<GameObject>(prefab, val, Quaternion.LookRotation(((Component)this).transform.forward));
			ZNetView component = val2.GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				if ((Object)(object)val2 != (Object)null)
				{
					Object.Destroy((Object)(object)val2);
				}
				((Character)player).Message((MessageType)2, "$hf_recruit_failed", 0, (Sprite)null);
				return;
			}
			inventory.RemoveItem("$item_coins", recruitCost, -1, true);
			string text = NextName();
			ZDO zDO = component.GetZDO();
			zDO.Set("hf_owner", player.GetPlayerID());
			zDO.Set("hf_home", ((Component)this).transform.position);
			zDO.Set("hf_name", text);
			zDO.Set("hf_role", 3);
			Message(player, "$hf_recruited", text);
		}

		public bool UseI