using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading.Tasks;
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: AssemblyTitle("AutoFeedWithContainerFilter")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AutoFeedWithContainerFilter")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("f21d2e46-cdd4-4fd7-a5d7-5925aff75ab7")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
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 AutoFeedWithContainerFilter;
[BepInPlugin("gizmorphium.AutoFeedWithContainerFilter", "Auto Feed with Container Filter", "0.1.1")]
public class BepInExPlugin : BaseUnityPlugin
{
[HarmonyPatch(typeof(MonsterAI), "UpdateConsumeItem")]
private static class UpdateConsumeItem_Patch
{
private static void Postfix(MonsterAI __instance, ZNetView ___m_nview, Character ___m_character, Tameable ___m_tamable, List<ItemDrop> ___m_consumeItems, float dt, bool __result)
{
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: 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_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
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_tamable.IsHungry() || ___m_consumeItems == null || ___m_consumeItems.Count == 0)
{
return;
}
string prefabName = GetPrefabName(((Object)((Component)__instance).gameObject).name);
if (animalDisallowTypes.Value.Split(new char[1] { ',' }).Contains(prefabName))
{
return;
}
List<Container> nearbyContainers = GetNearbyContainers(((Component)___m_character).gameObject.transform.position, containerRange.Value, __instance);
using List<ItemDrop>.Enumerator enumerator = __instance.m_consumeItems.GetEnumerator();
while (enumerator.MoveNext())
{
foreach (Container item2 in nearbyContainers)
{
if ((Utils.DistanceXZ(((Component)item2).transform.position, ((Component)__instance).transform.position) < moveProximity.Value && Mathf.Abs(((Component)item2).transform.position.y - ((Component)__instance).transform.position.y) > moveProximity.Value) || (requireBreedingConditions.Value && !canBreedNearContainer(___m_character, ___m_nview, item2)))
{
continue;
}
ItemData item = item2.GetInventory().GetItem(enumerator.Current.m_itemData.m_shared.m_name, -1, false);
if (item == null || feedDisallowTypes.Value.Split(new char[1] { ',' }).Contains(((Object)item.m_dropPrefab).name))
{
continue;
}
if ((double)(Time.time - lastFeed) < 0.1)
{
feedCount++;
FeedAnimal(__instance, ___m_tamable, ___m_character, item2, item, feedCount * 33);
}
else
{
feedCount = 0;
lastFeed = Time.time;
FeedAnimal(__instance, ___m_tamable, ___m_character, item2, item, 0);
}
return;
}
}
}
}
[HarmonyPatch(typeof(Terminal), "InputText")]
private static class InputText_Patch
{
private 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();
__instance.AddString(text);
__instance.AddString(((BaseUnityPlugin)context).Info.Metadata.Name + " config reloaded");
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> containerAllowTypes;
public static ConfigEntry<bool> logContainerNames;
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> requireBreedingConditions;
public static ConfigEntry<bool> modEnabled;
public static ConfigEntry<int> nexusID;
private static BepInExPlugin context;
private static float lastFeed;
private static int feedCount;
public static ManualLogSource MyLogger = Logger.CreateLogSource(Assembly.GetExecutingAssembly().GetName().Name);
private Harmony _harmony;
public static void Dbgl(string str = "", bool pref = true)
{
if (isDebug.Value)
{
Debug.Log((object)((pref ? (typeof(BepInExPlugin).Namespace + " ") : "") + str));
}
}
private 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.");
containerAllowTypes = ((BaseUnityPlugin)this).Config.Bind<string>("Config", "ContainerAllowTypes", "", "Types of container to allow as feeders, comma-separated. Leave blank to allow all compatible contianers. To use only the Balrond Trough from https://thunderstore.io/c/valheim/p/Balrond/balrond_containers/ use 'piece_chest_trough'. Names listed here are prefixes, so 'piece_chest' will allow 'piece_chest_wood' and 'piece_chest_trough', etc. If a modded container has a name that is incompatible with this mod, 'piece_chest,Container,magic_trunk' will allow all vanilla containers, any other containers starting with piece_chest or Container, and a modded container named magic_trunk.");
logContainerNames = ((BaseUnityPlugin)this).Config.Bind<bool>("Config", "LogContainerNames", false, "Log container names near your creature to the BepInEx LogOutput.log. Useful for finding container names to allow. Should normally be false as it will spam the log.");
requireMove = ((BaseUnityPlugin)this).Config.Bind<bool>("Config", "RequireMove", true, "Require creatures 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 creature will not eat as well.");
requireBreedingConditions = ((BaseUnityPlugin)this).Config.Bind<bool>("Config", "Require Breeding Conditions", true, "Require creatures to only eat if conditions are right for breeding. NOTE: This doesn't guarantee they will breed once they eat, just that there was at least one potential partner near the container and the limit on that type of creature hadn't been reached near the container at the time the creature decided to eat there.");
moveProximity = ((BaseUnityPlugin)this).Config.Bind<float>("Config", "MoveProximity", 2f, "How close to move towards the container if RequireMove is true.");
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 = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
}
}
private 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);
}
}
private void OnDestroy()
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
private 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 List<Container> GetNearbyContainers(Vector3 center, float range, MonsterAI monsterAI)
{
//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)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
try
{
List<Container> list = new List<Container>();
string[] array = (Utility.IsNullOrWhiteSpace(containerAllowTypes.Value) ? new string[2] { "piece_chest", "Container" } : containerAllowTypes.Value.Split(new char[1] { ',' }));
Collider[] array2 = Physics.OverlapSphere(center, Mathf.Max(range, 0f), LayerMask.GetMask(new string[1] { "piece" }));
foreach (Collider val in array2)
{
Transform parent = ((Component)val).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 val2 = (Container)obj;
if (val2 == null)
{
continue;
}
ZNetView component = ((Component)val2).GetComponent<ZNetView>();
if (((component != null) ? new bool?(component.IsValid()) : null) != true)
{
continue;
}
if (logContainerNames.Value)
{
MyLogger.LogInfo((object)("Nearby Container: " + ((Object)val2).name));
}
if (val2.GetInventory() == null)
{
continue;
}
bool flag = false;
string[] array3 = array;
foreach (string value in array3)
{
if (((Object)val2).name.StartsWith(value))
{
flag = true;
}
}
if (!flag)
{
continue;
}
if (requireOnlyFood.Value)
{
foreach (ItemData item in val2.GetInventory().GetAllItems())
{
if (monsterAI.m_consumeItems.Exists((ItemDrop i) => i.m_itemData.m_shared.m_name == item.m_shared.m_name))
{
}
}
}
list.Add(val2);
}
list.OrderBy((Container c) => Vector3.Distance(((Component)c).transform.position, center));
return list;
}
catch
{
return new List<Container>();
}
}
public static bool canBreedNearContainer(Character character, ZNetView nview, Container container)
{
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
//IL_01af: Unknown result type (might be due to invalid IL or missing references)
//IL_022d: Unknown result type (might be due to invalid IL or missing references)
Procreation component = ((Component)nview).GetComponent<Procreation>();
GameObject prefab = ZNetScene.instance.GetPrefab(nview.GetZDO().GetPrefab());
GameObject prefab2 = ZNetScene.instance.GetPrefab(Utils.GetPrefabName(component.m_offspring));
GameObject val = ((!requireMove.Value) ? ((Component)character).gameObject : ((Component)container).gameObject);
int nrOfInstances = SpawnSystem.GetNrOfInstances(prefab, val.transform.position, component.m_totalCheckRange, false, false);
int nrOfInstances2 = SpawnSystem.GetNrOfInstances(prefab2, val.transform.position, component.m_totalCheckRange, false, false);
int num = 0;
string text = ((Object)prefab).name + "(Clone)";
if ((Object)(object)prefab.GetComponent<BaseAI>() != (Object)null)
{
List<BaseAI> allInstances = BaseAI.GetAllInstances();
foreach (BaseAI item in allInstances)
{
if (((Object)((Component)item).gameObject).name != text || (component.m_partnerCheckRange > 0f && Vector3.Distance(val.transform.position, ((Component)item).transform.position) > component.m_totalCheckRange))
{
continue;
}
Procreation component2 = ((Component)item).GetComponent<Procreation>();
Character component3 = ((Component)item).GetComponent<Character>();
MethodInfo method = typeof(Procreation).GetMethod("IsPregnant", BindingFlags.Instance | BindingFlags.NonPublic);
bool flag = false;
if (method != null)
{
flag = (bool)method.Invoke(component2, null);
string arg = "is NOT pregnant.";
if (flag)
{
arg = "IS pregnant.";
}
Dbgl($"{((Object)((Component)item).gameObject).name} {((Component)item).transform.position} {arg}");
}
if (!component3.IsTamed() || flag)
{
Dbgl($"{((Object)((Component)item).gameObject).name} {((Component)item).transform.position} is not tamed.");
}
else if (flag)
{
Dbgl($"{((Object)((Component)item).gameObject).name} {((Component)item).transform.position} is already pregnant.");
}
else
{
num++;
}
}
}
if (nrOfInstances + nrOfInstances2 < component.m_maxCreatures && num >= 2)
{
Dbgl("Can breed.");
Dbgl($"There are {nrOfInstances} adult instances.");
Dbgl($"There are {nrOfInstances2} offspring instances.");
Dbgl($"There are {num} parter instances available to breed.");
Dbgl($"The max creatures for procreating is {component.m_maxCreatures} instances.");
return true;
}
Dbgl("Can't breed.");
Dbgl($"There are {nrOfInstances} adult instances.");
Dbgl($"There are {nrOfInstances2} offspring instances.");
Dbgl($"There are {num} parter instances available to breed.");
Dbgl($"The max creatures for procreating is {component.m_maxCreatures} instances.");
return false;
}
public static async void FeedAnimal(MonsterAI monsterAI, Tameable tamable, Character character, Container c, ItemData item, int delay)
{
await Task.Delay(delay);
if ((Object)(object)tamable == (Object)null || !tamable.IsHungry())
{
return;
}
if (requireOnlyFood.Value)
{
foreach (ItemData temp in c.GetInventory().GetAllItems())
{
if (!monsterAI.m_consumeItems.Exists((ItemDrop i) => i.m_itemData.m_shared.m_name == temp.m_shared.m_name))
{
return;
}
}
}
if (requireMove.Value)
{
float distance = Utils.DistanceXZ(((Component)monsterAI).transform.position, ((Component)c).transform.position);
if (distance > moveProximity.Value)
{
Dbgl($"{((Object)((Component)monsterAI).gameObject).name} {((Component)monsterAI).transform.position} trying to move to {((Component)c).transform.position}. Distance is {distance}");
float ground = default(float);
ZoneSystem.instance.GetGroundHeight(((Component)c).transform.position, ref ground);
Vector3 groundTarget = new Vector3(((Component)c).transform.position.x, ground, ((Component)c).transform.position.z);
Traverse traverseAI = Traverse.Create((object)monsterAI);
traverseAI.Field("m_lastFindPathTime").SetValue((object)0);
if (!traverseAI.Method("MoveTo", new object[4] { 0.05f, groundTarget, moveProximity.Value, false }).GetValue<bool>() || Mathf.Abs(((Component)c).transform.position.y - ((Component)monsterAI).transform.position.y) > moveProximity.Value)
{
return;
}
traverseAI.Method("LookAt", new object[1] { ((Component)c).transform.position }).GetValue();
if (!traverseAI.Method("IsLookingAt", new object[2]
{
((Component)c).transform.position,
90f
}).GetValue<bool>())
{
return;
}
traverseAI.Field("m_aiStatus").SetValue((object)"Consume item");
Dbgl(((Object)((Component)monsterAI).gameObject).name + " looking at");
}
else
{
Dbgl($"{((Object)((Component)monsterAI).gameObject).name} {((Component)monsterAI).transform.position} is close enough to eat. Distance is {distance}");
}
}
Dbgl($"{((Object)((Component)monsterAI).gameObject).name} {((Component)monsterAI).transform.position} consuming {((Object)item.m_dropPrefab).name} at {((Component)c).transform.position}, distance {Utils.DistanceXZ(((Component)monsterAI).transform.position, ((Component)c).transform.position)}");
ConsumeItem(item, monsterAI, character);
c.GetInventory().RemoveItem(item.m_shared.m_name, 1, -1, true);
typeof(Inventory).GetMethod("Changed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(c.GetInventory(), new object[0]);
typeof(Container).GetMethod("Save", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(c, new object[0]);
}
private 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)
monsterAI.m_onConsumedItem?.Invoke(null);
((Humanoid)((character is Humanoid) ? character : null)).m_consumeItemEffects.Create(((Component)character).transform.position, Quaternion.identity, (Transform)null, 1f, -1);
Traverse.Create((object)monsterAI).Field("m_animator").GetValue<ZSyncAnimation>()
.SetTrigger("consume");
}
}