Decompiled source of VillageCompanion v0.18.2

plugins/VillageCompanion.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using SoftReferenceableAssets;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace VillageCompanion;

[BepInPlugin("local.valheim.villagecompanion", "Village Companion", "0.18.2")]
public sealed class Plugin : BaseUnityPlugin
{
	internal static Plugin Instance;

	internal ConfigEntry<float> Health;

	internal ConfigEntry<float> GuardRadius;

	internal ConfigEntry<float> LogInterval;

	private ConfigEntry<bool> AutoSpawn;

	private ConfigEntry<float> SpawnInterval;

	private ConfigEntry<float> SpawnChance;

	private ConfigEntry<int> SpawnLimit;

	private ConfigEntry<string> DefenderIconPreviewPath;

	internal ConfigEntry<float> SummonCooldown;

	internal ConfigEntry<float> BowDefenseRange;

	internal ConfigEntry<float> HaulBrushRadius;

	internal ConfigEntry<float> HaulDeliveryRange;

	internal ConfigEntry<int> PersistenceTestPhase;

	internal ConfigEntry<bool> BuildCreativeBase;

	internal ConfigEntry<float> MineOreSeconds;

	internal ConfigEntry<float> MineWorkSeconds;

	internal ConfigEntry<float> MineRestSeconds;

	internal ConfigEntry<float> KnockoutSeconds;

	internal ConfigEntry<float> KnockoutFeedSeconds;

	private float nextRuinAttempt;

	private GameObject template;

	private GameObject root;

	private ZNetScene registeredScene;

	internal readonly List<Villager> villagers = new List<Villager>();

