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 AnimalFeedGuard v1.0.0
BepInEx/plugins/AnimalFeedGuard/AnimalFeedGuard.dll
Decompiled 5 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; 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("AnimalFeedGuard")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+c5dddd1db62830a856b662e8e41fafb08d31c869")] [assembly: AssemblyProduct("AnimalFeedGuard")] [assembly: AssemblyTitle("AnimalFeedGuard")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 AnimalFeedGuard { internal static class FeedRules { internal static bool WithinRadius(float squaredDistance, float radius) { if (radius > 0f && squaredDistance >= 0f) { return squaredDistance <= radius * radius; } return false; } internal static bool SameFood(string? item, string? animalFood) { if (!string.IsNullOrEmpty(item)) { return string.Equals(item, animalFood, StringComparison.Ordinal); } return false; } } [BepInPlugin("com.ziluck.valheim.animalfeedguard", "Animal Feed Guard", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { private readonly struct FeedingAnimal { internal readonly Vector3 Position; internal readonly List<ItemDrop> Foods; internal FeedingAnimal(Vector3 position, List<ItemDrop> foods) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) Position = position; Foods = foods; } } [HarmonyPatch(typeof(Player), "AutoPickup")] private static class AutomaticPickupPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { FieldInfo field = AccessTools.Field(typeof(ItemDrop), "m_autoPickup"); MethodInfo filter = AccessTools.Method(typeof(Plugin), "CanAutoPickup", (Type[])null, (Type[])null); List<CodeInstruction> list = instructions.ToList(); if (list.Count((CodeInstruction i) => CodeInstructionExtensions.LoadsField(i, field, false)) != 1) { throw new InvalidOperationException("Expected one ItemDrop.m_autoPickup check. Game version or another pickup mod changed this method."); } foreach (CodeInstruction item in list) { if (CodeInstructionExtensions.LoadsField(item, field, false)) { item.opcode = OpCodes.Call; item.operand = filter; } yield return item; } } } public const string Guid = "com.ziluck.valheim.animalfeedguard"; private static ConfigEntry<bool> protectionEnabled = null; private static ConfigEntry<float> radius = null; private Harmony? harmony; private static int cachedFrame = -1; private static readonly List<FeedingAnimal> animals = new List<FeedingAnimal>(); private void Awake() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown protectionEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Leave edible animal feed on the ground near tamed animals during automatic pickup. Manual pickup is unaffected."); radius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Protection Radius", 5f, new ConfigDescription("Maximum distance in metres between the dropped item and a living tamed animal that can eat it. 0 disables protection. Includes animals that are already fed. Uses full 3D distance, without a line-of-sight requirement.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>())); try { harmony = new Harmony("com.ziluck.valheim.animalfeedguard"); harmony.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Animal Feed Guard ready. Protection radius: {radius.Value}m."); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Animal Feed Guard could not patch automatic pickup. Feed protection is NOT active: {arg}"); Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } private void OnDestroy() { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } animals.Clear(); cachedFrame = -1; } internal static bool CanAutoPickup(ItemDrop item) { //IL_0065: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)item) || !item.m_autoPickup) { return false; } if (!protectionEnabled.Value || radius.Value <= 0f) { return true; } string text = item.m_itemData?.m_shared?.m_name; if (string.IsNullOrEmpty(text)) { return true; } RefreshAnimals(); Vector3 position = ((Component)item).transform.position; foreach (FeedingAnimal animal in animals) { Vector3 val = position - animal.Position; if (!FeedRules.WithinRadius(((Vector3)(ref val)).sqrMagnitude, radius.Value)) { continue; } foreach (ItemDrop food in animal.Foods) { if (Object.op_Implicit((Object)(object)food) && FeedRules.SameFood(text, food.m_itemData?.m_shared?.m_name)) { return false; } } } return true; } private static void RefreshAnimals() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) if (cachedFrame == Time.frameCount) { return; } cachedFrame = Time.frameCount; animals.Clear(); foreach (Character allCharacter in Character.GetAllCharacters()) { if (Object.op_Implicit((Object)(object)allCharacter) && !allCharacter.IsDead() && allCharacter.IsTamed()) { MonsterAI component = ((Component)allCharacter).GetComponent<MonsterAI>(); if (Object.op_Implicit((Object)(object)component) && component.m_consumeItems != null && component.m_consumeItems.Count != 0) { animals.Add(new FeedingAnimal(((Component)allCharacter).transform.position, component.m_consumeItems)); } } } } } }