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 Carturs Feeding Trough v1.2.0
plugins/CarturFeedingTrough/CarturFeedingTrough.dll
Decompiled 3 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("CarturFeedingTrough")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+5a42ad35c0fc9e5f44704ceae9200c4dc4886b0c")] [assembly: AssemblyProduct("CarturFeedingTrough")] [assembly: AssemblyTitle("CarturFeedingTrough")] [assembly: AssemblyVersion("1.0.1.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 CarturFeedingTrough { [HarmonyPatch(typeof(Procreation), "Awake")] internal static class BreedingCaps { internal const float MaxUsefulRange = 64f; private static readonly HashSet<string> s_reported = new HashSet<string>(); private static void Prefix(Procreation __instance) { try { int maxCreatures = __instance.m_maxCreatures; float totalCheckRange = __instance.m_totalCheckRange; float partnerCheckRange = __instance.m_partnerCheckRange; int num = Mathf.Max(Mathf.RoundToInt((float)maxCreatures * Plugin.MaxCreaturesMultiplier.Value), Plugin.MaxCreaturesMinimum.Value); if (num > 0) { __instance.m_maxCreatures = num; } float value = Plugin.TotalCheckRangeOverride.Value; if (value > 0f) { __instance.m_totalCheckRange = Mathf.Min(value, 64f); } float value2 = Plugin.PartnerCheckRangeMultiplier.Value; if (value2 > 0f) { __instance.m_partnerCheckRange = partnerCheckRange * value2; } if (__instance.m_maxCreatures != maxCreatures || __instance.m_totalCheckRange != totalCheckRange || __instance.m_partnerCheckRange != partnerCheckRange) { Report(__instance, maxCreatures, totalCheckRange, partnerCheckRange); } } catch (Exception arg) { Plugin.Log.LogWarning((object)$"breeding caps not applied, vanilla limits stand: {arg}"); } } private static void Report(Procreation p, int wasMax, float wasTotal, float wasPartner) { string text = PrefabName(((Component)p).gameObject); if (s_reported.Add(text)) { bool flag = (Object)(object)p.m_offspring != (Object)null && PrefabName(p.m_offspring) == text; int num = (flag ? (p.m_maxCreatures / 2) : p.m_maxCreatures); Plugin.Log.LogInfo((object)($"breeding {text}: max {wasMax} -> {p.m_maxCreatures}" + (flag ? $" (offspring is itself, so {num} animals in practice)" : "") + $", range {wasTotal} -> {p.m_totalCheckRange}" + $", partner {wasPartner} -> {p.m_partnerCheckRange}")); } } private static string PrefabName(GameObject go) { if ((Object)(object)go == (Object)null) { return "<null>"; } string name = ((Object)go).name; int num = name.IndexOf("(Clone)", StringComparison.Ordinal); if (num >= 0) { return name.Substring(0, num); } return name; } } internal static class MeshBlob { private static string AssetDir => Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "", "assets"); internal static Mesh LoadMesh(string fileName) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: 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_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0158: 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_0168: 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_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Expected O, but got Unknown string text = Path.Combine(AssetDir, fileName); if (!File.Exists(text)) { Plugin.Log.LogWarning((object)("missing " + text)); return null; } using BinaryReader binaryReader = new BinaryReader(File.OpenRead(text)); if (new string(binaryReader.ReadChars(4)) != "CTM1") { Plugin.Log.LogWarning((object)(fileName + " is not a CTM1 blob")); return null; } int num = binaryReader.ReadInt32(); int num2 = binaryReader.ReadInt32(); Vector3[] array = (Vector3[])(object)new Vector3[num]; for (int i = 0; i < num; i++) { array[i] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle()); } Vector3[] array2 = (Vector3[])(object)new Vector3[num]; for (int j = 0; j < num; j++) { array2[j] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle()); } Vector2[] array3 = (Vector2[])(object)new Vector2[num]; for (int k = 0; k < num; k++) { array3[k] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle()); } int[] array4 = new int[num2]; for (int l = 0; l < num2; l++) { array4[l] = binaryReader.ReadInt32(); } Mesh val = new Mesh { name = Path.GetFileNameWithoutExtension(fileName), vertices = array, normals = array2, uv = array3, triangles = array4 }; val.RecalculateTangents(); val.RecalculateBounds(); return val; } internal static Texture2D LoadTexture(string fileName, bool linear) { //IL_0030: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown string text = Path.Combine(AssetDir, fileName); if (!File.Exists(text)) { Plugin.Log.LogWarning((object)("missing " + text)); return null; } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear) { name = Path.GetFileNameWithoutExtension(fileName), wrapMode = (TextureWrapMode)0, filterMode = (FilterMode)1 }; if (LoadImageViaReflection(val, File.ReadAllBytes(text))) { return val; } Plugin.Log.LogWarning((object)("ImageConversion.LoadImage failed for " + text)); return null; } private static bool LoadImageViaReflection(Texture2D tex, byte[] data) { Type type = AccessTools.TypeByName("UnityEngine.ImageConversion"); if (type == null) { return false; } MethodInfo methodInfo = null; MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public); foreach (MethodInfo methodInfo2 in methods) { if (!(methodInfo2.Name != "LoadImage")) { ParameterInfo[] parameters = methodInfo2.GetParameters(); if (parameters.Length == 3 && parameters[1].ParameterType == typeof(byte[])) { methodInfo = methodInfo2; break; } } } if (methodInfo == null) { return false; } object obj = methodInfo.Invoke(null, new object[3] { tex, data, false }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } } [BepInPlugin("cartur.feedingtrough", "Cartur's Feeding Trough", "1.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInProcess("valheim.exe")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "cartur.feedingtrough"; public const string PluginName = "Cartur's Feeding Trough"; public const string PluginVersion = "1.2.0"; internal static ManualLogSource Log; internal static ConfigEntry<float> ConfinedReach; internal static ConfigEntry<float> MaxCreaturesMultiplier; internal static ConfigEntry<int> MaxCreaturesMinimum; internal static ConfigEntry<float> TotalCheckRangeOverride; internal static ConfigEntry<float> PartnerCheckRangeMultiplier; internal static ConfigEntry<bool> MoreTameableAnimals; internal static ConfigEntry<string> ExtraTameables; internal static ConfigEntry<bool> ListTameCandidates; internal static ConfigEntry<bool> PassiveProduction; internal static ConfigEntry<float> ProductionInterval; internal static ConfigEntry<float> ProductionPercent; private Harmony _harmony; private void Awake() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Expected O, but got Unknown //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Expected O, but got Unknown //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ConfinedReach = ((BaseUnityPlugin)this).Config.Bind<float>("Reach", "ConfinedReach", 0f, new ConfigDescription("For pens and towers where animals sit in a tight cell next to the trough and never eat from it. When there is no walkable path to the trough, an animal this many metres or closer, with nothing solid between it and the bowl, is still offered food. 0 turns this off and leaves behaviour as it was; 3 suits a 2x1 or 2x2 cell. Takes effect at once.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 6f), Array.Empty<object>())); MaxCreaturesMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "MaxCreaturesMultiplier", 1f, new ConfigDescription("Multiplies how many animals of one kind will breed in one spot. The game's own limit is 4 to 10 depending on the animal, so 4 takes a boar pen from 5 to 20. 1 leaves the game's limit alone. Restart the game after changing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>())); MaxCreaturesMinimum = ((BaseUnityPlugin)this).Config.Bind<int>("Breeding", "MaxCreaturesMinimum", 0, new ConfigDescription("A floor under the number above, whatever the multiplier works out to. 0 means no floor. Restart the game after changing.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>())); TotalCheckRangeOverride = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "TotalCheckRangeOverride", 0f, new ConfigDescription($"Radius in metres the animals are counted over. 0 keeps each animal's own value (4 to 20 in the game). Capped at {64f}: past that the game only counts animals that happen to be loaded. Restart the game after changing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 64f), Array.Empty<object>())); PartnerCheckRangeMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "PartnerCheckRangeMultiplier", 1f, new ConfigDescription("Multiplies how close two animals must be to court. Larger makes breeding easier in a crowded pen. 1 leaves the game's value alone. Restart the game after changing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>())); MoreTameableAnimals = ((BaseUnityPlugin)this).Config.Bind<bool>("Taming", "MoreTameableAnimals", false, "Makes the bear (Bjorn), Neck, Hatchling and Deathsquito tameable, and breedable into more of themselves, eating the foods listed in the mod's code (bear: berries, honey, mushrooms, fish, raw meat). Off leaves them wild. Restart the game after changing."); ExtraTameables = ((BaseUnityPlugin)this).Config.Bind<string>("Taming", "ExtraTameables", "", "More animals to make tameable, including ones added by other mods, written Prefab:Donor:Food,Food and separated by semicolons: for example Neck:Boar:FishRaw,RawMeat;MyModCreature:Wolf:RawMeat. Donor is a vanilla tameable (Boar, Wolf or Lox) whose taming effects and numbers are copied. Only creatures with MonsterAI and Humanoid can eat, so deer, hares and seals cannot be added. Empty adds none. Restart the game after changing."); ListTameCandidates = ((BaseUnityPlugin)this).Config.Bind<bool>("Taming", "ListTameCandidates", false, "Writes the prefab names of every creature that could be made tameable (it has MonsterAI and Humanoid and no Tameable yet), other mods' included, to the BepInEx log at startup, to copy into ExtraTameables. Restart the game after changing."); PassiveProduction = ((BaseUnityPlugin)this).Config.Bind<bool>("Production", "PassiveProduction", false, "Fed, tame animals periodically drop a share of what they would give if killed: hide, pelt, feathers, fangs. Meat and trophies never come this way. A few well-kept animals instead of a big farm. Restart the game after turning it on."); ProductionInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Production", "ProductionInterval", 600f, new ConfigDescription("Seconds between an animal's yields. The animal must be fed the whole time: going hungry restarts the count.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(30f, 7200f), Array.Empty<object>())); ProductionPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Production", "ProductionPercent", 0.25f, new ConfigDescription("Share of a kill's non-food drops given each time, 0 to 1. Fractions become a chance rather than rounding to nothing, so 0.25 of one hide is a one-in-four hide.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); try { _harmony = new Harmony("cartur.feedingtrough"); _harmony.PatchAll(typeof(Plugin).Assembly); TroughPiece.Register(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"loaded"); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"failed to load, game continues without it: {arg}"); } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal class Produce : MonoBehaviour { private static readonly int LastProduced = StringExtensionMethods.GetStableHashCode("CarturLastProduce"); private bool _wasHungry; private ZNetView _nview; private Character _character; private Tameable _tameable; private CharacterDrop _drops; private void Awake() { _nview = ((Component)this).GetComponent<ZNetView>(); _character = ((Component)this).GetComponent<Character>(); _tameable = ((Component)this).GetComponent<Tameable>(); _drops = ((Component)this).GetComponent<CharacterDrop>(); if (!((Object)(object)_nview == (Object)null) && !((Object)(object)_character == (Object)null) && !((Object)(object)_tameable == (Object)null) && !((Object)(object)_drops == (Object)null)) { ((MonoBehaviour)this).InvokeRepeating("Tick", Random.Range(10f, 30f), 10f); } } private void Tick() { if (!Plugin.PassiveProduction.Value || (Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner() || !_character.IsTamed()) { return; } ZDO zDO = _nview.GetZDO(); if (_tameable.IsHungry()) { _wasHungry = true; return; } if (_wasHungry) { _wasHungry = false; zDO.Set(LastProduced, ZNet.instance.GetTime().Ticks); return; } DateTime dateTime = new DateTime(zDO.GetLong(LastProduced, 0L)); double totalSeconds = (ZNet.instance.GetTime() - dateTime).TotalSeconds; if (dateTime.Ticks == 0L) { zDO.Set(LastProduced, ZNet.instance.GetTime().Ticks); } else if (!(totalSeconds < (double)Plugin.ProductionInterval.Value)) { zDO.Set(LastProduced, ZNet.instance.GetTime().Ticks); DropShare(); } } private void DropShare() { //IL_0107: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp01(Plugin.ProductionPercent.Value); if (num <= 0f || _drops.m_drops == null) { return; } List<KeyValuePair<GameObject, int>> list = new List<KeyValuePair<GameObject, int>>(); foreach (Drop drop in _drops.m_drops) { if (drop == null || (Object)(object)drop.m_prefab == (Object)null) { continue; } ItemDrop component = drop.m_prefab.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null) && Producible(component.m_itemData.m_shared)) { float num2 = drop.m_chance * (float)Random.Range(drop.m_amountMin, drop.m_amountMax + 1) * num; int num3 = Mathf.FloorToInt(num2); if (Random.value < num2 - (float)num3) { num3++; } if (num3 > 0) { list.Add(new KeyValuePair<GameObject, int>(drop.m_prefab, num3)); } } } if (list.Count > 0) { CharacterDrop.DropItems(list, ((Component)this).transform.position, 0.5f, _drops.m_cheated); } } private static bool Producible(SharedData shared) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 if (shared != null && shared.m_food <= 0f) { return (int)shared.m_itemType != 13; } return false; } } internal static class ProductionSetup { internal static int Attach(ZNetScene scene) { int num = 0; foreach (GameObject prefab in scene.m_prefabs) { if (!((Object)(object)prefab == (Object)null) && !((Object)(object)prefab.GetComponent<Tameable>() == (Object)null) && !((Object)(object)prefab.GetComponent<CharacterDrop>() == (Object)null) && !((Object)(object)prefab.GetComponent<Produce>() != (Object)null)) { prefab.AddComponent<Produce>(); num++; } } return num; } } internal enum Rearing { Itself, Egg, Baby } internal sealed class Species { internal readonly string Prefab; internal readonly string Donor; internal readonly string[] Foods; internal readonly Rearing Rearing; internal readonly string Offspring; internal static readonly Species[] All = new Species[4] { Simple("Bjorn", "Boar", "Blueberries", "Raspberry", "Honey", "Mushroom", "FishRaw", "RawMeat"), Simple("Neck", "Boar", "FishRaw", "RawMeat", "Mushroom", "Raspberry"), Simple("Hatchling", "Wolf", "FishRaw", "WolfMeat", "RawMeat", "DeerMeat"), Simple("Deathsquito", "Boar", "Bloodbag", "Entrails", "Honey", "Cloudberry") }; private Species(string prefab, string donor, Rearing rearing, string offspring, params string[] foods) { Prefab = prefab; Donor = donor; Rearing = rearing; Offspring = offspring; Foods = foods; } private static Species Simple(string prefab, string donor, params string[] foods) { return new Species(prefab, donor, Rearing.Itself, null, foods); } internal static List<Species> ParseExtra(string setting, StringBuilder report) { List<Species> list = new List<Species>(); string[] array = (setting ?? "").Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { string[] array2 = text.Trim().Split(new char[1] { ':' }); if (array2.Length != 3 || array2[0].Trim().Length == 0 || array2[1].Trim().Length == 0) { report.Append(" ExtraTameables entry '" + text.Trim() + "' skipped - write it Prefab:Donor:Food,Food\n"); continue; } List<string> list2 = new List<string>(); string[] array3 = array2[2].Split(new char[1] { ',' }); foreach (string text2 in array3) { if (text2.Trim().Length > 0) { list2.Add(text2.Trim()); } } list.Add(Simple(array2[0].Trim(), array2[1].Trim(), list2.ToArray())); } return list; } } internal static class TamePatch { [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetSceneReady { [HarmonyPriority(0)] private static void Postfix() { Apply("ZNetScene.Awake"); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDBReady { private static void Postfix() { Apply("ObjectDB.Awake"); } } private static bool s_applied; private const string HatchDonor = "AsksvinEgg"; private static void Apply(string from) { if (s_applied) { return; } ZNetScene instance = ZNetScene.instance; ObjectDB instance2 = ObjectDB.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || instance2.m_items.Count == 0) { return; } s_applied = true; if (!Plugin.MoreTameableAnimals.Value && string.IsNullOrWhiteSpace(Plugin.ExtraTameables.Value) && !Plugin.ListTameCandidates.Value && !Plugin.PassiveProduction.Value) { return; } try { StringBuilder stringBuilder = new StringBuilder("applying husbandry from " + from + "\n"); if (Plugin.ListTameCandidates.Value) { ListCandidates(instance, stringBuilder); } List<Species> list = new List<Species>(); if (Plugin.MoreTameableAnimals.Value) { list.AddRange(Species.All); } list.AddRange(Species.ParseExtra(Plugin.ExtraTameables.Value, stringBuilder)); foreach (Species item in list) { ApplyOne(instance, instance2, item, stringBuilder); } if (Plugin.PassiveProduction.Value) { int num = ProductionSetup.Attach(instance); stringBuilder.Append($" passive production attached to {num} tameable creatures\n"); } Plugin.Log.LogInfo((object)stringBuilder.ToString()); } catch (Exception arg) { Plugin.Log.LogWarning((object)$"husbandry could not be applied, creatures stay vanilla: {arg}"); } } private static void ListCandidates(ZNetScene scene, StringBuilder report) { List<string> list = new List<string>(); foreach (GameObject prefab in scene.m_prefabs) { if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<MonsterAI>() != (Object)null && (Object)(object)prefab.GetComponent<Humanoid>() != (Object)null && (Object)(object)prefab.GetComponent<Tameable>() == (Object)null) { list.Add(((Object)prefab).name); } } list.Sort(StringComparer.Ordinal); report.Append(string.Format(" creatures that could be made tameable ({0}): {1}\n", list.Count, string.Join(", ", list))); } private static void ApplyOne(ZNetScene scene, ObjectDB items, Species species, StringBuilder report) { GameObject prefab = scene.GetPrefab(species.Prefab); GameObject prefab2 = scene.GetPrefab(species.Donor); if ((Object)(object)prefab == (Object)null || (Object)(object)prefab2 == (Object)null) { report.Append(" " + species.Prefab + ": skipped - " + (((Object)(object)prefab == (Object)null) ? "creature" : ("donor " + species.Donor)) + " not found\n"); return; } if ((Object)(object)prefab.GetComponent<Tameable>() != (Object)null) { report.Append(" " + species.Prefab + ": skipped - already tameable\n"); return; } Tameable component = prefab2.GetComponent<Tameable>(); MonsterAI component2 = prefab.GetComponent<MonsterAI>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null) { report.Append(" " + species.Prefab + ": skipped - " + (((Object)(object)component2 == (Object)null) ? "no MonsterAI, so it cannot eat" : "donor has no Tameable") + "\n"); return; } Tameable val = prefab.AddComponent<Tameable>(); CopyFields<Tameable>(component, val); val.m_saddleItem = null; val.m_saddle = null; int num = SetFoods(items, component2, species, report); string arg = SetBreeding(scene, prefab2, prefab, species, report); report.Append(" " + species.Prefab + ": tameable like " + species.Donor + ", " + $"{num}/{species.Foods.Length} foods, {arg}\n"); } private static int SetFoods(ObjectDB items, MonsterAI ai, Species species, StringBuilder report) { List<ItemDrop> list = new List<ItemDrop>(); string[] foods = species.Foods; foreach (string text in foods) { GameObject itemPrefab = items.GetItemPrefab(text); ItemDrop val = (((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent<ItemDrop>()); if ((Object)(object)val == (Object)null) { report.Append(" food " + text + " did not resolve - left out\n"); } else { list.Add(val); } } if (list.Count > 0) { ai.m_consumeItems = list; } return list.Count; } private static string SetBreeding(ZNetScene scene, GameObject donor, GameObject target, Species species, StringBuilder report) { Procreation component = donor.GetComponent<Procreation>(); if ((Object)(object)component == (Object)null) { return "no breeding (donor has none)"; } GameObject val = target; EggGrow val2 = null; if (species.Rearing != Rearing.Itself) { val = scene.GetPrefab(species.Offspring); if ((Object)(object)val == (Object)null) { return "no breeding (" + species.Offspring + " not found)"; } if (species.Rearing == Rearing.Egg && (Object)(object)val.GetComponent<EggGrow>() == (Object)null) { GameObject prefab = scene.GetPrefab("AsksvinEgg"); val2 = ((prefab != null) ? prefab.GetComponent<EggGrow>() : null); if ((Object)(object)val2 == (Object)null) { return "no breeding (AsksvinEgg has no EggGrow to hatch like)"; } } } Procreation val3 = target.AddComponent<Procreation>(); CopyFields<Procreation>(component, val3); val3.m_seperatePartner = null; val3.m_noPartnerOffspring = null; val3.m_offspring = val; switch (species.Rearing) { case Rearing.Itself: val3.m_maxCreatures *= 2; return $"breeds into more {species.Prefab} (cap {val3.m_maxCreatures}, " + $"{val3.m_maxCreatures / 2} in practice)"; case Rearing.Egg: if ((Object)(object)val2 != (Object)null) { EggGrow val4 = val.AddComponent<EggGrow>(); CopyFields<EggGrow>(val2, val4); val4.m_grownPrefab = target; val4.m_growingObject = null; val4.m_notGrowingObject = null; } return "lays " + species.Offspring + ", which hatches near a fire"; case Rearing.Baby: if ((Object)(object)val.GetComponent<Growup>() == (Object)null) { Growup obj = val.AddComponent<Growup>(); obj.m_grownPrefab = target; obj.m_growTime = 3000f; obj.m_inheritTame = true; } return "breeds into " + species.Offspring + ", which grows up"; default: return "no breeding"; } } private static void CopyFields<T>(T from, T to) where T : Component { FieldInfo[] fields = typeof(T).GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { fieldInfo.SetValue(to, fieldInfo.GetValue(from)); } } } [HarmonyPatch(typeof(Tameable), "GetHoverText")] internal static class TameTimer { private static void Postfix(Tameable __instance, ref string __result) { if (string.IsNullOrEmpty(__result) || __instance.IsTamed()) { return; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } ZDO zDO = component.GetZDO(); if (zDO != null) { float num = zDO.GetFloat(ZDOVars.s_tameTimeLeft, __instance.m_tamingTime); if (!(num <= 0f) && !(num >= __instance.m_tamingTime)) { __result = __result + "\n" + Format(num) + " left"; } } } private static string Format(float seconds) { int num = Mathf.CeilToInt(seconds); int num2 = num / 60; int num3 = num % 60; if (num2 <= 0) { return $"{num3}s"; } return $"{num2}m {num3}s"; } } [HarmonyPatch(typeof(EnemyHud), "ShowHud")] internal static class TamingBarPatch { private static readonly FieldInfo HudsField = AccessTools.Field(typeof(EnemyHud), "m_huds"); private static readonly FieldInfo GuiField = AccessTools.Field(AccessTools.Inner(typeof(EnemyHud), "HudData"), "m_gui"); internal static readonly FieldInfo HoverTimerField = AccessTools.Field(AccessTools.Inner(typeof(EnemyHud), "HudData"), "m_hoverTimer"); private static bool s_reported; private static void Postfix(EnemyHud __instance, Character c) { if ((Object)(object)c == (Object)null) { return; } if (HudsField == null || GuiField == null) { Report($"cannot reach EnemyHud internals (m_huds={HudsField != null}, " + $"HudData.m_gui={GuiField != null}) - no taming bar this session"); return; } Tameable component = ((Component)c).GetComponent<Tameable>(); if ((Object)(object)component == (Object)null) { return; } try { object obj = (HudsField.GetValue(__instance) as IDictionary)?[c]; object? value = GuiField.GetValue(obj); GameObject val = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val == (Object)null) { Report("no hud object for " + ((Object)c).name + " - taming bar not added"); } else if (!((Object)(object)val.GetComponent<TamingBar>() != (Object)null)) { val.AddComponent<TamingBar>().Bind(component, obj); Report("taming bar attached to " + ((Object)c).name + "'s hud"); } } catch (Exception arg) { Plugin.Log.LogWarning((object)$"could not add the taming bar, health bar is unaffected: {arg}"); } } private static void Report(string message) { if (!s_reported) { s_reported = true; Plugin.Log.LogInfo((object)message); } } } internal class TamingBar : MonoBehaviour { private const float Gap = 2f; private static readonly Color Yellow = new Color(0.95f, 0.82f, 0.25f, 1f); private static bool s_said; private static bool s_saidHidden; private Tameable _tameable; private GuiBar _bar; private GameObject _root; private bool _built; private object _hudData; private static void Say(string message) { if (!s_said) { s_said = true; Plugin.Log.LogInfo((object)message); } } internal void Bind(Tameable tameable, object hudData) { _tameable = tameable; _hudData = hudData; } private void HoldHudOpen() { if (_hudData != null && !(TamingBarPatch.HoverTimerField == null)) { TamingBarPatch.HoverTimerField.SetValue(_hudData, 0f); } } private void Build() { //IL_013b: 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) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: 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_0193: 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_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) _built = true; Transform obj = ((Component)this).transform.Find("Health"); RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null); if ((Object)(object)val == (Object)null) { Say("hud has no 'Health' child - EnemyHud layout changed, no taming bar"); return; } _root = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Transform)val).parent); ((Object)_root).name = "CarturTaming"; Transform transform = _root.transform; RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null); if ((Object)(object)val2 == (Object)null) { return; } Transform val3 = ((Transform)val2).Find("health_fast"); Transform val4 = ((Transform)val2).Find("health_fast_friendly"); Transform val5 = PickBar(val3) ?? PickBar(val4); _bar = (((Object)(object)val5 == (Object)null) ? null : ((Component)val5).GetComponent<GuiBar>()); if ((Object)(object)_bar == (Object)null) { Say("cloned hud has no usable GuiBar - no taming bar"); Object.Destroy((Object)(object)_root); return; } ((Component)val5).gameObject.SetActive(true); Strip((Transform)(object)val2, "health_slow"); Strip((Transform)(object)val2, "HealthText"); if ((Object)(object)val3 != (Object)null && (Object)(object)val3 != (Object)(object)val5) { Object.Destroy((Object)(object)((Component)val3).gameObject); } if ((Object)(object)val4 != (Object)null && (Object)(object)val4 != (Object)(object)val5) { Object.Destroy((Object)(object)((Component)val4).gameObject); } Rect rect = val.rect; float height = ((Rect)(ref rect)).height; Transform obj2 = ((val3 is RectTransform) ? val3 : null); float num; if (obj2 == null) { num = 0f; } else { rect = ((RectTransform)obj2).rect; num = ((Rect)(ref rect)).height; } float num2 = Mathf.Max(height, num); if (num2 <= 0f) { num2 = 10f; } val2.anchoredPosition = val.anchoredPosition - new Vector2(0f, num2 + 2f); StringBuilder stringBuilder = new StringBuilder(); rect = val.rect; stringBuilder.Append($"taming bar built: Health rect={((Rect)(ref rect)).size} anchored={val.anchoredPosition} " + $"drop={num2 + 2f} -> taming anchored={val2.anchoredPosition}\n"); stringBuilder.Append(" hud root children: "); for (int i = 0; i < ((Component)this).transform.childCount; i++) { stringBuilder.Append(((Object)((Component)this).transform.GetChild(i)).name).Append(" "); } stringBuilder.Append("\n taming bar contents:\n"); RectTransform[] componentsInChildren = _root.GetComponentsInChildren<RectTransform>(true); foreach (RectTransform val6 in componentsInChildren) { string name = ((Object)val6).name; rect = val6.rect; stringBuilder.Append($" {name} size={((Rect)(ref rect)).size} pos={val6.anchoredPosition} " + $"active={((Component)val6).gameObject.activeSelf} img={(Object)(object)((Component)val6).GetComponent<Image>() != (Object)null}\n"); } Say(stringBuilder.ToString()); _bar.SetMaxValue(1f); _bar.SetColor(Yellow); _root.SetActive(false); } private static Transform PickBar(Transform t) { if (!((Object)(object)t != (Object)null) || !((Object)(object)((Component)t).GetComponent<GuiBar>() != (Object)null)) { return null; } return t; } private static void Strip(Transform parent, string childName) { Transform val = parent.Find(childName); if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } } private void Update() { if (!_built) { Build(); } if ((Object)(object)_root == (Object)null || (Object)(object)_bar == (Object)null) { return; } float num = Progress(); if (num < 0f) { if (_root.activeSelf) { _root.SetActive(false); } return; } if (!_root.activeSelf) { _root.SetActive(true); } _bar.SetValue(num); HoldHudOpen(); } private float Progress() { if ((Object)(object)_tameable == (Object)null || _tameable.IsTamed()) { return -1f; } ZNetView component = ((Component)_tameable).GetComponent<ZNetView>(); ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null); if (val == null || _tameable.m_tamingTime <= 0f) { return -1f; } float num = val.GetFloat(ZDOVars.s_tameTimeLeft, _tameable.m_tamingTime); if (num >= _tameable.m_tamingTime) { return -1f; } float num2 = Mathf.Clamp01(1f - num / _tameable.m_tamingTime); if (!s_saidHidden) { s_saidHidden = true; Plugin.Log.LogInfo((object)($"taming bar for {((Object)_tameable).name}: timeLeft={num} " + $"of {_tameable.m_tamingTime} -> {num2:P0}")); } return num2; } } internal class Trough : MonoBehaviour { private const float FloorY = 0.209f; internal static readonly Vector3 BaitLocalPosition = new Vector3(0f, 0.269f, 0f); private const float BaitSearchRadius = 0.3f; private static readonly int ItemMask = LayerMask.GetMask(new string[1] { "item" }); private const float InnerHalfX = 0.85f; private const float InnerHalfZ = 0.24f; private const int MaxVisuals = 14; private const int ItemsPerVisual = 4; internal static readonly List<Trough> All = new List<Trough>(); private Container _container; private Inventory _inventory; private Transform _holder; private readonly List<GameObject> _spawned = new List<GameObject>(); private void Awake() { All.Add(this); } private void Start() { _container = ((Component)this).GetComponent<Container>(); if (!((Object)(object)_container == (Object)null)) { _inventory = _container.GetInventory(); if (_inventory != null) { Inventory inventory = _inventory; inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, new Action(Rebuild)); Rebuild(); } } } private void OnDestroy() { All.Remove(this); if (_inventory != null) { Inventory inventory = _inventory; inventory.m_onChanged = (Action)Delegate.Remove(inventory.m_onChanged, new Action(Rebuild)); } } internal ItemDrop FindBait() { //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) Collider[] array = Physics.OverlapSphere(((Component)this).transform.TransformPoint(BaitLocalPosition), 0.3f, ItemMask); for (int i = 0; i < array.Length; i++) { Rigidbody attachedRigidbody = array[i].attachedRigidbody; ItemDrop val = (((Object)(object)attachedRigidbody == (Object)null) ? null : ((Component)attachedRigidbody).GetComponent<ItemDrop>()); if ((Object)(object)val != (Object)null) { return val; } } return null; } private void Rebuild() { //IL_0076: Unknown result type (might be due to invalid IL or missing references) foreach (GameObject item in _spawned) { if ((Object)(object)item != (Object)null) { Object.Destroy((Object)(object)item); } } _spawned.Clear(); List<ItemData> allItems = _inventory.GetAllItems(); if (allItems.Count == 0) { return; } if ((Object)(object)_holder == (Object)null) { _holder = new GameObject("TroughFill").transform; _holder.SetParent(((Component)this).transform, false); } Random rng = new Random(((Object)this).GetInstanceID()); int num = 0; foreach (ItemData item2 in allItems) { num += item2.m_stack; } int num2 = Mathf.Clamp(Mathf.CeilToInt((float)num / 4f), 1, 14); int num3 = 0; foreach (ItemData item3 in allItems) { if (!((Object)(object)item3.m_dropPrefab == (Object)null)) { int num4 = Mathf.Max(1, Mathf.RoundToInt((float)num2 * ((float)item3.m_stack / (float)num))); int num5 = 0; while (num5 < num4 && num3 < num2) { Place(item3.m_dropPrefab, num3, num2, rng); num5++; num3++; } } } } private void Place(GameObject dropPrefab, int index, int slots, Random rng) { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) bool forceDisableInit = ZNetView.m_forceDisableInit; ZNetView.m_forceDisableInit = true; GameObject val; try { val = Object.Instantiate<GameObject>(dropPrefab, _holder); } finally { ZNetView.m_forceDisableInit = forceDisableInit; } Strip(val); float num = ((slots == 1) ? 0.5f : ((float)index / (float)(slots - 1))); float num2 = Mathf.Lerp(-0.85f, 0.85f, num) + (float)(rng.NextDouble() - 0.5) * 0.08f; float num3 = (float)(rng.NextDouble() - 0.5) * 2f * 0.24f; float num4 = 0.209f + ((index >= slots / 2) ? 0.05f : 0f) + (float)rng.NextDouble() * 0.02f; val.transform.localPosition = new Vector3(num2, num4, num3); val.transform.localRotation = Quaternion.Euler((float)rng.NextDouble() * 30f, (float)rng.NextDouble() * 360f, (float)rng.NextDouble() * 30f); _spawned.Add(val); } private static void Strip(GameObject go) { ZNetView[] componentsInChildren = go.GetComponentsInChildren<ZNetView>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } ItemDrop[] componentsInChildren2 = go.GetComponentsInChildren<ItemDrop>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } Rigidbody[] componentsInChildren3 = go.GetComponentsInChildren<Rigidbody>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren3[i]); } Collider[] componentsInChildren4 = go.GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren4.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren4[i]); } Floating[] componentsInChildren5 = go.GetComponentsInChildren<Floating>(true); for (int i = 0; i < componentsInChildren5.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren5[i]); } Transform[] componentsInChildren6 = go.GetComponentsInChildren<Transform>(true); for (int i = 0; i < componentsInChildren6.Length; i++) { ((Component)componentsInChildren6[i]).gameObject.layer = LayerMask.NameToLayer("piece_nonsolid"); } } } [HarmonyPatch(typeof(MonsterAI), "FindClosestConsumableItem")] internal static class TroughFeeding { private static readonly MethodInfo CanConsumeMethod = AccessTools.Method(typeof(MonsterAI), "CanConsume", new Type[1] { typeof(ItemData) }, (Type[])null); private static bool s_loggedFirstFeed; private static bool s_loggedPathing; private static bool s_loggedNoTrough; private static bool s_loggedConfined; private static readonly int SolidMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "terrain" }); private static void Postfix(MonsterAI __instance, float maxRange, ref ItemDrop __result) { if ((Object)(object)__result != (Object)null || CanConsumeMethod == null) { return; } try { ItemDrop val = FindBait(__instance, maxRange); if ((Object)(object)val != (Object)null) { __result = val; } } catch (Exception arg) { Plugin.Log.LogWarning((object)$"trough feeding failed, animal falls back to vanilla: {arg}"); } } private static ItemDrop FindBait(MonsterAI ai, float maxRange) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) List<KeyValuePair<float, Trough>> list = new List<KeyValuePair<float, Trough>>(); foreach (Trough item in Trough.All) { if ((Object)(object)item == (Object)null) { continue; } ZNetView component = ((Component)item).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { float num = Vector3.Distance(((Component)ai).transform.position, ((Component)item).transform.position); if (num <= maxRange) { list.Add(new KeyValuePair<float, Trough>(num, item)); } } } if (list.Count == 0) { if (!s_loggedNoTrough) { s_loggedNoTrough = true; Plugin.Log.LogInfo((object)($"no trough within {maxRange} of {((Object)ai).name} " + $"(troughs loaded: {Trough.All.Count}) - said once")); } return null; } list.Sort((KeyValuePair<float, Trough> a, KeyValuePair<float, Trough> b) => a.Key.CompareTo(b.Key)); foreach (KeyValuePair<float, Trough> item2 in list) { ItemDrop val = BaitFrom(ai, item2.Value); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static ItemDrop BaitFrom(MonsterAI ai, Trough best) { ItemDrop val = best.FindBait(); if ((Object)(object)val != (Object)null) { if (!CanConsume(ai, val.m_itemData)) { return null; } Rigidbody component = ((Component)val).GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { component.isKinematic = true; } if (!Reachable(ai, best)) { return null; } return val; } Container component2 = ((Component)best).GetComponent<Container>(); if ((Object)(object)component2 == (Object)null || component2.IsInUse()) { return null; } Inventory inventory = component2.GetInventory(); if (inventory == null) { return null; } ItemData val2 = null; foreach (ItemData allItem in inventory.GetAllItems()) { if ((Object)(object)allItem.m_dropPrefab != (Object)null && CanConsume(ai, allItem)) { val2 = allItem; break; } } if (val2 == null) { return null; } if (!Reachable(ai, best)) { return null; } return TakeBait(best, component2, inventory, val2); } private static ItemDrop TakeBait(Trough trough, Container container, Inventory inventory, ItemData food) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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) ZNetView component = ((Component)container).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return null; } if (!component.IsOwner()) { if (component.GetZDO().GetInt(ZDOVars.s_inUse, 0) != 0) { return null; } component.ClaimOwnership(); } ItemData val = food.Clone(); if (!inventory.RemoveItem(food, 1)) { return null; } Vector3 val2 = ((Component)trough).transform.TransformPoint(Trough.BaitLocalPosition); ItemDrop val3 = ItemDrop.DropItem(val, 1, val2, Random.rotation); if ((Object)(object)val3 == (Object)null) { return null; } val3.m_autoPickup = false; Rigidbody component2 = ((Component)val3).GetComponent<Rigidbody>(); if ((Object)(object)component2 != (Object)null) { component2.isKinematic = true; } if (!s_loggedFirstFeed) { s_loggedFirstFeed = true; Plugin.Log.LogInfo((object)("first trough feed: " + val.m_shared.m_name + " offered to " + ((Object)trough).name)); } return val3; } private static bool Reachable(MonsterAI ai, Trough trough) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_0045: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_0069: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_008a: 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_009a: 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_009d: 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_00d5: Unknown result type (might be due to invalid IL or missing references) Pathfinding instance = Pathfinding.instance; if ((Object)(object)instance == (Object)null) { return true; } Vector3 position = ((Component)ai).transform.position; Vector3 position2 = ((Component)trough).transform.position; float num = Utils.DistanceXZ(position, position2); bool flag = num <= ai.m_consumeRange + 1f; Vector3 val = position - position2; val.y = 0f; Vector3 val2 = position2 + ((((Vector3)(ref val)).sqrMagnitude > 0.01f) ? ((Vector3)(ref val)).normalized : Vector3.forward) * 1.5f; bool flag2 = instance.HavePath(position, val2, ((BaseAI)ai).m_pathAgentType); bool flag3 = instance.HavePath(position, position2, ((BaseAI)ai).m_pathAgentType); bool flag4 = flag || flag2 || flag3; if (!flag4 && Plugin.ConfinedReach.Value > 0f && num <= Plugin.ConfinedReach.Value && ClearLine(position, trough)) { flag4 = true; if (!s_loggedConfined) { s_loggedConfined = true; Plugin.Log.LogInfo((object)$"trough reach: {((Object)ai).name} at {num:0.0} m has no path but a clear line, offered food (ConfinedReach) - said once"); } } if (!s_loggedPathing) { s_loggedPathing = true; Plugin.Log.LogInfo((object)($"trough pathing for {((Object)ai).name}: d={num:0.00} " + $"near={flag} viaBeside={flag2} direct={flag3} " + $"agent={((BaseAI)ai).m_pathAgentType} -> reachable={flag4}")); } return flag4; } internal static bool ClearLine(Vector3 from, Trough trough) { //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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_003a: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)trough).transform.TransformPoint(Trough.BaitLocalPosition) + Vector3.up * 0.3f; RaycastHit val2 = default(RaycastHit); if (Physics.Linecast(from + Vector3.up * 0.6f, val, ref val2, SolidMask)) { return (Object)(object)((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<Trough>() == (Object)(object)trough; } return true; } private static bool CanConsume(MonsterAI ai, ItemData item) { return (bool)CanConsumeMethod.Invoke(ai, new object[1] { item }); } } [HarmonyPatch(typeof(BaseAI), "MoveTo", new Type[] { typeof(float), typeof(Vector3), typeof(float), typeof(bool) })] internal static class TroughArrival { private static readonly FieldInfo ConsumeTarget = AccessTools.Field(typeof(MonsterAI), "m_consumeTarget"); private static readonly MethodInfo StopMoving = AccessTools.Method(typeof(BaseAI), "StopMoving", (Type[])null, (Type[])null); private static bool Prefix(BaseAI __instance, Vector3 point, ref bool __result) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_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_009e: 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_00bd: Unknown result type (might be due to invalid IL or missing references) float value = Plugin.ConfinedReach.Value; if (!(value <= 0f)) { MonsterAI val = (MonsterAI)(object)((__instance is MonsterAI) ? __instance : null); if (val != null && !(ConsumeTarget == null)) { object? value2 = ConsumeTarget.GetValue(val); ItemDrop val2 = (ItemDrop)((value2 is ItemDrop) ? value2 : null); if (!((Object)(object)val2 == (Object)null)) { Vector3 val3 = ((Component)val2).transform.position - point; if (!(((Vector3)(ref val3)).sqrMagnitude > 0.01f)) { foreach (Trough item in Trough.All) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item.FindBait() != (Object)(object)val2)) { if (Utils.DistanceXZ(((Component)val).transform.position, ((Component)item).transform.position) > value || !TroughFeeding.ClearLine(((Component)val).transform.position, item)) { return true; } StopMoving?.Invoke(val, null); __result = true; return false; } } return true; } } return true; } } return true; } } internal static class TroughPiece { internal const string PrefabName = "piece_cartur_trough"; internal const string NameToken = "$piece_cartur_trough"; internal const string DescriptionToken = "$piece_cartur_trough_description"; internal static Bounds BowlBounds { get; private set; } internal static void Register() { PrefabManager.OnVanillaPrefabsAvailable += Build; } private static void Build() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) PrefabManager.OnVanillaPrefabsAvailable -= Build; try { CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "English"; string text2 = "$piece_cartur_trough".Substring(1); localization.AddTranslation(ref text, ref text2, "Feeding Trough"); text = "English"; text2 = "$piece_cartur_trough_description".Substring(1); localization.AddTranslation(ref text, ref text2, "Fill it with food and your animals will come and eat from it."); PieceConfig val = new PieceConfig(); val.Name = "$piece_cartur_trough"; val.Description = "$piece_cartur_trough_description"; val.PieceTable = "Hammer"; val.Category = "Furniture"; val.CraftingStation = "piece_workbench"; val.Requirements = (RequirementConfig[])(object)new RequirementConfig[1] { new RequirementConfig("Wood", 10, 0, true) }; CustomPiece val2 = new CustomPiece("piece_cartur_trough", "piece_chest_wood", val); if ((Object)(object)val2.PiecePrefab == (Object)null) { Plugin.Log.LogWarning((object)"piece_chest_wood did not resolve - no trough this session"); } else if (Reskin(val2.PiecePrefab)) { val2.Piece.m_icon = RenderManager.Instance.Render(val2.PiecePrefab); PieceManager.Instance.AddPiece(val2); ManualLogSource log = Plugin.Log; Bounds bowlBounds = BowlBounds; log.LogInfo((object)("registered piece_cartur_trough (clone of piece_chest_wood, " + $"bowl bounds {((Bounds)(ref bowlBounds)).size})")); } } catch (Exception arg) { Plugin.Log.LogWarning((object)$"could not build the trough piece: {arg}"); } } private static bool Reskin(GameObject prefab) { //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_006b: Expected O, but got Unknown //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0121: 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_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) Mesh val = MeshBlob.LoadMesh("trough.mesh"); if ((Object)(object)val == (Object)null) { return false; } Transform val2 = prefab.transform.Find("New/woodchest"); MeshRenderer val3 = (((Object)(object)val2 == (Object)null) ? null : ((Component)val2).GetComponent<MeshRenderer>()); if ((Object)(object)val3 == (Object)null) { Plugin.Log.LogWarning((object)"chest prefab has no New/woodchest renderer - layout changed"); return false; } Material val4 = new Material(((Renderer)val3).sharedMaterial) { name = "cartur_trough" }; Texture2D val5 = MeshBlob.LoadTexture("trough_albedo.jpg", linear: false); Texture2D val6 = MeshBlob.LoadTexture("trough_normal.png", linear: true); if ((Object)(object)val5 != (Object)null) { val4.SetTexture("_MainTex", (Texture)(object)val5); } if ((Object)(object)val6 != (Object)null) { val4.SetTexture("_BumpMap", (Texture)(object)val6); } val4.SetFloat("_BumpScale", 1f); val4.SetFloat("_Metallic", 0f); val4.SetFloat("_Glossiness", 0.3f); DestroyChild(prefab, "New"); DestroyChild(prefab, "floor_2x2_snow"); GameObject val7 = new GameObject("TroughVisual") { layer = prefab.layer }; val7.transform.SetParent(prefab.transform, false); val7.AddComponent<MeshFilter>().sharedMesh = val; ((Renderer)val7.AddComponent<MeshRenderer>()).sharedMaterial = val4; Bounds bounds = val.bounds; BoxCollider obj = prefab.AddComponent<BoxCollider>(); obj.center = ((Bounds)(ref bounds)).center; obj.size = ((Bounds)(ref bounds)).size; ((Collider)obj).isTrigger = false; BowlBounds = bounds; Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { ((StaticTarget)component).m_primaryTarget = false; } Container component2 = prefab.GetComponent<Container>(); if ((Object)(object)component2 != (Object)null) { component2.m_name = "$piece_cartur_trough"; component2.m_width = 4; component2.m_height = 2; } prefab.AddComponent<Trough>(); return true; } private static void DestroyChild(GameObject prefab, string name) { Transform val = prefab.transform.Find(name); if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)((Component)val).gameObject); } } } }