	private void Awake()
	{
		//IL_0402: Unknown result type (might be due to invalid IL or missing references)
		//IL_0416: Expected O, but got Unknown
		//IL_0411: Unknown result type (might be due to invalid IL or missing references)
		//IL_069b: Unknown result type (might be due to invalid IL or missing references)
		//IL_06af: Expected O, but got Unknown
		//IL_06aa: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		DefenderIconPreviewPath = ((BaseUnityPlugin)this).Config.Bind<string>("Diagnostics", "DefenderIconPreviewPath", "", "Optional PNG export of the actual defender class icon; cleared after export.");
		Health = ((BaseUnityPlugin)this).Config.Bind<float>("Villager", "Health", 200f, "Starting health.");
		GuardRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Villager", "GuardRadius", 5f, "Idle wandering radius around the spawn/guard point in metres. Combat can leave this radius.");
		LogInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Diagnostics", "Interval", 10f, "Seconds between state logs; minimum 1.");
		AutoSpawn = ((BaseUnityPlugin)this).Config.Bind<bool>("NaturalSpawning", "Enabled", true, "Spawn only near surviving abandoned hut/town ruins in Meadows.");
		SpawnInterval = ((BaseUnityPlugin)this).Config.Bind<float>("NaturalSpawning", "Interval", 120f, "Seconds between ruin spawn attempts on the owning client.");
		SpawnChance = ((BaseUnityPlugin)this).Config.Bind<float>("NaturalSpawning", "Chance", 30f, "Percent chance per ruin spawn attempt.");
		SpawnLimit = ((BaseUnityPlugin)this).Config.Bind<int>("NaturalSpawning", "NearbyLimit", 2, "Maximum loaded villagers within 100 metres of a ruin.");
		SummonCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("SummonAnchor", "CooldownSeconds", 60f, "Cooldown per anchor after a successful summon. Minimum 1 second.");
		BowDefenseRange = ((BaseUnityPlugin)this).Config.Bind<float>("Villager", "BowDefenseRange", 30f, "Sight range in metres for turret-style bow defense; clamped to 5-60.");
		HaulBrushRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Hauling", "BrushRadius", 4f, "Radius in metres of the work-area paint brush; clamped to 2-10.");
		HaulDeliveryRange = ((BaseUnityPlugin)this).Config.Bind<float>("Hauling", "DeliveryRange", 60f, "Search for loaded marked chests this far from the painted work area.");
		MineOreSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Mining", "CopperOreSeconds", 600f, "Working seconds per miner for one copper/tin. Iron takes 2x, silver 3x, flametal 4.5x. Minimum 60; no offline catch-up.");
		MineWorkSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Mining", "WorkSeconds", 240f, "Seconds inside before resting outside. Minimum 30.");
		MineRestSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Mining", "RestSeconds", 60f, "Rest duration outside the mine. Minimum 10.");
		KnockoutSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Taming", "SleepSeconds", 600f, "One knockout arrow sleeps a wild tameable animal for this many world seconds; minimum 30.");
		KnockoutFeedSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Taming", "FeedCooldownSeconds", 10f, "Cooldown between hand feeds; minimum 1 second.");
		((Component)this).gameObject.AddComponent<CommandMenu>();
		((Component)this).gameObject.AddComponent<Tribes>();
		((Component)this).gameObject.AddComponent<SettlementNetwork>();
		if (((BaseUnityPlugin)this).Config.Bind<int>("Diagnostics", "RoutineExtraPhase", 0, "0 off; 1 role/miner checks, 2 saved settlement verification in VillagerFlatTest.").Value > 0)
		{
			((Component)this).gameObject.AddComponent<InGameRoutineExtraTests>();
		}
		((Component)this).gameObject.AddComponent<ChestFilterUI>();
		((Component)this).gameObject.AddComponent<VillagerClassUI>();
		((Component)this).gameObject.AddComponent<DevBuilderCatalogUI>();
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "RunRoutineTests", false, "One-time settlement routine checks in VillagerFlatTest.").Value)
		{
			((Component)this).gameObject.AddComponent<InGameRoutineTests>();
		}
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "CaptureGathererHut", false, "One-time capture of the hut beside the player in VillagerFlatTest.").Value)
		{
			((Component)this).gameObject.AddComponent<HutCaptureTest>();
		}
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "TestGathererHut", false, "One-time composite hut placement in VillagerFlatTest.").Value)
		{
			((Component)this).gameObject.AddComponent<HutPlacementTest>();
		}
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "TestGathererProduction", false, "One-time gatherer production checks in VillagerFlatTest.").Value)
		{
			((Component)this).gameObject.AddComponent<GathererProductionTest>();
		}
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "TestGathererReload", false, "One-time gatherer reload checks.").Value)
		{
			((Component)this).gameObject.AddComponent<GathererReloadTest>();
		}
		new ConsoleCommand("gathererhut", "capture [radius metres]: aim at hut to capture its build and nearby plants", (ConsoleEvent)delegate(ConsoleEventArgs args)
		{
			try
			{
				float result = 8f;
				if (args.Args.Length > 2 && !float.TryParse(args.Args[2], out result))
				{
					throw new ArgumentException("Use gathererhut capture 8");
				}
				if (args.Args.Length < 2 || args.Args[1] != "capture")
				{
					throw new ArgumentException("Use gathererhut capture 8");
				}
				GathererHut.Capture(result);
			}
			catch (Exception ex)
			{
				Log("Gatherer hut: " + ex.Message);
			}
		}, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "RunDevBuilderTests", false, "One-time developer builder checks in VillagerFlatTest.").Value)
		{
			((Component)this).gameObject.AddComponent<InGameDevBuilderTests>();
		}
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "RunDefenseTests", false, "One-time wall archers versus troll test in VillagerCreative.").Value)
		{
			((Component)this).gameObject.AddComponent<InGameDefenseTests>();
		}
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "RunAnimalTests", false, "One-time animal keeper checks in VillagerCreative.").Value)
		{
			((Component)this).gameObject.AddComponent<InGameAnimalTests>();
		}
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "RunClassTests", false, "One-time class menu tests in VillagerCreative.").Value)
		{
			((Component)this).gameObject.AddComponent<InGameClassTests>();
		}
		PersistenceTestPhase = ((BaseUnityPlugin)this).Config.Bind<int>("Diagnostics", "PersistenceTestPhase", 0, "Test-world only: 1 creates a saved checkpoint; 2 verifies it after restarting; 0 cleans up normal checks.");
		BuildCreativeBase = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "BuildCreativeBase", false, "One-time request: place a test room near the player in VillagerCreative, then reset this flag.");
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "RunInGameTests", false, "Run destructive integration checks in a disposable world; never enable in a normal save.").Value)
		{
			((Component)this).gameObject.AddComponent<InGameTests>();
		}
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "RunMineTests", false, "Run temporary miner integration checks in VillagerTest only.").Value)
		{
			((Component)this).gameObject.AddComponent<InGameMineTests>();
		}
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "RunBaseTests", false, "Build a small test cabin and exercise door pathing in VillagerTest only.").Value)
		{
			((Component)this).gameObject.AddComponent<InGameBaseTests>();
		}
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "CreativeTools", false, "Only in VillagerCreative: supply a hammer, enable free building, and prepare one persistent path-test follower with route logs.").Value)
		{
			((Component)this).gameObject.AddComponent<CreativeTestTools>();
		}
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "RunPatrolTests", false, "One-time patrol and player collision checks in VillagerCreative only.").Value)
		{
			((Component)this).gameObject.AddComponent<InGamePatrolTests>();
		}
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "RunKnockoutTests", false, "One-time knockout arrow, drag and feeding checks in VillagerCreative.").Value)
		{
			((Component)this).gameObject.AddComponent<InGameKnockoutTests>();
		}
		if (((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "RunFarmTests", false, "One-time farmer and wild gathering integration checks in VillagerCreative.").Value)
		{
			((Component)this).gameObject.AddComponent<InGameFarmTests>();
		}
		new ConsoleCommand("villager", "spawn [name] | follow | guard | carry | place | collect on/off | give [prefab] | unload | status | remove", new ConsoleEvent(Command), false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Village Companion loaded. Console: villager spawn. Experimental; use a test world.");
	}

	internal void Log(string message)
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)message);
	}

	private void Update()
	{
		string value = DefenderIconPreviewPath.Value;
		if (value != "" && (Object)(object)ObjectDB.instance != (Object)null && (Object)(object)ObjectDB.instance.GetItemPrefab("ShieldWood") != (Object)null)
		{
			Sprite val = VillagerClasses.DefenderIcon();
			if ((Object)(object)val != (Object)null)
			{
				File.WriteAllBytes(value, ImageConversion.EncodeToPNG(val.texture));
				DefenderIconPreviewPath.Value = "";
				((BaseUnityPlugin)this).Config.Save();
				Log("Defender shield/spear icon exported: " + value);
			}
		}
		if ((Object)(object)ZNetScene.instance == (Object)null)
		{
			registeredScene = null;
		}
		else
		{
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			EnsureRegistration();
			if ((Object)(object)template != (Object)null && AutoSpawn.Value && (Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)ZoneSystem.instance != (Object)null && Time.time >= nextRuinAttempt)
			{
				nextRuinAttempt = Time.time + Mathf.Max(10f, SpawnInterval.Value);
				try
				{
					RuinSpawning.TrySpawn(this, Mathf.Clamp(SpawnChance.Value, 0f, 100f), Mathf.Clamp(SpawnLimit.Value, 1, 20));
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Ruin spawning failed: " + ex));
				}
			}
		}
	}

	internal void EnsureRegistration()
	{
		if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null || (Object)(object)registeredScene == (Object)(object)ZNetScene.instance || (Object)(object)ObjectDB.instance.GetItemPrefab("Club") == (Object)null)
		{
			return;
		}
		try
		{
			Register();
			registeredScene = ZNetScene.instance;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Prefab setup failed: " + ex));
		}
	}

	private static void CopyFields(Component source, Component target, Type type)
	{
		FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
		foreach (FieldInfo fieldInfo in fields)
		{
			if (!fieldInfo.IsInitOnly && !(fieldInfo.Name == "m_nViewOverride"))
			{
				fieldInfo.SetValue(target, fieldInfo.GetValue(source));
			}
		}
	}

	private void Register()
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Expected O, but got Unknown
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_024b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0255: Expected O, but got Unknown
		//IL_0257: Unknown result type (might be due to invalid IL or missing references)
		//IL_0261: Expected O, but got Unknown
		//IL_0263: Unknown result type (might be due to invalid IL or missing references)
		//IL_026d: Expected O, but got Unknown
		//IL_026f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0279: Expected O, but got Unknown
		if ((Object)(object)root != (Object)null)
		{
			Object.Destroy((Object)(object)root);
		}
		root = new GameObject("VillageCompanion_Templates");
		root.SetActive(false);
		Object.DontDestroyOnLoad((Object)(object)root);
		GameObject prefab = ZNetScene.instance.GetPrefab("Player");
		GameObject prefab2 = ZNetScene.instance.GetPrefab("Skeleton");
		if ((Object)(object)prefab == (Object)null || (Object)(object)prefab2 == (Object)null)
		{
			throw new Exception("Player or Skeleton prefab missing.");
		}
		template = Object.Instantiate<GameObject>(prefab, root.transform, false);
		((Object)template).name = "VC_Villager";
		Player component = template.GetComponent<Player>();
		Humanoid val = template.AddComponent<Humanoid>();
		CopyFields((Component)(object)component, (Component)(object)val, typeof(Character));
		CopyFields((Component)(object)component, (Component)(object)val, typeof(Humanoid));
		Object.DestroyImmediate((Object)(object)component);
		Component component2 = template.GetComponent("PlayerController");
		if ((Object)(object)component2 != (Object)null)
		{
			Object.DestroyImmediate((Object)(object)component2);
		}
		((Character)val).m_name = "Villager";
		((Character)val).m_faction = (Faction)0;
		((Character)val).m_health = Mathf.Max(1f, Health.Value);
		val.m_randomWeapon = (GameObject[])(object)new GameObject[0];
		val.m_randomArmor = (GameObject[])(object)new GameObject[0];
		val.m_randomShield = (GameObject[])(object)new GameObject[0];
		val.m_randomSets = (ItemSet[])(object)new ItemSet[0];
		val.m_randomItems = (RandomItem[])(object)new RandomItem[0];
		val.m_defaultItems = (GameObject[])(object)new GameObject[3]
		{
			ObjectDB.instance.GetItemPrefab("Club"),
			ObjectDB.instance.GetItemPrefab("ArmorRagsChest"),
			ObjectDB.instance.GetItemPrefab("ArmorRagsLegs")
		};
		VisEquipment component3 = template.GetComponent<VisEquipment>();
		if ((Object)(object)component3 != (Object)null)
		{
			component3.m_isPlayer = false;
			component3.m_playerComponent = null;
		}
		MonsterAI val2 = template.AddComponent<MonsterAI>();
		CopyFields((Component)(object)prefab2.GetComponent<MonsterAI>(), (Component)(object)val2, typeof(BaseAI));
		CopyFields((Component)(object)prefab2.GetComponent<MonsterAI>(), (Component)(object)val2, typeof(MonsterAI));
		((BaseAI)val2).m_idleSound = new EffectList();
		((BaseAI)val2).m_alertedEffects = new EffectList();
		val2.m_wakeupEffects = new EffectList();
		val2.m_sleepEffects = new EffectList();
		val2.m_attackPlayerObjects = false;
		val2.m_enableHuntPlayer = false;
		((BaseAI)val2).m_randomMoveRange = Mathf.Max(1f, GuardRadius.Value);
		((BaseAI)val2).m_viewRange = Mathf.Max(15f, GuardRadius.Value);
		((BaseAI)val2).m_afraidOfFire = false;
		((BaseAI)val2).m_avoidFire = false;
		val2.m_sleeping = false;
		ZNetView component4 = template.GetComponent<ZNetView>();
		component4.m_persistent = true;
		component4.m_distant = false;
		typeof(MonsterAI).GetField("m_despawnInDay", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(val2, false);
		typeof(MonsterAI).GetField("m_eventCreature", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(val2, false);
		template.AddComponent<Villager>();
		template.AddComponent<VillagerInventory>();
		template.AddComponent<VillagerBowDefense>();
		template.AddComponent<VillagerHauler>();
		template.AddComponent<VillagerAnimalKeeper>();
		template.AddComponent<VillagerClassIcon>();
		template.AddComponent<VillagerClaim>();
		template.AddComponent<VillagerPersistence>();
		template.AddComponent<VillagerMiner>();
		template.AddComponent<VillagerRoutine>();
		template.SetActive(true);
		ZNetScene.instance.m_prefabs.Add(template);
		FieldInfo field = typeof(ZNetScene).GetField("m_namedPrefabs", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		((Dictionary<int, GameObject>)field.GetValue(ZNetScene.instance))[StringExtensionMethods.GetStableHashCode("VC_Villager")] = template;
		SummonAnchor.Register(root.transform);
		VillagerMine.Register(root.transform);
		KnockoutArrow.Register(root.transform);
		DevBuilder.Register(root.transform);
		GathererHut.Register(root.transform);
		nextRuinAttempt = Time.time + 10f;
		Log("Registered persistent Viking NPC prefab with MonsterAI and saved character claims.");
	}

	internal Villager SpawnAt(Vector3 position, string reason)
	{
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)template == (Object)null || (Object)(object)ZNetScene.instance != (Object)(object)registeredScene)
		{
			throw new Exception("Villager prefab is not ready.");
		}
		GameObject val = Object.Instantiate<GameObject>(template, position, Quaternion.identity);
		Villager component = val.GetComponent<Villager>();
		component.SetName(VillagerNames.Choose());
		Log("Spawn source=" + reason + " " + component.State());
		return component;
	}

	private Villager Nearest()
	{
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		Villager result = null;
		float num = 30f;
		foreach (Villager villager in villagers)
		{
			if (!((Object)(object)villager == (Object)null))
			{
				float num2 = Vector3.Distance(((Component)villager).transform.position, ((Component)Player.m_localPlayer).transform.position);
				if (num2 < num)
				{
					num = num2;
					result = villager;
				}
			}
		}
		return result;
	}

	private void Command(ConsoleEventArgs args)
	{
		//IL_01b5: 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_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_04cd: Unknown result type (might be due to invalid IL or missing references)
		//IL_04d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_04d7: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				args.Context.AddString("Enter a world first.");
				return;
			}
			if (args.Args.Length > 1 && args.Args[1] == "testfarm")
			{
				if (ZNet.instance.GetWorldName() != "VillagerCreative")
				{
					throw new Exception("testfarm requires VillagerCreative.");
				}
				if ((Object)(object)((Component)this).GetComponent<InGameFarmTests>() != (Object)null)
				{
					throw new Exception("A farm test is already running.");
				}
				((Component)this).gameObject.AddComponent<InGameFarmTests>();
				args.Context.AddString("Running temporary farmer and gathering checks.");
				return;
			}
			string text = ((args.Args.Length > 1) ? args.Args[1].ToLowerInvariant() : "help");
			switch (text)
			{
			case "testbase":
				if (ZNet.instance.GetWorldName() != "VillagerTest")
				{
					throw new Exception("testbase requires VillagerTest.");
				}
				if ((Object)(object)((Component)this).GetComponent<InGameBaseTests>() == (Object)null)
				{
					((Component)this).gameObject.AddComponent<InGameBaseTests>();
				}
				args.Context.AddString("Building a test cabin and checking door routes.");
				return;
			case "spawn":
			{
				if ((Object)(object)template == (Object)null || (Object)(object)registeredScene != (Object)(object)ZNetScene.instance)
				{
					throw new Exception("NPC prefab is not ready.");
				}
				GameObject val = Object.Instantiate<GameObject>(template, ((Component)Player.m_localPlayer).transform.position + ((Component)Player.m_localPlayer).transform.forward * 3f + Vector3.up, Quaternion.identity);
				val.GetComponent<Villager>().SetName((args.Args.Length > 2) ? string.Join(" ", args.Args, 2, args.Args.Length - 2) : VillagerNames.Choose());
				val.GetComponent<Villager>().SetMode("follow");
				args.Context.AddString("Villager spawned. Commands affect the nearest villager within 30m.");
				return;
			}
			case "help":
				args.Context.AddString("villager spawn [name], follow, guard, carry, place, collect on/off, give [item prefab], unload, status, remove");
				return;
			}
			Villager villager = Nearest();
			if ((Object)(object)villager == (Object)null)
			{
				throw new Exception("No villager within 30m.");
			}
			if (!villager.TryClaim(Player.m_localPlayer))
			{
				throw new Exception("Villager claim denied or pending.");
			}
			if (!villager.View.IsOwner())
			{
				throw new Exception("This client does not own this NPC. Run commands on its owning client.");
			}
			switch (text)
			{
			default:
				if (!(text == "place"))
				{
					switch (text)
					{
					case "collect":
						if (args.Args.Length != 3 || (args.Args[2] != "on" && args.Args[2] != "off"))
						{
							throw new Exception("Use villager collect on/off.");
						}
						villager.collect = args.Args[2] == "on";
						break;
					case "give":
					{
						if (args.Args.Length != 3)
						{
							throw new Exception("Use villager give SwordBronze (test equipment is spawned).");
						}
						GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(args.Args[2]);
						if ((Object)(object)itemPrefab == (Object)null)
						{
							throw new Exception("Unknown item prefab.");
						}
						if (!villager.Human.GetInventory().AddItem(itemPrefab, 1))
						{
							throw new Exception("Inventory full.");
						}
						villager.Human.EquipBestWeapon((Character)null, (StaticTarget)null, (Character)null, (Character)null);
						break;
					}
					case "unload":
					{
						Inventory inventory = villager.Human.GetInventory();
						foreach (ItemData item in new List<ItemData>(inventory.GetAllItems()))
						{
							if (!item.m_equipped && !VillagerInventory.IsLocked(inventory, item))
							{
								ItemDrop.DropItem(item, item.m_stack, ((Component)Player.m_localPlayer).transform.position + Vector3.up, Quaternion.identity);
								inventory.RemoveItem(item);
							}
						}
						break;
					}
					case "status":
						args.Context.AddString(villager.State());
						break;
					case "remove":
						if (villager.Human.GetInventory().GetAllItems().Exists((ItemData i) => !i.m_equipped))
						{
							throw new Exception("Unload collected items before removal.");
						}
						ZNetScene.instance.Destroy(((Component)villager).gameObject);
						break;
					default:
						throw new Exception("Unknown command. Use villager help.");
					}
					break;
				}
				goto case "follow";
			case "follow":
			case "guard":
			case "carry":
				villager.SetMode((text == "place") ? "guard" : text);
				break;
			}
			Log("Command=" + text + " " + villager.State());
			args.Context.AddString("Villager: " + text);
		}
		catch (Exception ex)
		{
			args.Context.AddString("Villager: " + ex.Message);
			((BaseUnityPlugin)this).Logger.LogError((object)ex);
		}
	}
}
public sealed class Villager : MonoBehaviour
{
	internal Humanoid Human;

