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";
}
}