Decompiled source of Manger v1.0.2

plugins\Manger.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Manger.Commands;
using Manger.Config;
using Manger.Content;
using Manger.Feed;
using Manger.Util;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Manger")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2")]
[assembly: AssemblyProduct("Manger")]
[assembly: AssemblyTitle("Manger")]
[assembly: AssemblyVersion("1.0.2.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 Manger
{
	internal static class ModInfo
	{
		internal const string Guid = "dafini.manger";

		internal const string Name = "Manger";

		internal const string Version = "1.0.2";

		internal const string PieceName = "manger_trough";
	}
	[BepInPlugin("dafini.manger", "Manger", "1.0.2")]
	[BepInProcess("valheim.exe")]
	[BepInProcess("valheim_server.exe")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "dafini.manger";

		public const string PluginName = "Manger";

		public const string PluginVersion = "1.0.2";

		private Harmony _harmony;

		private void Awake()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			Log.Bind(((BaseUnityPlugin)this).Logger);
			MangerConfig.Bind(((BaseUnityPlugin)this).Config);
			try
			{
				_harmony = new Harmony("dafini.manger");
				_harmony.PatchAll();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Manger failed to patch and is disabled for this session: " + ex));
				return;
			}
			MangerCommand.Register();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Manger 1.0.2 loaded.");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			PrefabShelf.Drop();
		}
	}
}
namespace Manger.Util
{
	internal static class Log
	{
		private static ManualLogSource _source;

		internal static void Bind(ManualLogSource source)
		{
			_source = source;
		}

		internal static void Info(string message)
		{
			ManualLogSource source = _source;
			if (source != null)
			{
				source.LogInfo((object)message);
			}
		}

		internal static void Warn(string message)
		{
			ManualLogSource source = _source;
			if (source != null)
			{
				source.LogWarning((object)message);
			}
		}

		internal static void Error(string message)
		{
			ManualLogSource source = _source;
			if (source != null)
			{
				source.LogError((object)message);
			}
		}

		internal static void Debug(string message)
		{
			if (MangerConfig.Verbose != null && MangerConfig.Verbose.Value)
			{
				ManualLogSource source = _source;
				if (source != null)
				{
					source.LogInfo((object)message);
				}
			}
		}
	}
}
namespace Manger.Feed
{
	internal static class Bowl
	{
		internal const float Height = 0.35f;

		internal static int Placed { get; private set; }

		internal static void ResetForTests()
		{
			Placed = 0;
		}

		internal static ItemDrop Place(ItemData template, int amount, Vector3 at, Quaternion rotation)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			if (template == null || amount <= 0)
			{
				return null;
			}
			ItemDrop val = ItemDrop.DropItem(template, amount, at, rotation);
			if ((Object)(object)val == (Object)null)
			{
				Log.Debug("manger: the game would not spawn the feed item");
				return null;
			}
			Pin(val);
			Placed++;
			return val;
		}

		internal static void Pin(ItemDrop drop)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)drop == (Object)null))
			{
				Rigidbody component = ((Component)drop).GetComponent<Rigidbody>();
				if ((Object)(object)component != (Object)null)
				{
					component.velocity = Vector3.zero;
					component.angularVelocity = Vector3.zero;
					component.isKinematic = true;
				}
				drop.m_autoPickup = false;
			}
		}

		internal static Vector3 Rest(Vector3 troughPosition)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(troughPosition.x, troughPosition.y + 0.35f, troughPosition.z);
		}

		internal static ItemDrop Find(ZDOID id)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			if (((ZDOID)(ref id)).IsNone() || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return null;
			}
			GameObject val = ZNetScene.instance.FindInstance(id);
			if (!((Object)(object)val == (Object)null))
			{
				return val.GetComponent<ItemDrop>();
			}
			return null;
		}

		internal static int StackOf(ItemDrop drop)
		{
			if (drop?.m_itemData != null)
			{
				return drop.m_itemData.m_stack;
			}
			return 0;
		}
	}
	internal enum Sight
	{
		Findable,
		WrongLayer,
		NoBody,
		NotNetworked,
		NotFood
	}
	internal static class Findable
	{
		internal const string Layer = "item";

		internal static Sight Judge(bool onItemLayer, bool hasBody, bool networked, bool edible)
		{
			if (!onItemLayer)
			{
				return Sight.WrongLayer;
			}
			if (!hasBody)
			{
				return Sight.NoBody;
			}
			if (!networked)
			{
				return Sight.NotNetworked;
			}
			if (!edible)
			{
				return Sight.NotFood;
			}
			return Sight.Findable;
		}

		internal static bool Can(bool onItemLayer, bool hasBody, bool networked, bool edible)
		{
			return Judge(onItemLayer, hasBody, networked, edible) == Sight.Findable;
		}
	}
	internal static class Fodder
	{
		private static readonly HashSet<string> Menu = new HashSet<string>(StringComparer.Ordinal);

		internal static int Count => Menu.Count;

		internal static IEnumerable<string> All => Menu;

		internal static bool Ready => Menu.Count > 0;

		internal static void Clear()
		{
			Menu.Clear();
		}

		internal static void Learn(IEnumerable<string> itemNames)
		{
			if (itemNames == null)
			{
				return;
			}
			foreach (string itemName in itemNames)
			{
				if (!string.IsNullOrEmpty(itemName))
				{
					Menu.Add(itemName);
				}
			}
		}

		internal static bool Accepts(string itemName)
		{
			if (!string.IsNullOrEmpty(itemName))
			{
				return Menu.Contains(itemName);
			}
			return false;
		}
	}
	internal enum Source
	{
		Chosen,
		Bag,
		Nearby,
		None
	}
	internal static class Forage
	{
		internal static ItemData First(IEnumerable<ItemData> items, Func<ItemData, bool> edible, string alreadyHolding)
		{
			if (items == null || edible == null)
			{
				return null;
			}
			foreach (ItemData item in items)
			{
				if (item?.m_shared != null && item.m_stack > 0 && edible(item) && (string.IsNullOrEmpty(alreadyHolding) || string.Equals(item.m_shared.m_name, alreadyHolding, StringComparison.Ordinal)))
				{
					return item;
				}
			}
			return null;
		}

		internal static bool MayTakeFrom(bool isPublic, bool inUse, bool admitted, bool hasItems)
		{
			return isPublic && !inUse && admitted && hasItems;
		}

		internal static bool WithinReach(float distance, float reach)
		{
			if (distance >= 0f)
			{
				return distance <= reach;
			}
			return false;
		}

		internal static ItemData Find(Player player, Vector3 at, string alreadyHolding, Func<ItemData, bool> edible, out Source source, out Inventory from)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Invalid comparison between Unknown and I4
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			source = Source.None;
			from = null;
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			ItemData val = ((inventory == null) ? null : First(inventory.GetAllItems(), edible, alreadyHolding));
			if (val != null)
			{
				source = Source.Bag;
				from = inventory;
				return val;
			}
			foreach (Container item in Chests(at))
			{
				Inventory inventory2 = item.GetInventory();
				if (inventory2 == null)
				{
					continue;
				}
				List<ItemData> allItems = inventory2.GetAllItems();
				if (MayTakeFrom((int)item.m_privacy == 2, item.IsInUse(), PrivateArea.CheckAccess(((Component)item).transform.position, 0f, false, true), allItems != null && allItems.Count > 0))
				{
					ItemData val2 = First(allItems, edible, alreadyHolding);
					if (val2 != null)
					{
						source = Source.Nearby;
						from = inventory2;
						return val2;
					}
				}
			}
			return null;
		}

		private static IEnumerable<Container> Chests(Vector3 at)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			float value = MangerConfig.Reach.Value;
			List<Container> list = new List<Container>();
			Collider[] array = Physics.OverlapSphere(at, value);
			foreach (Collider val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Container componentInParent = ((Component)val).GetComponentInParent<Container>();
					if (!((Object)(object)componentInParent == (Object)null) && !list.Contains(componentInParent) && WithinReach(Vector3.Distance(at, ((Component)componentInParent).transform.position), value))
					{
						list.Add(componentInParent);
					}
				}
			}
			return list;
		}

		internal static string Sentence(Source source, int amount, string food)
		{
			switch (source)
			{
			case Source.Chosen:
			case Source.Bag:
				return $"Stocked {amount} {food}";
			case Source.Nearby:
				return $"Stocked {amount} {food} from a chest nearby";
			default:
				return "Nothing here that any of your animals would eat";
			}
		}
	}
	internal enum Filling
	{
		Ok,
		NotFood,
		Mixed,
		Full,
		Warded
	}
	internal static class Portion
	{
		internal static int Moved(int offered, int alreadyIn, int capacity)
		{
			if (offered <= 0)
			{
				return 0;
			}
			int num = capacity - alreadyIn;
			if (num <= 0)
			{
				return 0;
			}
			if (offered >= num)
			{
				return num;
			}
			return offered;
		}

		internal static Filling Judge(bool edible, bool warded, string holding, string current, int alreadyIn, int capacity)
		{
			if (!edible)
			{
				return Filling.NotFood;
			}
			if (warded)
			{
				return Filling.Warded;
			}
			if (!string.IsNullOrEmpty(current) && !string.Equals(current, holding, StringComparison.Ordinal))
			{
				return Filling.Mixed;
			}
			if (alreadyIn >= capacity)
			{
				return Filling.Full;
			}
			return Filling.Ok;
		}

		internal static int Emptied(int inTrough)
		{
			if (inTrough <= 0)
			{
				return 0;
			}
			return inTrough;
		}
	}
	internal class Trough : MonoBehaviour, Interactable, Hoverable
	{
		internal const string BowlKey = "manger.bowl";

		private ZNetView _view;

		private bool Ready
		{
			get
			{
				if ((Object)(object)_view != (Object)null)
				{
					return _view.IsValid();
				}
				return false;
			}
		}

		private void Awake()
		{
			_view = ((Component)this).GetComponent<ZNetView>();
		}

		internal ItemDrop Food()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (!Ready)
			{
				return null;
			}
			return Bowl.Find(_view.GetZDO().GetZDOID("manger.bowl"));
		}

		internal int Amount()
		{
			return Bowl.StackOf(Food());
		}

		internal string FoodName()
		{
			ItemDrop val = Food();
			if (val?.m_itemData?.m_shared != null)
			{
				return val.m_itemData.m_shared.m_name;
			}
			return string.Empty;
		}

		private void Remember(ItemDrop item)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			if (Ready)
			{
				_view.ClaimOwnership();
				ZNetView val = (((Object)(object)item == (Object)null) ? null : Networked(item));
				_view.GetZDO().Set("manger.bowl", ((Object)(object)val == (Object)null) ? ZDOID.None : val.GetZDO().m_uid);
			}
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (hold)
			{
				return false;
			}
			if (!Ready)
			{
				return false;
			}
			Player val = (Player)(object)((user is Player) ? user : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if (!alt)
			{
				return Scrounge(val);
			}
			return Empty(val);
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			if (!Ready || item?.m_shared == null)
			{
				return false;
			}
			Player val = (Player)(object)((user is Player) ? user : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			Put(val, item, ((Humanoid)val).GetInventory(), Source.Chosen);
			return true;
		}

		private bool Scrounge(Player player)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			Source source;
			Inventory from;
			ItemData val = Forage.Find(player, ((Component)this).transform.position, FoodName(), Edible, out source, out from);
			if (val == null)
			{
				((Character)player).Message((MessageType)2, Forage.Sentence(Source.None, 0, string.Empty), 0, (Sprite)null, true);
				return false;
			}
			Put(player, val, from, source);
			return true;
		}

		private static bool Edible(ItemData item)
		{
			if (item?.m_shared != null)
			{
				return Fodder.Accepts(PrefabNameOf(item));
			}
			return false;
		}

		private void Put(Player player, ItemData item, Inventory from, Source source)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			string name = item.m_shared.m_name;
			ItemDrop val = Food();
			int num = Bowl.StackOf(val);
			bool warded = !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, true);
			Filling filling = Portion.Judge(Edible(item), warded, name, FoodName(), num, MangerConfig.Capacity.Value);
			if (filling != Filling.Ok)
			{
				((Character)player).Message((MessageType)2, Complaint(filling), 0, (Sprite)null, true);
				return;
			}
			int num2 = Portion.Moved(item.m_stack, num, MangerConfig.Capacity.Value);
			if (num2 <= 0)
			{
				return;
			}
			if ((Object)(object)val != (Object)null)
			{
				ZNetView obj = Networked(val);
				if (obj != null)
				{
					obj.ClaimOwnership();
				}
				val.SetStack(num + num2);
				Bowl.Pin(val);
			}
			else
			{
				ItemDrop val2 = Bowl.Place(item, num2, Bowl.Rest(((Component)this).transform.position), ((Component)this).transform.rotation);
				if ((Object)(object)val2 == (Object)null)
				{
					return;
				}
				Remember(val2);
			}
			if (from != null)
			{
				from.RemoveItem(item, num2);
			}
			((Character)player).Message((MessageType)2, Forage.Sentence(source, num2, name), 0, (Sprite)null, true);
			Log.Debug($"manger: stocked {num2} {name} from {source}, now {Amount()}");
		}

		private bool Empty(Player player)
		{
			ItemDrop val = Food();
			int num = Portion.Emptied(Bowl.StackOf(val));
			if (num <= 0)
			{
				((Character)player).Message((MessageType)2, "The trough is empty", 0, (Sprite)null, true);
				return false;
			}
			string name = val.m_itemData.m_shared.m_name;
			ItemData val2 = val.m_itemData.Clone();
			val2.m_stack = num;
			if (!((Humanoid)player).GetInventory().AddItem(val2))
			{
				((Character)player).Message((MessageType)2, "Your inventory is full", 0, (Sprite)null, true);
				return false;
			}
			ZNetView val3 = Networked(val);
			if ((Object)(object)val3 == (Object)null)
			{
				return false;
			}
			val3.ClaimOwnership();
			val3.Destroy();
			Remember(null);
			((Character)player).Message((MessageType)2, $"Took {num} {name}", 0, (Sprite)null, true);
			return true;
		}

		private static ZNetView Networked(ItemDrop item)
		{
			if (!((Object)(object)item == (Object)null))
			{
				return ((Component)item).GetComponent<ZNetView>();
			}
			return null;
		}

		internal static string PrefabNameOf(ItemData item)
		{
			if ((Object)(object)item?.m_dropPrefab != (Object)null)
			{
				return ((Object)item.m_dropPrefab).name;
			}
			if (item?.m_shared != null)
			{
				return item.m_shared.m_name;
			}
			return string.Empty;
		}

		private static string Complaint(Filling verdict)
		{
			return verdict switch
			{
				Filling.NotFood => "No animal here eats that", 
				Filling.Mixed => "The trough already holds something else", 
				Filling.Full => "The trough is full", 
				Filling.Warded => "You are not permitted to build here", 
				_ => "The trough refuses that", 
			};
		}

		public string GetHoverName()
		{
			return Wording.Localised(Wording.Name);
		}

		public string GetHoverText()
		{
			if (!Ready)
			{
				return string.Empty;
			}
			int num = Amount();
			return Wording.Localised((num <= 0) ? Wording.Empty() : Wording.Stocked(FoodName(), num));
		}

		public float GetHoverOffset()
		{
			return 0f;
		}
	}
	internal static class Wording
	{
		internal const string Use = "$KEY_Use";

		internal const string Alt = "$KEY_AltPlace";

		internal static string Name => "Trough";

		internal static string Empty()
		{
			return Name + " ( empty )\n[<color=yellow><b>$KEY_Use</b></color>] Stock with feed";
		}

		internal static string Stocked(string food, int amount)
		{
			return $"{Name} ( {food} x{amount} )\n" + "[<color=yellow><b>$KEY_Use</b></color>] Add more\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] Take it all back";
		}

		internal static string Localised(string raw)
		{
			if (string.IsNullOrEmpty(raw))
			{
				return string.Empty;
			}
			Localization instance = Localization.instance;
			if (instance != null)
			{
				return instance.Localize(raw);
			}
			return raw;
		}

		internal static bool HasToken(string text)
		{
			if (!string.IsNullOrEmpty(text))
			{
				return text.Contains("$");
			}
			return false;
		}
	}
}
namespace Manger.Content
{
	internal static class PrefabShelf
	{
		private static GameObject _shelf;

