Decompiled source of Carturs Feeding Trough v1.0.0

plugins/CarturFeedingTrough/CarturFeedingTrough.dll

Decompiled 12 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("CarturFeedingTrough")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+b2d0d9427f966cbdbec853bc8585dee492058655")]
[assembly: AssemblyProduct("CarturFeedingTrough")]
[assembly: AssemblyTitle("CarturFeedingTrough")]
[assembly: AssemblyVersion("1.0.0.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 CarturFeedingTrough
{
	internal static class MeshBlob
	{
		private static string AssetDir => Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "", "assets");

		internal static Mesh LoadMesh(string fileName)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Expected O, but got Unknown
			string text = Path.Combine(AssetDir, fileName);
			if (!File.Exists(text))
			{
				Plugin.Log.LogWarning((object)("missing " + text));
				return null;
			}
			using BinaryReader binaryReader = new BinaryReader(File.OpenRead(text));
			if (new string(binaryReader.ReadChars(4)) != "CTM1")
			{
				Plugin.Log.LogWarning((object)(fileName + " is not a CTM1 blob"));
				return null;
			}
			int num = binaryReader.ReadInt32();
			int num2 = binaryReader.ReadInt32();
			Vector3[] array = (Vector3[])(object)new Vector3[num];
			for (int i = 0; i < num; i++)
			{
				array[i] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			}
			Vector3[] array2 = (Vector3[])(object)new Vector3[num];
			for (int j = 0; j < num; j++)
			{
				array2[j] = new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
			}
			Vector2[] array3 = (Vector2[])(object)new Vector2[num];
			for (int k = 0; k < num; k++)
			{
				array3[k] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
			}
			int[] array4 = new int[num2];
			for (int l = 0; l < num2; l++)
			{
				array4[l] = binaryReader.ReadInt32();
			}
			Mesh val = new Mesh
			{
				name = Path.GetFileNameWithoutExtension(fileName),
				vertices = array,
				normals = array2,
				uv = array3,
				triangles = array4
			};
			val.RecalculateTangents();
			val.RecalculateBounds();
			return val;
		}

		internal static Texture2D LoadTexture(string fileName, bool linear)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			string text = Path.Combine(AssetDir, fileName);
			if (!File.Exists(text))
			{
				Plugin.Log.LogWarning((object)("missing " + text));
				return null;
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true, linear)
			{
				name = Path.GetFileNameWithoutExtension(fileName),
				wrapMode = (TextureWrapMode)0,
				filterMode = (FilterMode)1
			};
			if (LoadImageViaReflection(val, File.ReadAllBytes(text)))
			{
				return val;
			}
			Plugin.Log.LogWarning((object)("ImageConversion.LoadImage failed for " + text));
			return null;
		}

		private static bool LoadImageViaReflection(Texture2D tex, byte[] data)
		{
			Type type = AccessTools.TypeByName("UnityEngine.ImageConversion");
			if (type == null)
			{
				return false;
			}
			MethodInfo methodInfo = null;
			MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (!(methodInfo2.Name != "LoadImage"))
				{
					ParameterInfo[] parameters = methodInfo2.GetParameters();
					if (parameters.Length == 3 && parameters[1].ParameterType == typeof(byte[]))
					{
						methodInfo = methodInfo2;
						break;
					}
				}
			}
			if (methodInfo == null)
			{
				return false;
			}
			object obj = methodInfo.Invoke(null, new object[3] { tex, data, false });
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}
	}
	[BepInPlugin("cartur.feedingtrough", "Cartur's Feeding Trough", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInProcess("valheim.exe")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "cartur.feedingtrough";

		public const string PluginName = "Cartur's Feeding Trough";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				_harmony = new Harmony("cartur.feedingtrough");
				_harmony.PatchAll(typeof(Plugin).Assembly);
				TroughPiece.Register();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"loaded");
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"failed to load, game continues without it: {arg}");
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "GetHoverText")]
	internal static class TameTimer
	{
		private static void Postfix(Tameable __instance, ref string __result)
		{
			if (string.IsNullOrEmpty(__result) || __instance.IsTamed())
			{
				return;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return;
			}
			ZDO zDO = component.GetZDO();
			if (zDO != null)
			{
				float num = zDO.GetFloat(ZDOVars.s_tameTimeLeft, __instance.m_tamingTime);
				if (!(num <= 0f) && !(num >= __instance.m_tamingTime))
				{
					__result = __result + "\n" + Format(num) + " left";
				}
			}
		}

		private static string Format(float seconds)
		{
			int num = Mathf.CeilToInt(seconds);
			int num2 = num / 60;
			int num3 = num % 60;
			if (num2 <= 0)
			{
				return $"{num3}s";
			}
			return $"{num2}m {num3}s";
		}
	}
	[HarmonyPatch(typeof(EnemyHud), "ShowHud")]
	internal static class TamingBarPatch
	{
		private static readonly FieldInfo HudsField = AccessTools.Field(typeof(EnemyHud), "m_huds");

		private static readonly FieldInfo GuiField = AccessTools.Field(AccessTools.Inner(typeof(EnemyHud), "HudData"), "m_gui");

		internal static readonly FieldInfo HoverTimerField = AccessTools.Field(AccessTools.Inner(typeof(EnemyHud), "HudData"), "m_hoverTimer");

		private static bool s_reported;

		private static void Postfix(EnemyHud __instance, Character c)
		{
			if ((Object)(object)c == (Object)null)
			{
				return;
			}
			if (HudsField == null || GuiField == null)
			{
				Report($"cannot reach EnemyHud internals (m_huds={HudsField != null}, " + $"HudData.m_gui={GuiField != null}) - no taming bar this session");
				return;
			}
			Tameable component = ((Component)c).GetComponent<Tameable>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			try
			{
				object obj = (HudsField.GetValue(__instance) as IDictionary)?[c];
				object? value = GuiField.GetValue(obj);
				GameObject val = (GameObject)((value is GameObject) ? value : null);
				if ((Object)(object)val == (Object)null)
				{
					Report("no hud object for " + ((Object)c).name + " - taming bar not added");
				}
				else if (!((Object)(object)val.GetComponent<TamingBar>() != (Object)null))
				{
					val.AddComponent<TamingBar>().Bind(component, obj);
					Report("taming bar attached to " + ((Object)c).name + "'s hud");
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"could not add the taming bar, health bar is unaffected: {arg}");
			}
		}

		private static void Report(string message)
		{
			if (!s_reported)
			{
				s_reported = true;
				Plugin.Log.LogInfo((object)message);
			}
		}
	}
	internal class TamingBar : MonoBehaviour
	{
		private const float Gap = 2f;

		private static readonly Color Yellow = new Color(0.95f, 0.82f, 0.25f, 1f);

		private static bool s_said;

		private static bool s_saidHidden;

		private Tameable _tameable;

		private GuiBar _bar;

		private GameObject _root;

		private bool _built;

		private object _hudData;

		private static void Say(string message)
		{
			if (!s_said)
			{
				s_said = true;
				Plugin.Log.LogInfo((object)message);
			}
		}

		internal void Bind(Tameable tameable, object hudData)
		{
			_tameable = tameable;
			_hudData = hudData;
		}

		private void HoldHudOpen()
		{
			if (_hudData != null && !(TamingBarPatch.HoverTimerField == null))
			{
				TamingBarPatch.HoverTimerField.SetValue(_hudData, 0f);
			}
		}

		private void Build()
		{
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: 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_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Unknown result type (might be due to invalid IL or missing references)
			_built = true;
			Transform obj = ((Component)this).transform.Find("Health");
			RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				Say("hud has no 'Health' child - EnemyHud layout changed, no taming bar");
				return;
			}
			_root = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Transform)val).parent);
			((Object)_root).name = "CarturTaming";
			Transform transform = _root.transform;
			RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			Transform val3 = ((Transform)val2).Find("health_fast");
			Transform val4 = ((Transform)val2).Find("health_fast_friendly");
			Transform val5 = PickBar(val3) ?? PickBar(val4);
			_bar = (((Object)(object)val5 == (Object)null) ? null : ((Component)val5).GetComponent<GuiBar>());
			if ((Object)(object)_bar == (Object)null)
			{
				Say("cloned hud has no usable GuiBar - no taming bar");
				Object.Destroy((Object)(object)_root);
				return;
			}
			((Component)val5).gameObject.SetActive(true);
			Strip((Transform)(object)val2, "health_slow");
			Strip((Transform)(object)val2, "HealthText");
			if ((Object)(object)val3 != (Object)null && (Object)(object)val3 != (Object)(object)val5)
			{
				Object.Destroy((Object)(object)((Component)val3).gameObject);
			}
			if ((Object)(object)val4 != (Object)null && (Object)(object)val4 != (Object)(object)val5)
			{
				Object.Destroy((Object)(object)((Component)val4).gameObject);
			}
			Rect rect = val.rect;
			float height = ((Rect)(ref rect)).height;
			rect = ((RectTransform)val3).rect;
			float num = Mathf.Max(height, ((Rect)(ref rect)).height);
			if (num <= 0f)
			{
				num = 10f;
			}
			val2.anchoredPosition = val.anchoredPosition - new Vector2(0f, num + 2f);
			StringBuilder stringBuilder = new StringBuilder();
			rect = val.rect;
			stringBuilder.Append($"taming bar built: Health rect={((Rect)(ref rect)).size} anchored={val.anchoredPosition} " + $"drop={num + 2f} -> taming anchored={val2.anchoredPosition}\n");
			stringBuilder.Append("  hud root children: ");
			for (int i = 0; i < ((Component)this).transform.childCount; i++)
			{
				stringBuilder.Append(((Object)((Component)this).transform.GetChild(i)).name).Append(" ");
			}
			stringBuilder.Append("\n  taming bar contents:\n");
			RectTransform[] componentsInChildren = _root.GetComponentsInChildren<RectTransform>(true);
			foreach (RectTransform val6 in componentsInChildren)
			{
				string name = ((Object)val6).name;
				rect = val6.rect;
				stringBuilder.Append($"    {name} size={((Rect)(ref rect)).size} pos={val6.anchoredPosition} " + $"active={((Component)val6).gameObject.activeSelf} img={(Object)(object)((Component)val6).GetComponent<Image>() != (Object)null}\n");
			}
			Say(stringBuilder.ToString());
			_bar.SetMaxValue(1f);
			_bar.SetColor(Yellow);
			_root.SetActive(false);
		}

		private static Transform PickBar(Transform t)
		{
			if (!((Object)(object)t != (Object)null) || !((Object)(object)((Component)t).GetComponent<GuiBar>() != (Object)null))
			{
				return null;
			}
			return t;
		}

		private static void Strip(Transform parent, string childName)
		{
			Transform val = parent.Find(childName);
			if ((Object)(object)val != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
		}

		private void Update()
		{
			if (!_built)
			{
				Build();
			}
			if ((Object)(object)_root == (Object)null || (Object)(object)_bar == (Object)null)
			{
				return;
			}
			float num = Progress();
			if (num < 0f)
			{
				if (_root.activeSelf)
				{
					_root.SetActive(false);
				}
				return;
			}
			if (!_root.activeSelf)
			{
				_root.SetActive(true);
			}
			_bar.SetValue(num);
			HoldHudOpen();
		}

		private float Progress()
		{
			if ((Object)(object)_tameable == (Object)null || _tameable.IsTamed())
			{
				return -1f;
			}
			ZNetView component = ((Component)_tameable).GetComponent<ZNetView>();
			ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null);
			if (val == null || _tameable.m_tamingTime <= 0f)
			{
				return -1f;
			}
			float num = val.GetFloat(ZDOVars.s_tameTimeLeft, _tameable.m_tamingTime);
			if (num >= _tameable.m_tamingTime)
			{
				return -1f;
			}
			float num2 = Mathf.Clamp01(1f - num / _tameable.m_tamingTime);
			if (!s_saidHidden)
			{
				s_saidHidden = true;
				Plugin.Log.LogInfo((object)($"taming bar for {((Object)_tameable).name}: timeLeft={num} " + $"of {_tameable.m_tamingTime} -> {num2:P0}"));
			}
			return num2;
		}
	}
	internal class Trough : MonoBehaviour
	{
		private const float FloorY = 0.209f;

		internal static readonly Vector3 BaitLocalPosition = new Vector3(0f, 0.269f, 0f);

		private const float BaitSearchRadius = 0.3f;

		private static readonly int ItemMask = LayerMask.GetMask(new string[1] { "item" });

		private const float InnerHalfX = 0.85f;

		private const float InnerHalfZ = 0.24f;

		private const int MaxVisuals = 14;

		private const int ItemsPerVisual = 4;

		internal static readonly List<Trough> All = new List<Trough>();

		private Container _container;

		private Inventory _inventory;

		private Transform _holder;

		private readonly List<GameObject> _spawned = new List<GameObject>();

		private void Awake()
		{
			All.Add(this);
		}

		private void Start()
		{
			_container = ((Component)this).GetComponent<Container>();
			if (!((Object)(object)_container == (Object)null))
			{
				_inventory = _container.GetInventory();
				if (_inventory != null)
				{
					Inventory inventory = _inventory;
					inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, new Action(Rebuild));
					Rebuild();
				}
			}
		}

		private void OnDestroy()
		{
			All.Remove(this);
			if (_inventory != null)
			{
				Inventory inventory = _inventory;
				inventory.m_onChanged = (Action)Delegate.Remove(inventory.m_onChanged, new Action(Rebuild));
			}
		}

		internal ItemDrop FindBait()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Collider[] array = Physics.OverlapSphere(((Component)this).transform.TransformPoint(BaitLocalPosition), 0.3f, ItemMask);
			for (int i = 0; i < array.Length; i++)
			{
				Rigidbody attachedRigidbody = array[i].attachedRigidbody;
				ItemDrop val = (((Object)(object)attachedRigidbody == (Object)null) ? null : ((Component)attachedRigidbody).GetComponent<ItemDrop>());
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private void Rebuild()
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			foreach (GameObject item in _spawned)
			{
				if ((Object)(object)item != (Object)null)
				{
					Object.Destroy((Object)(object)item);
				}
			}
			_spawned.Clear();
			List<ItemData> allItems = _inventory.GetAllItems();
			if (allItems.Count == 0)
			{
				return;
			}
			if ((Object)(object)_holder == (Object)null)
			{
				_holder = new GameObject("TroughFill").transform;
				_holder.SetParent(((Component)this).transform, false);
			}
			Random rng = new Random(((Object)this).GetInstanceID());
			int num = 0;
			foreach (ItemData item2 in allItems)
			{
				num += item2.m_stack;
			}
			int num2 = Mathf.Clamp(Mathf.CeilToInt((float)num / 4f), 1, 14);
			int num3 = 0;
			foreach (ItemData item3 in allItems)
			{
				if (!((Object)(object)item3.m_dropPrefab == (Object)null))
				{
					int num4 = Mathf.Max(1, Mathf.RoundToInt((float)num2 * ((float)item3.m_stack / (float)num)));
					int num5 = 0;
					while (num5 < num4 && num3 < num2)
					{
						Place(item3.m_dropPrefab, num3, num2, rng);
						num5++;
						num3++;
					}
				}
			}
		}

		private void Place(GameObject dropPrefab, int index, int slots, Random rng)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			bool forceDisableInit = ZNetView.m_forceDisableInit;
			ZNetView.m_forceDisableInit = true;
			GameObject val;
			try
			{
				val = Object.Instantiate<GameObject>(dropPrefab, _holder);
			}
			finally
			{
				ZNetView.m_forceDisableInit = forceDisableInit;
			}
			Strip(val);
			float num = ((slots == 1) ? 0.5f : ((float)index / (float)(slots - 1)));
			float num2 = Mathf.Lerp(-0.85f, 0.85f, num) + (float)(rng.NextDouble() - 0.5) * 0.08f;
			float num3 = (float)(rng.NextDouble() - 0.5) * 2f * 0.24f;
			float num4 = 0.209f + ((index >= slots / 2) ? 0.05f : 0f) + (float)rng.NextDouble() * 0.02f;
			val.transform.localPosition = new Vector3(num2, num4, num3);
			val.transform.localRotation = Quaternion.Euler((float)rng.NextDouble() * 30f, (float)rng.NextDouble() * 360f, (float)rng.NextDouble() * 30f);
			_spawned.Add(val);
		}

		private static void Strip(GameObject go)
		{
			ZNetView[] componentsInChildren = go.GetComponentsInChildren<ZNetView>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			ItemDrop[] componentsInChildren2 = go.GetComponentsInChildren<ItemDrop>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren2[i]);
			}
			Rigidbody[] componentsInChildren3 = go.GetComponentsInChildren<Rigidbody>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren3[i]);
			}
			Collider[] componentsInChildren4 = go.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren4.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren4[i]);
			}
			Floating[] componentsInChildren5 = go.GetComponentsInChildren<Floating>(true);
			for (int i = 0; i < componentsInChildren5.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren5[i]);
			}
			Transform[] componentsInChildren6 = go.GetComponentsInChildren<Transform>(true);
			for (int i = 0; i < componentsInChildren6.Length; i++)
			{
				((Component)componentsInChildren6[i]).gameObject.layer = LayerMask.NameToLayer("piece_nonsolid");
			}
		}
	}
	[HarmonyPatch(typeof(MonsterAI), "FindClosestConsumableItem")]
	internal static class TroughFeeding
	{
		private static readonly MethodInfo CanConsumeMethod = AccessTools.Method(typeof(MonsterAI), "CanConsume", new Type[1] { typeof(ItemData) }, (Type[])null);

		private static bool s_loggedFirstFeed;

		private static bool s_loggedPathing;

		private static bool s_loggedNoTrough;

		private static void Postfix(MonsterAI __instance, float maxRange, ref ItemDrop __result)
		{
			if ((Object)(object)__result != (Object)null || CanConsumeMethod == null)
			{
				return;
			}
			try
			{
				ItemDrop val = FindBait(__instance, maxRange);
				if ((Object)(object)val != (Object)null)
				{
					__result = val;
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"trough feeding failed, animal falls back to vanilla: {arg}");
			}
		}

		private static ItemDrop FindBait(MonsterAI ai, float maxRange)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			Trough trough = null;
			float num = float.MaxValue;
			foreach (Trough item in Trough.All)
			{
				if ((Object)(object)item == (Object)null)
				{
					continue;
				}
				ZNetView component = ((Component)item).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid())
				{
					float num2 = Vector3.Distance(((Component)ai).transform.position, ((Component)item).transform.position);
					if (num2 <= maxRange && num2 < num)
					{
						trough = item;
						num = num2;
					}
				}
			}
			if ((Object)(object)trough == (Object)null)
			{
				if (!s_loggedNoTrough)
				{
					s_loggedNoTrough = true;
					Plugin.Log.LogInfo((object)($"no trough within {maxRange} of {((Object)ai).name} " + $"(troughs loaded: {Trough.All.Count}) - said once"));
				}
				return null;
			}
			ItemDrop val = trough.FindBait();
			if ((Object)(object)val != (Object)null)
			{
				if (!CanConsume(ai, val.m_itemData))
				{
					return null;
				}
				if (!Reachable(ai, trough))
				{
					return null;
				}
				return val;
			}
			Container component2 = ((Component)trough).GetComponent<Container>();
			if ((Object)(object)component2 == (Object)null || component2.IsInUse())
			{
				return null;
			}
			Inventory inventory = component2.GetInventory();
			if (inventory == null)
			{
				return null;
			}
			ItemData val2 = null;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if ((Object)(object)allItem.m_dropPrefab != (Object)null && CanConsume(ai, allItem))
				{
					val2 = allItem;
					break;
				}
			}
			if (val2 == null)
			{
				return null;
			}
			if (!Reachable(ai, trough))
			{
				return null;
			}
			return TakeBait(trough, component2, inventory, val2);
		}

		private static ItemDrop TakeBait(Trough trough, Container container, Inventory inventory, ItemData food)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			ZNetView component = ((Component)container).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return null;
			}
			if (!component.IsOwner())
			{
				return null;
			}
			ItemData val = food.Clone();
			if (!inventory.RemoveItem(food, 1))
			{
				return null;
			}
			Vector3 val2 = ((Component)trough).transform.TransformPoint(Trough.BaitLocalPosition);
			ItemDrop val3 = ItemDrop.DropItem(val, 1, val2, Random.rotation);
			if ((Object)(object)val3 == (Object)null)
			{
				return null;
			}
			val3.m_autoPickup = false;
			Rigidbody component2 = ((Component)val3).GetComponent<Rigidbody>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.isKinematic = true;
			}
			if (!s_loggedFirstFeed)
			{
				s_loggedFirstFeed = true;
				Plugin.Log.LogInfo((object)("first trough feed: " + val.m_shared.m_name + " offered to " + ((Object)trough).name));
			}
			return val3;
		}

		private static bool Reachable(MonsterAI ai, Trough trough)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			Pathfinding instance = Pathfinding.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return true;
			}
			Vector3 position = ((Component)ai).transform.position;
			Vector3 position2 = ((Component)trough).transform.position;
			float num = Utils.DistanceXZ(position, position2);
			bool flag = num <= ai.m_consumeRange + 1f;
			Vector3 val = default(Vector3);
			bool flag2 = instance.FindValidPoint(ref val, position2, 4f, ((BaseAI)ai).m_pathAgentType);
			bool flag3 = flag2 && instance.HavePath(position, val, ((BaseAI)ai).m_pathAgentType);
			bool flag4 = instance.HavePath(position, position2, ((BaseAI)ai).m_pathAgentType);
			bool flag5 = flag || flag3 || flag4;
			if (!s_loggedPathing)
			{
				s_loggedPathing = true;
				Plugin.Log.LogInfo((object)($"trough pathing for {((Object)ai).name}: d={num:0.00} " + $"near={flag} snapped={flag2} viaPoint={flag3} direct={flag4} " + $"agent={((BaseAI)ai).m_pathAgentType} -> reachable={flag5}"));
			}
			return flag5;
		}

		private static bool CanConsume(MonsterAI ai, ItemData item)
		{
			return (bool)CanConsumeMethod.Invoke(ai, new object[1] { item });
		}
	}
	internal static class TroughPiece
	{
		internal const string PrefabName = "piece_cartur_trough";

		internal const string NameToken = "$piece_cartur_trough";

		internal const string DescriptionToken = "$piece_cartur_trough_description";

		internal static Bounds BowlBounds { get; private set; }

		internal static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += Build;
		}

		private static void Build()
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			PrefabManager.OnVanillaPrefabsAvailable -= Build;
			try
			{
				CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
				string text = "English";
				string text2 = "$piece_cartur_trough".Substring(1);
				localization.AddTranslation(ref text, ref text2, "Feeding Trough");
				text = "English";
				text2 = "$piece_cartur_trough_description".Substring(1);
				localization.AddTranslation(ref text, ref text2, "Fill it with food and your animals will come and eat from it.");
				PieceConfig val = new PieceConfig();
				val.Name = "$piece_cartur_trough";
				val.Description = "$piece_cartur_trough_description";
				val.PieceTable = "Hammer";
				val.Category = "Furniture";
				val.CraftingStation = "piece_workbench";
				val.Requirements = (RequirementConfig[])(object)new RequirementConfig[1]
				{
					new RequirementConfig("Wood", 10, 0, true)
				};
				CustomPiece val2 = new CustomPiece("piece_cartur_trough", "piece_chest_wood", val);
				if ((Object)(object)val2.PiecePrefab == (Object)null)
				{
					Plugin.Log.LogWarning((object)"piece_chest_wood did not resolve - no trough this session");
				}
				else if (Reskin(val2.PiecePrefab))
				{
					val2.Piece.m_icon = RenderManager.Instance.Render(val2.PiecePrefab);
					PieceManager.Instance.AddPiece(val2);
					ManualLogSource log = Plugin.Log;
					Bounds bowlBounds = BowlBounds;
					log.LogInfo((object)("registered piece_cartur_trough (clone of piece_chest_wood, " + $"bowl bounds {((Bounds)(ref bowlBounds)).size})"));
				}
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"could not build the trough piece: {arg}");
			}
		}

		private static bool Reskin(GameObject prefab)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			Mesh val = MeshBlob.LoadMesh("trough.mesh");
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			Transform val2 = prefab.transform.Find("New/woodchest");
			MeshRenderer val3 = (((Object)(object)val2 == (Object)null) ? null : ((Component)val2).GetComponent<MeshRenderer>());
			if ((Object)(object)val3 == (Object)null)
			{
				Plugin.Log.LogWarning((object)"chest prefab has no New/woodchest renderer - layout changed");
				return false;
			}
			Material val4 = new Material(((Renderer)val3).sharedMaterial)
			{
				name = "cartur_trough"
			};
			Texture2D val5 = MeshBlob.LoadTexture("trough_albedo.jpg", linear: false);
			Texture2D val6 = MeshBlob.LoadTexture("trough_normal.png", linear: true);
			if ((Object)(object)val5 != (Object)null)
			{
				val4.SetTexture("_MainTex", (Texture)(object)val5);
			}
			if ((Object)(object)val6 != (Object)null)
			{
				val4.SetTexture("_BumpMap", (Texture)(object)val6);
			}
			val4.SetFloat("_BumpScale", 1f);
			val4.SetFloat("_Metallic", 0f);
			val4.SetFloat("_Glossiness", 0.3f);
			DestroyChild(prefab, "New");
			DestroyChild(prefab, "floor_2x2_snow");
			GameObject val7 = new GameObject("TroughVisual")
			{
				layer = prefab.layer
			};
			val7.transform.SetParent(prefab.transform, false);
			val7.AddComponent<MeshFilter>().sharedMesh = val;
			((Renderer)val7.AddComponent<MeshRenderer>()).sharedMaterial = val4;
			Bounds bounds = val.bounds;
			BoxCollider obj = prefab.AddComponent<BoxCollider>();
			obj.center = ((Bounds)(ref bounds)).center;
			obj.size = ((Bounds)(ref bounds)).size;
			((Collider)obj).isTrigger = false;
			BowlBounds = bounds;
			Piece component = prefab.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null)
			{
				((StaticTarget)component).m_primaryTarget = false;
			}
			Container component2 = prefab.GetComponent<Container>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.m_name = "$piece_cartur_trough";
				component2.m_width = 4;
				component2.m_height = 2;
			}
			prefab.AddComponent<Trough>();
			return true;
		}

		private static void DestroyChild(GameObject prefab, string name)
		{
			Transform val = prefab.transform.Find(name);
			if ((Object)(object)val != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)((Component)val).gameObject);
			}
		}
	}
}