Decompiled source of AutoFeed v0.2.3

Narolith.AutoFeed.dll

Decompiled 6 months ago
using 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";
	}
}