		internal static GameObject Root
		{
			get
			{
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Expected O, but got Unknown
				if ((Object)(object)_shelf != (Object)null)
				{
					return _shelf;
				}
				_shelf = new GameObject("MangerPrefabs");
				_shelf.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)_shelf);
				return _shelf;
			}
		}

		internal static void Drop()
		{
			if (!((Object)(object)_shelf == (Object)null))
			{
				Object.Destroy((Object)(object)_shelf);
				_shelf = null;
			}
		}
	}
	internal enum Stage
	{
		Prefab,
		Menu,
		Diet
	}
	internal static class TroughPiece
	{
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		internal static class Install
		{
			[HarmonyPrefix]
			private static void Prefix(ZNetScene __instance)
			{
				Ensure(__instance);
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		internal static class Items
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				Ensure(ZNetScene.instance);
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		internal static class ItemsCopied
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				Ensure(ZNetScene.instance);
			}
		}

		[HarmonyPatch(typeof(Player), "OnSpawned")]
		internal static class Spawned
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				Ensure(ZNetScene.instance);
			}
		}

		private static readonly string[] Donors = new string[3] { "piece_cookingstation", "piece_cookingstation_iron", "piece_workbench_ext1" };

		private const string HammerMarker = "piece_workbench";

		private static GameObject _trough;

		internal static bool PrefabReady { get; private set; }

		internal static bool InMenu { get; private set; }

		internal static bool DietRead { get; private set; }

		internal static string Trouble { get; private set; } = string.Empty;

		internal static string UsedDonor { get; private set; } = string.Empty;

		internal static void ResetForTests()
		{
			PrefabReady = false;
			InMenu = false;
			DietRead = false;
			Trouble = string.Empty;
			UsedDonor = string.Empty;
			_trough = null;
		}

		internal static bool Needs(bool enabled, bool done, bool prerequisiteReady)
		{
			return enabled && !done && prerequisiteReady;
		}

		internal static void Ensure(ZNetScene scene)
		{
			if (MangerConfig.Enabled == null || !MangerConfig.Enabled.Value)
			{
				return;
			}
			try
			{
				if (Needs(enabled: true, PrefabReady, (Object)(object)scene != (Object)null))
				{
					BuildPrefab(scene);
				}
				if (Needs(enabled: true, DietRead, (Object)(object)scene != (Object)null))
				{
					ReadDiets(scene);
				}
				if (Needs(enabled: true, InMenu, PrefabReady))
				{
					TrySeat();
				}
			}
			catch (Exception ex)
			{
				Trouble = ex.Message;
				Log.Error("Manger stumbled while registering its trough: " + ex);
			}
		}

		private static void BuildPrefab(ZNetScene scene)
		{
			GameObject val = Donate(scene);
			if ((Object)(object)val == (Object)null)
			{
				Trouble = "none of " + string.Join(", ", Donors) + " exist to clone";
				Log.Error("Manger found nothing to clone. No trough this session.");
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, PrefabShelf.Root.transform, false);
			((Object)val2).name = "manger_trough";
			Strip(val2);
			val2.AddComponent<Trough>();
			Piece component = val2.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null)
			{
				component.m_name = "Trough";
				component.m_description = "Holds animal feed where tames can reach it.";
				component.m_groundPiece = true;
				component.m_allowedInDungeons = false;
			}
			if (scene.m_prefabs != null && !scene.m_prefabs.Contains(val2))
			{
				scene.m_prefabs.Add(val2);
			}
			_trough = val2;
			PrefabReady = true;
			Log.Info("Manger: trough prefab built from " + UsedDonor + ".");
		}

		internal static bool TrySeat()
		{
			if ((Object)(object)_trough == (Object)null)
			{
				return false;
			}
			PieceTable val = HammerTable();
			if ((Object)(object)val == (Object)null)
			{
				Trouble = "the hammer's piece table is not available yet";
				Log.Debug("manger: no hammer table yet, will try again");
				return false;
			}
			if (!val.m_pieces.Contains(_trough))
			{
				val.m_pieces.Add(_trough);
			}
			InMenu = true;
			Trouble = string.Empty;
			Log.Info("Manger: trough added to the hammer.");
			return true;
		}

		internal static void ForTests_PrefabReady(GameObject stand)
		{
			_trough = stand;
			PrefabReady = (Object)(object)stand != (Object)null;
		}

		private static void ReadDiets(ZNetScene scene)
		{
			int num = LearnMenu(scene.m_prefabs);
			if (num <= 0)
			{
				Log.Debug("manger: no tameable creatures read yet, will try again");
				return;
			}
			DietRead = true;
			Log.Info($"Manger: read the diets of {num} tameable creature(s) - " + $"{Fodder.Count} thing(s) count as feed.");
		}

		private static GameObject Donate(ZNetScene scene)
		{
			if (scene.m_prefabs == null)
			{
				return null;
			}
			string[] donors = Donors;
			foreach (string text in donors)
			{
				foreach (GameObject prefab in scene.m_prefabs)
				{
					if ((Object)(object)prefab != (Object)null && ((Object)prefab).name == text)
					{
						UsedDonor = text;
						return prefab;
					}
				}
			}
			return null;
		}

		private static PieceTable HammerTable()
		{
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance != (Object)null)
			{
				GameObject itemPrefab = instance.GetItemPrefab("Hammer");
				PieceTable val = (((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent<ItemDrop>())?.m_itemData?.m_shared?.m_buildPieces;
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			PieceTable[] array = Resources.FindObjectsOfTypeAll<PieceTable>();
			foreach (PieceTable val2 in array)
			{
				if (val2?.m_pieces == null)
				{
					continue;
				}
				foreach (GameObject piece in val2.m_pieces)
				{
					if ((Object)(object)piece != (Object)null && ((Object)piece).name == "piece_workbench")
					{
						return val2;
					}
				}
			}
			return null;
		}

		private static void Strip(GameObject trough)
		{
			CookingStation[] componentsInChildren = trough.GetComponentsInChildren<CookingStation>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			CraftingStation[] componentsInChildren2 = trough.GetComponentsInChildren<CraftingStation>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren2[i]);
			}
			Container[] componentsInChildren3 = trough.GetComponentsInChildren<Container>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren3[i]);
			}
		}

		internal static int LearnMenu(IEnumerable<GameObject> prefabs)
		{
			if (prefabs == null)
			{
				return 0;
			}
			int num = 0;
			foreach (GameObject prefab in prefabs)
			{
				if ((Object)(object)prefab == (Object)null)
				{
					continue;
				}
				MonsterAI component = prefab.GetComponent<MonsterAI>();
				if (component?.m_consumeItems == null || component.m_consumeItems.Count == 0 || (Object)(object)prefab.GetComponent<Tameable>() == (Object)null)
				{
					continue;
				}
				List<string> list = new List<string>();
				foreach (ItemDrop consumeItem in component.m_consumeItems)
				{
					if ((Object)(object)consumeItem != (Object)null)
					{
						list.Add(((Object)consumeItem).name);
					}
				}
				Fodder.Learn(list);
				num++;
			}
			return num;
		}
	}
}
namespace Manger.Config
{
	internal static class MangerConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<int> Capacity;