	internal ZNetView View;

	private MonsterAI ai;

	private string mode = "guard";

	private long followPlayer;

	private float nextFollowCheck;

	private float nextPlayerCollisionCheck;

	internal bool collect;

	private float logTime;

	private float pickupTime;

	private PinData pin;

	private Minimap pinMap;

	private Vector3 home;

	private readonly Dictionary<Collider, bool> colliderStates = new Dictionary<Collider, bool>();

	private bool previousGravity;

	private readonly List<Vector3> patrolRoute = new List<Vector3>();

	private int patrolIndex;

	private int patrolDirection = 1;

	private static readonly MethodInfo AssignPatrolPoint = typeof(BaseAI).GetMethod("SetPatrolPoint", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Vector3) }, null);

	private static readonly MethodInfo MoveToPoint = typeof(BaseAI).GetMethod("MoveTo", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[4]
	{
		typeof(float),
		typeof(Vector3),
		typeof(float),
		typeof(bool)
	}, null);

	private static readonly MethodInfo WanderPoint = typeof(BaseAI).GetMethod("RandomMovementArroundPoint", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[4]
	{
		typeof(float),
		typeof(Vector3),
		typeof(float),
		typeof(bool)
	}, null);

	internal Vector3 DefenseOrigin => (patrolRoute.Count > 0) ? patrolRoute[patrolIndex] : home;

	internal bool Defending => mode == "guard";

	internal bool Hauling => mode == "haul";

	internal bool AnimalKeeping => mode == "animal";

	internal bool Farming => mode == "farm";

	internal bool Mining => mode == "mine";

	internal bool CanControl
	{
		get
		{
			VillagerClaim component = ((Component)this).GetComponent<VillagerClaim>();
			VillagerPersistence component2 = ((Component)this).GetComponent<VillagerPersistence>();
			return (Object)(object)component != (Object)null && component.LocalControl && ((Object)(object)component2 == (Object)null || component2.Ready);
		}
	}

	private void SetPatrolDestination(Vector3 point)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		AssignPatrolPoint.Invoke(ai, new object[1] { point });
	}

	internal void BowPatrol(float dt)
	{
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: 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)
		if (patrolRoute.Count > 0)
		{
			Vector3 val = patrolRoute[patrolIndex] - ((Component)this).transform.position;
			float num = Mathf.Abs(val.y);
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude <= 0.64f && num < 2f)
			{
				((Character)Human).SetMoveDir(Vector3.zero);
				return;
			}
			MoveToPoint.Invoke(ai, new object[4]
			{
				dt,
				patrolRoute[patrolIndex],
				0.8f,
				false
			});
		}
		else
		{
			WanderPoint.Invoke(ai, new object[4]
			{
				dt,
				home,
				Mathf.Max(1f, Plugin.Instance.GuardRadius.Value),
				false
			});
		}
	}

	internal void IgnorePlayerCollisions()
	{
		Collider[] componentsInChildren = ((Component)this).GetComponentsInChildren<Collider>(true);
		ZDO val = (((Object)(object)View == (Object)null) ? null : View.GetZDO());
		bool flag = ((val == null) ? mode : val.GetString("vc_mode", mode)) == "follow";
		foreach (Player allPlayer in Player.GetAllPlayers())
		{
			Collider[] componentsInChildren2 = ((Component)allPlayer).GetComponentsInChildren<Collider>(true);
			foreach (Collider val2 in componentsInChildren2)
			{
				Collider[] array = componentsInChildren;
				foreach (Collider val3 in array)
				{
					if ((Object)(object)val3 != (Object)null && (Object)(object)val2 != (Object)null && !val3.isTrigger && !val2.isTrigger && val3.enabled && val2.enabled && Physics.GetIgnoreCollision(val3, val2) != !flag)
					{
						Physics.IgnoreCollision(val3, val2, !flag);
					}
				}
			}
		}
		foreach (Villager villager in Plugin.Instance.villagers)
		{
			if ((Object)(object)villager == (Object)null || (Object)(object)villager == (Object)(object)this)
			{
				continue;
			}
			ZDO val4 = (((Object)(object)villager.View == (Object)null) ? null : villager.View.GetZDO());
			bool flag2 = ((val4 == null) ? villager.mode : val4.GetString("vc_mode", villager.mode)) == "follow";
			bool flag3 = !flag || !flag2;
			Collider[] componentsInChildren2 = ((Component)villager).GetComponentsInChildren<Collider>(true);
			foreach (Collider val2 in componentsInChildren2)
			{
				Collider[] array = componentsInChildren;
				foreach (Collider val3 in array)
				{
					if ((Object)(object)val3 != (Object)null && (Object)(object)val2 != (Object)null && !val3.isTrigger && !val2.isTrigger && val3.enabled && val2.enabled && Physics.GetIgnoreCollision(val3, val2) != flag3)
					{
						Physics.IgnoreCollision(val3, val2, flag3);
					}
				}
			}
		}
	}

	internal void SetDefense(List<Vector3> points)
	{
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: 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)
		if (points == null || points.Count == 0)
		{
			throw new ArgumentException("Choose a guard point or patrol route.");
		}
		((Component)this).GetComponent<VillagerBowDefense>().ResetRecovery();
		SetMode("guard");
		patrolRoute.AddRange(points);
		patrolIndex = 0;
		patrolDirection = 1;
		home = points[0];
		((BaseAI)ai).m_randomMoveRange = 0f;
		SetPatrolDestination(home);
		SaveNow();
		Plugin instance = Plugin.Instance;
		object[] array = new object[8]
		{
			"Defense assigned: points=",
			patrolRoute.Count,
			" start=",
			((Vector3)(ref home)).ToString("F1"),
			" end=",
			null,
			null,
			null
		};
		Vector3 val = points[points.Count - 1];
		array[5] = ((Vector3)(ref val)).ToString("F1");
		array[6] = " ";
		array[7] = State();
		instance.Log(string.Concat(array));
	}

	private void Awake()
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		Human = ((Component)this).GetComponent<Humanoid>();
		View = ((Component)this).GetComponent<ZNetView>();
		ai = ((Component)this).GetComponent<MonsterAI>();
		home = ((Component)this).transform.position;
		Plugin.Instance.villagers.Add(this);
	}

	private void Start()
	{
		if (View.GetZDO() != null)
		{
			string text = View.GetZDO().GetString("vc_name", "");
			if (!string.IsNullOrEmpty(text))
			{
				((Character)Human).m_name = text;
			}
			else if (View.IsOwner())
			{
				SetName((((Character)Human).m_name == "Villager") ? VillagerNames.Choose() : ((Character)Human).m_name);
			}
		}
		if (View.IsOwner())
		{
			((Character)Human).SetTamed(true);
			if (!View.GetZDO().GetBool("vc_initialized", false))
			{
				((Character)Human).SetMaxHealth(Mathf.Max(1f, Plugin.Instance.Health.Value));
				((Character)Human).SetHealth(((Character)Human).GetMaxHealth());
				View.GetZDO().Set("vc_initialized", true);
			}
			((BaseAI)ai).m_randomMoveRange = Mathf.Max(1f, Plugin.Instance.GuardRadius.Value);
			if (mode == "guard")
			{
				((BaseAI)ai).SetPatrolPoint();
			}
			Plugin.Instance.Log("Villager spawned: " + State());
		}
	}

	internal void SetName(string name)
	{
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		((Character)Human).m_name = name;
		if (View.GetZDO() != null && View.IsOwner())
		{
			View.GetZDO().Set("vc_name", name);
		}
		Plugin.Instance.Log("Villager name assigned: " + name + " id=" + ((Character)Human).GetZDOID());
		SaveNow();
	}

	internal void SetMode(string value)
	{
		//IL_0045: 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_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0308: Unknown result type (might be due to invalid IL or missing references)
		//IL_0312: Unknown result type (might be due to invalid IL or missing references)
		//IL_0317: Unknown result type (might be due to invalid IL or missing references)
		//IL_031c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0321: Unknown result type (might be due to invalid IL or missing references)
		//IL_0380: Unknown result type (might be due to invalid IL or missing references)
		//IL_0385: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
		if (value != "gather" && (Object)(object)View != (Object)null && View.GetZDO() != null)
		{
			View.GetZDO().Set("vc_gatherHut", ZDOID.None);
			View.GetZDO().Set("vc_gatherHutToken", "");
		}
		VillagerMiner component = ((Component)this).GetComponent<VillagerMiner>();
		if (Mining && value != "mine" && (Object)(object)component != (Object)null && component.MineID != ZDOID.None)
		{
			component.Leave(teleport: false);
		}
		patrolRoute.Clear();
		((BaseAI)ai).m_randomMoveRange = Mathf.Max(1f, Plugin.Instance.GuardRadius.Value);
		bool flag = mode == "carry";
		mode = value;
		if (mode == "follow" && (Object)(object)Player.m_localPlayer != (Object)null)
		{
			followPlayer = Player.m_localPlayer.GetPlayerID();
		}
		((Behaviour)ai).enabled = mode != "carry";
		if (mode == "carry")
		{
			((Character)Human).SetMoveDir(Vector3.zero);
		}
		Rigidbody component2 = ((Component)this).GetComponent<Rigidbody>();
		if (mode == "carry" && !flag)
		{
			colliderStates.Clear();
			Collider[] componentsInChildren = ((Component)this).GetComponentsInChildren<Collider>();
			foreach (Collider val in componentsInChildren)
			{
				if (!val.isTrigger)
				{
					colliderStates[val] = val.enabled;
					val.enabled = false;
				}
			}
			if ((Object)(object)component2 != (Object)null)
			{
				previousGravity = component2.useGravity;
				component2.useGravity = false;
			}
		}
		if (flag && mode != "carry")
		{
			foreach (KeyValuePair<Collider, bool> colliderState in colliderStates)
			{
				if ((Object)(object)colliderState.Key != (Object)null)
				{
					colliderState.Key.enabled = colliderState.Value;
				}
			}
			if ((Object)(object)component2 != (Object)null)
			{
				component2.useGravity = previousGravity;
			}
		}
		if (flag && mode != "carry")
		{
			MoveBody(((Component)Player.m_localPlayer).transform.position + ((Component)Player.m_localPlayer).transform.forward * 2f + Vector3.up);
		}
		if (mode == "follow")
		{
			((BaseAI)ai).ResetPatrolPoint();
			ai.SetFollowTarget(((Component)Player.m_localPlayer).gameObject);
		}
		else
		{
			ai.SetFollowTarget((GameObject)null);
			home = ((Component)this).transform.position;
			((BaseAI)ai).SetPatrolPoint();
		}
		if (View.GetZDO() != null)
		{
			View.GetZDO().Set("vc_mode", mode);
			View.GetZDO().Set("vc_home", home);
		}
		Plugin.Instance.Log("Mode changed: " + State());
		SaveNow();
	}

	internal bool TryClaim(Player player)
	{
		VillagerClaim component = ((Component)this).GetComponent<VillagerClaim>();
		return (Object)(object)component != (Object)null && component.TryClaim(player);
	}

	internal void SaveNow()
	{
		VillagerPersistence component = ((Component)this).GetComponent<VillagerPersistence>();
		if ((Object)(object)component != (Object)null)
		{
			component.Save();
		}
	}

	internal void CaptureJob(VillagerSave save)
	{
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		save.Name = ((Character)Human).m_name;
		save.Mode = mode;
		save.Home = home;
		save.Collect = collect;
		save.FollowPlayer = followPlayer;
		save.Route.AddRange(patrolRoute);
		save.Waypoint = patrolIndex;
		save.Direction = patrolDirection;
	}

	internal void RestoreJob(VillagerSave save)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01da: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e2: 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_02da: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0326: Unknown result type (might be due to invalid IL or missing references)
		((Character)Human).m_name = save.Name;
		home = save.Home;
		collect = save.Collect;
		followPlayer = save.FollowPlayer;
		mode = (((save.Mode == "gather" && View.GetZDO().GetString("vc_gatherHutToken", "") != "") || save.Mode == "follow" || save.Mode == "haul" || save.Mode == "farm" || save.Mode == "animal" || save.Mode == "carry" || (save.Mode == "mine" && View.GetZDO().GetZDOID("vc_mineID") != ZDOID.None)) ? save.Mode : "guard");
		patrolRoute.Clear();
		patrolRoute.AddRange(save.Route);
		patrolIndex = ((patrolRoute.Count != 0) ? Mathf.Clamp(save.Waypoint, 0, patrolRoute.Count - 1) : 0);
		patrolDirection = ((save.Direction >= 0) ? 1 : (-1));
		if (mode == "carry")
		{
			mode = "guard";
			Vector3 position = ((Component)this).transform.position;
			float num = default(float);
			if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGroundHeight(position, ref num))
			{
				position.y = num + 0.2f;
			}
			MoveBody(position);
			home = position;
		}
		if ((mode == "haul" || mode == "farm" || mode == "animal") && save.Area.Count == 0)
		{
			mode = "guard";
		}
		((Behaviour)ai).enabled = true;
		ai.SetFollowTarget((GameObject)null);
		((BaseAI)ai).m_randomMoveRange = ((patrolRoute.Count > 0) ? 0f : Mathf.Max(1f, Plugin.Instance.GuardRadius.Value));
		if (mode == "follow")
		{
			UpdateFollower();
		}
		else
		{
			SetPatrolDestination((patrolRoute.Count > 0) ? patrolRoute[patrolIndex] : home);
		}
		if (View.IsOwner())
		{
			View.GetZDO().Set("vc_mode", mode);
			View.GetZDO().Set("vc_home", home);
		}
	}

	private void UpdateFollower()
	{
		//IL_0094: Unknown result type (might be due to invalid IL or missing references)
		Player val = null;
		foreach (Player allPlayer in Player.GetAllPlayers())
		{
			if (allPlayer.GetPlayerID() == followPlayer && !((Character)allPlayer).IsDead())
			{
				val = allPlayer;
				break;
			}
		}
		ai.SetFollowTarget(((Object)(object)val == (Object)null) ? null : ((Component)val).gameObject);
		if ((Object)(object)val != (Object)null)
		{
			((BaseAI)ai).ResetPatrolPoint();
		}
		else
		{
			SetPatrolDestination(home);
		}
	}

	internal string State()
	{
		//IL_0085: 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)
		Character targetCreature = ((BaseAI)ai).GetTargetCreature();
		VillagerHauler component = ((Component)this).GetComponent<VillagerHauler>();
		object[] array = new object[23]
		{
			"name=",
			((Character)Human).m_name,
			" mode=",
			mode,
			" routePoints=",
			patrolRoute.Count,
			" waypoint=",
			patrolIndex,
			" position=",
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null,
			null
		};
		Vector3 position = ((Component)this).transform.position;
		array[9] = ((Vector3)(ref position)).ToString("F1");
		array[10] = " health=";
		array[11] = ((Character)Human).GetHealth().ToString("F0");
		array[12] = " collect=";
		array[13] = collect;
		array[14] = " items=";
		array[15] = Human.GetInventory().GetAllItems().Count;
		array[16] = " target=";
		array[17] = (((Object)(object)targetCreature == (Object)null) ? "none" : targetCreature.m_name);
		array[18] = " owner=";
		array[19] = View.IsOwner();
		array[20] = " marker=";
		array[21] = pin != null;
		array[22] = (((Hauling || Farming || AnimalKeeping) && (Object)(object)component != (Object)null) ? (" job=" + component.Status + " cargo=" + component.CargoCount()) : "");
		return string.Concat(array);
	}

	private void MoveBody(Vector3 position)
	{
		//IL_003e: 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_0020: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		Rigidbody component = ((Component)this).GetComponent<Rigidbody>();
		if ((Object)(object)component != (Object)null)
		{
			component.position = position;
			component.linearVelocity = Vector3.zero;
			component.angularVelocity = Vector3.zero;
		}
		((Component)this).transform.position = position;
	}

	private void Update()
	{
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_0152: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_0229: Unknown result type (might be due to invalid IL or missing references)
		//IL_023a: Unknown result type (might be due to invalid IL or missing references)
		//IL_023f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0244: Unknown result type (might be due to invalid IL or missing references)
		//IL_035b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0360: Unknown result type (might be due to invalid IL or missing references)
		//IL_036a: Unknown result type (might be due to invalid IL or missing references)
		//IL_036f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0404: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)Human == (Object)null || ((Character)Human).IsDead())
		{
			return;
		}
		if (Time.time >= nextPlayerCollisionCheck)
		{
			nextPlayerCollisionCheck = Time.time + 0.5f;
			IgnorePlayerCollisions();
		}
		if (View.GetZDO() != null)
		{
			string text = View.GetZDO().GetString("vc_name", "");
			if (!string.IsNullOrEmpty(text))
			{
				((Character)Human).m_name = text;
			}
		}
		if ((Object)(object)Minimap.instance != (Object)null)
		{
			if ((Object)(object)pinMap != (Object)(object)Minimap.instance)
			{
				pinMap = Minimap.instance;
				pin = pinMap.AddPin(((Component)this).transform.position, (PinType)3, ((Character)Human).m_name, false, false, 0L, default(PlatformUserID));
				Plugin.Instance.Log("NPC map marker created: " + ((Character)Human).m_name);
			}
			if (pin != null)
			{
				pin.m_pos = ((Component)this).transform.position;
				pin.m_name = ((Character)Human).m_name;
			}
		}
		if (!View.IsOwner() || VillagerRoutine.Paused(this))
		{
			return;
		}
		if (mode == "follow" && Time.time >= nextFollowCheck)
		{
			nextFollowCheck = Time.time + 1f;
			UpdateFollower();
		}
		if (mode == "guard" && patrolRoute.Count > 1 && (Object)(object)((BaseAI)ai).GetTargetCreature() == (Object)null)
		{
			Vector3 val = ((Component)this).transform.position - patrolRoute[patrolIndex];
			val.y = 0f;
			if (((Vector3)(ref val)).sqrMagnitude < 0.81f)
			{
				if (patrolIndex == patrolRoute.Count - 1)
				{
					patrolDirection = -1;
				}
				else if (patrolIndex == 0)
				{
					patrolDirection = 1;
				}
				patrolIndex += patrolDirection;
				SetPatrolDestination(patrolRoute[patrolIndex]);
				SaveNow();
				Plugin.Instance.Log("Patrol waypoint=" + patrolIndex + " " + State());
			}
		}
		if (mode == "carry" && (Object)(object)Player.m_localPlayer != (Object)null)
		{
			MoveBody(((Component)Player.m_localPlayer).transform.position + Vector3.up * 2f);
		}
		if (collect && mode != "carry" && mode != "haul" && mode != "farm" && mode != "mine" && Time.time >= pickupTime)
		{
			pickupTime = Time.time + 1f;
			HashSet<ItemDrop> hashSet = new HashSet<ItemDrop>();
			Collider[] array = Physics.OverlapSphere(((Component)this).transform.position, 2.5f);
			foreach (Collider val2 in array)
			{
				ItemDrop componentInParent = ((Component)val2).GetComponentInParent<ItemDrop>();
				if ((Object)(object)componentInParent == (Object)null || !hashSet.Add(componentInParent) || !componentInParent.CanPickup(false))
				{
					continue;
				}
				ZNetView component = ((Component)componentInParent).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsOwner())
				{
					string name = componentInParent.m_itemData.m_shared.m_name;
					if (Human.Pickup(((Component)componentInParent).gameObject, false, false))
					{
						Plugin.Instance.Log("Picked up " + name + " " + State());
					}
				}
			}
		}
		if (Time.time >= logTime)
		{
			logTime = Time.time + Mathf.Max(1f, Plugin.Instance.LogInterval.Value);
			Plugin.Instance.Log(State());
		}
	}

	private void OnDestroy()
	{
		if ((Object)(object)Plugin.Instance != (Object)null)
		{
			Plugin.Instance.villagers.Remove(this);
			Plugin.Instance.Log("Villager unloaded/destroyed: " + (((Object)(object)Human == (Object)null) ? "unknown" : ((Character)Human).m_name));
		}
		if ((Object)(object)pinMap != (Object)null && pin != null)
		{
			pinMap.RemovePin(pin);
		}
	}
}
internal static class VillagerNames
{
	internal static readonly string[] Pool = new string[30]
	{
		"Arne", "Birger", "Bo", "Erik", "Frode", "Gorm", "Halfdan", "Harald", "Knud", "Leif",
		"Njal", "Roar", "Rune", "Torsten", "Ulf", "Astrid", "Bodil", "Frida", "Gro", "Estrid",
		"Hilda", "Gudrun", "Gunhild", "Helga", "Inga", "Liv", "Signe", "Sigrid", "Tora", "Thyra"
	};

