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 LivingVillages v0.35.26
BepInEx/plugins/LivingVillages/LivingVillages.dll
Decompiled 10 hours 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.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Net; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using LivingVillages.Planning; using Microsoft.CodeAnalysis; using Splatform; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("LivingVillages")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.35.26.0")] [assembly: AssemblyInformationalVersion("0.35.26+92a8ca74ab5986fa5a570847c9625610e7b3dbf4")] [assembly: AssemblyProduct("LivingVillages")] [assembly: AssemblyTitle("LivingVillages")] [assembly: AssemblyVersion("0.35.26.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace LivingVillages { internal sealed class QuestCard { internal string Id; internal string Title; internal string Source; internal string Objectives; internal string Reward; } internal static class ActiveQuestCards { internal static List<QuestCard> Read(Player player) { List<QuestCard> list = new List<QuestCard>(); QuestCard questCard = ElderQuest.ActiveCard(player); if (questCard != null) { list.Add(questCard); } RequestProgress pantry = VillageRequests.Read(player).Pantry; if (pantry.Stage == 1) { list.Add(new QuestCard { Id = "pantry", Title = "Stock the pantry", Source = "Village elder", Objectives = string.Format("{0}: {1}/10 delivered\n\n{2}: {3}/5 delivered", (pantry.Tier == 0) ? "Raspberries" : "Blueberries", pantry.First, (pantry.Tier == 0) ? "Honey" : "Yellow mushrooms", pantry.Second), Reward = ((pantry.Tier == 0) ? "50 gold • 150 XP" : "75 gold • 175 XP") }); } VillageChainState villageChainState = VillageChains.Read(player); foreach (VillageChain item in from c in villageChainState.Chains orderby c.Village, c.Tier select c) { for (int num = 0; num < 5; num++) { if ((item.Accepted & (1 << num)) != 0 && (item.Done & (1 << num)) == 0) { list.Add(new QuestCard { Id = item.Village + "/" + item.Tier + "/" + num, Title = VillageChainCatalog.Roles[num] + " supplies", Source = VillageChainCatalog.Providers[num] + " • " + VillageChainCatalog.Tiers[item.Tier] + "\n" + VillageChains.VillageLabel(item.Village), Objectives = $"{VillageChains.ItemName(item.Tier, num)}\n\n{item.Delivered[num]} / {VillageChainCatalog.Counts[item.Tier][num]} delivered", Reward = (villageChainState.CanEarnSkill(num) ? ("+1 " + VillageChainCatalog.Roles[num] + "\n") : "") + $"{10 + item.Tier * 5} gold • {75 + item.Tier * 25} XP" }); } } } return list; } } internal static class AnimalFeed { internal static VillageStock.Entry[] Register() { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Expected O, but got Unknown List<VillageStock.Entry> list = new List<VillageStock.Entry> { new VillageStock.Entry("LV_BoarCrate", 1, 100) }; AnimalFeedDefinition[] all = AnimalFeedRules.All; foreach (AnimalFeedDefinition animalFeedDefinition in all) { GameObject val = PrefabManager.Instance.CreateClonedPrefab(animalFeedDefinition.Prefab, "Barley"); SharedData shared = val.GetComponent<ItemDrop>().m_itemData.m_shared; shared.m_name = animalFeedDefinition.Name + " Specialty Feed (" + animalFeedDefinition.Stars + " star)"; shared.m_description = "Aim at a tamed adult " + animalFeedDefinition.Name.ToLowerInvariant() + " and use this item from your hotbar. Ten portions upgrade a " + (animalFeedDefinition.Stars - 1) + "-star animal to " + animalFeedDefinition.Stars + " stars. Progress is saved on the animal. Not eaten automatically."; shared.m_itemType = (ItemType)1; shared.m_maxStackSize = 50; shared.m_weight = 0.2f; shared.m_value = 0; ItemManager.Instance.AddItem(new CustomItem(val, false)); list.Add(new VillageStock.Entry(animalFeedDefinition.Prefab, 1, animalFeedDefinition.Price, animalFeedDefinition.Key)); } return list.ToArray(); } internal static string Species(Character animal) { if (!Object.op_Implicit((Object)(object)animal)) { return ""; } return Utils.GetPrefabName(((Component)animal).gameObject); } internal static bool Unlocked(AnimalFeedDefinition feed) { if (feed.Key.Length != 0) { if (Object.op_Implicit((Object)(object)ZoneSystem.instance)) { return ZoneSystem.instance.GetGlobalKey(feed.Key); } return false; } return true; } internal static string ProgressKey(int stars) { return "lv_specialty_feed_" + stars; } internal static void Say(string text) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } } [HarmonyPatch(typeof(Humanoid), "UseItem")] internal static class UseAnimalFeed { private static bool Prefix(Humanoid __instance, Inventory __0, ItemData __1) { object prefab; if (__1 == null) { prefab = null; } else { GameObject dropPrefab = __1.m_dropPrefab; prefab = ((dropPrefab != null) ? ((Object)dropPrefab).name : null); } AnimalFeedDefinition animalFeedDefinition = AnimalFeedRules.Find((string)prefab); if (animalFeedDefinition == null) { return true; } if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)AnimalFeedNetwork.Instance)) { return false; } Player localPlayer = Player.m_localPlayer; if (__0 != null && __0 != ((Humanoid)localPlayer).GetInventory()) { return false; } GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject(); Character val = (Object.op_Implicit((Object)(object)hoverObject) ? hoverObject.GetComponentInParent<Character>() : null); if (!Object.op_Implicit((Object)(object)val)) { AnimalFeed.Say("Aim at the animal before using its specialty feed."); return false; } AnimalFeedNetwork.Instance.Begin(localPlayer, val, __1, animalFeedDefinition); return false; } } [HarmonyPatch(typeof(Tameable), "GetHoverText")] internal static class AnimalFeedHover { private static void Postfix(Tameable __instance, ref string __result) { Character component = ((Component)__instance).GetComponent<Character>(); if (!Object.op_Implicit((Object)(object)component) || !component.IsTamed() || component.IsDead()) { return; } string species = AnimalFeed.Species(component); if (!Array.Exists(AnimalFeedRules.All, (AnimalFeedDefinition f) => f.Species == species)) { return; } if (component.GetLevel() >= 3) { __result += "\nSpecialty feed: two-star maximum"; return; } ZNetView component2 = ((Component)component).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component2) && component2.IsValid()) { int level = component.GetLevel(); int num = Mathf.Clamp(component2.GetZDO().GetInt(AnimalFeed.ProgressKey(level), 0), 0, 10); __result = __result + "\nSpecialty feed: " + num + "/" + 10 + " toward " + level + " stars"; } } } [HarmonyPatch(typeof(Character), "Awake")] internal static class AnimalFeedLevelWatcher { private static void Postfix(Character __instance) { if (Array.Exists(AnimalFeedRules.All, (AnimalFeedDefinition f) => f.Species == AnimalFeed.Species(__instance))) { ((Component)__instance).gameObject.AddComponent<AnimalFeedLevelSync>(); } } } public sealed class AnimalFeedLevelSync : MonoBehaviour { private static readonly FieldRef<Character, int> Level = AccessTools.FieldRefAccess<Character, int>("m_level"); private Character animal; private ZNetView view; private void Awake() { animal = ((Component)this).GetComponent<Character>(); view = ((Component)this).GetComponent<ZNetView>(); ((MonoBehaviour)this).InvokeRepeating("Refresh", 0.5f, 0.5f); } private void Refresh() { if (!Object.op_Implicit((Object)(object)animal) || !Object.op_Implicit((Object)(object)view) || !view.IsValid()) { return; } int num = view.GetZDO().GetInt(ZDOVars.s_level, 1); if (num >= 1 && num != animal.GetLevel()) { if (view.IsOwner()) { animal.SetLevel(num); return; } Level.Invoke(animal) = num; animal.m_onLevelSet?.Invoke(num); } } } public sealed class AnimalFeedNetwork : MonoBehaviour { private sealed class Pending { internal string Ticket; internal string Prefab; internal string Rejection = ""; internal long World; internal ZDOID Animal; internal string Serialize() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) ZPackage val = new ZPackage(); val.Write(Ticket); val.Write(Prefab); val.Write(World); val.Write(Animal); val.Write(Rejection); return val.GetBase64(); } internal static Pending Read(string data) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) ZPackage val = new ZPackage(data); return new Pending { Ticket = val.ReadString(), Prefab = val.ReadString(), World = val.ReadLong(), Animal = val.ReadZDOID(), Rejection = val.ReadString() }; } } internal static AnimalFeedNetwork Instance; private const string Request = "LV_AnimalFeed_Request"; private const string Response = "LV_AnimalFeed_Response"; private const string Missing = "LV_AnimalFeed_Missing"; private const string Gone = "LV_AnimalFeed_Gone"; private const string PendingKey = "lv_feed_pending_v1"; private ZRoutedRpc registered; private float nextRetry; private void Awake() { Instance = this; } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { if (ZRoutedRpc.instance != registered && ZRoutedRpc.instance != null) { registered = ZRoutedRpc.instance; registered.Register<ZPackage>("LV_AnimalFeed_Request", (Action<long, ZPackage>)Receive); registered.Register<ZPackage>("LV_AnimalFeed_Response", (Action<long, ZPackage>)Reply); registered.Register<ZPackage>("LV_AnimalFeed_Missing", (Action<long, ZPackage>)CheckMissing); registered.Register<ZPackage>("LV_AnimalFeed_Gone", (Action<long, ZPackage>)ConfirmMissing); } if (Time.unscaledTime < nextRetry) { return; } nextRetry = Time.unscaledTime + 2f; Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)ZNet.instance)) { return; } Pending pending = Load(localPlayer); if (pending != null) { if (pending.Rejection.Length > 0) { Refund(localPlayer, pending); } else { Send(localPlayer, pending); } } } private static Pending Load(Player player) { if (!player.m_customData.TryGetValue("lv_feed_pending_v1", out var value)) { return null; } try { return Pending.Read(value); } catch (Exception ex) { Logger.LogWarning((object)("Cannot read pending animal feed: " + ex.Message)); return null; } } internal bool Begin(Player player, Character animal, ItemData item, AnimalFeedDefinition feed) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) if (player.m_customData.ContainsKey("lv_feed_pending_v1")) { AnimalFeed.Say("Waiting for the previous feeding to finish. Stay near that animal and leave room for a returned portion."); return false; } if (registered == null || !Object.op_Implicit((Object)(object)ZNet.instance) || ((Character)player).IsDead() || ((Character)player).InIntro() || !((Humanoid)player).GetInventory().ContainsItem(item)) { return false; } ZNetView component = ((Component)animal).GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || animal.IsDead() || Vector3.Distance(((Component)player).transform.position, ((Component)animal).transform.position) > 5f) { return false; } if (!PrivateArea.CheckAccess(((Component)animal).transform.position, 0f, false, false)) { return false; } string text = AnimalFeedRules.Validate(feed, AnimalFeed.Species(animal), animal.IsTamed(), animal.GetLevel(), AnimalFeed.Unlocked(feed)); if (text.Length > 0) { AnimalFeed.Say(text); return false; } Pending pending = new Pending { Ticket = Guid.NewGuid().ToString("N"), Prefab = feed.Prefab, World = ZNet.instance.GetWorldUID(), Animal = component.GetZDO().m_uid }; ((Humanoid)player).GetInventory().RemoveOneItem(item); player.m_customData["lv_feed_pending_v1"] = pending.Serialize(); Send(player, pending); return true; } private void Send(Player player, Pending pending) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) if (registered == null || pending.World != ZNet.instance.GetWorldUID()) { return; } ZDOMan instance = ZDOMan.instance; ZDO val = ((instance != null) ? instance.GetZDO(pending.Animal) : null); ZNetView component = ((Component)player).GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid()) { return; } if (val == null || val.GetOwner() == 0L) { ZPackage val2 = new ZPackage(); val2.Write(pending.Ticket); val2.Write(pending.Animal); val2.Write(component.GetZDO().m_uid); long num = Server(); if (num != 0L) { registered.InvokeRoutedRPC(num, "LV_AnimalFeed_Missing", new object[1] { val2 }); } } else { ZPackage val3 = new ZPackage(); val3.Write(pending.Ticket); val3.Write(pending.Prefab); val3.Write(pending.Animal); val3.Write(component.GetZDO().m_uid); registered.InvokeRoutedRPC(val.GetOwner(), "LV_AnimalFeed_Request", new object[1] { val3 }); } } private void Receive(long sender, ZPackage p) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Expected O, but got Unknown //IL_0252: Unknown result type (might be due to invalid IL or missing references) try { string text = p.ReadString(); string prefab = p.ReadString(); ZDOID val = p.ReadZDOID(); ZDOID val2 = p.ReadZDOID(); if (!Guid.TryParseExact(text, "N", out var _) || AnimalFeedRules.Find(prefab) == null) { return; } ZDO zDO = ZDOMan.instance.GetZDO(val2); if (zDO == null || zDO.GetOwner() != sender) { return; } long num = zDO.GetLong("playerID", 0L); if (num == 0L) { return; } GameObject val3 = ZNetScene.instance.FindInstance(val); Character val4 = (Object.op_Implicit((Object)(object)val3) ? val3.GetComponent<Character>() : null); ZNetView val5 = (Object.op_Implicit((Object)(object)val4) ? ((Component)val4).GetComponent<ZNetView>() : null); if (!Object.op_Implicit((Object)(object)val5) || !val5.IsValid() || !val5.IsOwner()) { return; } ZDO zDO2 = val5.GetZDO(); string text2 = "lv_feed_receipt_" + num + "_" + text; string text3 = zDO2.GetString(text2, ""); string text4; if (text3.StartsWith(text + "|", StringComparison.Ordinal)) { text4 = text3.Substring(text.Length + 1); } else { AnimalFeedDefinition animalFeedDefinition = AnimalFeedRules.Find(prefab); text4 = AnimalFeedRules.Validate(animalFeedDefinition, AnimalFeed.Species(val4), val4.IsTamed(), val4.GetLevel(), AnimalFeed.Unlocked(animalFeedDefinition)); if (val4.IsDead()) { text4 = "This animal cannot be fed."; } if (Vector3.Distance(zDO.GetPosition(), ((Component)val4).transform.position) > 5f) { text4 = "Move closer to the animal."; } if (text4.Length == 0) { string text5 = AnimalFeed.ProgressKey(animalFeedDefinition.Stars); int num2 = AnimalFeedRules.NextProgress(zDO2.GetInt(text5, 0)); zDO2.Set(text5, num2); if (num2 == 10) { val4.SetLevel(animalFeedDefinition.Stars + 1); } text4 = "OK:" + ((num2 == 10) ? (animalFeedDefinition.Name + " upgraded to " + animalFeedDefinition.Stars + " stars.") : ("Specialty feed: " + num2 + "/" + 10)); } zDO2.Set(text2, text + "|" + text4); } ZPackage val6 = new ZPackage(); val6.Write(text); val6.Write(val); val6.Write(text4); registered.InvokeRoutedRPC(sender, "LV_AnimalFeed_Response", new object[1] { val6 }); } catch (Exception ex) { Logger.LogWarning((object)("Animal feed request failed: " + ex.Message)); } } private static long Server() { if (!ZNet.instance.IsServer()) { return ZNet.instance.GetServerPeer()?.m_uid ?? 0; } return ZNet.GetUID(); } private void CheckMissing(long sender, ZPackage p) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer()) { return; } try { string text = p.ReadString(); ZDOID val = p.ReadZDOID(); ZDO zDO = ZDOMan.instance.GetZDO(p.ReadZDOID()); if (Guid.TryParseExact(text, "N", out var _) && zDO != null && zDO.GetOwner() == sender && zDO.GetLong("playerID", 0L) != 0L && ZDOMan.instance.GetZDO(val) == null) { ZPackage val2 = new ZPackage(); val2.Write(text); val2.Write(val); registered.InvokeRoutedRPC(sender, "LV_AnimalFeed_Gone", new object[1] { val2 }); } } catch (Exception ex) { Logger.LogWarning((object)("Animal feed status failed: " + ex.Message)); } } private void ConfirmMissing(long sender, ZPackage p) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ZNet.instance) || sender != Server() || !Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return; } try { string text = p.ReadString(); ZDOID val = p.ReadZDOID(); Player localPlayer = Player.m_localPlayer; Pending pending = Load(localPlayer); if (pending != null && !(pending.Ticket != text) && !(pending.Animal != val) && pending.World == ZNet.instance.GetWorldUID()) { pending.Rejection = "The animal no longer exists."; localPlayer.m_customData["lv_feed_pending_v1"] = pending.Serialize(); Refund(localPlayer, pending); } } catch (Exception ex) { Logger.LogWarning((object)("Animal feed status response failed: " + ex.Message)); } } private void Reply(long sender, ZPackage p) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) try { string text = p.ReadString(); ZDOID val = p.ReadZDOID(); string text2 = p.ReadString(); Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)ZNet.instance)) { return; } Pending pending = Load(localPlayer); if (pending == null || pending.Ticket != text || pending.Animal != val || pending.World != ZNet.instance.GetWorldUID()) { return; } ZDO zDO = ZDOMan.instance.GetZDO(val); if (zDO != null && zDO.GetOwner() == sender) { if (text2.StartsWith("OK:", StringComparison.Ordinal)) { localPlayer.m_customData.Remove("lv_feed_pending_v1"); AnimalFeed.Say(text2.Substring(3)); } else { pending.Rejection = text2; localPlayer.m_customData["lv_feed_pending_v1"] = pending.Serialize(); Refund(localPlayer, pending); } } } catch (Exception ex) { Logger.LogWarning((object)("Animal feed response failed: " + ex.Message)); } } private static void Refund(Player player, Pending pending) { GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab(pending.Prefab) : null); if (Object.op_Implicit((Object)(object)val) && ((Humanoid)player).GetInventory().CanAddItem(val, 1) && ((Humanoid)player).GetInventory().AddItem(val, 1)) { player.m_customData.Remove("lv_feed_pending_v1"); AnimalFeed.Say(pending.Rejection + " Feed returned."); } } } internal sealed class AnimalFeedDefinition { internal readonly string Species; internal readonly string Name; internal readonly string Key; internal readonly string Prefab; internal readonly int Stars; internal readonly int Price; internal AnimalFeedDefinition(string species, string name, int stars, string key) { Species = species; Name = name; Stars = stars; Key = key; Price = ((stars == 1) ? 25 : 50); Prefab = "LV_Feed_" + species + "_" + stars; } } internal static class AnimalFeedRules { internal const int Portions = 10; internal static readonly AnimalFeedDefinition[] All = new AnimalFeedDefinition[12] { new AnimalFeedDefinition("Boar", "Boar", 1, ""), new AnimalFeedDefinition("Boar", "Boar", 2, "defeated_eikthyr"), new AnimalFeedDefinition("Wolf", "Wolf", 1, "defeated_bonemass"), new AnimalFeedDefinition("Wolf", "Wolf", 2, "defeated_dragon"), new AnimalFeedDefinition("Lox", "Lox", 1, "defeated_dragon"), new AnimalFeedDefinition("Lox", "Lox", 2, "defeated_goblinking"), new AnimalFeedDefinition("Hen", "Hen", 1, "defeated_goblinking"), new AnimalFeedDefinition("Hen", "Hen", 2, "defeated_queen"), new AnimalFeedDefinition("Asksvin", "Asksvin", 1, "defeated_queen"), new AnimalFeedDefinition("Asksvin", "Asksvin", 2, "defeated_fader"), new AnimalFeedDefinition("Moose", "Moose", 1, "defeated_fader"), new AnimalFeedDefinition("Moose", "Moose", 2, "defeated_fader") }; internal static AnimalFeedDefinition Find(string prefab) { return Array.Find(All, (AnimalFeedDefinition f) => f.Prefab == prefab); } internal static string Validate(AnimalFeedDefinition feed, string species, bool tame, int level, bool unlocked) { if (feed == null) { return "Unknown specialty feed."; } if (species != feed.Species) { return "Use this feed on an adult " + feed.Name.ToLowerInvariant() + "."; } if (!tame) { return "Tame this animal first."; } if (level >= 3) { return "This animal already has two stars."; } if (level != feed.Stars) { return "This feed requires a " + (feed.Stars - 1) + "-star animal."; } if (!unlocked) { return "Defeat the required boss in this world first."; } return ""; } internal static int NextProgress(int progress) { return Math.Min(10, Math.Max(0, progress) + 1); } } internal static class AttributeBenefits { internal static readonly string[] Keys = new string[15] { "HealthPerRank", "HealthRegenPerSecondPerRank", "HealthPoisonResistancePercentPerRank", "StaminaPerRank", "StaminaCarryWeightPerRank", "StaminaRegenPerSecondPerRank", "StaminaPoisonResistancePercentPerRank", "WeaponDamagePercentPerRank", "StrengthCarryWeightPerRank", "ArmorPerRank", "StaggerCapacityPercentPerRank", "EitrPerRank", "EitrRegenPerSecondPerRank", "EitrRegenPerSecondCap", "PoisonResistancePercentCap" }; internal static readonly float[] Defaults = new float[15] { 2f, 0.08f, 2f, 2f, 8f, 0.4f, 2f, 1f, 5f, 1f, 1f, 3f, 0.1f, 3.5f, 100f }; internal static Func<int, float> ReadValue = null; private static readonly int[][] Groups = new int[5][] { new int[3] { 0, 1, 2 }, new int[4] { 3, 4, 5, 6 }, new int[2] { 7, 8 }, new int[2] { 9, 10 }, new int[2] { 11, 12 } }; private static readonly string[] Units = new string[13] { "max health", "health/sec", "% poison resist", "max stamina", "carry", "stamina/sec", "% poison resist", "% weapon damage", "carry", "armor", "% stagger capacity", "max eitr", "eitr/sec" }; internal static float Get(int key) { float num = ((ReadValue == null) ? Defaults[key] : ReadValue(key)); if (float.IsNaN(num) || float.IsInfinity(num)) { return Defaults[key]; } return Math.Max(0f, Math.Min((key == 14) ? 100f : 10000f, num)); } internal static int Rank(int rank) { return Math.Max(0, Math.Min(50, rank)); } internal static float Total(int key, int rank) { return Get(key) * (float)Rank(rank); } internal static float Poison(int health, int stamina) { return Math.Min(Get(14), Total(2, health) + Total(6, stamina)); } internal static float EitrRecovery(int rank) { return Math.Min(Get(13), Total(12, rank)); } internal static bool BenefitEnabled(int key) { if (Get(key) > 0f && ((key != 2 && key != 6) || Get(14) > 0f)) { if (key == 12) { return Get(13) > 0f; } return true; } return false; } internal static bool Enabled(int attribute) { int[] array = Groups[attribute]; for (int i = 0; i < array.Length; i++) { if (BenefitEnabled(array[i])) { return true; } } return false; } internal static string Number(float value) { return value.ToString("0.####", CultureInfo.InvariantCulture); } internal static string Describe(int attribute, int rank = 1) { List<string> list = new List<string>(); int[] array = Groups[attribute]; foreach (int num in array) { if (BenefitEnabled(num)) { float value = ((num == 12) ? EitrRecovery(rank) : Total(num, rank)); string text = Units[num]; list.Add("+" + Number(value) + (text.StartsWith("%") ? "" : " ") + text); } } return string.Join(", ", list); } internal static string Signature() { string[] array = new string[Defaults.Length]; for (int i = 0; i < array.Length; i++) { array[i] = Get(i).ToString("R", CultureInfo.InvariantCulture); } return string.Join(";", array); } } internal static class AttributeConfiguration { internal static void Bind(ConfigFile config) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown ConfigEntry<float>[] entries = new ConfigEntry<float>[AttributeBenefits.Keys.Length]; for (int i = 0; i < entries.Length; i++) { entries[i] = config.Bind<float>("Attribute Benefits", AttributeBenefits.Keys[i], AttributeBenefits.Defaults[i], new ConfigDescription(i switch { 14 => "Maximum combined poison damage reduction from Health and Stamina, in percent. Applied after vanilla resistance. 0 disables attribute poison resistance.", 13 => "Maximum total bonus eitr regeneration per second. 0 disables bonus eitr regeneration.", _ => "Bonus per purchased attribute rank. Regeneration values are per second; percentage values use 2 for 2 percent. 0 disables this benefit and hides its description.", } + " Synchronized from the server in multiplayer.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, (float)((i == 14) ? 100 : 10000)), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); } AttributeBenefits.ReadValue = (int index) => entries[index].Value; } } [HarmonyPatch(typeof(Character), "ApplyDamage")] internal static class AttributePoisonResistance { internal static float Percent(int health, int stamina) { return AttributeBenefits.Poison(health, stamina); } internal static void Prefix(Character __instance, HitData __0) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && __0 != null && !(__0.m_damage.m_poison <= 0f)) { int[] ranks = PlayerAttributes.Read(val).Ranks; __0.m_damage.m_poison *= (100f - Percent(ranks[0], ranks[1])) / 100f; } } } internal static class RegenRates { internal static float Health(int rank) { return AttributeBenefits.Total(1, rank); } internal static float Stamina(int rank) { return AttributeBenefits.Total(5, rank); } internal static float Eitr(int rank) { return AttributeBenefits.EitrRecovery(rank); } } [HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })] internal static class AttributeRegeneration { private sealed class Tick { internal double Time; internal double Health; internal int Rank = -1; internal float Rate = -1f; } private static readonly ConditionalWeakTable<Player, Tick> ticks = new ConditionalWeakTable<Player, Tick>(); internal static void Postfix(Player __instance, float __0) { if (!Object.op_Implicit((Object)(object)__instance) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } Tick orCreateValue = ticks.GetOrCreateValue(__instance); if (((Character)__instance).IsDead() || ((Character)__instance).InIntro() || ((Character)__instance).IsTeleporting() || __0 <= 0f || float.IsNaN(__0) || float.IsInfinity(__0)) { orCreateValue.Time = (orCreateValue.Health = 0.0); return; } int[] ranks = PlayerAttributes.Read(__instance).Ranks; float num = RegenRates.Health(ranks[0]); if (orCreateValue.Rank != ranks[0] || orCreateValue.Rate != num) { orCreateValue.Time = (orCreateValue.Health = 0.0); orCreateValue.Rank = ranks[0]; orCreateValue.Rate = num; } if (((Character)__instance).GetHealth() >= ((Character)__instance).GetMaxHealth()) { orCreateValue.Time = (orCreateValue.Health = 0.0); } else { orCreateValue.Time += __0; orCreateValue.Health += RegenRates.Health(ranks[0]) * __0; if (orCreateValue.Time >= 1.0) { if (orCreateValue.Health > 0.0) { ((Character)__instance).Heal((float)orCreateValue.Health, false); } orCreateValue.Time = (orCreateValue.Health = 0.0); } } ((Character)__instance).AddStamina(RegenRates.Stamina(ranks[1]) * __0); if (!((Character)__instance).InAttack() && !((Character)__instance).InDodge() && ((Character)__instance).GetMaxEitr() > 0f) { ((Character)__instance).AddEitr(RegenRates.Eitr(ranks[4]) * __0); } } } public sealed class AttributeScreen : MonoBehaviour { internal static AttributeScreen Instance; internal ConfigEntry<KeyCode> ToggleKey; private Player owner; private AttributeRanks staged; private AttributeRanks baseline; private bool open; private NpcWindow window; private static readonly string[] Names = new string[5] { "Health", "Stamina", "Strength", "Defense", "Eitr" }; private string settingsSignature; internal static bool IsOpen { get; private set; } private void Awake() { Instance = this; } internal void Close() { if (open) { GUIManager.BlockInput(false); } open = false; IsOpen = false; window?.Dispose(); window = null; } private void OnDestroy() { Close(); } private void OnDisable() { Close(); } private void Update() { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead() || (Object.op_Implicit((Object)(object)owner) && (Object)(object)owner != (Object)(object)Player.m_localPlayer)) { Close(); owner = null; return; } if (open && settingsSignature != AttributeBenefits.Signature()) { baseline = PlayerAttributes.Read(owner); staged = PlayerAttributes.Read(owner); Render(); } if (open && Input.GetKeyDown((KeyCode)27)) { Close(); } else if (ToggleKey != null && Input.GetKeyDown(ToggleKey.Value)) { Toggle(); } } internal void Toggle() { if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && !((Character)Player.m_localPlayer).IsDead()) { if (open) { Close(); } else if (!QuestJournal.IsOpen && !VillageChainScreen.IsOpen && !ForgeRepairScreen.IsOpen && !XpPartyScreen.IsOpen && !Console.IsVisible() && !TextInput.IsVisible() && !InventoryGui.IsVisible() && !StoreGui.IsVisible() && (!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()) && !Object.op_Implicit((Object)(object)BoarPlacement.Active) && !VillageRequestScreen.IsOpen) { owner = Player.m_localPlayer; baseline = PlayerAttributes.Read(owner); staged = PlayerAttributes.Read(owner); window = new NpcWindow("LV_Attributes"); open = true; IsOpen = true; GUIManager.BlockInput(true); Render(); } } } private void Render() { if (window == null || !Object.op_Implicit((Object)(object)owner)) { return; } settingsSignature = AttributeBenefits.Signature(); float scrollPosition = window.ScrollPosition; window.CompactMode = true; window.Clear("CHARACTER ATTRIBUTES"); int available = PlayerAttributes.Budget(owner) - staged.Spent; window.Label($"Level {Experience.Read(owner).Level} / 50 Available points: {available}", 42f); for (int i = 0; i < 5; i++) { int attribute = i; window.Section(delegate { window.Label($"{Names[attribute]} {baseline.Ranks[attribute]} → {staged.Ranks[attribute]}", 34f, 22f); bool flag = AttributeBenefits.Enabled(attribute); window.Label(flag ? (AttributeBenefits.Describe(attribute) + " per rank") : "Disabled by current settings", 44f); float cursor = window.Cursor; ((Selectable)window.ButtonAt("−", delegate { if (staged.Ranks[attribute] > baseline.Ranks[attribute]) { staged.Ranks[attribute]--; } Render(); }, 36f, cursor, 90f, 36f)).interactable = staged.Ranks[attribute] > baseline.Ranks[attribute]; int num = AttributeRanks.Cost(attribute, staged.Ranks[attribute] + 1); ((Selectable)window.ButtonAt($"+ ({num} pts)", delegate { if (AttributeBenefits.Enabled(attribute) && staged.Ranks[attribute] < 50 && PlayerAttributes.Budget(owner) - staged.Spent >= AttributeRanks.Cost(attribute, staged.Ranks[attribute] + 1)) { staged.Ranks[attribute]++; } Render(); }, 140f, cursor, 180f, 36f)).interactable = flag && staged.Ranks[attribute] < 50 && available >= num; window.Space(42f); }); } window.Section(delegate { for (int j = 0; j < 5; j++) { if (AttributeBenefits.Enabled(j)) { window.Label(Names[j] + ": " + AttributeBenefits.Describe(j, staged.Ranks[j]), 50f); } } if (AttributeBenefits.Get(13) > 0f && AttributeBenefits.Get(12) > 0f) { window.Label("Eitr recovery cap: " + AttributeBenefits.Number(AttributeBenefits.Get(13)) + "/sec", 34f); } if (AttributeBenefits.Get(14) > 0f && (AttributeBenefits.Get(2) > 0f || AttributeBenefits.Get(6) > 0f)) { window.Label("Combined poison reduction: " + AttributeBenefits.Number(AttributeBenefits.Poison(staged.Ranks[0], staged.Ranks[1])) + "% (cap " + AttributeBenefits.Number(AttributeBenefits.Get(14)) + "%)", 34f); } window.Button("Apply points", delegate { if (PlayerAttributes.Apply(owner, staged)) { baseline = PlayerAttributes.Read(owner); staged = PlayerAttributes.Read(owner); ((Character)owner).Message((MessageType)2, "Attribute points applied.", 0, (Sprite)null, false); } Render(); }, staged.Spent > baseline.Spent && available >= 0); window.Button("Discard changes", delegate { baseline = PlayerAttributes.Read(owner); staged = PlayerAttributes.Read(owner); Render(); }); }); window.FinishCompact(800f); window.ScrollPosition = scrollPosition; } } [HarmonyPatch(typeof(Character), "GetStaggerTreshold")] internal static class AttributeStagger { internal static void Postfix(Character __instance, ref float __result) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null) { __result *= 1f + AttributeBenefits.Total(10, PlayerAttributes.Read(val).Ranks[3]) / 100f; } } } internal static class AutomaticVillagePlanning { internal sealed class Reservation { internal Plan Plan; internal PlannedSurface Surface; internal ZDO Data; } internal sealed class FallbackCandidate { internal Plan Survey; internal double Score; } private static ZDOMan world; private static readonly Dictionary<Vector2s, Reservation> reservations = new Dictionary<Vector2s, Reservation>(); internal static Reservation Constructing; internal static Func<bool> FallbackEnabled = () => false; internal static Func<bool> ForceFallbackTest = () => false; internal static Func<bool> HouseFallbackEnabled = () => false; internal static Func<double> VillageSearchSeconds = () => 30.0; internal static Func<double> HouseSearchSeconds = () => 6.0; private static readonly MethodInfo register = AccessTools.Method(typeof(ZoneSystem), "RegisterLocation", (Type[])null, (Type[])null); private static readonly MethodInfo generated = AccessTools.Method(typeof(ZoneSystem), "IsZoneGenerated", (Type[])null, (Type[])null); internal static IEnumerable<Reservation> Loaded { get { if (world != ZDOMan.instance) { return Enumerable.Empty<Reservation>(); } return reservations.Values; } } internal static Plan FitHomes(Plan core, Func<bool> canContinue, bool relax) { Plan plan = OptionalHomePlanning.Extend(core, canContinue); if (!relax || plan.Layout.Homes.Length >= 2 || !canContinue()) { return plan; } return OptionalHomePlanning.Extend(plan, canContinue, fallback: true); } internal static void RememberFallback(List<FallbackCandidate> candidates, Plan survey, double separation) { if (survey.Original == null || survey.Meadow == null || survey.Original.Length != 12769) { return; } double num = 0.0; for (int i = 0; i < survey.Original.Length; i++) { double num2 = survey.Original[i]; if (double.IsNaN(num2) || double.IsInfinity(num2)) { return; } if (i % 113 > 0) { num += Math.Abs(num2 - survey.Original[i - 1]); } if (i >= 113) { num += Math.Abs(num2 - survey.Original[i - 113]); } } double score = survey.Original.Max() - survey.Original.Min() + num / (double)survey.Original.Length; FallbackCandidate[] array = candidates.Where((FallbackCandidate c) => Math.Pow(c.Survey.WorldX - survey.WorldX, 2.0) + Math.Pow(c.Survey.WorldZ - survey.WorldZ, 2.0) < separation * separation).ToArray(); if (!array.Any((FallbackCandidate c) => c.Score <= score)) { FallbackCandidate[] array2 = array; foreach (FallbackCandidate item in array2) { candidates.Remove(item); } candidates.Add(new FallbackCandidate { Survey = survey, Score = score }); candidates.Sort((FallbackCandidate a, FallbackCandidate b) => a.Score.CompareTo(b.Score)); if (candidates.Count > 2) { candidates.RemoveAt(2); } } } internal static Limits FallbackLimits() { return new Limits { FastReject = true, Cut = 4.0, Fill = 4.0, RoadSlope = 0.28, CrossSlope = 0.14, BankSlope = 0.75 }; } internal static IEnumerator TryFallback(ZoneSystem zone, ZoneLocation location, List<FallbackCandidate> candidates, List<Reservation> fresh, double seconds = 8.0) { WorldGenerator generator = WorldGenerator.instance; ZDOMan manager = ZDOMan.instance; if (location.m_quantity <= 0 || zone.GetLocationList().Any((LocationInstance v) => v.m_location.m_prefabName == "LV_MeadowsHamlet")) { yield break; } Stopwatch clock = Stopwatch.StartNew(); int maximum = Math.Min(2, location.m_quantity); Log($"No normal village found; retrying {candidates.Count} retained candidates with relaxed terrain limits (up to {maximum} villages, eight-second budget)."); foreach (FallbackCandidate candidate in candidates) { if (fresh.Count >= maximum || clock.Elapsed.TotalSeconds >= seconds || WorldGenerator.instance != generator || ZDOMan.instance != manager) { yield break; } Plan survey = candidate.Survey; Vector3 center = new Vector3((float)survey.WorldX, 0f, (float)survey.WorldZ); float separation = Mathf.Max(1200f, location.m_minDistanceFromSimilar); if (!ClearReservation(zone, center, separation)) { continue; } Task<Plan> task = Task.Run(() => Planner.Solve(survey.Layout, survey.Original, survey.Meadow, survey.Water, FallbackLimits())); while (!task.IsCompleted) { if (clock.Elapsed.TotalSeconds >= seconds || WorldGenerator.instance != generator || ZDOMan.instance != manager) { task.ContinueWith(delegate(Task<Plan> t) { _ = t.Exception; }, TaskContinuationOptions.OnlyOnFaulted); yield break; } yield return null; } if (clock.Elapsed.TotalSeconds >= seconds || WorldGenerator.instance != generator || ZDOMan.instance != manager) { yield break; } if (task.IsFaulted) { Log("Fallback fit failed: " + task.Exception.GetBaseException().Message); continue; } Plan result = task.GetAwaiter().GetResult(); if (!result.Valid) { Log("Fallback candidate rejected: " + string.Join("; ", result.Reasons)); } else if (ClearReservation(zone, center, separation)) { result.WorldX = survey.WorldX; result.WorldZ = survey.WorldZ; result.Yaw = survey.Yaw; Reservation reservation = Reserve(zone, location, result); reservation.Data.Set("lv_fallback_plan", true); reservation.Data.Set("lv_fallback_reason", string.Join("; ", survey.Reasons)); reservation.Data.Set("lv_fallback_forced", survey.Reasons.Contains("Debug test: normal reservation deliberately skipped")); fresh.Add(reservation); Log($"Reserved fallback village at X={result.WorldX:F1}, Z={result.WorldZ:F1}; cut={result.Cut:F2}, fill={result.Fill:F2}, road={result.RoadSlope:P1}."); } } Log($"Fallback finished: {fresh.Count}/{maximum} villages reserved. Optional houses will be checked separately."); } internal static void Load() { //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) if (world == ZDOMan.instance) { return; } ZDOMan instance = ZDOMan.instance; world = null; reservations.Clear(); Constructing = null; if (instance == null) { return; } List<ZDO> list = new List<ZDO>(); int num = 0; while (!instance.GetAllZDOsWithPrefabIterative("LV_TestPlannedTerrain", list, ref num)) { } foreach (ZDO item in list) { if (!item.GetBool("lv_auto_plan", false)) { continue; } PlannedSurface plannedSurface = PlannedSurface.Decode(item.GetByteArray("lv_plan_surface", (byte[])null)); using MemoryStream input = new MemoryStream(item.GetByteArray("lv_plan_levels", (byte[])null)); using BinaryReader binaryReader = new BinaryReader(input); int num2 = binaryReader.ReadInt32(); Layout layout = OptionalHomePlanning.Decode(item.GetByteArray("lv_plan_homes", (byte[])null), num2); if (num2 != layout.Nodes.Length) { throw new InvalidDataException("Saved village platform count is incompatible."); } double[] array = new double[num2]; for (int i = 0; i < num2; i++) { array[i] = binaryReader.ReadDouble(); if (double.IsNaN(array[i]) || double.IsInfinity(array[i])) { throw new InvalidDataException("Invalid saved village platform height."); } } Vector3 position = item.GetPosition(); OptionalHomePlanning.BindJunctions(layout, array); Plan plan = new Plan { Layout = layout, WorldX = position.x, WorldZ = position.z, Yaw = item.GetFloat("lv_plan_yaw", 0f), Levels = array, Heights = ((IEnumerable<float>)plannedSurface.Height).Select((Func<float, double>)((float h) => h)).ToArray(), Original = ((IEnumerable<float>)plannedSurface.Original).Select((Func<float, double>)((float h) => h)).ToArray(), Kind = (byte[])plannedSurface.Paint.Clone() }; reservations[ZoneSystem.GetZone(position)] = new Reservation { Plan = plan, Surface = plannedSurface, Data = item }; } world = instance; Log($"Loaded {reservations.Count} world-saved village plans."); } internal static Reservation Find(Vector3 position) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Load(); if (!reservations.TryGetValue(ZoneSystem.GetZone(position), out var value)) { return null; } return value; } private static Reservation Reserve(ZoneSystem zone, ZoneLocation location, Plan plan) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor((float)plan.WorldX, (float)plan.Levels[7], (float)plan.WorldZ); PlannedSurface plannedSurface = PlannedSurface.From(plan); using MemoryStream memoryStream = new MemoryStream(); using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true)) { binaryWriter.Write(plan.Levels.Length); double[] levels = plan.Levels; foreach (double value in levels) { binaryWriter.Write(value); } } ZDO val2 = world.CreateNewZDO(val, StringExtensionMethods.GetStableHashCode("LV_TestPlannedTerrain")); val2.SetPrefab(StringExtensionMethods.GetStableHashCode("LV_TestPlannedTerrain")); val2.Persistent = true; val2.SetRotation(Quaternion.Euler(0f, (float)plan.Yaw, 0f)); val2.Set("lv_plan_surface", plannedSurface.Encode()); val2.Set("lv_plan_levels", memoryStream.ToArray()); val2.Set("lv_plan_yaw", (float)plan.Yaw); val2.Set("lv_auto_plan", true); Reservation reservation = new Reservation { Plan = plan, Surface = plannedSurface, Data = val2 }; reservations[ZoneSystem.GetZone(val)] = reservation; register.Invoke(zone, new object[3] { location, val, false }); return reservation; } private static bool ClearReservation(ZoneSystem zone, Vector3 center, float separation) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) foreach (LocationInstance location in zone.GetLocationList()) { float num = Utils.DistanceXZ(center, location.m_position); float num2 = ((location.m_location.m_prefabName == "LV_MeadowsHamlet") ? separation : (80f + location.m_location.m_exteriorRadius)); if (!(num < num2)) { Vector2s zone2 = ZoneSystem.GetZone(center); if (!((Vector2s)(ref zone2)).Equals(ZoneSystem.GetZone(location.m_position))) { continue; } } return false; } for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if ((bool)generated.Invoke(zone, new object[1] { ZoneSystem.GetZone(center + new Vector3((float)(j * 64), 0f, (float)(i * 64))) })) { return false; } } } return true; } private static bool CoarseFit(WorldGenerator generator, Layout layout, Vector3 center, Quaternion rotation, float water) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Invalid comparison between Unknown and I4 //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) Pad[] pads = layout.Pads; foreach (Pad pad in pads) { float num = float.PositiveInfinity; float num2 = float.NegativeInfinity; for (int j = -1; j <= 1; j++) { for (int k = -1; k <= 1; k++) { Vector3 val = center + rotation * new Vector3((float)(pad.X + (double)j * pad.HalfX), 0f, (float)(pad.Z + (double)k * pad.HalfZ)); if ((int)generator.GetBiome(val.x, val.z, 0.02f, false) != 1) { return false; } float height = generator.GetHeight(val.x, val.z); num = Mathf.Min(num, height); num2 = Mathf.Max(num2, height); if (num2 - num > 5f || height < water - 2f) { return false; } } } } return true; } internal static IEnumerator Search(ZoneSystem zone, ZoneLocation location, ZPackage iterations, double budgetSeconds = 30.0) { List<Reservation> fresh = new List<Reservation>(); WorldGenerator generator = WorldGenerator.instance; ZDOMan manager = ZDOMan.instance; List<FallbackCandidate> candidates = ((FallbackEnabled() || ForceFallbackTest()) ? new List<FallbackCandidate>() : null); IEnumerator core = SearchCore(zone, location, iterations, budgetSeconds, fresh, candidates); try { while (core.MoveNext()) { yield return core.Current; } } finally { IDisposable disposable = core as IDisposable; if (disposable != null) { disposable.Dispose(); } } if (WorldGenerator.instance != generator || ZDOMan.instance != manager) { yield break; } if (fresh.Count == 0) { if (candidates != null) { { IEnumerator fallback = TryFallback(zone, location, candidates, fresh); try { while (fallback.MoveNext()) { yield return fallback.Current; } } finally { IDisposable disposable2 = fallback as IDisposable; if (disposable2 != null) { disposable2.Dispose(); } } } } if (fresh.Count == 0 || WorldGenerator.instance != generator || ZDOMan.instance != manager) { yield break; } } double houseBudget = Math.Max(0.0, HouseSearchSeconds()); bool relaxHouses = HouseFallbackEnabled(); Log($"Core search complete; checking optional houses ({houseBudget:F0}-second budget; relaxed house fallback={relaxHouses})."); Plan[] originals = fresh.Select((Reservation r) => r.Plan).ToArray(); Task<Plan[]> task = Task.Run(delegate { Stopwatch clock = Stopwatch.StartNew(); return originals.Select((Plan p) => FitHomes(p, () => clock.Elapsed.TotalSeconds < houseBudget, relaxHouses)).ToArray(); }); while (!task.IsCompleted) { if (WorldGenerator.instance != generator || ZDOMan.instance != manager) { task.ContinueWith(delegate(Task<Plan[]> t) { _ = t.Exception; }, TaskContinuationOptions.OnlyOnFaulted); yield break; } yield return null; } if (WorldGenerator.instance != generator || ZDOMan.instance != manager) { yield break; } if (task.IsFaulted) { Log("Optional house fitting failed; core villages retained: " + task.Exception.GetBaseException().Message); yield break; } Plan[] result = task.GetAwaiter().GetResult(); for (int num = 0; num < fresh.Count; num++) { Reservation reservation = fresh[num]; Plan plan = result[num]; if (reservation.Data.GetBool("lv_plan_complete", false)) { continue; } if (plan != originals[num]) { PlannedSurface plannedSurface = PlannedSurface.From(plan); using MemoryStream memoryStream = new MemoryStream(); using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8, leaveOpen: true)) { binaryWriter.Write(plan.Levels.Length); double[] levels = plan.Levels; foreach (double value in levels) { binaryWriter.Write(value); } } reservation.Data.Set("lv_plan_surface", plannedSurface.Encode()); reservation.Data.Set("lv_plan_levels", memoryStream.ToArray()); reservation.Data.Set("lv_plan_homes", OptionalHomePlanning.Encode(plan.Layout)); reservation.Plan = plan; reservation.Surface = plannedSurface; } Log($"Optional houses at X={plan.WorldX:F1}, Z={plan.WorldZ:F1}: {plan.Layout.Homes.Length}/2; " + ((plan.Layout.Homes.Length == 0) ? "core village retained" : string.Join(", ", plan.Layout.Homes.Select((HomePlacement h) => $"{h.Name} [slot {h.Variant}]"))) + "."); } } private static IEnumerator SearchCore(ZoneSystem zone, ZoneLocation location, ZPackage iterations, double budgetSeconds, List<Reservation> fresh, List<FallbackCandidate> candidates) { int visited = 0; Stopwatch elapsed = Stopwatch.StartNew(); try { Load(); WorldGenerator generator = WorldGenerator.instance; ZDOMan manager = world; foreach (Reservation value3 in reservations.Values) { Vector3 position = value3.Data.GetPosition(); if (!zone.GetLocationList().Any(delegate(LocationInstance v) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) Vector2s zone2 = ZoneSystem.GetZone(v.m_position); return ((Vector2s)(ref zone2)).Equals(ZoneSystem.GetZone(position)); })) { register.Invoke(zone, new object[3] { location, position, value3.Data.GetBool("lv_plan_complete", false) }); } } int wanted = Math.Max(0, Math.Min(6, location.m_quantity)); int accepted = zone.GetLocationList().Count((LocationInstance v) => v.m_location.m_prefabName == "LV_MeadowsHamlet"); if (accepted >= wanted) { yield break; } bool forceFallback = ForceFallbackTest(); if (forceFallback && accepted > 0) { yield break; } if (forceFallback) { Log("DEBUG: normal reservations will be skipped to exercise fallback placement."); } Layout layout = Layout.Current(); int solves = 0; int coarseRejected = 0; int occupied = 0; Dictionary<string, int> failures = new Dictionary<string, int>(); Random random = new Random(generator.GetSeed() ^ 0x4C565031); double angleOffset = random.NextDouble() * Math.PI * 2.0; Log($"Automatic planned generation: {accepted}/{wanted} reserved; searching for one nearby village and separated outer Meadows villages."); for (float radius = Mathf.Max(200f, location.m_minDistance); radius <= 5500f; radius += 128f) { if (accepted >= wanted) { break; } if (solves >= 256) { break; } if ((accepted > 0 || (forceFallback && candidates != null && candidates.Count > 0)) && radius < 1500f) { continue; } int ringFits = 0; int points = Mathf.CeilToInt(MathF.PI * 2f * radius / 96f); for (int point = 0; point < points && accepted < wanted && solves < 256 && ringFits < 16; point++) { if (WorldGenerator.instance != generator || ZDOMan.instance != manager || elapsed.Elapsed.TotalSeconds >= budgetSeconds) { yield break; } double num = angleOffset + (double)point * 2.399963229728653; Vector3 center = new Vector3((float)Math.Cos(num) * radius, 0f, (float)Math.Sin(num) * radius); if (accepted > 0) { if (radius < 1500f) { break; } int sector = Sector(center); if (zone.GetLocationList().Any((LocationInstance v) => v.m_location.m_prefabName == "LV_MeadowsHamlet" && Utils.DistanceXZ(v.m_position, default(Vector3)) >= 1500f && Sector(v.m_position) == sector)) { continue; } } visited++; if (visited % 8 == 0) { yield return null; if (WorldGenerator.instance != generator || ZDOMan.instance != manager || elapsed.Elapsed.TotalSeconds >= budgetSeconds) { yield break; } } if ((int)generator.GetBiome(center.x, center.z, 0.02f, false) != 1) { coarseRejected++; continue; } if (!ClearReservation(zone, center, Mathf.Max(1200f, location.m_minDistanceFromSimilar))) { occupied++; continue; } Dictionary<int, (double Height, bool Meadow)> sampleCache = new Dictionary<int, (double, bool)>(); for (int turn = 0; turn < 4; turn++) { if (solves >= 256) { break; } if (ringFits >= 16) { break; } Quaternion rotation = Quaternion.Euler(0f, (float)(turn * 90), 0f); if (!CoarseFit(generator, layout, center, rotation, zone.m_waterLevel)) { coarseRejected++; continue; } double[] heights = new double[12769]; bool[] meadow = new bool[heights.Length]; Stopwatch slice = Stopwatch.StartNew(); for (int i = 0; i < heights.Length; i++) { int num2 = i % 113 - 56; int num3 = i / 113 - 56; int num4 = turn switch { 2 => -num2, 1 => num3, 0 => num2, _ => -num3, }; int num5 = turn switch { 2 => -num3, 1 => -num2, 0 => num3, _ => num2, }; int key = (num5 + 56) * 113 + num4 + 56; if (!sampleCache.TryGetValue(key, out (double, bool) value)) { value = (generator.GetHeight(center.x + (float)num4, center.z + (float)num5), (int)generator.GetBiome(center.x + (float)num4, center.z + (float)num5, 0.02f, false) == 1); sampleCache.Add(key, value); } heights[i] = value.Item1; meadow[i] = value.Item2; if (i % 32 == 31 && slice.ElapsedMilliseconds >= 3) { yield return null; slice.Restart(); if (WorldGenerator.instance != generator || ZDOMan.instance != manager || elapsed.Elapsed.TotalSeconds >= budgetSeconds) { yield break; } } } double water = zone.m_waterLevel; Stopwatch fitClock = Stopwatch.StartNew(); Task<Plan> task = Task.Run(() => Planner.Solve(layout, heights, meadow, water, new Limits { FastReject = true })); while (!task.IsCompleted) { if (WorldGenerator.instance != generator || ZDOMan.instance != manager || elapsed.Elapsed.TotalSeconds >= budgetSeconds) { task.ContinueWith(delegate(Task<Plan> t) { _ = t.Exception; }, TaskContinuationOptions.OnlyOnFaulted); yield break; } yield return null; } if (WorldGenerator.instance != generator || ZDOMan.instance != manager || elapsed.Elapsed.TotalSeconds >= budgetSeconds) { yield break; } Plan result = task.GetAwaiter().GetResult(); solves++; ringFits++; Log(string.Format("Fit {0}: {1} in {2:F0}ms; elapsed search {3:F1}s.", solves, result.Valid ? "accepted" : "rejected", fitClock.Elapsed.TotalMilliseconds, elapsed.Elapsed.TotalSeconds)); if (!result.Valid) { if (candidates != null && accepted == 0) { result.WorldX = center.x; result.WorldZ = center.z; result.Yaw = turn * 90; RememberFallback(candidates, result, Mathf.Max(1200f, location.m_minDistanceFromSimilar)); } foreach (string reason in result.Reasons) { string key2 = reason.Split(':')[0]; failures[key2] = ((!failures.TryGetValue(key2, out var value2)) ? 1 : (value2 + 1)); } if (solves % 10 == 0) { Log($"Search progress: {accepted}/{wanted} villages, {solves}/256 detailed fits, {visited} sites checked."); } continue; } result.WorldX = center.x; result.WorldZ = center.z; result.Yaw = turn * 90; if (forceFallback) { result.Reasons.Add("Debug test: normal reservation deliberately skipped"); RememberFallback(candidates, result, Mathf.Max(1200f, location.m_minDistanceFromSimilar)); if (candidates.Count < Math.Min(2, wanted)) { break; } yield break; } fresh.Add(Reserve(zone, location, result)); accepted++; Log($"Reserved planned village {accepted}/{wanted}: X={center.x:F1}, Z={center.z:F1}, yaw={result.Yaw:F0}, distance={radius:F0}m; cut={result.Cut:F2}, fill={result.Fill:F2}, road={result.RoadSlope:P1}."); break; } yield return null; } yield return null; } Log($"Automatic generation finished: {accepted}/{wanted} villages; {solves} detailed fits, {visited} sites, {coarseRejected} coarse rejects, {occupied} occupied/explored rejects. " + string.Join("; ", from p in failures.OrderByDescending((KeyValuePair<string, int> p) => p.Value).Take(6) select p.Key + "=" + p.Value)); if (accepted == 0) { Log("No acceptable site found inside 5500m/search budget. Normal search has no reservations."); } int Sector(Vector3 p) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) double num6 = Math.Atan2(p.z, p.x) - angleOffset; num6 = (num6 % (Math.PI * 2.0) + Math.PI * 2.0) % (Math.PI * 2.0); return Math.Min(4, (int)(num6 / (Math.PI * 2.0 / 5.0))); } } finally { if (elapsed.Elapsed.TotalSeconds >= budgetSeconds) { Log($"Village search time budget reached ({elapsed.Elapsed.TotalSeconds:F1}s); keeping accepted plans and continuing world loading. Any enabled fallback will be checked separately."); } iterations.Write(visited); iterations.SetPos(0); } } internal static void Log(string message) { Logger.LogInfo((object)("[Automatic village] " + message)); } } [HarmonyPatch(typeof(ZoneSystem), "GenerateLocationsTimeSliced", new Type[] { typeof(ZoneLocation), typeof(Stopwatch), typeof(ZPackage) })] internal static class AutomaticVillageSearchHook { private static bool Prefix(ZoneSystem __instance, ZoneLocation __0, ZPackage __2, ref IEnumerator __result) { if (__0.m_prefabName != "LV_MeadowsHamlet") { return true; } __result = AutomaticVillagePlanning.Search(__instance, __0, __2, AutomaticVillagePlanning.VillageSearchSeconds()); return false; } } public sealed class BarracksLinkAnchor : MonoBehaviour { public bool End; } [HarmonyPatch(typeof(TerrainModifier), "GetRadius")] internal static class BarracksLinkRadius { private static void Postfix(TerrainModifier __instance, ref float __result) { if (Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<BarracksLinkAnchor>())) { __result = 45f; } } } internal static class BarracksLink { internal static readonly Vector3[] Route = CreateRoute(); private static Vector3[] CreateRoute() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) float[,] points = BarracksLinkProfile.Points; Vector3[] array = (Vector3[])(object)new Vector3[points.GetLength(0)]; for (int i = 0; i < array.Length; i++) { array[i] = new Vector3(points[i, 0], 0f, points[i, 1]); } return array; } internal static void Register() { for (int i = 0; i < 2; i++) { string text = "LV_BarracksLink" + i; Plugin.RegisterGroundPatch(text, (PaintType)3, 0f); GameObject prefab = PrefabManager.Instance.GetPrefab(text); prefab.AddComponent<BarracksLinkAnchor>().End = i == 1; prefab.GetComponent<TerrainModifier>().m_paintCleared = false; } } internal static void Build(Transform parent) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) VillageLayout.Place(parent, "LV_BarracksLink0", Route[0], 0f); VillageLayout.Place(parent, "LV_BarracksLink1", Route[Route.Length - 1], 0f); } } [HarmonyPatch(typeof(Heightmap), "ApplyModifiers")] internal static class GradeBarracksLink { [HarmonyPriority(0)] private static void Postfix(Heightmap __instance, List<float> ___m_heights, int ___m_width, float ___m_scale) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) List<TerrainModifier> allInstances = TerrainModifier.GetAllInstances(); foreach (TerrainModifier item in allInstances) { if (!Object.op_Implicit((Object)(object)item) || !((Behaviour)item).isActiveAndEnabled) { continue; } BarracksLinkAnchor component = ((Component)item).GetComponent<BarracksLinkAnchor>(); if (!Object.op_Implicit((Object)(object)component) || component.End) { continue; } Quaternion rotation = ((Component)item).transform.rotation; Vector3 val = ((Component)item).transform.position - rotation * BarracksLink.Route[0]; Vector3 val2 = val + rotation * BarracksLink.Route[4]; TerrainModifier val3 = null; foreach (TerrainModifier item2 in allInstances) { if (Object.op_Implicit((Object)(object)item2) && ((Behaviour)item2).isActiveAndEnabled) { BarracksLinkAnchor component2 = ((Component)item2).GetComponent<BarracksLinkAnchor>(); if (Object.op_Implicit((Object)(object)component2) && component2.End && Utils.DistanceXZ(((Component)item2).transform.position, val2) < 0.2f) { val3 = item2; break; } } } if (!Object.op_Implicit((Object)(object)val3)) { continue; } Vector3 position = ((Component)__instance).transform.position; if (Utils.DistanceXZ(position, ((Component)item).transform.position) > 95f) { continue; } Quaternion val4 = Quaternion.Inverse(rotation); float num = (float)___m_width * ___m_scale * 0.5f; for (int i = 0; i <= ___m_width; i++) { for (int j = 0; j <= ___m_width; j++) { Vector3 val5 = val4 * (new Vector3(position.x - num + (float)j * ___m_scale, val.y, position.z - num + (float)i * ___m_scale) - val); int index = i * (___m_width + 1) + j; ___m_heights[index] = BarracksLinkProfile.Adjust(val5.x, val5.z, ___m_heights[index], ((Component)item).transform.position.y - position.y, ((Component)val3).transform.position.y - position.y); } } } } } internal static class BarracksLinkProfile { internal static readonly float[,] Points = new float[5, 2] { { 10f, -4f }, { 10f, -9f }, { 24f, -9f }, { 32f, -5f }, { 32f, 2f } }; internal static float Adjust(float x, float z, float before, float start, float end) { if (x <= 7f || (x >= 11.7f && x <= 18.3f && z >= -5.3f && z <= 7.3f) || (x >= 27.7f && x <= 36.3f && z >= 3.7f && z <= 24.3f)) { return before; } double num = double.PositiveInfinity; double num2 = 0.0; double num3 = 0.0; for (int i = 1; i < Points.GetLength(0); i++) { double num4 = Points[i - 1, 0]; double num5 = Points[i - 1, 1]; double num6 = (double)Points[i, 0] - num4; double num7 = (double)Points[i, 1] - num5; double num8 = Math.Sqrt(num6 * num6 + num7 * num7); double num9 = Clamp((((double)x - num4) * num6 + ((double)z - num5) * num7) / (num8 * num8), 0.0, 1.0); double num10 = (double)x - num4 - num6 * num9; double num11 = (double)z - num5 - num7 * num9; double num12 = Math.Sqrt(num10 * num10 + num11 * num11); if (num12 < num) { num = num12; num2 = num3 + num9 * num8; } num3 += num8; } double num13 = 1.4 + 1.2 * Clamp((num2 / num3 - 0.75) * 4.0, 0.0, 1.0); if (num >= num13 + 4.0) { return before; } double v = (double)start + (double)(end - start) * Smooth((num2 - 1.0) / (num3 - 2.0)); double num14 = (1.0 - Smooth((num - num13) / 4.0)) * Smooth((x - 7f) / 2f); return (float)((double)before + (Clamp(v, before - 2f, before + 2f) - (double)before) * num14); } private static double Clamp(double v, double min, double max) { return Math.Max(min, Math.Min(max, v)); } private static double Smooth(double v) { v = Clamp(v, 0.0, 1.0); return v * v * (3.0 - 2.0 * v); } } internal enum BedroomDoorAction { None, Wait, Open, Close } internal sealed class BedroomDoorRoutine { private bool? target; private bool finished; internal BedroomDoorAction Tick(bool wantOpen, bool travelling, int state, bool openReady, bool closedReady) { if (target != wantOpen) { target = wantOpen; finished = false; } if (finished && !travelling) { return BedroomDoorAction.None; } if (wantOpen ? openReady : closedReady) { finished = true; return BedroomDoorAction.None; } finished = false; if (wantOpen && state == 0 && closedReady) { return BedroomDoorAction.Open; } if (!wantOpen && state != 0 && openReady) { return BedroomDoorAction.Close; } return BedroomDoorAction.Wait; } } public sealed class BenchSite : MonoBehaviour { } public sealed class BenchGrade : MonoBehaviour { } internal static class BenchTerrain { internal static void Build(Transform parent, Vector3 position, float yaw) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) Transform transform = new GameObject("BenchSite").transform; transform.SetParent(parent, false); transform.localPosition = position; transform.localRotation = Quaternion.Euler(0f, yaw, 0f); ((Component)transform).gameObject.AddComponent<BenchSite>(); VillageLayout.Place(transform, "LV_BenchGrade", Vector3.zero, 0f); SnapToGround component = VillageLayout.Place(transform, "LV_Green_piece_bench01", new Vector3(0f, 0.05f, 0f), 0f).GetComponent<SnapToGround>(); if (Object.op_Implicit((Object)(object)component)) { Object.DestroyImmediate((Object)(object)component); } } } [HarmonyPatch(typeof(Heightmap), "LevelTerrain")] internal static class LevelBenchFootprint { private static bool Prefix(Heightmap __instance, Vector3 __0, float __1, List<float> ___m_heights, int ___m_width, float ___m_scale) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) bool flag = false; foreach (TerrainModifier allInstance in TerrainModifier.GetAllInstances()) { if (Object.op_Implicit((Object)(object)allInstance) && ((Behaviour)allInstance).isActiveAndEnabled && Object.op_Implicit((Object)(object)((Component)allInstance).GetComponent<BenchGrade>())) { Vector3 val = ((Component)allInstance).transform.position - __0; if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { flag = true; break; } } } if (!flag) { return true; } Vector3 position = ((Component)__instance).transform.position; float num = (float)___m_width * ___m_scale * 0.5f; for (int i = 0; i <= ___m_width; i++) { for (int j = 0; j <= ___m_width; j++) { float num2 = position.x - num + (float)j * ___m_scale - __0.x; float num3 = position.z - num + (float)i * ___m_scale - __0.z; float num4 = Mathf.Sqrt(num2 * num2 + num3 * num3); if (!(num4 >= __1)) { float num5 = 1f - Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(1.6f, __1, num4)); int index = i * (___m_width + 1) + j; ___m_heights[index] = Mathf.Lerp(___m_heights[index], __0.y - position.y, num5); } } } return false; } } internal static class BlueprintHouse { internal sealed class Part { internal string Name; internal Vector3 Position; internal Vector3 Scale; internal Quaternion Rotation; } internal static readonly List<Part> Parts = Read(); private static List<Part> Read() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) List<Part> list = new List<Part>(); using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("LivingVillages.House.blueprint") ?? throw new InvalidOperationException("Missing embedded house blueprint."); using StreamReader streamReader = new StreamReader(stream); bool flag = false; Vector3 val = new Vector3(1f, 0f, -0.5f); Quaternion val2 = Quaternion.Euler(0f, 90f, 0f); int num = 0; string text; Vector3 val3 = default(Vector3); while ((text = streamReader.ReadLine()) != null) { string[] f; if (text == "#Pieces") { flag = true; } else { if (!flag || string.IsNullOrWhiteSpace(text) || text.StartsWith("#")) { continue; } f = text.Split(';'); ((Vector3)(ref val3))..ctor(N(2), N(3), N(4)); if (f[0] == "wood_pole2") { Vector3 val4 = val3 - val; if (((Vector3)(ref val4)).sqrMagnitude < 0.0001f) { num++; continue; } } Part obj = new Part { Name = f[0], Position = val2 * (val3 - val) - Vector3.up }; Quaternion val5 = new Quaternion(N(5), N(6), N(7), N(8)); obj.Rotation = val2 * ((Quaternion)(ref val5)).normalized; obj.Scale = new Vector3(N(10), N(11), N(12)); list.Add(obj); } float N(int i) { return float.Parse(f[i], CultureInfo.InvariantCulture); } } if (list.Count != 202 || num != 1) { throw new InvalidOperationException("Unexpected House02 piece count or merchant marker."); } return list; } internal static string PrefabId(string source, string role) { return "LV_House_" + role + "_" + source; } internal static void Register() { //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Expected O, but got Unknown //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Expected O, but got Unknown string[] array = new string[4] { "Elder", "Provisions", "Materials", "Harvest" }; foreach (string role in array) { foreach (string item in Parts.Select((Part part) => part.Name).Concat(new string[1] { "wood_floor_1x1" }).Distinct()) { string text = PrefabId(item, role); if (!Object.op_Implicit((Object)(object)PrefabManager.Instance.GetPrefab(text))) { GameObject val = PrefabManager.Instance.CreateClonedPrefab(text, item); if (!Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("Missing house source " + item); } val.GetComponent<ZNetView>().m_persistent = true; val.GetComponent<ZNetView>().m_syncInitialScale = true; val.AddComponent<VillageProperty>(); if (item == "wood_door") { val.AddComponent<VillageBedroomDoor>(); } WearNTear component = val.GetComponent<WearNTear>(); if (Object.op_Implicit((Object)(object)component)) { component.m_noRoofWear = true; component.m_noSupportWear = true; } if (Object.op_Implicit((Object)(object)val.GetComponent<ItemStand>()) || Object.op_Implicit((Object)(object)val.GetComponent<Sign>())) { val.AddComponent<ShopDisplay>().Role = role; } PrefabManager.Instance.AddPrefab(new CustomPrefab(val, false)); } } } if (!Object.op_Implicit((Object)(object)PrefabManager.Instance.GetPrefab("LV_VillageCarrot"))) { GameObject val2 = PrefabManager.Instance.CreateClonedPrefab("LV_VillageCarrot", "Pickable_Carrot"); val2.AddComponent<VillageProperty>(); val2.GetComponent<ZNetView>().m_persistent = true; PrefabManager.Instance.AddPrefab(new CustomPrefab(val2, false)); } } internal static void Build(Transform parent, Vector3 origin, float yaw, string role, string npc, bool mirrored = false) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) Transform transform = new GameObject("BlueprintHouse_" + role).transform; transform.SetParent(parent, false); transform.localPosition = origin; transform.localRotation = Quaternion.Euler(0f, yaw, 0f); ShelterFoundation shelterFoundation = ((Component)transform).gameObject.AddComponent<ShelterFoundation>(); shelterFoundation.Blueprint = true; shelterFoundation.ExtendedHouse = true; shelterFoundation.Mirrored = mirrored; string text = (mirrored ? "LV_House02FillMirrorPlanned" : "LV_House02FillPlanned"); GameObject obj = Object.Instantiate<GameObject>(PrefabManager.Instance.GetPrefab(text), transform); ((Object)obj).name = text; obj.transform.localPosition = new Vector3(0f, -0.2f, 0f); obj.transform.localRotation = Quaternion.identity; shelterFoundation.EntranceGrades = (Transform[])(object)new Transform[8]; for (int i = 0; i < shelterFoundation.EntranceGrades.Length; i++) { GameObject val = Object.Instantiate<GameObject>(PrefabManager.Instance.GetPrefab("LV_EntranceGrade"), transform); ((Object)val).name = "LV_EntranceGrade"; shelterFoundation.EntranceGrades[i] = val.transform; } foreach (Part part in Parts) { if ((role == "Harvest" || role == "Materials") && part.Name == "itemstand" && part.Position.x > 3f) { continue; } GameObject val2 = Object.Instantiate<GameObject>(PrefabManager.Instance.GetPrefab(PrefabId(part.Name, role)), transform); ((Object)val2).name = PrefabId(part.Name, role); val2.transform.localPosition = part.Position; val2.transform.localRotation = part.Rotation; val2.transform.localScale = part.Scale; if (mirrored) { val2.transform.localPosition = Reflect(part.Position); val2.transform.localRotation = Quaternion.LookRotation(Reflect(part.Rotation * Vector3.forward), Reflect(part.Rotation * Vector3.up)); if (part.Name != "sign" && part.Name != "itemstand") { val2.transform.localScale = new Vector3(0f - part.Scale.x, part.Scale.y, part.Scale.z); } } if (part.Name == "wood_pole2" && part.Position.y < -0.5f) { val2.AddComponent<FoundationPost>(); } if (part.Name == "wood_stair") { shelterFoundation.Stairs = val2.transform; } } GameObject obj2 = Object.Instantiate<GameObject>(PrefabManager.Instance.GetPrefab(npc), transform); ((Object)obj2).name = npc; obj2.transform.localPosition = new Vector3(0f, 0.15f, 0f); obj2.transform.localRotation = Quaternion.Euler(0f, (float)((!mirrored) ? 180 : 0), 0f); static Vector3 Reflect(Vector3 v) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) return new Vector3(v.x, v.y, 0f - v.z); } } } public sealed class BoarPlacement : MonoBehaviour { internal static BoarPlacement Active; internal static float BlockControlsUntil; private ItemData crate; private Player player; private GameObject preview; private Material material; private float ready; internal void Begin(Player owner, ItemData item) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown player = owner; crate = item; Active = this; ready = Time.time + 0.4f; preview = GameObject.CreatePrimitive((PrimitiveType)2); Object.Destroy((Object)(object)preview.GetComponent<Collider>()); preview.transform.localScale = new Vector3(1.4f, 0.025f, 1.4f); Shader val = Shader.Find("Sprites/Default") ?? Shader.Find("Standard"); material = new Material(val); preview.GetComponent<Renderer>().material = material; if (Object.op_Implicit((Object)(object)InventoryGui.instance)) { InventoryGui.instance.Hide(); } ((Character)player).Message((MessageType)2, "Aim at clear ground. Left-click: place boar. Right-click/Escape: cancel.", 0, (Sprite)null, false); } private void OnDestroy() { BlockControlsUntil = Time.time + 0.2f; if (Object.op_Implicit((Object)(object)preview)) { Object.Destroy((Object)(object)preview); } if (Object.op_Implicit((Object)(object)material)) { Object.Destroy((Object)(object)material); } if ((Object)(object)Active == (Object)(object)this) { Active = null; } } private bool Position(out Vector3 point) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) point = ((Component)player).transform.position; Camera main = Camera.main; RaycastHit val = default(RaycastHit); if (!Object.op_Implicit((Object)(object)main) || !Physics.Raycast(((Component)main).transform.position, ((Component)main).transform.forward, ref val, 15f, -1, (QueryTriggerInteraction)1)) { return false; } point = ((RaycastHit)(ref val)).point; if (!Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Heightmap>()) || ((RaycastHit)(ref val)).normal.y < 0.85f || Vector3.Distance(((Component)player).transform.position, point) > 6f || point.y < ZoneSystem.instance.m_waterLevel + 0.3f || !PrivateArea.CheckAccess(point, 0f, false, false)) { return false; } Collider[] array = Physics.OverlapCapsule(point + Vector3.up * 0.55f, point + Vector3.up * 1.2f, 0.5f, -1, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { if (!Object.op_Implicit((Object)(object)((Component)array[i]).GetComponentInParent<Heightmap>())) { return false; } } for (int j = -1; j <= 1; j++) { for (int k = -1; k <= 1; k++) { if (Mathf.Abs(ZoneSystem.instance.GetGroundHeight(point + new Vector3((float)j * 0.6f, 0f, (float)k * 0.6f)) - point.y) > 0.3f) { return false; } } } return true; } private void Update() { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || ((Character)player).IsDead() || !Object.op_Implicit((Object)(object)ZoneSystem.instance) || !((Humanoid)player).GetInventory().GetAllItems().Contains(crate)) { Object.Destroy((Object)(object)this); return; } if (Time.time >= ready && (Input.GetKeyDown((KeyCode)27) || Input.GetMouseButtonDown(1))) { Object.Destroy((Object)(object)this); return; } Vector3 point; bool flag = Position(out point); preview.transform.position = point + Vector3.up * 0.05f; material.color = (flag ? Color.green : Color.red); if (Time.time < ready || !Input.GetMouseButtonDown(0)) { return; } if (!flag) { ((Character)player).Message((MessageType)2, "Choose clear, dry, level ground within six metres.", 0, (Sprite)null, false); return; } GameObject prefab = PrefabManager.Instance.GetPrefab("Boar"); if (!Object.op_Implicit((Object)(object)prefab)) { ((Character)player).Message((MessageType)2, "Boar unavailable. Your crate has been kept.", 0, (Sprite)null, false); return; } GameObject val = Object.Instantiate<GameObject>(prefab, point + Vector3.up * 0.15f, ((Character)player).GetLookYaw()); Character component = val.GetComponent<Character>(); ZNetView component2 = val.GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component2) || !component2.IsValid() || !component2.IsOwner()) { if (Object.op_Implicit((Object)(object)component2) && component2.IsValid()) { component2.Destroy(); } else { Object.Destroy((Object)(object)val); } return;