Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of VillageCompanion v0.18.2
plugins/VillageCompanion.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
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