	internal static string Choose()
	{
		HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
		foreach (Villager villager in Plugin.Instance.villagers)
		{
			if ((Object)(object)villager != (Object)null && (Object)(object)villager.Human != (Object)null && !((Character)villager.Human).IsDead())
			{
				hashSet.Add(((Character)villager.Human).m_name);
			}
		}
		List<string> list = new List<string>();
		string[] pool = Pool;
		foreach (string item in pool)
		{
			if (!hashSet.Contains(item))
			{
				list.Add(item);
			}
		}
		return (list.Count > 0) ? list[Random.Range(0, list.Count)] : Pool[Random.Range(0, Pool.Length)];
	}
}
[DefaultExecutionOrder(10000)]
public sealed class CommandMenu : MonoBehaviour
{
	private enum Stage
	{
		Closed,
		Menu,
		ClassMenu,
		TribeMenu,
		AnchorMenu,
		MineMenu,
		HutMenu,
		SelectVillager,
		SelectMine,
		Ground,
		Paint
	}

	internal static CommandMenu Instance;

	private GameObject classPanel;

	private TextMeshProUGUI classTitle;

	private string selectedClass;

	private Stage stage;

	private string command;

	private string message;

	private Villager selected;

	private Villager aimed;

	private readonly List<Villager> selection = new List<Villager>();

