Decompiled source of LivingVillages v0.35.26

BepInEx/plugins/LivingVillages/LivingVillages.dll

Decompiled 10 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using LivingVillages.Planning;
using Microsoft.CodeAnalysis;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LivingVillages
{
	internal sealed class QuestCard
	{
		internal string Id;

		internal string Title;

		internal string Source;

		internal string Objectives;

		internal string Reward;
	}
	internal static class ActiveQuestCards
	{
		internal static List<QuestCard> Read(Player player)
		{
			List<QuestCard> list = new List<QuestCard>();
			QuestCard questCard = ElderQuest.ActiveCard(player);
			if (questCard != null)
			{
				list.Add(questCard);
			}
			RequestProgress pantry = VillageRequests.Read(player).Pantry;
			if (pantry.Stage == 1)
			{
				list.Add(new QuestCard
				{
					Id = "pantry",
					Title = "Stock the pantry",
					Source = "Village elder",
					Objectives = string.Format("{0}: {1}/10 delivered\n\n{2}: {3}/5 delivered", (pantry.Tier == 0) ? "Raspberries" : "Blueberries", pantry.First, (pantry.Tier == 0) ? "Honey" : "Yellow mushrooms", pantry.Second),
					Reward = ((pantry.Tier == 0) ? "50 gold • 150 XP" : "75 gold • 175 XP")
				});
			}
			VillageChainState villageChainState = VillageChains.Read(player);
			foreach (VillageChain item in from c in villageChainState.Chains
				orderby c.Village, c.Tier
				select c)
			{
				for (int num = 0; num < 5; num++)
				{
					if ((item.Accepted & (1 << num)) != 0 && (item.Done & (1 << num)) == 0)
					{
						list.Add(new QuestCard
						{
							Id = item.Village + "/" + item.Tier + "/" + num,
							Title = VillageChainCatalog.Roles[num] + " supplies",
							Source = VillageChainCatalog.Providers[num] + " • " + VillageChainCatalog.Tiers[item.Tier] + "\n" + VillageChains.VillageLabel(item.Village),
							Objectives = $"{VillageChains.ItemName(item.Tier, num)}\n\n{item.Delivered[num]} / {VillageChainCatalog.Counts[item.Tier][num]} delivered",
							Reward = (villageChainState.CanEarnSkill(num) ? ("+1 " + VillageChainCatalog.Roles[num] + "\n") : "") + $"{10 + item.Tier * 5} gold • {75 + item.Tier * 25} XP"
						});
					}
				}
			}
			return list;
		}
	}
	internal static class AnimalFeed
	{
		internal static VillageStock.Entry[] Register()
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			List<VillageStock.Entry> list = new List<VillageStock.Entry>
			{
				new VillageStock.Entry("LV_BoarCrate", 1, 100)
			};
			AnimalFeedDefinition[] all = AnimalFeedRules.All;
			foreach (AnimalFeedDefinition animalFeedDefinition in all)
			{
				GameObject val = PrefabManager.Instance.CreateClonedPrefab(animalFeedDefinition.Prefab, "Barley");
				SharedData shared = val.GetComponent<ItemDrop>().m_itemData.m_shared;
				shared.m_name = animalFeedDefinition.Name + " Specialty Feed (" + animalFeedDefinition.Stars + " star)";
				shared.m_description = "Aim at a tamed adult " + animalFeedDefinition.Name.ToLowerInvariant() + " and use this item from your hotbar. Ten portions upgrade a " + (animalFeedDefinition.Stars - 1) + "-star animal to " + animalFeedDefinition.Stars + " stars. Progress is saved on the animal. Not eaten automatically.";
				shared.m_itemType = (ItemType)1;
				shared.m_maxStackSize = 50;
				shared.m_weight = 0.2f;
				shared.m_value = 0;
				ItemManager.Instance.AddItem(new CustomItem(val, false));
				list.Add(new VillageStock.Entry(animalFeedDefinition.Prefab, 1, animalFeedDefinition.Price, animalFeedDefinition.Key));
			}
			return list.ToArray();
		}

		internal static string Species(Character animal)
		{
			if (!Object.op_Implicit((Object)(object)animal))
			{
				return "";
			}
			return Utils.GetPrefabName(((Component)animal).gameObject);
		}

		internal static bool Unlocked(AnimalFeedDefinition feed)
		{
			if (feed.Key.Length != 0)
			{
				if (Object.op_Implicit((Object)(object)ZoneSystem.instance))
				{
					return ZoneSystem.instance.GetGlobalKey(feed.Key);
				}
				return false;
			}
			return true;
		}

		internal static string ProgressKey(int stars)
		{
			return "lv_specialty_feed_" + stars;
		}

		internal static void Say(string text)
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "UseItem")]
	internal static class UseAnimalFeed
	{
		private static bool Prefix(Humanoid __instance, Inventory __0, ItemData __1)
		{
			object prefab;
			if (__1 == null)
			{
				prefab = null;
			}
			else
			{
				GameObject dropPrefab = __1.m_dropPrefab;
				prefab = ((dropPrefab != null) ? ((Object)dropPrefab).name : null);
			}
			AnimalFeedDefinition animalFeedDefinition = AnimalFeedRules.Find((string)prefab);
			if (animalFeedDefinition == null)
			{
				return true;
			}
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)AnimalFeedNetwork.Instance))
			{
				return false;
			}
			Player localPlayer = Player.m_localPlayer;
			if (__0 != null && __0 != ((Humanoid)localPlayer).GetInventory())
			{
				return false;
			}
			GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
			Character val = (Object.op_Implicit((Object)(object)hoverObject) ? hoverObject.GetComponentInParent<Character>() : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				AnimalFeed.Say("Aim at the animal before using its specialty feed.");
				return false;
			}
			AnimalFeedNetwork.Instance.Begin(localPlayer, val, __1, animalFeedDefinition);
			return false;
		}
	}
	[HarmonyPatch(typeof(Tameable), "GetHoverText")]
	internal static class AnimalFeedHover
	{
		private static void Postfix(Tameable __instance, ref string __result)
		{
			Character component = ((Component)__instance).GetComponent<Character>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsTamed() || component.IsDead())
			{
				return;
			}
			string species = AnimalFeed.Species(component);
			if (!Array.Exists(AnimalFeedRules.All, (AnimalFeedDefinition f) => f.Species == species))
			{
				return;
			}
			if (component.GetLevel() >= 3)
			{
				__result += "\nSpecialty feed: two-star maximum";
				return;
			}
			ZNetView component2 = ((Component)component).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component2) && component2.IsValid())
			{
				int level = component.GetLevel();
				int num = Mathf.Clamp(component2.GetZDO().GetInt(AnimalFeed.ProgressKey(level), 0), 0, 10);
				__result = __result + "\nSpecialty feed: " + num + "/" + 10 + " toward " + level + " stars";
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Awake")]
	internal static class AnimalFeedLevelWatcher
	{
		private static void Postfix(Character __instance)
		{
			if (Array.Exists(AnimalFeedRules.All, (AnimalFeedDefinition f) => f.Species == AnimalFeed.Species(__instance)))
			{
				((Component)__instance).gameObject.AddComponent<AnimalFeedLevelSync>();
			}
		}
	}
	public sealed class AnimalFeedLevelSync : MonoBehaviour
	{
		private static readonly FieldRef<Character, int> Level = AccessTools.FieldRefAccess<Character, int>("m_level");

		private Character animal;

		private ZNetView view;

		private void Awake()
		{
			animal = ((Component)this).GetComponent<Character>();
			view = ((Component)this).GetComponent<ZNetView>();
			((MonoBehaviour)this).InvokeRepeating("Refresh", 0.5f, 0.5f);
		}

		private void Refresh()
		{
			if (!Object.op_Implicit((Object)(object)animal) || !Object.op_Implicit((Object)(object)view) || !view.IsValid())
			{
				return;
			}
			int num = view.GetZDO().GetInt(ZDOVars.s_level, 1);
			if (num >= 1 && num != animal.GetLevel())
			{
				if (view.IsOwner())
				{
					animal.SetLevel(num);
					return;
				}
				Level.Invoke(animal) = num;
				animal.m_onLevelSet?.Invoke(num);
			}
		}
	}
	public sealed class AnimalFeedNetwork : MonoBehaviour
	{
		private sealed class Pending
		{
			internal string Ticket;

			internal string Prefab;

			internal string Rejection = "";

			internal long World;

			internal ZDOID Animal;

			internal string Serialize()
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: 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_0029: 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_0035: Unknown result type (might be due to invalid IL or missing references)
				ZPackage val = new ZPackage();
				val.Write(Ticket);
				val.Write(Prefab);
				val.Write(World);
				val.Write(Animal);
				val.Write(Rejection);
				return val.GetBase64();
			}

			internal static Pending Read(string data)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Expected O, but got Unknown
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				ZPackage val = new ZPackage(data);
				return new Pending
				{
					Ticket = val.ReadString(),
					Prefab = val.ReadString(),
					World = val.ReadLong(),
					Animal = val.ReadZDOID(),
					Rejection = val.ReadString()
				};
			}
		}

		internal static AnimalFeedNetwork Instance;

		private const string Request = "LV_AnimalFeed_Request";

		private const string Response = "LV_AnimalFeed_Response";

		private const string Missing = "LV_AnimalFeed_Missing";

		private const string Gone = "LV_AnimalFeed_Gone";

		private const string PendingKey = "lv_feed_pending_v1";

		private ZRoutedRpc registered;

		private float nextRetry;

		private void Awake()
		{
			Instance = this;
		}

		private void OnDestroy()
		{
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void Update()
		{
			if (ZRoutedRpc.instance != registered && ZRoutedRpc.instance != null)
			{
				registered = ZRoutedRpc.instance;
				registered.Register<ZPackage>("LV_AnimalFeed_Request", (Action<long, ZPackage>)Receive);
				registered.Register<ZPackage>("LV_AnimalFeed_Response", (Action<long, ZPackage>)Reply);
				registered.Register<ZPackage>("LV_AnimalFeed_Missing", (Action<long, ZPackage>)CheckMissing);
				registered.Register<ZPackage>("LV_AnimalFeed_Gone", (Action<long, ZPackage>)ConfirmMissing);
			}
			if (Time.unscaledTime < nextRetry)
			{
				return;
			}
			nextRetry = Time.unscaledTime + 2f;
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return;
			}
			Pending pending = Load(localPlayer);
			if (pending != null)
			{
				if (pending.Rejection.Length > 0)
				{
					Refund(localPlayer, pending);
				}
				else
				{
					Send(localPlayer, pending);
				}
			}
		}

		private static Pending Load(Player player)
		{
			if (!player.m_customData.TryGetValue("lv_feed_pending_v1", out var value))
			{
				return null;
			}
			try
			{
				return Pending.Read(value);
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Cannot read pending animal feed: " + ex.Message));
				return null;
			}
		}

		internal bool Begin(Player player, Character animal, ItemData item, AnimalFeedDefinition feed)
		{
			//IL_0077: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			if (player.m_customData.ContainsKey("lv_feed_pending_v1"))
			{
				AnimalFeed.Say("Waiting for the previous feeding to finish. Stay near that animal and leave room for a returned portion.");
				return false;
			}
			if (registered == null || !Object.op_Implicit((Object)(object)ZNet.instance) || ((Character)player).IsDead() || ((Character)player).InIntro() || !((Humanoid)player).GetInventory().ContainsItem(item))
			{
				return false;
			}
			ZNetView component = ((Component)animal).GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || animal.IsDead() || Vector3.Distance(((Component)player).transform.position, ((Component)animal).transform.position) > 5f)
			{
				return false;
			}
			if (!PrivateArea.CheckAccess(((Component)animal).transform.position, 0f, false, false))
			{
				return false;
			}
			string text = AnimalFeedRules.Validate(feed, AnimalFeed.Species(animal), animal.IsTamed(), animal.GetLevel(), AnimalFeed.Unlocked(feed));
			if (text.Length > 0)
			{
				AnimalFeed.Say(text);
				return false;
			}
			Pending pending = new Pending
			{
				Ticket = Guid.NewGuid().ToString("N"),
				Prefab = feed.Prefab,
				World = ZNet.instance.GetWorldUID(),
				Animal = component.GetZDO().m_uid
			};
			((Humanoid)player).GetInventory().RemoveOneItem(item);
			player.m_customData["lv_feed_pending_v1"] = pending.Serialize();
			Send(player, pending);
			return true;
		}

		private void Send(Player player, Pending pending)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			if (registered == null || pending.World != ZNet.instance.GetWorldUID())
			{
				return;
			}
			ZDOMan instance = ZDOMan.instance;
			ZDO val = ((instance != null) ? instance.GetZDO(pending.Animal) : null);
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
			{
				return;
			}
			if (val == null || val.GetOwner() == 0L)
			{
				ZPackage val2 = new ZPackage();
				val2.Write(pending.Ticket);
				val2.Write(pending.Animal);
				val2.Write(component.GetZDO().m_uid);
				long num = Server();
				if (num != 0L)
				{
					registered.InvokeRoutedRPC(num, "LV_AnimalFeed_Missing", new object[1] { val2 });
				}
			}
			else
			{
				ZPackage val3 = new ZPackage();
				val3.Write(pending.Ticket);
				val3.Write(pending.Prefab);
				val3.Write(pending.Animal);
				val3.Write(component.GetZDO().m_uid);
				registered.InvokeRoutedRPC(val.GetOwner(), "LV_AnimalFeed_Request", new object[1] { val3 });
			}
		}

		private void Receive(long sender, ZPackage p)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Expected O, but got Unknown
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string text = p.ReadString();
				string prefab = p.ReadString();
				ZDOID val = p.ReadZDOID();
				ZDOID val2 = p.ReadZDOID();
				if (!Guid.TryParseExact(text, "N", out var _) || AnimalFeedRules.Find(prefab) == null)
				{
					return;
				}
				ZDO zDO = ZDOMan.instance.GetZDO(val2);
				if (zDO == null || zDO.GetOwner() != sender)
				{
					return;
				}
				long num = zDO.GetLong("playerID", 0L);
				if (num == 0L)
				{
					return;
				}
				GameObject val3 = ZNetScene.instance.FindInstance(val);
				Character val4 = (Object.op_Implicit((Object)(object)val3) ? val3.GetComponent<Character>() : null);
				ZNetView val5 = (Object.op_Implicit((Object)(object)val4) ? ((Component)val4).GetComponent<ZNetView>() : null);
				if (!Object.op_Implicit((Object)(object)val5) || !val5.IsValid() || !val5.IsOwner())
				{
					return;
				}
				ZDO zDO2 = val5.GetZDO();
				string text2 = "lv_feed_receipt_" + num + "_" + text;
				string text3 = zDO2.GetString(text2, "");
				string text4;
				if (text3.StartsWith(text + "|", StringComparison.Ordinal))
				{
					text4 = text3.Substring(text.Length + 1);
				}
				else
				{
					AnimalFeedDefinition animalFeedDefinition = AnimalFeedRules.Find(prefab);
					text4 = AnimalFeedRules.Validate(animalFeedDefinition, AnimalFeed.Species(val4), val4.IsTamed(), val4.GetLevel(), AnimalFeed.Unlocked(animalFeedDefinition));
					if (val4.IsDead())
					{
						text4 = "This animal cannot be fed.";
					}
					if (Vector3.Distance(zDO.GetPosition(), ((Component)val4).transform.position) > 5f)
					{
						text4 = "Move closer to the animal.";
					}
					if (text4.Length == 0)
					{
						string text5 = AnimalFeed.ProgressKey(animalFeedDefinition.Stars);
						int num2 = AnimalFeedRules.NextProgress(zDO2.GetInt(text5, 0));
						zDO2.Set(text5, num2);
						if (num2 == 10)
						{
							val4.SetLevel(animalFeedDefinition.Stars + 1);
						}
						text4 = "OK:" + ((num2 == 10) ? (animalFeedDefinition.Name + " upgraded to " + animalFeedDefinition.Stars + " stars.") : ("Specialty feed: " + num2 + "/" + 10));
					}
					zDO2.Set(text2, text + "|" + text4);
				}
				ZPackage val6 = new ZPackage();
				val6.Write(text);
				val6.Write(val);
				val6.Write(text4);
				registered.InvokeRoutedRPC(sender, "LV_AnimalFeed_Response", new object[1] { val6 });
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Animal feed request failed: " + ex.Message));
			}
		}

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

		private void CheckMissing(long sender, ZPackage p)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_007a: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer())
			{
				return;
			}
			try
			{
				string text = p.ReadString();
				ZDOID val = p.ReadZDOID();
				ZDO zDO = ZDOMan.instance.GetZDO(p.ReadZDOID());
				if (Guid.TryParseExact(text, "N", out var _) && zDO != null && zDO.GetOwner() == sender && zDO.GetLong("playerID", 0L) != 0L && ZDOMan.instance.GetZDO(val) == null)
				{
					ZPackage val2 = new ZPackage();
					val2.Write(text);
					val2.Write(val);
					registered.InvokeRoutedRPC(sender, "LV_AnimalFeed_Gone", new object[1] { val2 });
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Animal feed status failed: " + ex.Message));
			}
		}

		private void ConfirmMissing(long sender, ZPackage p)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || sender != Server() || !Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				return;
			}
			try
			{
				string text = p.ReadString();
				ZDOID val = p.ReadZDOID();
				Player localPlayer = Player.m_localPlayer;
				Pending pending = Load(localPlayer);
				if (pending != null && !(pending.Ticket != text) && !(pending.Animal != val) && pending.World == ZNet.instance.GetWorldUID())
				{
					pending.Rejection = "The animal no longer exists.";
					localPlayer.m_customData["lv_feed_pending_v1"] = pending.Serialize();
					Refund(localPlayer, pending);
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Animal feed status response failed: " + ex.Message));
			}
		}

		private void Reply(long sender, ZPackage p)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_007b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				string text = p.ReadString();
				ZDOID val = p.ReadZDOID();
				string text2 = p.ReadString();
				Player localPlayer = Player.m_localPlayer;
				if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)ZNet.instance))
				{
					return;
				}
				Pending pending = Load(localPlayer);
				if (pending == null || pending.Ticket != text || pending.Animal != val || pending.World != ZNet.instance.GetWorldUID())
				{
					return;
				}
				ZDO zDO = ZDOMan.instance.GetZDO(val);
				if (zDO != null && zDO.GetOwner() == sender)
				{
					if (text2.StartsWith("OK:", StringComparison.Ordinal))
					{
						localPlayer.m_customData.Remove("lv_feed_pending_v1");
						AnimalFeed.Say(text2.Substring(3));
					}
					else
					{
						pending.Rejection = text2;
						localPlayer.m_customData["lv_feed_pending_v1"] = pending.Serialize();
						Refund(localPlayer, pending);
					}
				}
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("Animal feed response failed: " + ex.Message));
			}
		}

		private static void Refund(Player player, Pending pending)
		{
			GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab(pending.Prefab) : null);
			if (Object.op_Implicit((Object)(object)val) && ((Humanoid)player).GetInventory().CanAddItem(val, 1) && ((Humanoid)player).GetInventory().AddItem(val, 1))
			{
				player.m_customData.Remove("lv_feed_pending_v1");
				AnimalFeed.Say(pending.Rejection + " Feed returned.");
			}
		}
	}
	internal sealed class AnimalFeedDefinition
	{
		internal readonly string Species;

		internal readonly string Name;

		internal readonly string Key;

		internal readonly string Prefab;

		internal readonly int Stars;

		internal readonly int Price;

		internal AnimalFeedDefinition(string species, string name, int stars, string key)
		{
			Species = species;
			Name = name;
			Stars = stars;
			Key = key;
			Price = ((stars == 1) ? 25 : 50);
			Prefab = "LV_Feed_" + species + "_" + stars;
		}
	}
	internal static class AnimalFeedRules
	{
		internal const int Portions = 10;

		internal static readonly AnimalFeedDefinition[] All = new AnimalFeedDefinition[12]
		{
			new AnimalFeedDefinition("Boar", "Boar", 1, ""),
			new AnimalFeedDefinition("Boar", "Boar", 2, "defeated_eikthyr"),
			new AnimalFeedDefinition("Wolf", "Wolf", 1, "defeated_bonemass"),
			new AnimalFeedDefinition("Wolf", "Wolf", 2, "defeated_dragon"),
			new AnimalFeedDefinition("Lox", "Lox", 1, "defeated_dragon"),
			new AnimalFeedDefinition("Lox", "Lox", 2, "defeated_goblinking"),
			new AnimalFeedDefinition("Hen", "Hen", 1, "defeated_goblinking"),
			new AnimalFeedDefinition("Hen", "Hen", 2, "defeated_queen"),
			new AnimalFeedDefinition("Asksvin", "Asksvin", 1, "defeated_queen"),
			new AnimalFeedDefinition("Asksvin", "Asksvin", 2, "defeated_fader"),
			new AnimalFeedDefinition("Moose", "Moose", 1, "defeated_fader"),
			new AnimalFeedDefinition("Moose", "Moose", 2, "defeated_fader")
		};

		internal static AnimalFeedDefinition Find(string prefab)
		{
			return Array.Find(All, (AnimalFeedDefinition f) => f.Prefab == prefab);
		}

		internal static string Validate(AnimalFeedDefinition feed, string species, bool tame, int level, bool unlocked)
		{
			if (feed == null)
			{
				return "Unknown specialty feed.";
			}
			if (species != feed.Species)
			{
				return "Use this feed on an adult " + feed.Name.ToLowerInvariant() + ".";
			}
			if (!tame)
			{
				return "Tame this animal first.";
			}
			if (level >= 3)
			{
				return "This animal already has two stars.";
			}
			if (level != feed.Stars)
			{
				return "This feed requires a " + (feed.Stars - 1) + "-star animal.";
			}
			if (!unlocked)
			{
				return "Defeat the required boss in this world first.";
			}
			return "";
		}

		internal static int NextProgress(int progress)
		{
			return Math.Min(10, Math.Max(0, progress) + 1);
		}
	}
	internal static class AttributeBenefits
	{
		internal static readonly string[] Keys = new string[15]
		{
			"HealthPerRank", "HealthRegenPerSecondPerRank", "HealthPoisonResistancePercentPerRank", "StaminaPerRank", "StaminaCarryWeightPerRank", "StaminaRegenPerSecondPerRank", "StaminaPoisonResistancePercentPerRank", "WeaponDamagePercentPerRank", "StrengthCarryWeightPerRank", "ArmorPerRank",
			"StaggerCapacityPercentPerRank", "EitrPerRank", "EitrRegenPerSecondPerRank", "EitrRegenPerSecondCap", "PoisonResistancePercentCap"
		};

		internal static readonly float[] Defaults = new float[15]
		{
			2f, 0.08f, 2f, 2f, 8f, 0.4f, 2f, 1f, 5f, 1f,
			1f, 3f, 0.1f, 3.5f, 100f
		};

		internal static Func<int, float> ReadValue = null;

		private static readonly int[][] Groups = new int[5][]
		{
			new int[3] { 0, 1, 2 },
			new int[4] { 3, 4, 5, 6 },
			new int[2] { 7, 8 },
			new int[2] { 9, 10 },
			new int[2] { 11, 12 }
		};

		private static readonly string[] Units = new string[13]
		{
			"max health", "health/sec", "% poison resist", "max stamina", "carry", "stamina/sec", "% poison resist", "% weapon damage", "carry", "armor",
			"% stagger capacity", "max eitr", "eitr/sec"
		};

		internal static float Get(int key)
		{
			float num = ((ReadValue == null) ? Defaults[key] : ReadValue(key));
			if (float.IsNaN(num) || float.IsInfinity(num))
			{
				return Defaults[key];
			}
			return Math.Max(0f, Math.Min((key == 14) ? 100f : 10000f, num));
		}

		internal static int Rank(int rank)
		{
			return Math.Max(0, Math.Min(50, rank));
		}

		internal static float Total(int key, int rank)
		{
			return Get(key) * (float)Rank(rank);
		}

		internal static float Poison(int health, int stamina)
		{
			return Math.Min(Get(14), Total(2, health) + Total(6, stamina));
		}

		internal static float EitrRecovery(int rank)
		{
			return Math.Min(Get(13), Total(12, rank));
		}

		internal static bool BenefitEnabled(int key)
		{
			if (Get(key) > 0f && ((key != 2 && key != 6) || Get(14) > 0f))
			{
				if (key == 12)
				{
					return Get(13) > 0f;
				}
				return true;
			}
			return false;
		}

		internal static bool Enabled(int attribute)
		{
			int[] array = Groups[attribute];
			for (int i = 0; i < array.Length; i++)
			{
				if (BenefitEnabled(array[i]))
				{
					return true;
				}
			}
			return false;
		}

		internal static string Number(float value)
		{
			return value.ToString("0.####", CultureInfo.InvariantCulture);
		}

		internal static string Describe(int attribute, int rank = 1)
		{
			List<string> list = new List<string>();
			int[] array = Groups[attribute];
			foreach (int num in array)
			{
				if (BenefitEnabled(num))
				{
					float value = ((num == 12) ? EitrRecovery(rank) : Total(num, rank));
					string text = Units[num];
					list.Add("+" + Number(value) + (text.StartsWith("%") ? "" : " ") + text);
				}
			}
			return string.Join(", ", list);
		}

		internal static string Signature()
		{
			string[] array = new string[Defaults.Length];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = Get(i).ToString("R", CultureInfo.InvariantCulture);
			}
			return string.Join(";", array);
		}
	}
	internal static class AttributeConfiguration
	{
		internal static void Bind(ConfigFile config)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			ConfigEntry<float>[] entries = new ConfigEntry<float>[AttributeBenefits.Keys.Length];
			for (int i = 0; i < entries.Length; i++)
			{
				entries[i] = config.Bind<float>("Attribute Benefits", AttributeBenefits.Keys[i], AttributeBenefits.Defaults[i], new ConfigDescription(i switch
				{
					14 => "Maximum combined poison damage reduction from Health and Stamina, in percent. Applied after vanilla resistance. 0 disables attribute poison resistance.", 
					13 => "Maximum total bonus eitr regeneration per second. 0 disables bonus eitr regeneration.", 
					_ => "Bonus per purchased attribute rank. Regeneration values are per second; percentage values use 2 for 2 percent. 0 disables this benefit and hides its description.", 
				} + " Synchronized from the server in multiplayer.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, (float)((i == 14) ? 100 : 10000)), new object[1] { (object)new ConfigurationManagerAttributes
				{
					IsAdminOnly = true
				} }));
			}
			AttributeBenefits.ReadValue = (int index) => entries[index].Value;
		}
	}
	[HarmonyPatch(typeof(Character), "ApplyDamage")]
	internal static class AttributePoisonResistance
	{
		internal static float Percent(int health, int stamina)
		{
			return AttributeBenefits.Poison(health, stamina);
		}

		internal static void Prefix(Character __instance, HitData __0)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && __0 != null && !(__0.m_damage.m_poison <= 0f))
			{
				int[] ranks = PlayerAttributes.Read(val).Ranks;
				__0.m_damage.m_poison *= (100f - Percent(ranks[0], ranks[1])) / 100f;
			}
		}
	}
	internal static class RegenRates
	{
		internal static float Health(int rank)
		{
			return AttributeBenefits.Total(1, rank);
		}

		internal static float Stamina(int rank)
		{
			return AttributeBenefits.Total(5, rank);
		}

		internal static float Eitr(int rank)
		{
			return AttributeBenefits.EitrRecovery(rank);
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })]
	internal static class AttributeRegeneration
	{
		private sealed class Tick
		{
			internal double Time;

			internal double Health;

			internal int Rank = -1;

			internal float Rate = -1f;
		}

		private static readonly ConditionalWeakTable<Player, Tick> ticks = new ConditionalWeakTable<Player, Tick>();

		internal static void Postfix(Player __instance, float __0)
		{
			if (!Object.op_Implicit((Object)(object)__instance) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			Tick orCreateValue = ticks.GetOrCreateValue(__instance);
			if (((Character)__instance).IsDead() || ((Character)__instance).InIntro() || ((Character)__instance).IsTeleporting() || __0 <= 0f || float.IsNaN(__0) || float.IsInfinity(__0))
			{
				orCreateValue.Time = (orCreateValue.Health = 0.0);
				return;
			}
			int[] ranks = PlayerAttributes.Read(__instance).Ranks;
			float num = RegenRates.Health(ranks[0]);
			if (orCreateValue.Rank != ranks[0] || orCreateValue.Rate != num)
			{
				orCreateValue.Time = (orCreateValue.Health = 0.0);
				orCreateValue.Rank = ranks[0];
				orCreateValue.Rate = num;
			}
			if (((Character)__instance).GetHealth() >= ((Character)__instance).GetMaxHealth())
			{
				orCreateValue.Time = (orCreateValue.Health = 0.0);
			}
			else
			{
				orCreateValue.Time += __0;
				orCreateValue.Health += RegenRates.Health(ranks[0]) * __0;
				if (orCreateValue.Time >= 1.0)
				{
					if (orCreateValue.Health > 0.0)
					{
						((Character)__instance).Heal((float)orCreateValue.Health, false);
					}
					orCreateValue.Time = (orCreateValue.Health = 0.0);
				}
			}
			((Character)__instance).AddStamina(RegenRates.Stamina(ranks[1]) * __0);
			if (!((Character)__instance).InAttack() && !((Character)__instance).InDodge() && ((Character)__instance).GetMaxEitr() > 0f)
			{
				((Character)__instance).AddEitr(RegenRates.Eitr(ranks[4]) * __0);
			}
		}
	}
	public sealed class AttributeScreen : MonoBehaviour
	{
		internal static AttributeScreen Instance;

		internal ConfigEntry<KeyCode> ToggleKey;

		private Player owner;

		private AttributeRanks staged;

		private AttributeRanks baseline;

		private bool open;

		private NpcWindow window;

		private static readonly string[] Names = new string[5] { "Health", "Stamina", "Strength", "Defense", "Eitr" };

		private string settingsSignature;

		internal static bool IsOpen { get; private set; }

		private void Awake()
		{
			Instance = this;
		}

		internal void Close()
		{
			if (open)
			{
				GUIManager.BlockInput(false);
			}
			open = false;
			IsOpen = false;
			window?.Dispose();
			window = null;
		}

		private void OnDestroy()
		{
			Close();
		}

		private void OnDisable()
		{
			Close();
		}

		private void Update()
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead() || (Object.op_Implicit((Object)(object)owner) && (Object)(object)owner != (Object)(object)Player.m_localPlayer))
			{
				Close();
				owner = null;
				return;
			}
			if (open && settingsSignature != AttributeBenefits.Signature())
			{
				baseline = PlayerAttributes.Read(owner);
				staged = PlayerAttributes.Read(owner);
				Render();
			}
			if (open && Input.GetKeyDown((KeyCode)27))
			{
				Close();
			}
			else if (ToggleKey != null && Input.GetKeyDown(ToggleKey.Value))
			{
				Toggle();
			}
		}

		internal void Toggle()
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && !((Character)Player.m_localPlayer).IsDead())
			{
				if (open)
				{
					Close();
				}
				else if (!QuestJournal.IsOpen && !VillageChainScreen.IsOpen && !ForgeRepairScreen.IsOpen && !XpPartyScreen.IsOpen && !Console.IsVisible() && !TextInput.IsVisible() && !InventoryGui.IsVisible() && !StoreGui.IsVisible() && (!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()) && !Object.op_Implicit((Object)(object)BoarPlacement.Active) && !VillageRequestScreen.IsOpen)
				{
					owner = Player.m_localPlayer;
					baseline = PlayerAttributes.Read(owner);
					staged = PlayerAttributes.Read(owner);
					window = new NpcWindow("LV_Attributes");
					open = true;
					IsOpen = true;
					GUIManager.BlockInput(true);
					Render();
				}
			}
		}

		private void Render()
		{
			if (window == null || !Object.op_Implicit((Object)(object)owner))
			{
				return;
			}
			settingsSignature = AttributeBenefits.Signature();
			float scrollPosition = window.ScrollPosition;
			window.CompactMode = true;
			window.Clear("CHARACTER ATTRIBUTES");
			int available = PlayerAttributes.Budget(owner) - staged.Spent;
			window.Label($"Level {Experience.Read(owner).Level} / 50     Available points: {available}", 42f);
			for (int i = 0; i < 5; i++)
			{
				int attribute = i;
				window.Section(delegate
				{
					window.Label($"{Names[attribute]}   {baseline.Ranks[attribute]} → {staged.Ranks[attribute]}", 34f, 22f);
					bool flag = AttributeBenefits.Enabled(attribute);
					window.Label(flag ? (AttributeBenefits.Describe(attribute) + " per rank") : "Disabled by current settings", 44f);
					float cursor = window.Cursor;
					((Selectable)window.ButtonAt("−", delegate
					{
						if (staged.Ranks[attribute] > baseline.Ranks[attribute])
						{
							staged.Ranks[attribute]--;
						}
						Render();
					}, 36f, cursor, 90f, 36f)).interactable = staged.Ranks[attribute] > baseline.Ranks[attribute];
					int num = AttributeRanks.Cost(attribute, staged.Ranks[attribute] + 1);
					((Selectable)window.ButtonAt($"+ ({num} pts)", delegate
					{
						if (AttributeBenefits.Enabled(attribute) && staged.Ranks[attribute] < 50 && PlayerAttributes.Budget(owner) - staged.Spent >= AttributeRanks.Cost(attribute, staged.Ranks[attribute] + 1))
						{
							staged.Ranks[attribute]++;
						}
						Render();
					}, 140f, cursor, 180f, 36f)).interactable = flag && staged.Ranks[attribute] < 50 && available >= num;
					window.Space(42f);
				});
			}
			window.Section(delegate
			{
				for (int j = 0; j < 5; j++)
				{
					if (AttributeBenefits.Enabled(j))
					{
						window.Label(Names[j] + ": " + AttributeBenefits.Describe(j, staged.Ranks[j]), 50f);
					}
				}
				if (AttributeBenefits.Get(13) > 0f && AttributeBenefits.Get(12) > 0f)
				{
					window.Label("Eitr recovery cap: " + AttributeBenefits.Number(AttributeBenefits.Get(13)) + "/sec", 34f);
				}
				if (AttributeBenefits.Get(14) > 0f && (AttributeBenefits.Get(2) > 0f || AttributeBenefits.Get(6) > 0f))
				{
					window.Label("Combined poison reduction: " + AttributeBenefits.Number(AttributeBenefits.Poison(staged.Ranks[0], staged.Ranks[1])) + "% (cap " + AttributeBenefits.Number(AttributeBenefits.Get(14)) + "%)", 34f);
				}
				window.Button("Apply points", delegate
				{
					if (PlayerAttributes.Apply(owner, staged))
					{
						baseline = PlayerAttributes.Read(owner);
						staged = PlayerAttributes.Read(owner);
						((Character)owner).Message((MessageType)2, "Attribute points applied.", 0, (Sprite)null, false);
					}
					Render();
				}, staged.Spent > baseline.Spent && available >= 0);
				window.Button("Discard changes", delegate
				{
					baseline = PlayerAttributes.Read(owner);
					staged = PlayerAttributes.Read(owner);
					Render();
				});
			});
			window.FinishCompact(800f);
			window.ScrollPosition = scrollPosition;
		}
	}
	[HarmonyPatch(typeof(Character), "GetStaggerTreshold")]
	internal static class AttributeStagger
	{
		internal static void Postfix(Character __instance, ref float __result)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null)
			{
				__result *= 1f + AttributeBenefits.Total(10, PlayerAttributes.Read(val).Ranks[3]) / 100f;
			}
		}
	}
	internal static class AutomaticVillagePlanning
	{
		internal sealed class Reservation
		{
			internal Plan Plan;

			internal PlannedSurface Surface;

			internal ZDO Data;
		}

		internal sealed class FallbackCandidate
		{
			internal Plan Survey;

			internal double Score;
		}

		private static ZDOMan world;

		private static readonly Dictionary<Vector2s, Reservation> reservations = new Dictionary<Vector2s, Reservation>();

		internal static Reservation Constructing;

		internal static Func<bool> FallbackEnabled = () => false;

		internal static Func<bool> ForceFallbackTest = () => false;

		internal static Func<bool> HouseFallbackEnabled = () => false;

		internal static Func<double> VillageSearchSeconds = () => 30.0;

		internal static Func<double> HouseSearchSeconds = () => 6.0;

		private static readonly MethodInfo register = AccessTools.Method(typeof(ZoneSystem), "RegisterLocation", (Type[])null, (Type[])null);

		private static readonly MethodInfo generated = AccessTools.Method(typeof(ZoneSystem), "IsZoneGenerated", (Type[])null, (Type[])null);

		internal static IEnumerable<Reservation> Loaded
		{
			get
			{
				if (world != ZDOMan.instance)
				{
					return Enumerable.Empty<Reservation>();
				}
				return reservations.Values;
			}
		}

		internal static Plan FitHomes(Plan core, Func<bool> canContinue, bool relax)
		{
			Plan plan = OptionalHomePlanning.Extend(core, canContinue);
			if (!relax || plan.Layout.Homes.Length >= 2 || !canContinue())
			{
				return plan;
			}
			return OptionalHomePlanning.Extend(plan, canContinue, fallback: true);
		}

		internal static void RememberFallback(List<FallbackCandidate> candidates, Plan survey, double separation)
		{
			if (survey.Original == null || survey.Meadow == null || survey.Original.Length != 12769)
			{
				return;
			}
			double num = 0.0;
			for (int i = 0; i < survey.Original.Length; i++)
			{
				double num2 = survey.Original[i];
				if (double.IsNaN(num2) || double.IsInfinity(num2))
				{
					return;
				}
				if (i % 113 > 0)
				{
					num += Math.Abs(num2 - survey.Original[i - 1]);
				}
				if (i >= 113)
				{
					num += Math.Abs(num2 - survey.Original[i - 113]);
				}
			}
			double score = survey.Original.Max() - survey.Original.Min() + num / (double)survey.Original.Length;
			FallbackCandidate[] array = candidates.Where((FallbackCandidate c) => Math.Pow(c.Survey.WorldX - survey.WorldX, 2.0) + Math.Pow(c.Survey.WorldZ - survey.WorldZ, 2.0) < separation * separation).ToArray();
			if (!array.Any((FallbackCandidate c) => c.Score <= score))
			{
				FallbackCandidate[] array2 = array;
				foreach (FallbackCandidate item in array2)
				{
					candidates.Remove(item);
				}
				candidates.Add(new FallbackCandidate
				{
					Survey = survey,
					Score = score
				});
				candidates.Sort((FallbackCandidate a, FallbackCandidate b) => a.Score.CompareTo(b.Score));
				if (candidates.Count > 2)
				{
					candidates.RemoveAt(2);
				}
			}
		}

		internal static Limits FallbackLimits()
		{
			return new Limits
			{
				FastReject = true,
				Cut = 4.0,
				Fill = 4.0,
				RoadSlope = 0.28,
				CrossSlope = 0.14,
				BankSlope = 0.75
			};
		}

		internal static IEnumerator TryFallback(ZoneSystem zone, ZoneLocation location, List<FallbackCandidate> candidates, List<Reservation> fresh, double seconds = 8.0)
		{
			WorldGenerator generator = WorldGenerator.instance;
			ZDOMan manager = ZDOMan.instance;
			if (location.m_quantity <= 0 || zone.GetLocationList().Any((LocationInstance v) => v.m_location.m_prefabName == "LV_MeadowsHamlet"))
			{
				yield break;
			}
			Stopwatch clock = Stopwatch.StartNew();
			int maximum = Math.Min(2, location.m_quantity);
			Log($"No normal village found; retrying {candidates.Count} retained candidates with relaxed terrain limits (up to {maximum} villages, eight-second budget).");
			foreach (FallbackCandidate candidate in candidates)
			{
				if (fresh.Count >= maximum || clock.Elapsed.TotalSeconds >= seconds || WorldGenerator.instance != generator || ZDOMan.instance != manager)
				{
					yield break;
				}
				Plan survey = candidate.Survey;
				Vector3 center = new Vector3((float)survey.WorldX, 0f, (float)survey.WorldZ);
				float separation = Mathf.Max(1200f, location.m_minDistanceFromSimilar);
				if (!ClearReservation(zone, center, separation))
				{
					continue;
				}
				Task<Plan> task = Task.Run(() => Planner.Solve(survey.Layout, survey.Original, survey.Meadow, survey.Water, FallbackLimits()));
				while (!task.IsCompleted)
				{
					if (clock.Elapsed.TotalSeconds >= seconds || WorldGenerator.instance != generator || ZDOMan.instance != manager)
					{
						task.ContinueWith(delegate(Task<Plan> t)
						{
							_ = t.Exception;
						}, TaskContinuationOptions.OnlyOnFaulted);
						yield break;
					}
					yield return null;
				}
				if (clock.Elapsed.TotalSeconds >= seconds || WorldGenerator.instance != generator || ZDOMan.instance != manager)
				{
					yield break;
				}
				if (task.IsFaulted)
				{
					Log("Fallback fit failed: " + task.Exception.GetBaseException().Message);
					continue;
				}
				Plan result = task.GetAwaiter().GetResult();
				if (!result.Valid)
				{
					Log("Fallback candidate rejected: " + string.Join("; ", result.Reasons));
				}
				else if (ClearReservation(zone, center, separation))
				{
					result.WorldX = survey.WorldX;
					result.WorldZ = survey.WorldZ;
					result.Yaw = survey.Yaw;
					Reservation reservation = Reserve(zone, location, result);
					reservation.Data.Set("lv_fallback_plan", true);
					reservation.Data.Set("lv_fallback_reason", string.Join("; ", survey.Reasons));
					reservation.Data.Set("lv_fallback_forced", survey.Reasons.Contains("Debug test: normal reservation deliberately skipped"));
					fresh.Add(reservation);
					Log($"Reserved fallback village at X={result.WorldX:F1}, Z={result.WorldZ:F1}; cut={result.Cut:F2}, fill={result.Fill:F2}, road={result.RoadSlope:P1}.");
				}
			}
			Log($"Fallback finished: {fresh.Count}/{maximum} villages reserved. Optional houses will be checked separately.");
		}

		internal static void Load()
		{
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			if (world == ZDOMan.instance)
			{
				return;
			}
			ZDOMan instance = ZDOMan.instance;
			world = null;
			reservations.Clear();
			Constructing = null;
			if (instance == null)
			{
				return;
			}
			List<ZDO> list = new List<ZDO>();
			int num = 0;
			while (!instance.GetAllZDOsWithPrefabIterative("LV_TestPlannedTerrain", list, ref num))
			{
			}
			foreach (ZDO item in list)
			{
				if (!item.GetBool("lv_auto_plan", false))
				{
					continue;
				}
				PlannedSurface plannedSurface = PlannedSurface.Decode(item.GetByteArray("lv_plan_surface", (byte[])null));
				using MemoryStream input = new MemoryStream(item.GetByteArray("lv_plan_levels", (byte[])null));
				using BinaryReader binaryReader = new BinaryReader(input);
				int num2 = binaryReader.ReadInt32();
				Layout layout = OptionalHomePlanning.Decode(item.GetByteArray("lv_plan_homes", (byte[])null), num2);
				if (num2 != layout.Nodes.Length)
				{
					throw new InvalidDataException("Saved village platform count is incompatible.");
				}
				double[] array = new double[num2];
				for (int i = 0; i < num2; i++)
				{
					array[i] = binaryReader.ReadDouble();
					if (double.IsNaN(array[i]) || double.IsInfinity(array[i]))
					{
						throw new InvalidDataException("Invalid saved village platform height.");
					}
				}
				Vector3 position = item.GetPosition();
				OptionalHomePlanning.BindJunctions(layout, array);
				Plan plan = new Plan
				{
					Layout = layout,
					WorldX = position.x,
					WorldZ = position.z,
					Yaw = item.GetFloat("lv_plan_yaw", 0f),
					Levels = array,
					Heights = ((IEnumerable<float>)plannedSurface.Height).Select((Func<float, double>)((float h) => h)).ToArray(),
					Original = ((IEnumerable<float>)plannedSurface.Original).Select((Func<float, double>)((float h) => h)).ToArray(),
					Kind = (byte[])plannedSurface.Paint.Clone()
				};
				reservations[ZoneSystem.GetZone(position)] = new Reservation
				{
					Plan = plan,
					Surface = plannedSurface,
					Data = item
				};
			}
			world = instance;
			Log($"Loaded {reservations.Count} world-saved village plans.");
		}

		internal static Reservation Find(Vector3 position)
		{
			//IL_000a: 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)
			Load();
			if (!reservations.TryGetValue(ZoneSystem.GetZone(position), out var value))
			{
				return null;
			}
			return value;
		}

		private static Reservation Reserve(ZoneSystem zone, ZoneLocation location, Plan plan)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: 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_014a: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor((float)plan.WorldX, (float)plan.Levels[7], (float)plan.WorldZ);
			PlannedSurface plannedSurface = PlannedSurface.From(plan);
			using MemoryStream memoryStream = new MemoryStream();
			using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true))
			{
				binaryWriter.Write(plan.Levels.Length);
				double[] levels = plan.Levels;
				foreach (double value in levels)
				{
					binaryWriter.Write(value);
				}
			}
			ZDO val2 = world.CreateNewZDO(val, StringExtensionMethods.GetStableHashCode("LV_TestPlannedTerrain"));
			val2.SetPrefab(StringExtensionMethods.GetStableHashCode("LV_TestPlannedTerrain"));
			val2.Persistent = true;
			val2.SetRotation(Quaternion.Euler(0f, (float)plan.Yaw, 0f));
			val2.Set("lv_plan_surface", plannedSurface.Encode());
			val2.Set("lv_plan_levels", memoryStream.ToArray());
			val2.Set("lv_plan_yaw", (float)plan.Yaw);
			val2.Set("lv_auto_plan", true);
			Reservation reservation = new Reservation
			{
				Plan = plan,
				Surface = plannedSurface,
				Data = val2
			};
			reservations[ZoneSystem.GetZone(val)] = reservation;
			register.Invoke(zone, new object[3] { location, val, false });
			return reservation;
		}

		private static bool ClearReservation(ZoneSystem zone, Vector3 center, float separation)
		{
			//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_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_0022: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			foreach (LocationInstance location in zone.GetLocationList())
			{
				float num = Utils.DistanceXZ(center, location.m_position);
				float num2 = ((location.m_location.m_prefabName == "LV_MeadowsHamlet") ? separation : (80f + location.m_location.m_exteriorRadius));
				if (!(num < num2))
				{
					Vector2s zone2 = ZoneSystem.GetZone(center);
					if (!((Vector2s)(ref zone2)).Equals(ZoneSystem.GetZone(location.m_position)))
					{
						continue;
					}
				}
				return false;
			}
			for (int i = -1; i <= 1; i++)
			{
				for (int j = -1; j <= 1; j++)
				{
					if ((bool)generated.Invoke(zone, new object[1] { ZoneSystem.GetZone(center + new Vector3((float)(j * 64), 0f, (float)(i * 64))) }))
					{
						return false;
					}
				}
			}
			return true;
		}

		private static bool CoarseFit(WorldGenerator generator, Layout layout, Vector3 center, Quaternion rotation, float water)
		{
			//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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Invalid comparison between Unknown and I4
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			Pad[] pads = layout.Pads;
			foreach (Pad pad in pads)
			{
				float num = float.PositiveInfinity;
				float num2 = float.NegativeInfinity;
				for (int j = -1; j <= 1; j++)
				{
					for (int k = -1; k <= 1; k++)
					{
						Vector3 val = center + rotation * new Vector3((float)(pad.X + (double)j * pad.HalfX), 0f, (float)(pad.Z + (double)k * pad.HalfZ));
						if ((int)generator.GetBiome(val.x, val.z, 0.02f, false) != 1)
						{
							return false;
						}
						float height = generator.GetHeight(val.x, val.z);
						num = Mathf.Min(num, height);
						num2 = Mathf.Max(num2, height);
						if (num2 - num > 5f || height < water - 2f)
						{
							return false;
						}
					}
				}
			}
			return true;
		}

		internal static IEnumerator Search(ZoneSystem zone, ZoneLocation location, ZPackage iterations, double budgetSeconds = 30.0)
		{
			List<Reservation> fresh = new List<Reservation>();
			WorldGenerator generator = WorldGenerator.instance;
			ZDOMan manager = ZDOMan.instance;
			List<FallbackCandidate> candidates = ((FallbackEnabled() || ForceFallbackTest()) ? new List<FallbackCandidate>() : null);
			IEnumerator core = SearchCore(zone, location, iterations, budgetSeconds, fresh, candidates);
			try
			{
				while (core.MoveNext())
				{
					yield return core.Current;
				}
			}
			finally
			{
				IDisposable disposable = core as IDisposable;
				if (disposable != null)
				{
					disposable.Dispose();
				}
			}
			if (WorldGenerator.instance != generator || ZDOMan.instance != manager)
			{
				yield break;
			}
			if (fresh.Count == 0)
			{
				if (candidates != null)
				{
					{
						IEnumerator fallback = TryFallback(zone, location, candidates, fresh);
						try
						{
							while (fallback.MoveNext())
							{
								yield return fallback.Current;
							}
						}
						finally
						{
							IDisposable disposable2 = fallback as IDisposable;
							if (disposable2 != null)
							{
								disposable2.Dispose();
							}
						}
					}
				}
				if (fresh.Count == 0 || WorldGenerator.instance != generator || ZDOMan.instance != manager)
				{
					yield break;
				}
			}
			double houseBudget = Math.Max(0.0, HouseSearchSeconds());
			bool relaxHouses = HouseFallbackEnabled();
			Log($"Core search complete; checking optional houses ({houseBudget:F0}-second budget; relaxed house fallback={relaxHouses}).");
			Plan[] originals = fresh.Select((Reservation r) => r.Plan).ToArray();
			Task<Plan[]> task = Task.Run(delegate
			{
				Stopwatch clock = Stopwatch.StartNew();
				return originals.Select((Plan p) => FitHomes(p, () => clock.Elapsed.TotalSeconds < houseBudget, relaxHouses)).ToArray();
			});
			while (!task.IsCompleted)
			{
				if (WorldGenerator.instance != generator || ZDOMan.instance != manager)
				{
					task.ContinueWith(delegate(Task<Plan[]> t)
					{
						_ = t.Exception;
					}, TaskContinuationOptions.OnlyOnFaulted);
					yield break;
				}
				yield return null;
			}
			if (WorldGenerator.instance != generator || ZDOMan.instance != manager)
			{
				yield break;
			}
			if (task.IsFaulted)
			{
				Log("Optional house fitting failed; core villages retained: " + task.Exception.GetBaseException().Message);
				yield break;
			}
			Plan[] result = task.GetAwaiter().GetResult();
			for (int num = 0; num < fresh.Count; num++)
			{
				Reservation reservation = fresh[num];
				Plan plan = result[num];
				if (reservation.Data.GetBool("lv_plan_complete", false))
				{
					continue;
				}
				if (plan != originals[num])
				{
					PlannedSurface plannedSurface = PlannedSurface.From(plan);
					using MemoryStream memoryStream = new MemoryStream();
					using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true))
					{
						binaryWriter.Write(plan.Levels.Length);
						double[] levels = plan.Levels;
						foreach (double value in levels)
						{
							binaryWriter.Write(value);
						}
					}
					reservation.Data.Set("lv_plan_surface", plannedSurface.Encode());
					reservation.Data.Set("lv_plan_levels", memoryStream.ToArray());
					reservation.Data.Set("lv_plan_homes", OptionalHomePlanning.Encode(plan.Layout));
					reservation.Plan = plan;
					reservation.Surface = plannedSurface;
				}
				Log($"Optional houses at X={plan.WorldX:F1}, Z={plan.WorldZ:F1}: {plan.Layout.Homes.Length}/2; " + ((plan.Layout.Homes.Length == 0) ? "core village retained" : string.Join(", ", plan.Layout.Homes.Select((HomePlacement h) => $"{h.Name} [slot {h.Variant}]"))) + ".");
			}
		}

		private static IEnumerator SearchCore(ZoneSystem zone, ZoneLocation location, ZPackage iterations, double budgetSeconds, List<Reservation> fresh, List<FallbackCandidate> candidates)
		{
			int visited = 0;
			Stopwatch elapsed = Stopwatch.StartNew();
			try
			{
				Load();
				WorldGenerator generator = WorldGenerator.instance;
				ZDOMan manager = world;
				foreach (Reservation value3 in reservations.Values)
				{
					Vector3 position = value3.Data.GetPosition();
					if (!zone.GetLocationList().Any(delegate(LocationInstance v)
					{
						//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_0006: Unknown result type (might be due to invalid IL or missing references)
						//IL_000b: Unknown result type (might be due to invalid IL or missing references)
						//IL_000f: Unknown result type (might be due to invalid IL or missing references)
						//IL_0014: Unknown result type (might be due to invalid IL or missing references)
						Vector2s zone2 = ZoneSystem.GetZone(v.m_position);
						return ((Vector2s)(ref zone2)).Equals(ZoneSystem.GetZone(position));
					}))
					{
						register.Invoke(zone, new object[3]
						{
							location,
							position,
							value3.Data.GetBool("lv_plan_complete", false)
						});
					}
				}
				int wanted = Math.Max(0, Math.Min(6, location.m_quantity));
				int accepted = zone.GetLocationList().Count((LocationInstance v) => v.m_location.m_prefabName == "LV_MeadowsHamlet");
				if (accepted >= wanted)
				{
					yield break;
				}
				bool forceFallback = ForceFallbackTest();
				if (forceFallback && accepted > 0)
				{
					yield break;
				}
				if (forceFallback)
				{
					Log("DEBUG: normal reservations will be skipped to exercise fallback placement.");
				}
				Layout layout = Layout.Current();
				int solves = 0;
				int coarseRejected = 0;
				int occupied = 0;
				Dictionary<string, int> failures = new Dictionary<string, int>();
				Random random = new Random(generator.GetSeed() ^ 0x4C565031);
				double angleOffset = random.NextDouble() * Math.PI * 2.0;
				Log($"Automatic planned generation: {accepted}/{wanted} reserved; searching for one nearby village and separated outer Meadows villages.");
				for (float radius = Mathf.Max(200f, location.m_minDistance); radius <= 5500f; radius += 128f)
				{
					if (accepted >= wanted)
					{
						break;
					}
					if (solves >= 256)
					{
						break;
					}
					if ((accepted > 0 || (forceFallback && candidates != null && candidates.Count > 0)) && radius < 1500f)
					{
						continue;
					}
					int ringFits = 0;
					int points = Mathf.CeilToInt(MathF.PI * 2f * radius / 96f);
					for (int point = 0; point < points && accepted < wanted && solves < 256 && ringFits < 16; point++)
					{
						if (WorldGenerator.instance != generator || ZDOMan.instance != manager || elapsed.Elapsed.TotalSeconds >= budgetSeconds)
						{
							yield break;
						}
						double num = angleOffset + (double)point * 2.399963229728653;
						Vector3 center = new Vector3((float)Math.Cos(num) * radius, 0f, (float)Math.Sin(num) * radius);
						if (accepted > 0)
						{
							if (radius < 1500f)
							{
								break;
							}
							int sector = Sector(center);
							if (zone.GetLocationList().Any((LocationInstance v) => v.m_location.m_prefabName == "LV_MeadowsHamlet" && Utils.DistanceXZ(v.m_position, default(Vector3)) >= 1500f && Sector(v.m_position) == sector))
							{
								continue;
							}
						}
						visited++;
						if (visited % 8 == 0)
						{
							yield return null;
							if (WorldGenerator.instance != generator || ZDOMan.instance != manager || elapsed.Elapsed.TotalSeconds >= budgetSeconds)
							{
								yield break;
							}
						}
						if ((int)generator.GetBiome(center.x, center.z, 0.02f, false) != 1)
						{
							coarseRejected++;
							continue;
						}
						if (!ClearReservation(zone, center, Mathf.Max(1200f, location.m_minDistanceFromSimilar)))
						{
							occupied++;
							continue;
						}
						Dictionary<int, (double Height, bool Meadow)> sampleCache = new Dictionary<int, (double, bool)>();
						for (int turn = 0; turn < 4; turn++)
						{
							if (solves >= 256)
							{
								break;
							}
							if (ringFits >= 16)
							{
								break;
							}
							Quaternion rotation = Quaternion.Euler(0f, (float)(turn * 90), 0f);
							if (!CoarseFit(generator, layout, center, rotation, zone.m_waterLevel))
							{
								coarseRejected++;
								continue;
							}
							double[] heights = new double[12769];
							bool[] meadow = new bool[heights.Length];
							Stopwatch slice = Stopwatch.StartNew();
							for (int i = 0; i < heights.Length; i++)
							{
								int num2 = i % 113 - 56;
								int num3 = i / 113 - 56;
								int num4 = turn switch
								{
									2 => -num2, 
									1 => num3, 
									0 => num2, 
									_ => -num3, 
								};
								int num5 = turn switch
								{
									2 => -num3, 
									1 => -num2, 
									0 => num3, 
									_ => num2, 
								};
								int key = (num5 + 56) * 113 + num4 + 56;
								if (!sampleCache.TryGetValue(key, out (double, bool) value))
								{
									value = (generator.GetHeight(center.x + (float)num4, center.z + (float)num5), (int)generator.GetBiome(center.x + (float)num4, center.z + (float)num5, 0.02f, false) == 1);
									sampleCache.Add(key, value);
								}
								heights[i] = value.Item1;
								meadow[i] = value.Item2;
								if (i % 32 == 31 && slice.ElapsedMilliseconds >= 3)
								{
									yield return null;
									slice.Restart();
									if (WorldGenerator.instance != generator || ZDOMan.instance != manager || elapsed.Elapsed.TotalSeconds >= budgetSeconds)
									{
										yield break;
									}
								}
							}
							double water = zone.m_waterLevel;
							Stopwatch fitClock = Stopwatch.StartNew();
							Task<Plan> task = Task.Run(() => Planner.Solve(layout, heights, meadow, water, new Limits
							{
								FastReject = true
							}));
							while (!task.IsCompleted)
							{
								if (WorldGenerator.instance != generator || ZDOMan.instance != manager || elapsed.Elapsed.TotalSeconds >= budgetSeconds)
								{
									task.ContinueWith(delegate(Task<Plan> t)
									{
										_ = t.Exception;
									}, TaskContinuationOptions.OnlyOnFaulted);
									yield break;
								}
								yield return null;
							}
							if (WorldGenerator.instance != generator || ZDOMan.instance != manager || elapsed.Elapsed.TotalSeconds >= budgetSeconds)
							{
								yield break;
							}
							Plan result = task.GetAwaiter().GetResult();
							solves++;
							ringFits++;
							Log(string.Format("Fit {0}: {1} in {2:F0}ms; elapsed search {3:F1}s.", solves, result.Valid ? "accepted" : "rejected", fitClock.Elapsed.TotalMilliseconds, elapsed.Elapsed.TotalSeconds));
							if (!result.Valid)
							{
								if (candidates != null && accepted == 0)
								{
									result.WorldX = center.x;
									result.WorldZ = center.z;
									result.Yaw = turn * 90;
									RememberFallback(candidates, result, Mathf.Max(1200f, location.m_minDistanceFromSimilar));
								}
								foreach (string reason in result.Reasons)
								{
									string key2 = reason.Split(':')[0];
									failures[key2] = ((!failures.TryGetValue(key2, out var value2)) ? 1 : (value2 + 1));
								}
								if (solves % 10 == 0)
								{
									Log($"Search progress: {accepted}/{wanted} villages, {solves}/256 detailed fits, {visited} sites checked.");
								}
								continue;
							}
							result.WorldX = center.x;
							result.WorldZ = center.z;
							result.Yaw = turn * 90;
							if (forceFallback)
							{
								result.Reasons.Add("Debug test: normal reservation deliberately skipped");
								RememberFallback(candidates, result, Mathf.Max(1200f, location.m_minDistanceFromSimilar));
								if (candidates.Count < Math.Min(2, wanted))
								{
									break;
								}
								yield break;
							}
							fresh.Add(Reserve(zone, location, result));
							accepted++;
							Log($"Reserved planned village {accepted}/{wanted}: X={center.x:F1}, Z={center.z:F1}, yaw={result.Yaw:F0}, distance={radius:F0}m; cut={result.Cut:F2}, fill={result.Fill:F2}, road={result.RoadSlope:P1}.");
							break;
						}
						yield return null;
					}
					yield return null;
				}
				Log($"Automatic generation finished: {accepted}/{wanted} villages; {solves} detailed fits, {visited} sites, {coarseRejected} coarse rejects, {occupied} occupied/explored rejects. " + string.Join("; ", from p in failures.OrderByDescending((KeyValuePair<string, int> p) => p.Value).Take(6)
					select p.Key + "=" + p.Value));
				if (accepted == 0)
				{
					Log("No acceptable site found inside 5500m/search budget. Normal search has no reservations.");
				}
				int Sector(Vector3 p)
				{
					//IL_0000: 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)
					double num6 = Math.Atan2(p.z, p.x) - angleOffset;
					num6 = (num6 % (Math.PI * 2.0) + Math.PI * 2.0) % (Math.PI * 2.0);
					return Math.Min(4, (int)(num6 / (Math.PI * 2.0 / 5.0)));
				}
			}
			finally
			{
				if (elapsed.Elapsed.TotalSeconds >= budgetSeconds)
				{
					Log($"Village search time budget reached ({elapsed.Elapsed.TotalSeconds:F1}s); keeping accepted plans and continuing world loading. Any enabled fallback will be checked separately.");
				}
				iterations.Write(visited);
				iterations.SetPos(0);
			}
		}

		internal static void Log(string message)
		{
			Logger.LogInfo((object)("[Automatic village] " + message));
		}
	}
	[HarmonyPatch(typeof(ZoneSystem), "GenerateLocationsTimeSliced", new Type[]
	{
		typeof(ZoneLocation),
		typeof(Stopwatch),
		typeof(ZPackage)
	})]
	internal static class AutomaticVillageSearchHook
	{
		private static bool Prefix(ZoneSystem __instance, ZoneLocation __0, ZPackage __2, ref IEnumerator __result)
		{
			if (__0.m_prefabName != "LV_MeadowsHamlet")
			{
				return true;
			}
			__result = AutomaticVillagePlanning.Search(__instance, __0, __2, AutomaticVillagePlanning.VillageSearchSeconds());
			return false;
		}
	}
	public sealed class BarracksLinkAnchor : MonoBehaviour
	{
		public bool End;
	}
	[HarmonyPatch(typeof(TerrainModifier), "GetRadius")]
	internal static class BarracksLinkRadius
	{
		private static void Postfix(TerrainModifier __instance, ref float __result)
		{
			if (Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<BarracksLinkAnchor>()))
			{
				__result = 45f;
			}
		}
	}
	internal static class BarracksLink
	{
		internal static readonly Vector3[] Route = CreateRoute();

		private static Vector3[] CreateRoute()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			float[,] points = BarracksLinkProfile.Points;
			Vector3[] array = (Vector3[])(object)new Vector3[points.GetLength(0)];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = new Vector3(points[i, 0], 0f, points[i, 1]);
			}
			return array;
		}

		internal static void Register()
		{
			for (int i = 0; i < 2; i++)
			{
				string text = "LV_BarracksLink" + i;
				Plugin.RegisterGroundPatch(text, (PaintType)3, 0f);
				GameObject prefab = PrefabManager.Instance.GetPrefab(text);
				prefab.AddComponent<BarracksLinkAnchor>().End = i == 1;
				prefab.GetComponent<TerrainModifier>().m_paintCleared = false;
			}
		}

		internal static void Build(Transform parent)
		{
			//IL_000c: 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)
			VillageLayout.Place(parent, "LV_BarracksLink0", Route[0], 0f);
			VillageLayout.Place(parent, "LV_BarracksLink1", Route[Route.Length - 1], 0f);
		}
	}
	[HarmonyPatch(typeof(Heightmap), "ApplyModifiers")]
	internal static class GradeBarracksLink
	{
		[HarmonyPriority(0)]
		private static void Postfix(Heightmap __instance, List<float> ___m_heights, int ___m_width, float ___m_scale)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: 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_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: 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_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			List<TerrainModifier> allInstances = TerrainModifier.GetAllInstances();
			foreach (TerrainModifier item in allInstances)
			{
				if (!Object.op_Implicit((Object)(object)item) || !((Behaviour)item).isActiveAndEnabled)
				{
					continue;
				}
				BarracksLinkAnchor component = ((Component)item).GetComponent<BarracksLinkAnchor>();
				if (!Object.op_Implicit((Object)(object)component) || component.End)
				{
					continue;
				}
				Quaternion rotation = ((Component)item).transform.rotation;
				Vector3 val = ((Component)item).transform.position - rotation * BarracksLink.Route[0];
				Vector3 val2 = val + rotation * BarracksLink.Route[4];
				TerrainModifier val3 = null;
				foreach (TerrainModifier item2 in allInstances)
				{
					if (Object.op_Implicit((Object)(object)item2) && ((Behaviour)item2).isActiveAndEnabled)
					{
						BarracksLinkAnchor component2 = ((Component)item2).GetComponent<BarracksLinkAnchor>();
						if (Object.op_Implicit((Object)(object)component2) && component2.End && Utils.DistanceXZ(((Component)item2).transform.position, val2) < 0.2f)
						{
							val3 = item2;
							break;
						}
					}
				}
				if (!Object.op_Implicit((Object)(object)val3))
				{
					continue;
				}
				Vector3 position = ((Component)__instance).transform.position;
				if (Utils.DistanceXZ(position, ((Component)item).transform.position) > 95f)
				{
					continue;
				}
				Quaternion val4 = Quaternion.Inverse(rotation);
				float num = (float)___m_width * ___m_scale * 0.5f;
				for (int i = 0; i <= ___m_width; i++)
				{
					for (int j = 0; j <= ___m_width; j++)
					{
						Vector3 val5 = val4 * (new Vector3(position.x - num + (float)j * ___m_scale, val.y, position.z - num + (float)i * ___m_scale) - val);
						int index = i * (___m_width + 1) + j;
						___m_heights[index] = BarracksLinkProfile.Adjust(val5.x, val5.z, ___m_heights[index], ((Component)item).transform.position.y - position.y, ((Component)val3).transform.position.y - position.y);
					}
				}
			}
		}
	}
	internal static class BarracksLinkProfile
	{
		internal static readonly float[,] Points = new float[5, 2]
		{
			{ 10f, -4f },
			{ 10f, -9f },
			{ 24f, -9f },
			{ 32f, -5f },
			{ 32f, 2f }
		};

		internal static float Adjust(float x, float z, float before, float start, float end)
		{
			if (x <= 7f || (x >= 11.7f && x <= 18.3f && z >= -5.3f && z <= 7.3f) || (x >= 27.7f && x <= 36.3f && z >= 3.7f && z <= 24.3f))
			{
				return before;
			}
			double num = double.PositiveInfinity;
			double num2 = 0.0;
			double num3 = 0.0;
			for (int i = 1; i < Points.GetLength(0); i++)
			{
				double num4 = Points[i - 1, 0];
				double num5 = Points[i - 1, 1];
				double num6 = (double)Points[i, 0] - num4;
				double num7 = (double)Points[i, 1] - num5;
				double num8 = Math.Sqrt(num6 * num6 + num7 * num7);
				double num9 = Clamp((((double)x - num4) * num6 + ((double)z - num5) * num7) / (num8 * num8), 0.0, 1.0);
				double num10 = (double)x - num4 - num6 * num9;
				double num11 = (double)z - num5 - num7 * num9;
				double num12 = Math.Sqrt(num10 * num10 + num11 * num11);
				if (num12 < num)
				{
					num = num12;
					num2 = num3 + num9 * num8;
				}
				num3 += num8;
			}
			double num13 = 1.4 + 1.2 * Clamp((num2 / num3 - 0.75) * 4.0, 0.0, 1.0);
			if (num >= num13 + 4.0)
			{
				return before;
			}
			double v = (double)start + (double)(end - start) * Smooth((num2 - 1.0) / (num3 - 2.0));
			double num14 = (1.0 - Smooth((num - num13) / 4.0)) * Smooth((x - 7f) / 2f);
			return (float)((double)before + (Clamp(v, before - 2f, before + 2f) - (double)before) * num14);
		}

		private static double Clamp(double v, double min, double max)
		{
			return Math.Max(min, Math.Min(max, v));
		}

		private static double Smooth(double v)
		{
			v = Clamp(v, 0.0, 1.0);
			return v * v * (3.0 - 2.0 * v);
		}
	}
	internal enum BedroomDoorAction
	{
		None,
		Wait,
		Open,
		Close
	}
	internal sealed class BedroomDoorRoutine
	{
		private bool? target;

		private bool finished;

		internal BedroomDoorAction Tick(bool wantOpen, bool travelling, int state, bool openReady, bool closedReady)
		{
			if (target != wantOpen)
			{
				target = wantOpen;
				finished = false;
			}
			if (finished && !travelling)
			{
				return BedroomDoorAction.None;
			}
			if (wantOpen ? openReady : closedReady)
			{
				finished = true;
				return BedroomDoorAction.None;
			}
			finished = false;
			if (wantOpen && state == 0 && closedReady)
			{
				return BedroomDoorAction.Open;
			}
			if (!wantOpen && state != 0 && openReady)
			{
				return BedroomDoorAction.Close;
			}
			return BedroomDoorAction.Wait;
		}
	}
	public sealed class BenchSite : MonoBehaviour
	{
	}
	public sealed class BenchGrade : MonoBehaviour
	{
	}
	internal static class BenchTerrain
	{
		internal static void Build(Transform parent, Vector3 position, float yaw)
		{
			//IL_0005: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = new GameObject("BenchSite").transform;
			transform.SetParent(parent, false);
			transform.localPosition = position;
			transform.localRotation = Quaternion.Euler(0f, yaw, 0f);
			((Component)transform).gameObject.AddComponent<BenchSite>();
			VillageLayout.Place(transform, "LV_BenchGrade", Vector3.zero, 0f);
			SnapToGround component = VillageLayout.Place(transform, "LV_Green_piece_bench01", new Vector3(0f, 0.05f, 0f), 0f).GetComponent<SnapToGround>();
			if (Object.op_Implicit((Object)(object)component))
			{
				Object.DestroyImmediate((Object)(object)component);
			}
		}
	}
	[HarmonyPatch(typeof(Heightmap), "LevelTerrain")]
	internal static class LevelBenchFootprint
	{
		private static bool Prefix(Heightmap __instance, Vector3 __0, float __1, List<float> ___m_heights, int ___m_width, float ___m_scale)
		{
			//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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: 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_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			foreach (TerrainModifier allInstance in TerrainModifier.GetAllInstances())
			{
				if (Object.op_Implicit((Object)(object)allInstance) && ((Behaviour)allInstance).isActiveAndEnabled && Object.op_Implicit((Object)(object)((Component)allInstance).GetComponent<BenchGrade>()))
				{
					Vector3 val = ((Component)allInstance).transform.position - __0;
					if (((Vector3)(ref val)).sqrMagnitude < 0.001f)
					{
						flag = true;
						break;
					}
				}
			}
			if (!flag)
			{
				return true;
			}
			Vector3 position = ((Component)__instance).transform.position;
			float num = (float)___m_width * ___m_scale * 0.5f;
			for (int i = 0; i <= ___m_width; i++)
			{
				for (int j = 0; j <= ___m_width; j++)
				{
					float num2 = position.x - num + (float)j * ___m_scale - __0.x;
					float num3 = position.z - num + (float)i * ___m_scale - __0.z;
					float num4 = Mathf.Sqrt(num2 * num2 + num3 * num3);
					if (!(num4 >= __1))
					{
						float num5 = 1f - Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(1.6f, __1, num4));
						int index = i * (___m_width + 1) + j;
						___m_heights[index] = Mathf.Lerp(___m_heights[index], __0.y - position.y, num5);
					}
				}
			}
			return false;
		}
	}
	internal static class BlueprintHouse
	{
		internal sealed class Part
		{
			internal string Name;

			internal Vector3 Position;

			internal Vector3 Scale;

			internal Quaternion Rotation;
		}

		internal static readonly List<Part> Parts = Read();

		private static List<Part> Read()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: 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_011d: 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_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: 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_0133: 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_015b: 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_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: 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)
			//IL_018f: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			List<Part> list = new List<Part>();
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("LivingVillages.House.blueprint") ?? throw new InvalidOperationException("Missing embedded house blueprint.");
			using StreamReader streamReader = new StreamReader(stream);
			bool flag = false;
			Vector3 val = new Vector3(1f, 0f, -0.5f);
			Quaternion val2 = Quaternion.Euler(0f, 90f, 0f);
			int num = 0;
			string text;
			Vector3 val3 = default(Vector3);
			while ((text = streamReader.ReadLine()) != null)
			{
				string[] f;
				if (text == "#Pieces")
				{
					flag = true;
				}
				else
				{
					if (!flag || string.IsNullOrWhiteSpace(text) || text.StartsWith("#"))
					{
						continue;
					}
					f = text.Split(';');
					((Vector3)(ref val3))..ctor(N(2), N(3), N(4));
					if (f[0] == "wood_pole2")
					{
						Vector3 val4 = val3 - val;
						if (((Vector3)(ref val4)).sqrMagnitude < 0.0001f)
						{
							num++;
							continue;
						}
					}
					Part obj = new Part
					{
						Name = f[0],
						Position = val2 * (val3 - val) - Vector3.up
					};
					Quaternion val5 = new Quaternion(N(5), N(6), N(7), N(8));
					obj.Rotation = val2 * ((Quaternion)(ref val5)).normalized;
					obj.Scale = new Vector3(N(10), N(11), N(12));
					list.Add(obj);
				}
				float N(int i)
				{
					return float.Parse(f[i], CultureInfo.InvariantCulture);
				}
			}
			if (list.Count != 202 || num != 1)
			{
				throw new InvalidOperationException("Unexpected House02 piece count or merchant marker.");
			}
			return list;
		}

		internal static string PrefabId(string source, string role)
		{
			return "LV_House_" + role + "_" + source;
		}

		internal static void Register()
		{
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Expected O, but got Unknown
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Expected O, but got Unknown
			string[] array = new string[4] { "Elder", "Provisions", "Materials", "Harvest" };
			foreach (string role in array)
			{
				foreach (string item in Parts.Select((Part part) => part.Name).Concat(new string[1] { "wood_floor_1x1" }).Distinct())
				{
					string text = PrefabId(item, role);
					if (!Object.op_Implicit((Object)(object)PrefabManager.Instance.GetPrefab(text)))
					{
						GameObject val = PrefabManager.Instance.CreateClonedPrefab(text, item);
						if (!Object.op_Implicit((Object)(object)val))
						{
							throw new InvalidOperationException("Missing house source " + item);
						}
						val.GetComponent<ZNetView>().m_persistent = true;
						val.GetComponent<ZNetView>().m_syncInitialScale = true;
						val.AddComponent<VillageProperty>();
						if (item == "wood_door")
						{
							val.AddComponent<VillageBedroomDoor>();
						}
						WearNTear component = val.GetComponent<WearNTear>();
						if (Object.op_Implicit((Object)(object)component))
						{
							component.m_noRoofWear = true;
							component.m_noSupportWear = true;
						}
						if (Object.op_Implicit((Object)(object)val.GetComponent<ItemStand>()) || Object.op_Implicit((Object)(object)val.GetComponent<Sign>()))
						{
							val.AddComponent<ShopDisplay>().Role = role;
						}
						PrefabManager.Instance.AddPrefab(new CustomPrefab(val, false));
					}
				}
			}
			if (!Object.op_Implicit((Object)(object)PrefabManager.Instance.GetPrefab("LV_VillageCarrot")))
			{
				GameObject val2 = PrefabManager.Instance.CreateClonedPrefab("LV_VillageCarrot", "Pickable_Carrot");
				val2.AddComponent<VillageProperty>();
				val2.GetComponent<ZNetView>().m_persistent = true;
				PrefabManager.Instance.AddPrefab(new CustomPrefab(val2, false));
			}
		}

		internal static void Build(Transform parent, Vector3 origin, float yaw, string role, string npc, bool mirrored = false)
		{
			//IL_000b: 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_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = new GameObject("BlueprintHouse_" + role).transform;
			transform.SetParent(parent, false);
			transform.localPosition = origin;
			transform.localRotation = Quaternion.Euler(0f, yaw, 0f);
			ShelterFoundation shelterFoundation = ((Component)transform).gameObject.AddComponent<ShelterFoundation>();
			shelterFoundation.Blueprint = true;
			shelterFoundation.ExtendedHouse = true;
			shelterFoundation.Mirrored = mirrored;
			string text = (mirrored ? "LV_House02FillMirrorPlanned" : "LV_House02FillPlanned");
			GameObject obj = Object.Instantiate<GameObject>(PrefabManager.Instance.GetPrefab(text), transform);
			((Object)obj).name = text;
			obj.transform.localPosition = new Vector3(0f, -0.2f, 0f);
			obj.transform.localRotation = Quaternion.identity;
			shelterFoundation.EntranceGrades = (Transform[])(object)new Transform[8];
			for (int i = 0; i < shelterFoundation.EntranceGrades.Length; i++)
			{
				GameObject val = Object.Instantiate<GameObject>(PrefabManager.Instance.GetPrefab("LV_EntranceGrade"), transform);
				((Object)val).name = "LV_EntranceGrade";
				shelterFoundation.EntranceGrades[i] = val.transform;
			}
			foreach (Part part in Parts)
			{
				if ((role == "Harvest" || role == "Materials") && part.Name == "itemstand" && part.Position.x > 3f)
				{
					continue;
				}
				GameObject val2 = Object.Instantiate<GameObject>(PrefabManager.Instance.GetPrefab(PrefabId(part.Name, role)), transform);
				((Object)val2).name = PrefabId(part.Name, role);
				val2.transform.localPosition = part.Position;
				val2.transform.localRotation = part.Rotation;
				val2.transform.localScale = part.Scale;
				if (mirrored)
				{
					val2.transform.localPosition = Reflect(part.Position);
					val2.transform.localRotation = Quaternion.LookRotation(Reflect(part.Rotation * Vector3.forward), Reflect(part.Rotation * Vector3.up));
					if (part.Name != "sign" && part.Name != "itemstand")
					{
						val2.transform.localScale = new Vector3(0f - part.Scale.x, part.Scale.y, part.Scale.z);
					}
				}
				if (part.Name == "wood_pole2" && part.Position.y < -0.5f)
				{
					val2.AddComponent<FoundationPost>();
				}
				if (part.Name == "wood_stair")
				{
					shelterFoundation.Stairs = val2.transform;
				}
			}
			GameObject obj2 = Object.Instantiate<GameObject>(PrefabManager.Instance.GetPrefab(npc), transform);
			((Object)obj2).name = npc;
			obj2.transform.localPosition = new Vector3(0f, 0.15f, 0f);
			obj2.transform.localRotation = Quaternion.Euler(0f, (float)((!mirrored) ? 180 : 0), 0f);
			static Vector3 Reflect(Vector3 v)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				return new Vector3(v.x, v.y, 0f - v.z);
			}
		}
	}
	public sealed class BoarPlacement : MonoBehaviour
	{
		internal static BoarPlacement Active;

		internal static float BlockControlsUntil;

		private ItemData crate;

		private Player player;

		private GameObject preview;

		private Material material;

		private float ready;

		internal void Begin(Player owner, ItemData item)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			player = owner;
			crate = item;
			Active = this;
			ready = Time.time + 0.4f;
			preview = GameObject.CreatePrimitive((PrimitiveType)2);
			Object.Destroy((Object)(object)preview.GetComponent<Collider>());
			preview.transform.localScale = new Vector3(1.4f, 0.025f, 1.4f);
			Shader val = Shader.Find("Sprites/Default") ?? Shader.Find("Standard");
			material = new Material(val);
			preview.GetComponent<Renderer>().material = material;
			if (Object.op_Implicit((Object)(object)InventoryGui.instance))
			{
				InventoryGui.instance.Hide();
			}
			((Character)player).Message((MessageType)2, "Aim at clear ground. Left-click: place boar. Right-click/Escape: cancel.", 0, (Sprite)null, false);
		}

		private void OnDestroy()
		{
			BlockControlsUntil = Time.time + 0.2f;
			if (Object.op_Implicit((Object)(object)preview))
			{
				Object.Destroy((Object)(object)preview);
			}
			if (Object.op_Implicit((Object)(object)material))
			{
				Object.Destroy((Object)(object)material);
			}
			if ((Object)(object)Active == (Object)(object)this)
			{
				Active = null;
			}
		}

		private bool Position(out Vector3 point)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: 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_015b: 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)
			point = ((Component)player).transform.position;
			Camera main = Camera.main;
			RaycastHit val = default(RaycastHit);
			if (!Object.op_Implicit((Object)(object)main) || !Physics.Raycast(((Component)main).transform.position, ((Component)main).transform.forward, ref val, 15f, -1, (QueryTriggerInteraction)1))
			{
				return false;
			}
			point = ((RaycastHit)(ref val)).point;
			if (!Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Heightmap>()) || ((RaycastHit)(ref val)).normal.y < 0.85f || Vector3.Distance(((Component)player).transform.position, point) > 6f || point.y < ZoneSystem.instance.m_waterLevel + 0.3f || !PrivateArea.CheckAccess(point, 0f, false, false))
			{
				return false;
			}
			Collider[] array = Physics.OverlapCapsule(point + Vector3.up * 0.55f, point + Vector3.up * 1.2f, 0.5f, -1, (QueryTriggerInteraction)1);
			for (int i = 0; i < array.Length; i++)
			{
				if (!Object.op_Implicit((Object)(object)((Component)array[i]).GetComponentInParent<Heightmap>()))
				{
					return false;
				}
			}
			for (int j = -1; j <= 1; j++)
			{
				for (int k = -1; k <= 1; k++)
				{
					if (Mathf.Abs(ZoneSystem.instance.GetGroundHeight(point + new Vector3((float)j * 0.6f, 0f, (float)k * 0.6f)) - point.y) > 0.3f)
					{
						return false;
					}
				}
			}
			return true;
		}

		private void Update()
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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_00b8: 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_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || ((Character)player).IsDead() || !Object.op_Implicit((Object)(object)ZoneSystem.instance) || !((Humanoid)player).GetInventory().GetAllItems().Contains(crate))
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			if (Time.time >= ready && (Input.GetKeyDown((KeyCode)27) || Input.GetMouseButtonDown(1)))
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			Vector3 point;
			bool flag = Position(out point);
			preview.transform.position = point + Vector3.up * 0.05f;
			material.color = (flag ? Color.green : Color.red);
			if (Time.time < ready || !Input.GetMouseButtonDown(0))
			{
				return;
			}
			if (!flag)
			{
				((Character)player).Message((MessageType)2, "Choose clear, dry, level ground within six metres.", 0, (Sprite)null, false);
				return;
			}
			GameObject prefab = PrefabManager.Instance.GetPrefab("Boar");
			if (!Object.op_Implicit((Object)(object)prefab))
			{
				((Character)player).Message((MessageType)2, "Boar unavailable. Your crate has been kept.", 0, (Sprite)null, false);
				return;
			}
			GameObject val = Object.Instantiate<GameObject>(prefab, point + Vector3.up * 0.15f, ((Character)player).GetLookYaw());
			Character component = val.GetComponent<Character>();
			ZNetView component2 = val.GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component2) || !component2.IsValid() || !component2.IsOwner())
			{
				if (Object.op_Implicit((Object)(object)component2) && component2.IsValid())
				{
					component2.Destroy();
				}
				else
				{
					Object.Destroy((Object)(object)val);
				}
				return;