		internal static ConfigEntry<bool> TamesWild;

		internal static ConfigEntry<int> BreedingCap;

		internal static ConfigEntry<float> Reach;

		internal static ConfigEntry<bool> Verbose;

		internal static void Bind(ConfigFile cfg)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			Enabled = cfg.Bind<bool>("General", "Enabled", true, "Master switch. Off means the trough is not added to the build menu.");
			Capacity = cfg.Bind<int>("Trough", "Capacity", 50, new ConfigDescription("How many items one trough holds. The food sits on it as a real world item, so this is a stack size rather than an inventory.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 999), Array.Empty<object>()));
			TamesWild = cfg.Bind<bool>("Trough", "TamesWild", true, "A stocked trough tames wild animals that wander in and eat from it. This is the game's own behaviour - feeding a wild tameable is exactly how taming works - so turning it OFF is the part that costs extra code. On means a baited pen tames unattended. Note that wolves are tameable too.");
			BreedingCap = cfg.Bind<int>("Trough", "BreedingCap", 0, new ConfigDescription("Stop feeding once this many tames are already near the trough. A permanently stocked pen breeds without supervision, and Valheim handles large herds badly - this is the lever for that. ZERO MEANS NO CAP, which is the default: it is your pen and your framerate.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>()));
			Reach = cfg.Bind<float>("Trough", "Reach", 8f, new ConfigDescription("How far the trough will reach into nearby chests when you press Use with nothing suitable in your bag. Your own inventory is always tried first. Set to 0 to only ever use what you are carrying.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 32f), Array.Empty<object>()));
			Verbose = cfg.Bind<bool>("Advanced", "Verbose", false, "Log every decision. Useful for a bug report, noisy otherwise.");
		}
	}
}
namespace Manger.Commands
{
	internal static class MangerCommand
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__0_0;

			internal void <Register>b__0_0(ConsoleEventArgs args)
			{
				args.Context.AddString(Report());
			}
		}

		internal static void Register()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			object obj = <>c.<>9__0_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					args.Context.AddString(Report());
				};
				<>c.<>9__0_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("manger", "what Manger registered and what animals eat", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		internal static string Report()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("Manger 1.0.2 - " + (MangerConfig.Enabled.Value ? "on" : "OFF"));
			stringBuilder.AppendLine("  prefab:    " + (TroughPiece.PrefabReady ? ("built" + (string.IsNullOrEmpty(TroughPiece.UsedDonor) ? "" : (" from " + TroughPiece.UsedDonor))) : "NOT BUILT"));
			stringBuilder.AppendLine("  build menu: " + (TroughPiece.InMenu ? "in the hammer" : "NOT IN IT"));
			stringBuilder.AppendLine("  diets:     " + (TroughPiece.DietRead ? "read" : "NOT READ"));
			if (!string.IsNullOrEmpty(TroughPiece.Trouble))
			{
				stringBuilder.AppendLine("  last trouble: " + TroughPiece.Trouble);
			}
			stringBuilder.AppendLine($"  capacity {MangerConfig.Capacity.Value}, " + "tames wild: " + (MangerConfig.TamesWild.Value ? "yes" : "no") + ", breeding cap: " + ((MangerConfig.BreedingCap.Value <= 0) ? "none" : MangerConfig.BreedingCap.Value.ToString()));
			if (!Fodder.Ready)
			{
				stringBuilder.AppendLine("  feed list: EMPTY - no tameable creature has been read yet, so the trough will refuse everything. This is a load-order problem rather than a disagreement about carrots.");
				return stringBuilder.ToString();
			}
			stringBuilder.AppendLine($"  this install's animals eat {Fodder.Count} thing(s):");
			StringBuilder stringBuilder2 = new StringBuilder("   ");
			foreach (string item in Fodder.All)
			{
				if (stringBuilder2.Length + item.Length > 74)
				{
					stringBuilder.AppendLine(stringBuilder2.ToString());
					stringBuilder2 = new StringBuilder("   ");
				}
				stringBuilder2.Append(' ').Append(item);
			}
			if (stringBuilder2.Length > 3)
			{
				stringBuilder.AppendLine(stringBuilder2.ToString());
			}
			return stringBuilder.ToString();
		}
	}
}