Decompiled source of Auto Feeder v0.9.3

AutoFeed.dll

Decompiled 2 days ago
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyCompany("vanbushi")]
[assembly: AssemblyTitle("Auto Feed")]
[assembly: AssemblyDescription("Auto Feed for Valheim 1.0.x. Maintained by vanbushi; originally created by aedenthorn (https://www.nexusmods.com/valheim/mods/985).")]
[assembly: AssemblyFileVersion("0.9.3.0")]
[assembly: AssemblyInformationalVersion("0.9.3")]
[assembly: AssemblyVersion("0.9.3.0")]
public class AedenthornUtils
{
	public static bool IgnoreKeyPresses(bool extra = false)
	{
		if (!extra)
		{
			int result;
			if (!((Object)(object)ZNetScene.instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && !Minimap.IsOpen() && !Console.IsVisible() && !TextInput.IsVisible() && !ZNet.instance.InPasswordDialog())
			{
				Chat instance = Chat.instance;
				result = ((instance != null && instance.HasFocus()) ? 1 : 0);
			}
			else
			{
				result = 1;
			}
			return (byte)result != 0;
		}
		int result2;
		if (!((Object)(object)ZNetScene.instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && !Minimap.IsOpen() && !Console.IsVisible() && !TextInput.IsVisible() && !ZNet.instance.InPasswordDialog())
		{
			Chat instance2 = Chat.instance;
			if ((instance2 == null || !instance2.HasFocus()) && !StoreGui.IsVisible() && !InventoryGui.IsVisible() && !Menu.IsVisible())
			{
				TextViewer instance3 = TextViewer.instance;
				result2 = ((instance3 != null && instance3.IsVisible()) ? 1 : 0);
				goto IL_00d2;
			}
		}
		result2 = 1;
		goto IL_00d2;
		IL_00d2:
		return (byte)result2 != 0;
	}

	public static bool CheckKeyDown(string value)
	{
		try
		{
			return Input.GetKeyDown(value.ToLower());
		}
		catch
		{
			return false;
		}
	}

	public static bool CheckKeyHeld(string value, bool req = true)
	{
		try
		{
			return Input.GetKey(value.ToLower());
		}
		catch
		{
			return !req;
		}
	}
}
namespace AutoFeed;

[BepInPlugin("vanbushi.AutoFeed", "Auto Feed", "0.9.3")]
public class BepInExPlugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(MonsterAI), "UpdateConsumeItem")]
	public static class UpdateConsumeItem_Patch
	{
		public static void Postfix(MonsterAI __instance, ZNetView ___m_nview, Character ___m_character, Tameable ___m_tamable, List<ItemDrop> ___m_consumeItems, float dt, bool __result)
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0448: Unknown result type (might be due to invalid IL or missing references)
			//IL_0491: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0581: Unknown result type (might be due to invalid IL or missing references)
			//IL_0599: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_0358: Unknown result type (might be due to invalid IL or missing references)
			string prefabName = GetPrefabName(((Object)((Component)__instance).gameObject).name);
			if (!modEnabled.Value || !isOn.Value || __result || !Object.op_Implicit((Object)(object)___m_character) || !Object.op_Implicit((Object)(object)___m_nview) || !___m_nview.IsOwner() || (Object)(object)___m_tamable == (Object)null || !___m_character.IsTamed() || !___m_tamable.IsHungry() || ___m_consumeItems == null || ___m_consumeItems.Count == 0 || TrimAll(animalDisallowTypes.Value.Split(new char[1] { ',' })).Contains(prefabName))
			{
				return;
			}
			Vector3 position = ((Component)__instance).gameObject.transform.position;
			Traverse val = Traverse.Create((object)__instance);
			val.Field("m_pathAgentType").SetValue((object)(AgentType)1);
			Container val2 = null;
			Vector3 val3 = default(Vector3);
			((Vector3)(ref val3))..ctor(0f, 0f, 0f);
			float num = containerRange.Value + 1f;
			Collider[] array = Physics.OverlapSphere(position, Mathf.Max(containerRange.Value, 0f), LayerMask.GetMask(new string[1] { "piece" }));
			foreach (Collider val4 in array)
			{
				Transform parent = ((Component)val4).transform.parent;
				object obj;
				if (parent == null)
				{
					obj = null;
				}
				else
				{
					Transform parent2 = parent.parent;
					if (parent2 == null)
					{
						obj = null;
					}
					else
					{
						GameObject gameObject = ((Component)parent2).gameObject;
						obj = ((gameObject != null) ? gameObject.GetComponent<Container>() : null);
					}
				}
				Container val5 = (Container)obj;
				if (val5 == null)
				{
					continue;
				}
				ZNetView component = ((Component)val5).GetComponent<ZNetView>();
				if (((component != null) ? new bool?(component.IsValid()) : ((bool?)null)) != true)
				{
					continue;
				}
				string[] array2 = TrimAll(containerNameStartsWith.Value.Split(new char[1] { ',' }));
				foreach (string value in array2)
				{
					if (!((Object)val5).name.StartsWith(value) || val5.GetInventory() == null)
					{
						continue;
					}
					Vector3 position2 = ((Component)val5).transform.position;
					float num2 = Vector3.Distance(position2, position);
					if (!(num2 < moveProximity.Value) && !val.Method("HavePath", new object[1] { position2 }).GetValue<bool>())
					{
						continue;
					}
					bool flag = true;
					bool flag2 = false;
					foreach (ItemData item in val5.GetInventory().GetAllItems())
					{
						if (__instance.m_consumeItems.Exists((ItemDrop val6) => val6.m_itemData.m_shared.m_name == item.m_shared.m_name) && !TrimAll(feedDisallowTypes.Value.Split(new char[1] { ',' })).Contains(((Object)item.m_dropPrefab).name))
						{
							flag2 = true;
							if (!requireOnlyFood.Value)
							{
								break;
							}
						}
						else if (requireOnlyFood.Value)
						{
							flag = false;
							break;
						}
					}
					if (flag && flag2 && num > num2)
					{
						val2 = val5;
						num = num2;
						val3 = position2;
					}
				}
			}
			if ((Object)(object)val2 != (Object)null)
			{
				Dbgl($"{((Object)((Component)__instance).gameObject).name} found container: {val3}", pref: false, (LogLevel)32);
				if (requireMove.Value)
				{
					Dbgl($"{((Object)((Component)__instance).gameObject).name} {position} trying to move to {val3} {Utils.DistanceXZ(position, val3)}", pref: false, (LogLevel)32);
					val.Field("m_lastFindPathTime").SetValue((object)0);
					if (!val.Method("MoveTo", new object[4] { 0.05f, val3, moveProximity.Value, false }).GetValue<bool>())
					{
						return;
					}
					val.Method("LookAt", new object[1] { val3 }).GetValue();
					if (!val.Method("IsLookingAt", new object[3] { val3, 20f, false }).GetValue<bool>())
					{
						return;
					}
				}
				using List<ItemDrop>.Enumerator enumerator2 = __instance.m_consumeItems.GetEnumerator();
				while (enumerator2.MoveNext())
				{
					ItemData item2 = val2.GetInventory().GetItem(enumerator2.Current.m_itemData.m_shared.m_name, -1, false);
					if (item2 != null && !TrimAll(feedDisallowTypes.Value.Split(new char[1] { ',' })).Contains(((Object)item2.m_dropPrefab).name))
					{
						Dbgl($"{((Object)((Component)__instance).gameObject).name} {position} consuming {((Object)item2.m_dropPrefab).name} at {val3}, distance {Utils.DistanceXZ(position, val3)}", pref: false, (LogLevel)32);
						ConsumeItem(item2, __instance, ___m_character);
						val2.GetInventory().RemoveItem(item2.m_shared.m_name, 1, -1, true);
						typeof(Container).GetMethod("Save", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(val2, new object[0]);
						break;
					}
				}
				return;
			}
			Dbgl(((Object)((Component)__instance).gameObject).name + " could not find container", pref: false, (LogLevel)32);
		}
	}

	[HarmonyPatch(typeof(Terminal), "InputText")]
	public static class InputText_Patch
	{
		public static bool Prefix(Terminal __instance)
		{
			if (!modEnabled.Value)
			{
				return true;
			}
			string text = ((TMP_InputField)__instance.m_input).text;
			if (text.ToLower().Equals(typeof(BepInExPlugin).Namespace.ToLower() + " reset"))
			{
				((BaseUnityPlugin)context).Config.Reload();
				((BaseUnityPlugin)context).Config.Save();
				Traverse.Create((object)__instance).Method("AddString", new object[1] { text }).GetValue();
				Traverse.Create((object)__instance).Method("AddString", new object[1] { ((BaseUnityPlugin)context).Info.Metadata.Name + " config reloaded" }).GetValue();
				return false;
			}
			return true;
		}
	}

	public static ConfigEntry<bool> isDebug;

	public static ConfigEntry<float> containerRange;

	public static ConfigEntry<float> moveProximity;

	public static ConfigEntry<string> feedDisallowTypes;

	public static ConfigEntry<string> animalDisallowTypes;

	public static ConfigEntry<string> containerNameStartsWith;

	public static ConfigEntry<string> toggleKey;

	public static ConfigEntry<string> toggleString;

	public static ConfigEntry<bool> isOn;

	public static ConfigEntry<bool> requireMove;

	public static ConfigEntry<bool> requireOnlyFood;

	public static ConfigEntry<bool> modEnabled;

	public static ConfigEntry<int> nexusID;

	private static BepInExPlugin context;

	public static void Dbgl(string str = "", bool pref = false, LogLevel logLevel = (LogLevel)32)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		if (isDebug.Value)
		{
			((BaseUnityPlugin)context).Logger.Log(logLevel, (object)((pref ? (typeof(BepInExPlugin).Namespace + " ") : "") + str));
		}
	}

	public void Awake()
	{
		context = this;
		containerRange = ((BaseUnityPlugin)this).Config.Bind<float>("Config", "ContainerRange", 10f, "Container range in metres.");
		feedDisallowTypes = ((BaseUnityPlugin)this).Config.Bind<string>("Config", "FeedDisallowTypes", "", "Types of item to disallow as feed, comma-separated.");
		animalDisallowTypes = ((BaseUnityPlugin)this).Config.Bind<string>("Config", "AnimalDisallowTypes", "", "Types of creature to disallow to feed, comma-separated.");
		requireMove = ((BaseUnityPlugin)this).Config.Bind<bool>("Config", "RequireMove", true, "Require animals to move to container to feed.");
		requireOnlyFood = ((BaseUnityPlugin)this).Config.Bind<bool>("Config", "RequireOnlyFood", false, "Don't allow feeding from containers that have items that the animal will not eat as well.");
		moveProximity = ((BaseUnityPlugin)this).Config.Bind<float>("Config", "MoveProximity", 2f, "How close to move towards the container if RequireMove is true.");
		containerNameStartsWith = ((BaseUnityPlugin)this).Config.Bind<string>("Config", "ContainerNameFilter", "piece_chest,Container", "Only feed from containers which's name start like this, comma-separated.");
		toggleKey = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ToggleKey", "", "Key to toggle behaviour. Leave blank to disable the toggle key. Use https://docs.unity3d.com/Manual/ConventionalGameInput.html");
		toggleString = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ToggleString", "Auto Feed: {0}", "Text to show on toggle. {0} is replaced with true/false");
		modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable this mod");
		isDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "IsDebug", false, "Show debug logs");
		nexusID = ((BaseUnityPlugin)this).Config.Bind<int>("General", "NexusID", 985, "Nexus mod ID for updates");
		isOn = ((BaseUnityPlugin)this).Config.Bind<bool>("ZAuto", "IsOn", true, "Behaviour is currently on or not");
		if (modEnabled.Value)
		{
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
		}
	}

	public void Update()
	{
		if (AedenthornUtils.CheckKeyDown(toggleKey.Value) && !AedenthornUtils.IgnoreKeyPresses(extra: true))
		{
			isOn.Value = !isOn.Value;
			((BaseUnityPlugin)this).Config.Save();
			((Character)Player.m_localPlayer).Message((MessageType)2, string.Format(toggleString.Value, isOn.Value), 0, (Sprite)null, false);
		}
	}

	public static string GetPrefabName(string name)
	{
		char[] anyOf = new char[2] { '(', ' ' };
		int num = name.IndexOfAny(anyOf);
		if (num >= 0)
		{
			return name.Substring(0, num);
		}
		return name;
	}

	public static void ConsumeItem(ItemData item, MonsterAI monsterAI, Character character)
	{
		//IL_0025: 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_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Unknown result type (might be due to invalid IL or missing references)
		monsterAI.m_onConsumedItem?.Invoke(null);
		((Humanoid)((character is Humanoid) ? character : null)).m_consumeItemEffects.Create(((Component)character).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
		Traverse.Create((object)monsterAI).Field("m_animator").GetValue<ZSyncAnimation>()
			.SetTrigger("consume");
	}

	public static string[] TrimAll(string[] a)
	{
		for (int i = 0; i < a.Length; i++)
		{
			a[i] = a[i].Trim();
		}
		return a;
	}
}