	private readonly Dictionary<Villager, LineRenderer> selectionRings = new Dictionary<Villager, LineRenderer>();

	private readonly Dictionary<Villager, VillagerSelectionHighlight> selectionHighlights = new Dictionary<Villager, VillagerSelectionHighlight>();

	private GameObject uiRoot;

	private GameObject panel;

	private GameObject hintBox;

	private TextMeshProUGUI hint;

	private LineRenderer routeLine;

	private LineRenderer targetLine;

	private Material lineMaterial;

	private readonly List<Vector3> points = new List<Vector3>();

	private bool drawing;

	private bool hasGround;

	private Vector3 ground;

	private int stageFrame;

	private float messageUntil;

	private float releaseBlockUntil;

	private Harmony patches;

	private TMP_FontAsset nativeFont;

	private Sprite panelSprite;

	private Sprite buttonSprite;

	private GameObject anchorPanel;

	private SummonAnchor currentAnchor;

	private TextMeshProUGUI anchorStatus;

	private Button summonButton;

	private string anchorFeedback = "";

	private GameObject paintPreview;

	private Mesh paintMesh;

	private Material paintMaterial;

	private float brushRadius;

	private Vector3 gridOrigin;

	private float gridYaw;

	private bool gridReady;

	private GameObject minePanel;

	private VillagerMine currentMine;

	private TextMeshProUGUI mineStatus;

	private readonly List<Button> oreButtons = new List<Button>();

	private string mineFeedback = "";

	private GameObject tribePanel;

	private GameObject tribeRows;

	private TMP_InputField tribeName;

	private TextMeshProUGUI tribeStatus;

	private float nextTribeRefresh;

	private int tribePage;

	private string tribeSignature;

	private Button tribeCreate;

	private Button tribeLeave;

	private GameObject hutPanel;

	private GathererHutJob currentHut;

	private TextMeshProUGUI hutStatus;

	private TextMeshProUGUI hutSampleLabel;

	private readonly List<Villager> hutSelection = new List<Villager>();

	private readonly List<Button> hutWorkerButtons = new List<Button>();

	private readonly List<TextMeshProUGUI> hutWorkerLabels = new List<TextMeshProUGUI>();

	private List<Villager> hutCandidates = new List<Villager>();

	private string hutFeedback = "";

	private int hutPage;

	private int hutSample;

	private float nextHutRefresh;

	internal static bool Active => (Object)(object)Instance != (Object)null && Instance.stage != Stage.Closed;

	internal static bool BlockGameplay => (Object)(object)Instance != (Object)null && (Active || Time.unscaledTime < Instance.releaseBlockUntil);

	internal static bool Choosing => (Object)(object)Instance != (Object)null && (Instance.stage == Stage.Menu || Instance.stage == Stage.ClassMenu || Instance.stage == Stage.TribeMenu || Instance.stage == Stage.AnchorMenu || Instance.stage == Stage.MineMenu || Instance.stage == Stage.HutMenu);

	internal static void ReleaseMenuCursor()
	{
		ZCursor.LockState = (CursorLockMode)0;
		ZCursor.Show();
		AccessTools.Method(typeof(ZCursor), "SetVisible", (Type[])null, (Type[])null).Invoke(null, new object[1] { true });
		Cursor.visible = true;
	}

	private void LateUpdate()
	{
		if (Choosing)
		{
			ReleaseMenuCursor();
		}
	}

	internal void OpenMine(VillagerMine mine)
	{
		if (!((Object)(object)mine == (Object)null) && !Active && !OtherUI())
		{
			EnsureUI();
			currentMine = mine;
			mineFeedback = "";
			SetStage(Stage.MineMenu);
		}
	}

