Please disclose if your mod was created primarily 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 AutoFeed v0.2.3
Narolith.AutoFeed.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("Narolith.AutoFeed")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Valheim mod to auto feed animals from a nearby chest")] [assembly: AssemblyFileVersion("0.2.3.0")] [assembly: AssemblyInformationalVersion("0.2.3")] [assembly: AssemblyProduct("Narolith.AutoFeed")] [assembly: AssemblyTitle("Narolith.AutoFeed")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.2.3.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 AutoFeed { public static class ColliderExtensions { public static List<Container> GetContainersOrderedByDistanceFromCenter(this Collider[] colliders, Vector3 center) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) IOrderedEnumerable<Container> orderedEnumerable = from collider in colliders select ((Component)collider).GetComponentInParent<Container>() into container where container != null && IsValidZNetView(((Component)container).GetComponent<ZNetView>()) && IsNonEmptyChest(container) orderby Vector3.Distance(((Component)container).transform.position, center) select container; List<Container> list = new List<Container>(); foreach (Container item in orderedEnumerable) { list.Add(item); } return list; } private static bool IsValidZNetView(ZNetView? zNetView) { if (zNetView != null) { return zNetView.IsValid(); } return false; } private static bool IsNonEmptyChest(Container container) { if (((Object)container).name.StartsWith("piece_chest")) { return container.GetInventory() != null; } return false; } } public static class ContainerExtensions { public static bool ContainersContainItemFromList(this List<Container> containers, List<ItemDrop> itemDrops, out Container? targetContainer, out ItemData? targetItem) { return FindItemInContainers(containers, CreateItemDictionary(itemDrops), out targetContainer, out targetItem); } private static Dictionary<string, List<ItemData>> CreateItemDictionary(List<ItemDrop> itemDrops) { return (from i in itemDrops group i by i.m_itemData.m_shared.m_name).ToDictionary((IGrouping<string, ItemDrop> g) => g.Key, (IGrouping<string, ItemDrop> g) => g.Select((ItemDrop i) => i.m_itemData).ToList()); } private static bool FindItemInContainers(List<Container> containers, Dictionary<string, List<ItemData>> itemDropDict, out Container? targetContainer, out ItemData? targetItem) { foreach (Container container in containers) { if (TryFindMatchingItem(container.GetInventory().GetAllItems(), itemDropDict, out targetItem)) { targetContainer = container; return true; } } targetContainer = null; targetItem = null; return false; } private static bool TryFindMatchingItem(List<ItemData> items, Dictionary<string, List<ItemData>> itemDropDict, out ItemData? targetItem) { foreach (ItemData item in items) { if (itemDropDict.TryGetValue(item.m_shared.m_name, out List<ItemData> value)) { targetItem = value.First(); return true; } } targetItem = null; return false; } } public static class MonsterAIExtensions { public static void FeedMonsterWithThrottling(this MonsterAI __instance, Tameable ___m_tamable, Character ___m_character, Container container, ItemData item) { if (FeedIntervalPassed()) { __instance.FeedAnimal(___m_tamable, ___m_character, container, item); Plugin.LastFeedTime = Time.time; } } public static void FeedAnimal(this MonsterAI monsterAI, Tameable tamable, Character character, Container container, ItemData item) { if (tamable != null && monsterAI != null && tamable.IsHungry()) { monsterAI.ConsumeItem(character); container.GetInventory().RemoveItem(item.m_shared.m_name, 1, -1, true); typeof(Inventory).GetMethod("Changed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(container.GetInventory(), new object[0]); typeof(Container).GetMethod("Save", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(container, new object[0]); } } public static void ConsumeItem(this MonsterAI monsterAI, Character character) { //IL_0029: 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) monsterAI.m_onConsumedItem?.Invoke(null); Character obj = ((character is Humanoid) ? character : null); if (obj != null) { ((Humanoid)obj).m_consumeItemEffects.Create(((Component)character).transform.position, Quaternion.identity, (Transform)null, 1f, -1); } Traverse.Create((object)monsterAI).Field("m_animator").GetValue<ZSyncAnimation>() .SetTrigger("consume"); } private static bool FeedIntervalPassed() { return Time.time - Plugin.LastFeedTime >= 0.1f; } } public static class Vector3Extensions { public static List<Container> GetContainersInRange(this Vector3 center, float radiusRange) { //IL_0000: 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) try { return Physics.OverlapSphere(center, Mathf.Max(radiusRange, 0f), LayerMask.GetMask(new string[1] { "piece" })).GetContainersOrderedByDistanceFromCenter(center); } catch { return new List<Container>(); } } } [BepInPlugin("Narolith.AutoFeed", "Narolith.AutoFeed", "0.2.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(MonsterAI), "UpdateConsumeItem")] private static class UpdateConsumeItemPatch { private static void Postfix(MonsterAI __instance, Character ___m_character, Tameable ___m_tamable, List<ItemDrop> ___m_consumeItems, bool __result) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) Character ___m_character2 = ___m_character; List<ItemDrop> ___m_consumeItems2 = ___m_consumeItems; Tameable ___m_tamable2 = ___m_tamable; if (ModEnabled() && HasCharacterData() && IsTamedAndHungry() && HasValidFoodTypes() && !HasFoundFood() && ((Component)___m_character2).gameObject.transform.position.GetContainersInRange(ContainerRange.Value).ContainersContainItemFromList(___m_consumeItems2, out Container targetContainer, out ItemData targetItem)) { __instance.FeedMonsterWithThrottling(___m_tamable2, ___m_character2, targetContainer, targetItem); } bool HasCharacterData() { return ___m_character2 != null; } bool HasFoundFood() { return __result; } bool HasValidFoodTypes() { if (___m_consumeItems2 != null) { return ___m_consumeItems2.Count > 0; } return false; } bool IsTamedAndHungry() { if (___m_tamable2 != null) { return ___m_tamable2.IsHungry(); } return false; } static bool ModEnabled() { return Plugin.ModEnabled.Value; } } } public static float LastFeedTime; public static ConfigEntry<float> ContainerRange; public static ConfigEntry<bool> ModEnabled; private void Awake() { ContainerRange = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Container Range", 10f, "The radiusRange in which the tames monster will look for containers to feed from."); ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Whether the mod is enabled."); if (ModEnabled.Value) { Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null); } } } public static class PluginSettings { public const string ChestPrefix = "piece_chest"; public const float FeedInterval = 0.1f; public const string ChestLayer = "piece"; } public static class PluginInfo { public const string PLUGIN_GUID = "Narolith.AutoFeed"; public const string PLUGIN_NAME = "Narolith.AutoFeed"; public const string PLUGIN_VERSION = "0.2.3"; } }