	internal void OpenAnchor(SummonAnchor anchor)
	{
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)anchor == (Object)null) && !Active && !OtherUI())
		{
			EnsureUI();
			currentAnchor = anchor;
			anchorFeedback = "";
			SetStage(Stage.AnchorMenu);
			Plugin instance = Plugin.Instance;
			Vector3 position = ((Component)anchor).transform.position;
			instance.Log("Summon Anchor menu opened at " + ((Vector3)(ref position)).ToString("F1"));
		}
	}

	private void Awake()
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		Instance = this;
		patches = new Harmony("local.valheim.villagecompanion.menu");
		patches.PatchAll(typeof(CommandMenu).Assembly);
	}

	private bool OtherUI()
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Invalid comparison between Unknown and I4
		return InventoryGui.IsVisible() || Menu.IsVisible() || Console.IsVisible() || ((Object)(object)Chat.instance != (Object)null && Chat.instance.IsChatDialogWindowVisible()) || ((Object)(object)Minimap.instance != (Object)null && (int)Minimap.instance.m_mode == 2);
	}

	private void Update()
	{
		//IL_0197: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0263: Unknown result type (might be due to invalid IL or missing references)
		//IL_0273: Unknown result type (might be due to invalid IL or missing references)
		//IL_0582: Unknown result type (might be due to invalid IL or missing references)
		//IL_097b: Unknown result type (might be due to invalid IL or missing references)
		//IL_09d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_09db: Unknown result type (might be due to invalid IL or missing references)
		//IL_09dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_09e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_09f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_09f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a0b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a0e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a31: Unknown result type (might be due to invalid IL or missing references)
		//IL_0ab3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0ab8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0acc: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || (Object)(object)ZNetScene.instance == (Object)null)
		{
			if (Active)
			{
				Close();
			}
		}
		else if (OtherUI())
		{
			if (Active)
			{
				Close();
			}
		}
		else if (Input.GetKeyDown((KeyCode)46) && ((Object)(object)tribeName == (Object)null || !tribeName.isFocused))
		{
			if (Active)
			{
				Close();
				return;
			}
			EnsureUI();
			SetStage(Stage.Menu);
		}
		else if (!Active)
		{
			if ((Object)(object)hintBox != (Object)null)
			{
				hintBox.SetActive(Time.unscaledTime < messageUntil);
			}
		}
		else if (Input.GetKeyDown((KeyCode)27))
		{
			Close();
		}
		else if (stage == Stage.HutMenu)
		{
			RefreshHut();
		}
		else if (stage == Stage.TribeMenu)
		{
			RefreshTribe();
		}
		else if (stage == Stage.MineMenu)
		{
			if ((Object)(object)currentMine == (Object)null || Vector3.Distance(((Component)localPlayer).transform.position, ((Component)currentMine).transform.position) > 4f)
			{
				Close();
				return;
			}
			((TMP_Text)mineStatus).text = currentMine.Status() + "\n" + mineFeedback;
			for (int i = 0; i < oreButtons.Count; i++)
			{
				((Selectable)oreButtons[i]).interactable = VillagerMine.Discovered(localPlayer, MineRules.Ores[i]);
			}
		}
		else if (stage == Stage.AnchorMenu)
		{
			if ((Object)(object)currentAnchor == (Object)null || Vector3.Distance(((Component)localPlayer).transform.position, ((Component)currentAnchor).transform.position) > 4f)
			{
				Close();
				return;
			}
			double num = currentAnchor.Remaining();
			((Selectable)summonButton).interactable = num <= 0.0;
			((TMP_Text)anchorStatus).text = ((num > 0.0) ? ("Recharging · " + Math.Ceiling(num) + " seconds") : "Ready to summon a villager") + "\n" + anchorFeedback;
		}
		else if (stage == Stage.ClassMenu && (!SelectionValid() || selection.Exists((Villager v) => VillagerClasses.Get(v) != selectedClass)))
		{
			ReselectClasses();
		}
		else
		{
			if (Choosing)
			{
				return;
			}
			if ((Object)(object)Camera.main == (Object)null)
			{
				Cancel("Camera unavailable.");
				return;
			}
			if (stage == Stage.SelectVillager)
			{
				selection.RemoveAll((Villager v) => (Object)(object)v == (Object)null || ((Character)v.Human).IsDead() || !v.View.IsOwner());
				aimed = AimVillager();
				ShowTarget(aimed);
				ShowSelection();
				SetHint("<b>" + Label(command) + " · " + selection.Count + " selected</b>\n" + (((Object)(object)aimed == (Object)null) ? "Aim at a villager within 30 metres" : (((Character)aimed.Human).m_name + (selection.Contains(aimed) ? " · Selected" : " · Click to select"))) + "\n<color=#e8b84e>[Left click]</color> Select / deselect    <color=#e8b84e>[E]</color> Confirm group    <color=#e8b84e>[Esc]</color> Cancel");
				if (Input.GetMouseButtonDown(0) && (Object)(object)aimed != (Object)null && Time.frameCount > stageFrame)
				{
					if (!aimed.TryClaim(localPlayer))
					{
						SetHint("Villager claim denied or pending. Only its claimant can give orders.");
						return;
					}
					bool flag = selection.Remove(aimed);
					if (!flag)
					{
						selection.Add(aimed);
					}
					Plugin.Instance.Log(string.Concat("Menu selection=", flag ? "removed" : "added", " villager=", ((Character)aimed.Human).m_name, " id=", ((Character)aimed.Human).GetZDOID(), " count=", selection.Count, " command=", command));
					ShowSelection();
				}
				if (!Input.GetKeyDown((KeyCode)101) || Time.frameCount <= stageFrame)
				{
					return;
				}
				if (selection.Count == 0)
				{
					SetHint("Click at least one villager before pressing E.");
					return;
				}
				Plugin.Instance.Log("Menu group confirmed: count=" + selection.Count + " command=" + command);
				if (command == "class")
				{
					ConfirmClassSelection();
				}
				else if (command == "mine")
				{
					SetStage(Stage.SelectMine);
					ShowTarget(null);
				}
				else if (command == "defend" || command == "haul" || command == "farm" || command == "animal")
				{
					points.Clear();
					brushRadius = Mathf.Clamp(Plugin.Instance.HaulBrushRadius.Value, 2f, 10f);
					SetStage((command == "defend") ? Stage.Ground : Stage.Paint);
					ShowTarget(null);
				}
				else
				{
					ApplyCommand();
				}
				return;
			}
			if (!SelectionValid())
			{
				Cancel("A selected villager is unavailable. Select the group again.");
				return;
			}
			if ((stage == Stage.SelectMine || stage == Stage.Paint || stage == Stage.Ground) && selection.Exists((Villager v) => VillagerClasses.Get(v) != selectedClass))
			{
				ReselectClasses();
				return;
			}
			ShowSelection();
			if (stage == Stage.SelectMine)
			{
				VillagerMine villagerMine = AimMine();
				SetHint("<b>Mine · " + selection.Count + " villagers</b>\nAim at a Village Mine and left click to assign · Maximum 3 miners\nEvery selected villager needs a pickaxe    <color=#e8b84e>[Esc]</color> Cancel");
				if (Time.frameCount > stageFrame && Input.GetMouseButtonDown(0) && (Object)(object)villagerMine != (Object)null)
				{
					if (villagerMine.Assign(localPlayer, new List<Villager>(selection), out var result))
					{
						Done(result);
						return;
					}
					SetHint(result);
					VillagerInventory.Notice(result);
				}
				return;
			}
			hasGround = AimGround(out ground);
			if (stage == Stage.Paint)
			{
				PaintArea();
				return;
			}
			SetHint("<b>Defend · " + selection.Count + " villagers</b>\n" + (hasGround ? "Click: guard this spot   Hold left click + aim: draw patrol" : "Aim at clear ground within 60 metres") + "\nRelease left click to confirm    <color=#e8b84e>[. / Esc]</color> Cancel");
			if (Time.frameCount <= stageFrame)
			{
				return;
			}
			if (Input.GetMouseButtonDown(0) && hasGround)
			{
				points.Clear();
				points.Add(ground);
				drawing = true;
			}
			if (drawing && Input.GetMouseButton(0) && hasGround && points.Count < 64)
			{
				Vector3 val = points[points.Count - 1];
				if (Vector3.Distance(val, ground) >= 1f && Vector3.Distance(val, ground) <= 6f && RouteLength() + Vector3.Distance(val, ground) <= 100f)
				{
					points.Add(ground);
				}
			}
			PreviewGround();
			if (!drawing || !Input.GetMouseButtonUp(0))
			{
				return;
			}
			drawing = false;
			try
			{
				if (!hasGround)
				{
					points.Clear();
					SetHint("Release over valid ground to confirm. Try again.");
					return;
				}
				if (RouteLength() < 1.5f)
				{
					Vector3 item = points[0];
					points.Clear();
					points.Add(item);
				}
				foreach (Villager item2 in selection)
				{
					item2.SetDefense(new List<Vector3>(points));
				}
				Done(((points.Count == 1) ? "Guard spot" : "Patrol route") + " assigned to " + selection.Count + " villagers.");
			}
			catch (Exception ex)
			{
				Cancel(ex.Message);
			}
		}
	}

	private float RouteLength()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		float num = 0f;
		for (int i = 1; i < points.Count; i++)
		{
			num += Vector3.Distance(points[i - 1], points[i]);
		}
		return num;
	}

	private void ReselectClasses()
	{
		selection.Clear();
		ShowSelection();
		command = "class";
		SetStage(Stage.SelectVillager);
		VillagerInventory.Notice("Select villagers of the same class. Please reselect your group.");
	}

	private void ConfirmClassSelection()
	{
		if (!SelectionValid())
		{
			ReselectClasses();
			return;
		}
		selectedClass = VillagerClasses.Get(selection[0]);
		if (selection.Exists((Villager v) => VillagerClasses.Get(v) != selectedClass))
		{
			ReselectClasses();
			return;
		}
		BuildClassOrders();
		SetStage(Stage.ClassMenu);
		ShowTarget(null);
	}

	private void BeginClassOrder(string value)
	{
		if (!SelectionValid() || selection.Exists((Villager v) => VillagerClasses.Get(v) != selectedClass))
		{
			ReselectClasses();
			return;
		}
		command = value;
		switch (value)
		{
		case "mine":
			SetStage(Stage.SelectMine);
			break;
		default:
			if (!(value == "animal"))
			{
				ApplyCommand();
				break;
			}
			goto case "defend";
		case "defend":
		case "haul":
		case "farm":
			points.Clear();
			brushRadius = Mathf.Clamp(Plugin.Instance.HaulBrushRadius.Value, 2f, 10f);
			SetStage((value == "defend") ? Stage.Ground : Stage.Paint);
			break;
		}
	}

	private void BuildClassOrders()
	{
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cd: Expected O, but got Unknown
		//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0210: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0226: Expected O, but got Unknown
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0266: Unknown result type (might be due to invalid IL or missing references)
		//IL_0272: Unknown result type (might be due to invalid IL or missing references)
		//IL_027c: Expected O, but got Unknown
		//IL_04c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_04f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_047e: Unknown result type (might be due to invalid IL or missing references)
		//IL_048d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0497: Unknown result type (might be due to invalid IL or missing references)
		//IL_037d: Unknown result type (might be due to invalid IL or missing references)
		//IL_038d: Unknown result type (might be due to invalid IL or missing references)
		//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0403: Expected O, but got Unknown
		//IL_041f: Unknown result type (might be due to invalid IL or missing references)
		//IL_042f: Unknown result type (might be due to invalid IL or missing references)
		//IL_043b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0445: Expected O, but got Unknown
		if ((Object)(object)classPanel != (Object)null)
		{
			Object.Destroy((Object)(object)classPanel);
		}
		classPanel = Box("ClassOrders", uiRoot.transform, new Vector2(520f, (float)((selectedClass == "animal") ? 740 : 360)), Vector2.zero, panelSprite);
		classTitle = Text("ClassTitle", classPanel.transform, VillagerClasses.Name(selectedClass) + " · " + selection.Count + " selected", new Vector2(470f, 60f), new Vector2(0f, (float)((selectedClass == "animal") ? 320 : 125)), 30f, new Color(1f, 0.76f, 0.28f));
		string work = ((selectedClass == "defender") ? "defend" : ((selectedClass == "harvest") ? "farm" : selectedClass));
		TribeButton(classPanel.transform, Label(work), new Vector2(440f, 48f), new Vector2(0f, (float)((selectedClass == "animal") ? 240 : 45)), (UnityAction)delegate
		{
			BeginClassOrder(work);
		});
		TribeButton(classPanel.transform, "Stop work / stand here", new Vector2(440f, 48f), new Vector2(0f, (float)((selectedClass == "animal") ? 180 : (-15))), (UnityAction)delegate
		{
			BeginClassOrder("place");
		});
		TribeButton(classPanel.transform, "Reselect villagers", new Vector2(440f, 48f), new Vector2(0f, (float)((selectedClass == "animal") ? 120 : (-75))), (UnityAction)delegate
		{
			selection.Clear();
			ShowSelection();
			command = "class";
			SetStage(Stage.SelectVillager);
		});
		if (selectedClass == "animal")
		{
			Text("AnimalKeepHint", classPanel.transform, "Keep adults per species (2–50)", new Vector2(460f, 40f), new Vector2(0f, 60f), 21f, Color.white);
			for (int num = 0; num < VillagerAnimalKeeper.Species.Length; num++)
			{
				string species = VillagerAnimalKeeper.Species[num];
				int count = ((Component)selection[0]).GetComponent<VillagerAnimalKeeper>().Keep(species);
				bool flag = selection.TrueForAll((Villager v) => ((Component)v).GetComponent<VillagerAnimalKeeper>().Keep(species) == count);
				TextMeshProUGUI label = Text("AnimalKeepCount", classPanel.transform, VillagerAnimalKeeper.Names[num] + ": " + (flag ? count.ToString() : "Mixed"), new Vector2(280f, 45f), new Vector2(0f, (float)(-num * 60)), 23f, new Color(1f, 0.78f, 0.3f));
				string name = VillagerAnimalKeeper.Names[num];
				TribeButton(classPanel.transform, "−", new Vector2(65f, 45f), new Vector2(-185f, (float)(-num * 60)), (UnityAction)delegate
				{
					count = AnimalKeeperRules.Keep(count - 1);
					foreach (Villager item in selection)
					{
						((Component)item).GetComponent<VillagerAnimalKeeper>().SetKeep(species, count);
					}
					((TMP_Text)label).text = name + ": " + count;
				});
				TribeButton(classPanel.transform, "+", new Vector2(65f, 45f), new Vector2(185f, (float)(-num * 60)), (UnityAction)delegate
				{
					count = AnimalKeeperRules.Keep(count + 1);
					foreach (Villager item2 in selection)
					{
						((Component)item2).GetComponent<VillagerAnimalKeeper>().SetKeep(species, count);
					}
					((TMP_Text)label).text = name + ": " + count;
				});
			}
			Text("AnimalKeepFooter", classPanel.transform, "Founding adults and babies are preserved.\nOnly excess grown offspring are harvested.\nFood and all output need matching chests.", new Vector2(460f, 95f), new Vector2(0f, -265f), 19f, Color.white);
		}
		Text("ClassFooter", classPanel.transform, "[Esc / .] Close", new Vector2(460f, 35f), new Vector2(0f, (float)((selectedClass == "animal") ? (-330) : (-140))), 19f, Color.white);
	}

	private void PaintArea()
	{
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0224: Unknown result type (might be due to invalid IL or missing references)
		//IL_022a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0235: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_028b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0290: Unknown result type (might be due to invalid IL or missing references)
		//IL_0293: Unknown result type (might be due to invalid IL or missing references)
		//IL_0297: Unknown result type (might be due to invalid IL or missing references)
		//IL_029c: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_017e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0185: Unknown result type (might be due to invalid IL or missing references)
		//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0402: Unknown result type (might be due to invalid IL or missing references)
		SetHint("<b>" + ((command == "animal") ? "Animals" : ((command == "farm") ? "Farm" : "Haul")) + " · " + selection.Count + " villagers · " + points.Count + " grid cells</b>\n<color=#e8b84e>[Left click / drag]</color> Select 2m cells   <color=#e8b84e>[Right click]</color> Erase\n<color=#e8b84e>[E]</color> Confirm area    <color=#e8b84e>[. / Esc]</color> Cancel");
		if (Time.frameCount <= stageFrame)
		{
			return;
		}
		if (hasGround && !gridReady)
		{
			List<Transform> list = new List<Transform>();
			List<Piece> list2 = new List<Piece>();
			Piece.GetSnapPoints(ground, 10f, list, list2);
			float num = float.MaxValue;
			foreach (Piece item in list2)
			{
				string text = ((Object)item).name.Replace("(Clone)", "");
				if (!text.StartsWith("wood_floor") && !text.StartsWith("stone_floor"))
				{
					continue;
				}
				List<Transform> list3 = new List<Transform>();
				item.GetSnapPoints(list3);
				foreach (Transform item2 in list3)
				{
					float num2 = Vector3.Distance(ground, item2.position);
					if (num2 < num)
					{
						num = num2;
						gridOrigin = item2.position;
						gridYaw = ((Component)item).transform.eulerAngles.y;
					}
				}
			}
			gridReady = true;
		}
		Vector3 cell = (hasGround ? HaulArea.GridCell(ground, gridOrigin, gridYaw) : Vector3.zero);
		bool flag = false;
		if (hasGround && Input.GetMouseButton(0) && points.Count < 4096)
		{
			bool flag2 = false;
			foreach (Vector3 point in points)
			{
				Vector3 val = point - cell;
				val.y = 0f;
				if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
				{
					flag2 = true;
					break;
				}
			}
			if (!flag2)
			{
				points.Add(cell);
				flag = true;
			}
		}
		if (hasGround && Input.GetMouseButton(1))
		{
			flag |= points.RemoveAll(delegate(Vector3 p)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0003: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val2 = p - cell;
				val2.y = 0f;
				return ((Vector3)(ref val2)).sqrMagnitude < 0.01f;
			}) > 0;
		}
		if (flag)
		{
			if ((Object)(object)paintMesh != (Object)null)
			{
				Object.Destroy((Object)(object)paintMesh);
			}
			paintMesh = HaulArea.GridMesh(points, gridYaw);
			paintPreview.GetComponent<MeshFilter>().sharedMesh = paintMesh;
		}
		paintPreview.SetActive(points.Count > 0);
		routeLine.positionCount = (hasGround ? 5 : 0);
		if (hasGround)
		{
			for (int num3 = 0; num3 < 5; num3++)
			{
				routeLine.SetPosition(num3, HaulArea.CellCorner(cell, gridYaw, num3));
			}
		}
		if (!Input.GetKeyDown((KeyCode)101))
		{
			return;
		}
		if (points.Count == 0)
		{
			SetHint("Paint an area before pressing E.");
			return;
		}
		try
		{
			if (command == "farm" && selection.Exists((Villager v) => !v.Human.GetInventory().GetAllItems().Exists((ItemData i) => ChestFilters.ItemKey(i) == "Cultivator")))
			{
				throw new Exception("Give every selected farmer a cultivator first.");
			}
			foreach (Villager item3 in selection)
			{
				((Component)item3).GetComponent<VillagerHauler>().Assign(new List<Vector3>(points), -1f, command == "farm", gridYaw);
			}
			Done(((command == "farm") ? "Farming" : "Hauling") + " area assigned to " + selection.Count + " villagers.");
		}
		catch (Exception ex)
		{
			Cancel(ex.Message);
		}
	}

	private static Ray AimRay()
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: 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)
		return Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0f));
	}

	private Villager AimVillager()
	{
		//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_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0193: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e6: 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_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0208: Unknown result type (might be due to invalid IL or missing references)
		//IL_0217: Unknown result type (might be due to invalid IL or missing references)
		Ray val = AimRay();
		Villager villager = null;
		float num = 35f;
		foreach (Villager villager2 in Plugin.Instance.villagers)
		{
			if ((Object)(object)villager2 == (Object)null || ((Character)villager2.Human).IsDead() || Vector3.Distance(((Component)villager2).transform.position, ((Component)Player.m_localPlayer).transform.position) > 30f)
			{
				continue;
			}
			Collider component = ((Component)villager2).GetComponent<Collider>();
			if ((Object)(object)component != (Object)null && component.enabled)
			{
				continue;
			}
			Vector3 val2 = ((Component)villager2).transform.position + Vector3.up - ((Ray)(ref val)).origin;
			float num2 = Vector3.Dot(val2, ((Ray)(ref val)).direction);
			if (num2 > 0f && num2 < num)
			{
				Vector3 val3 = val2 - ((Ray)(ref val)).direction * num2;
				if (((Vector3)(ref val3)).sqrMagnitude < 0.6f)
				{
					villager = villager2;
					num = num2;
				}
			}
		}
		RaycastHit[] array = Physics.RaycastAll(val, 35f, -1, (QueryTriggerInteraction)1);
		Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
		RaycastHit[] array2 = array;
		for (int num3 = 0; num3 < array2.Length; num3++)
		{
			RaycastHit val4 = array2[num3];
			if (!((Object)(object)((Component)((RaycastHit)(ref val4)).collider).GetComponentInParent<Player>() != (Object)null))
			{
				if ((Object)(object)villager != (Object)null && num < ((RaycastHit)(ref val4)).distance)
				{
					return villager;
				}
				Villager componentInParent = ((Component)((RaycastHit)(ref val4)).collider).GetComponentInParent<Villager>();
				if ((Object)(object)componentInParent != (Object)null && !((Character)componentInParent.Human).IsDead() && Vector3.Distance(((Component)componentInParent).transform.position, ((Component)Player.m_localPlayer).transform.position) <= 30f)
				{
					return componentInParent;
				}
				return null;
			}
		}
		return villager;
	}

	private bool AimGround(out Vector3 result)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: 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_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		result = Vector3.zero;
		RaycastHit[] array = Physics.RaycastAll(AimRay(), 80f, -1, (QueryTriggerInteraction)1);
		Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
		RaycastHit[] array2 = array;
		for (int num = 0; num < array2.Length; num++)
		{
			RaycastHit val = array2[num];
			if (!((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Character>() != (Object)null))
			{
				if ((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Heightmap>() == (Object)null || ((RaycastHit)(ref val)).normal.y < 0.65f || Vector3.Distance(((RaycastHit)(ref val)).point, ((Component)Player.m_localPlayer).transform.position) > 60f)
				{
					return false;
				}
				result = ((RaycastHit)(ref val)).point;
				return true;
			}
		}
		return false;
	}

	private VillagerMine AimMine()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		RaycastHit[] array = Physics.RaycastAll(AimRay(), 65f, -1, (QueryTriggerInteraction)1);
		Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
		RaycastHit[] array2 = array;
		for (int num = 0; num < array2.Length; num++)
		{
			RaycastHit val = array2[num];
			if (!((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Character>() != (Object)null))
			{
				return ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<VillagerMine>();
			}
		}
		return null;
	}

	private void ApplyCommand()
	{
		//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_0206: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (!SelectionValid())
			{
				throw new Exception("A selected villager is unavailable. Select the group again.");
			}
			int count = selection.Count;
			int num = 0;
			bool flag = !selection.TrueForAll((Villager v) => v.collect);
			foreach (Villager item in selection)
			{
				selected = item;
				if (command == "follow" || command == "carry")
				{
					selected.SetMode(command);
				}
				else if (command == "place")
				{
					selected.SetMode("guard");
				}
				else if (command == "collect")
				{
					selected.collect = flag;
				}
				else if (command == "status")
				{
					num += selected.Human.GetInventory().GetAllItems().Count;
					Plugin.Instance.Log("Menu inspect " + selected.State());
				}
				else if (command == "unload")
				{
					Inventory inventory = selected.Human.GetInventory();
					foreach (ItemData item2 in new List<ItemData>(inventory.GetAllItems()))
					{
						if (!item2.m_equipped && !VillagerInventory.IsLocked(inventory, item2))
						{
							ItemDrop.DropItem(item2, item2.m_stack, ((Component)Player.m_localPlayer).transform.position + Vector3.up, Quaternion.identity);
							inventory.RemoveItem(item2);
						}
					}
				}
				Plugin.Instance.Log("Menu command=" + command + " " + selected.State());
			}
			Done((command == "status") ? (count + " villagers selected · " + num + " inventory items\nIndividual details recorded in the log.") : ((command == "collect") ? ("Item collection " + (flag ? "enabled" : "disabled") + " for " + count + " villagers.") : (Label(command) + " assigned to " + count + " villagers.")));
		}
		catch (Exception ex)
		{
			Cancel(ex.Message);
		}
	}

	private static string Label(string value)
	{
		if (value == "class")
		{
			return "Class orders";
		}
		if (value == "animal")
		{
			return "Tend animals";
		}
		return value switch
		{
			"defend" => "Defend", 
			"haul" => "Haul items", 
			"farm" => "Farm crops", 
			"mine" => "Mine ore", 
			"follow" => "Follow me", 
			"carry" => "Carry villager", 
			"place" => "Place villager", 
			"collect" => "Toggle item collection", 
			"unload" => "Unload items", 
			_ => "Inspect villager", 
		};
	}

	private void SetStage(Stage next)
	{
		//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)
		if (next == Stage.Paint)
		{
			gridReady = false;
			gridOrigin = Vector3.zero;
			gridYaw = 0f;
		}
		stage = next;
		stageFrame = Time.frameCount;
		panel.SetActive(next == Stage.Menu);
		if ((Object)(object)classPanel != (Object)null)
		{
			classPanel.SetActive(next == Stage.ClassMenu);
		}
		anchorPanel.SetActive(next == Stage.AnchorMenu);
		minePanel.SetActive(next == Stage.MineMenu);
		if ((Object)(object)hutPanel != (Object)null)
		{
			hutPanel.SetActive(next == Stage.HutMenu);
		}
		tribePanel.SetActive(next == Stage.TribeMenu);
		if (next == Stage.TribeMenu)
		{
			nextTribeRefresh = 0f;
			RefreshTribe();
		}
		hintBox.SetActive(next != Stage.Closed && !Choosing);
		if (Choosing)
		{
			ReleaseMenuCursor();
		}
		else
		{
			ZCursor.LockState = (CursorLockMode)1;
			ZCursor.Hide();
		}
		Plugin.Instance.Log(string.Concat("Menu stage=", next, " command=", command));
	}

	private void Close()
	{
		releaseBlockUntil = Time.unscaledTime + 0.2f;
		stage = Stage.Closed;
		drawing = false;
		points.Clear();
		selected = null;
		aimed = null;
		selection.Clear();
		foreach (VillagerSelectionHighlight value in selectionHighlights.Values)
		{
			if ((Object)(object)value != (Object)null)
			{
				value.ClearAppearance();
				Object.Destroy((Object)(object)value);
			}
		}
		selectionHighlights.Clear();
		foreach (LineRenderer value2 in selectionRings.Values)
		{
			if ((Object)(object)value2 != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)value2).gameObject);
			}
		}
		selectionRings.Clear();
		if ((Object)(object)panel != (Object)null)
		{
			panel.SetActive(false);
		}
		if ((Object)(object)classPanel != (Object)null)
		{
			classPanel.SetActive(false);
		}
		if ((Object)(object)anchorPanel != (Object)null)
		{
			anchorPanel.SetActive(false);
		}
		if ((Object)(object)minePanel != (Object)null)
		{
			minePanel.SetActive(false);
		}
		if ((Object)(object)tribePanel != (Object)null)
		{
			tribePanel.SetActive(false);
		}
		if ((Object)(object)hutPanel != (Object)null)
		{
			hutPanel.SetActive(false);
		}
		currentHut = null;
		hutSelection.Clear();
		currentMine = null;
		currentAnchor = null;
		if ((Object)(object)hintBox != (Object)null)
		{
			hintBox.SetActive(false);
		}
		if ((Object)(object)routeLine != (Object)null)
		{
			routeLine.positionCount = 0;
		}
		if ((Object)(object)targetLine != (Object)null)
		{
			targetLine.positionCount = 0;
		}
		if ((Object)(object)paintPreview != (Object)null)
		{
			paintPreview.SetActive(false);
		}
		if ((Object)(object)paintMesh != (Object)null)
		{
			Object.Destroy((Object)(object)paintMesh);
			paintMesh = null;
		}
		if ((Object)(object)Player.m_localPlayer != (Object)null && !OtherUI())
		{
			ZCursor.LockState = (CursorLockMode)1;
			ZCursor.Hide();
		}
	}

	private void Done(string value)
	{
		Close();
		SetHint(value);
		messageUntil = Time.unscaledTime + 5f;
		Plugin.Instance.Log("Menu result=" + value);
	}

	private void Cancel(string value)
	{
		Done(value);
	}

	private void SetHint(string value)
	{
		message = value;
		if ((Object)(object)hint != (Object)null)
		{
			((TMP_Text)hint).text = value;
			hintBox.SetActive(true);
		}
	}

	private void ShowTarget(Villager v)
	{
		//IL_004e: 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_006e: 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)
		if ((Object)(object)v == (Object)null)
		{
			targetLine.positionCount = 0;
			return;
		}
		targetLine.positionCount = 33;
		for (int i = 0; i < 33; i++)
		{
			float num = (float)i * (float)Math.PI / 16f;
			targetLine.SetPosition(i, ((Component)v).transform.position + new Vector3(Mathf.Cos(num), 0.12f, Mathf.Sin(num)) * 0.8f);
		}
	}

	private bool SelectionValid()
	{
		return selection.Count > 0 && selection.TrueForAll((Villager v) => (Object)(object)v != (Object)null && !((Character)v.Human).IsDead() && (Object)(object)v.View != (Object)null && v.View.IsOwner() && v.CanControl);
	}

	private void ShowSelection()
	{
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0223: Unknown result type (might be due to invalid IL or missing references)
		//IL_0228: Unknown result type (might be due to invalid IL or missing references)
		List<Villager> list = new List<Villager>();
		foreach (KeyValuePair<Villager, VillagerSelectionHighlight> selectionHighlight in selectionHighlights)
		{
			if ((Object)(object)selectionHighlight.Key == (Object)null || !selection.Contains(selectionHighlight.Key))
			{
				if ((Object)(object)selectionHighlight.Value != (Object)null)
				{
					selectionHighlight.Value.ClearAppearance();
					Object.Destroy((Object)(object)selectionHighlight.Value);
				}
				list.Add(selectionHighlight.Key);
			}
		}
		foreach (Villager item in list)
		{
			selectionHighlights.Remove(item);
		}
		foreach (KeyValuePair<Villager, LineRenderer> selectionRing in selectionRings)
		{
			if ((Object)(object)selectionRing.Value != (Object)null)
			{
				selectionRing.Value.positionCount = 0;
			}
		}
		foreach (Villager item2 in selection)
		{
			if (!selectionHighlights.ContainsKey(item2))
			{
				selectionHighlights.Add(item2, ((Component)item2).gameObject.AddComponent<VillagerSelectionHighlight>());
			}
			if (!selectionRings.TryGetValue(item2, out var value))
			{
				value = Line("SelectedVillager", new Color(1f, 0.76f, 0.2f));
				selectionRings.Add(item2, value);
			}
			value.positionCount = 33;
			for (int i = 0; i < 33; i++)
			{
				float num = (float)i * (float)Math.PI / 16f;
				value.SetPosition(i, ((Component)item2).transform.position + new Vector3(Mathf.Cos(num) * 0.95f, 0.15f, Mathf.Sin(num) * 0.95f));
			}
		}
	}

	private void PreviewGround()
	{
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_00bf: 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_00e6: Unknown result type (might be due to invalid IL or missing references)
		if (drawing && points.Count > 1)
		{
			routeLine.positionCount = points.Count;
			for (int i = 0; i < points.Count; i++)
			{
				routeLine.SetPosition(i, points[i] + Vector3.up * 0.12f);
			}
		}
		else if (hasGround)
		{
			routeLine.positionCount = 33;
			for (int i = 0; i < 33; i++)
			{
				float num = (float)i * (float)Math.PI / 16f;
				routeLine.SetPosition(i, ground + new Vector3(Mathf.Cos(num) * 0.6f, 0.12f, Mathf.Sin(num) * 0.6f));
			}
		}
		else
		{
			routeLine.positionCount = 0;
		}
	}

	private void EnsureUI()
	{
		//IL_0205: Unknown result type (might be due to invalid IL or missing references)
		//IL_020f: Expected O, but got Unknown
		//IL_0269: Unknown result type (might be due to invalid IL or missing references)
		//IL_029d: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0325: Unknown result type (might be due to invalid IL or missing references)
		//IL_0334: Unknown result type (might be due to invalid IL or missing references)
		//IL_0340: Unknown result type (might be due to invalid IL or missing references)
		//IL_034a: Expected O, but got Unknown
		//IL_036b: Unknown result type (might be due to invalid IL or missing references)
		//IL_037a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0384: Unknown result type (might be due to invalid IL or missing references)
		//IL_041c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0435: Unknown result type (might be due to invalid IL or missing references)
		//IL_048a: Unknown result type (might be due to invalid IL or missing references)
		//IL_048f: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_04cc: Expected O, but got Unknown
		//IL_0505: Unknown result type (might be due to invalid IL or missing references)
		//IL_0514: Unknown result type (might be due to invalid IL or missing references)
		//IL_051e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0545: Unknown result type (might be due to invalid IL or missing references)
		//IL_0554: Unknown result type (might be due to invalid IL or missing references)
		//IL_059c: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_05ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_05d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_05f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0630: Unknown result type (might be due to invalid IL or missing references)
		//IL_063a: Expected O, but got Unknown
		//IL_065d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0667: Expected O, but got Unknown
		//IL_0681: Unknown result type (might be due to invalid IL or missing references)
		//IL_06cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_06d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0706: Unknown result type (might be due to invalid IL or missing references)
		//IL_0715: Unknown result type (might be due to invalid IL or missing references)
		//IL_072e: Unknown result type (might be due to invalid IL or missing references)
		//IL_075a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0769: Unknown result type (might be due to invalid IL or missing references)
		//IL_0773: Unknown result type (might be due to invalid IL or missing references)
		//IL_079d: Unknown result type (might be due to invalid IL or missing references)
		//IL_07ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_0806: Unknown result type (might be due to invalid IL or missing references)
		//IL_080b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0824: Unknown result type (might be due to invalid IL or missing references)
		//IL_0841: Unknown result type (might be due to invalid IL or missing references)
		//IL_084b: Expected O, but got Unknown
		//IL_086c: Unknown result type (might be due to invalid IL or missing references)
		//IL_087b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0885: Unknown result type (might be due to invalid IL or missing references)
		//IL_08b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_08be: Unknown result type (might be due to invalid IL or missing references)
		//IL_08f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0902: Unknown result type (might be due to invalid IL or missing references)
		//IL_091b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0947: Unknown result type (might be due to invalid IL or missing references)
		//IL_0956: Unknown result type (might be due to invalid IL or missing references)
		//IL_0960: Unknown result type (might be due to invalid IL or missing references)
		//IL_098f: Unknown result type (might be due to invalid IL or missing references)
		//IL_099e: Unknown result type (might be due to invalid IL or missing references)
		//IL_09a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a01: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a1a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a79: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a7e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a97: Unknown result type (might be due to invalid IL or missing references)
		//IL_0ab1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0abb: Expected O, but got Unknown
		//IL_0af2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b01: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b4f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b54: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b6d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b86: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b90: Expected O, but got Unknown
		//IL_0bb1: Unknown result type (might be due to invalid IL or missing references)
		//IL_0bc0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0bca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Invalid comparison between Unknown and I4
		//IL_0105: Unknown result type (might be due to invalid IL or missing references)
		//IL_010a: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)uiRoot != (Object)null)
		{
			return;
		}
		if ((Object)(object)InventoryGui.instance != (Object)null)
		{
			TextMeshProUGUI[] componentsInChildren = ((Component)InventoryGui.instance).GetComponentsInChildren<TextMeshProUGUI>(true);
			TextMeshProUGUI[] array = componentsInChildren;
			foreach (TextMeshProUGUI val in array)
			{
				if ((Object)(object)((TMP_Text)val).font != (Object)null)
				{
					nativeFont = ((TMP_Text)val).font;
					break;
				}
			}
			Image component = ((Component)InventoryGui.instance.m_inventoryRoot).GetComponent<Image>();
			if ((Object)(object)component != (Object)null)
			{
				panelSprite = component.sprite;
			}
			if ((Object)(object)panelSprite == (Object)null)
			{
				Image[] componentsInChildren2 = ((Component)InventoryGui.instance.m_inventoryRoot).GetComponentsInChildren<Image>(true);
				foreach (Image val2 in componentsInChildren2)
				{
					if ((Object)(object)val2.sprite != (Object)null && (int)val2.type == 1)
					{
						Rect rect = ((Graphic)val2).rectTransform.rect;
						if (((Rect)(ref rect)).width > 200f)
						{
							panelSprite = val2.sprite;
							break;
						}
					}
				}
			}
			Button[] componentsInChildren3 = ((Component)InventoryGui.instance).GetComponentsInChildren<Button>(true);
			foreach (Button val3 in componentsInChildren3)
			{
				Graphic targetGraphic = ((Selectable)val3).targetGraphic;
				Image val4 = (Image)(object)((targetGraphic is Image) ? targetGraphic : null);
				if ((Object)(object)val4 != (Object)null && (Object)(object)val4.sprite != (Object)null)
				{
					buttonSprite = val4.sprite;
					break;
				}
			}
		}
		uiRoot = new GameObject("VC_CommandMenu", new Type[4]
		{
			typeof(RectTransform),
			typeof(Canvas),
			typeof(CanvasScaler),
			typeof(GraphicRaycaster)
		});
		uiRoot.transform.SetParent(((Component)this).transform, false);
		Canvas component2 = uiRoot.GetComponent<Canvas>();
		component2.renderMode = (RenderMode)0;
		component2.sortingOrder = 100;
		CanvasScaler component3 = uiRoot.GetComponent<CanvasScaler>();
		component3.uiScaleMode = (ScaleMode)1;
		component3.referenceResolution = new Vector2(1920f, 1080f);
		component3.matchWidthOrHeight = 0.5f;
		panel = Box("CommandPanel", uiRoot.transform, new Vector2(520f, 560f), Vector2.zero, panelSprite);
		Text("Title", panel.transform, "Villager commands", new Vector2(470f, 60f), new Vector2(0f, 225f), 32f, new Color(1f, 0.76f, 0.28f));
		TribeButton(panel.transform, "Tribe", new Vector2(175f, 40f), new Vector2(165f, 265f), (UnityAction)delegate
		{
			SetStage(Stage.TribeMenu);
		});
		Text("Subtitle", panel.transform, "Set classes in inventory · E confirms selection", new Vector2(470f, 55f), new Vector2(0f, 175f), 20f, Color.white);
		string[] array2 = new string[6] { "class", "follow", "carry", "place", "unload", "status" };
		for (int num = 0; num < arr