Decompiled source of QuickBreeding v1.5.1

QuickBreeding.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("QuickBreeding")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.5.1.0")]
[assembly: AssemblyInformationalVersion("1.5.1+56a986fff1755d858bb42055beff427198966309")]
[assembly: AssemblyProduct("QuickBreeding")]
[assembly: AssemblyTitle("QuickBreeding")]
[assembly: AssemblyVersion("1.5.1.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 QuickBreeding
{
	internal class AnimalOverrides
	{
		private readonly ConfigFile _file;

		private readonly Dictionary<string, ConfigEntry<int>> _maxCreatures = new Dictionary<string, ConfigEntry<int>>();

		private readonly Dictionary<string, ConfigEntry<string>> _breedingFoods = new Dictionary<string, ConfigEntry<string>>();

		private readonly Dictionary<string, ConfigEntry<bool>> _generateFeed = new Dictionary<string, ConfigEntry<bool>>();

		public AnimalOverrides(ConfigFile file)
		{
			_file = file;
		}

		public bool IsBound(string prefabName)
		{
			if (prefabName != null)
			{
				return _maxCreatures.ContainsKey(prefabName);
			}
			return false;
		}

		public bool IsExcluded(string prefabName)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return true;
			}
			string text = QuickBreedingPlugin.Settings?.ExcludedAnimals?.Value;
			if (string.IsNullOrWhiteSpace(text))
			{
				return false;
			}
			string[] array = text.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				if (string.Equals(array[i].Trim(), prefabName, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		public void Bind(string prefabName, string displayName, string defaultFood, bool offerGeneratedItem)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			if (!string.IsNullOrEmpty(prefabName) && !_maxCreatures.ContainsKey(prefabName))
			{
				string text = (string.IsNullOrWhiteSpace(displayName) ? prefabName : displayName);
				string text2 = "5 - Animal: " + text;
				_maxCreatures[prefabName] = _file.Bind<int>(text2, "MaxCreatures", 0, new ConfigDescription("Population cap for this animal. 0 = use the global setting.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), new object[1] { (object)new ConfigurationManagerAttributes
				{
					IsAdminOnly = true
				} }));
				_breedingFoods[prefabName] = _file.Bind<string>(text2, "BreedingFoods", defaultFood ?? string.Empty, new ConfigDescription("Foods that trigger breeding for this animal when hand-fed. Blank = this animal cannot be hand-fed into breeding at all.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
				{
					IsAdminOnly = true
				} }));
				if (offerGeneratedItem)
				{
					_generateFeed[prefabName] = _file.Bind<bool>(text2, "GenerateFeedItem", true, "Whether to create this animal's feed item. Turn off if you would rather use something you already have, then set BreedingFoods above to that item.");
				}
			}
		}

		public int MaxCreatures(string prefabName)
		{
			if (prefabName == null || !_maxCreatures.TryGetValue(prefabName, out var value))
			{
				return 0;
			}
			return value.Value;
		}

		public string BreedingFoods(string prefabName)
		{
			if (prefabName == null || !_breedingFoods.TryGetValue(prefabName, out var value))
			{
				return string.Empty;
			}
			return value.Value;
		}

		public bool ShouldGenerateFeed(string prefabName)
		{
			if (prefabName != null && _generateFeed.TryGetValue(prefabName, out var value))
			{
				return value.Value;
			}
			return false;
		}
	}
	internal static class BreedingItems
	{
		private const string Enricher = "MushroomYellow";

		private const string PrepTable = "piece_preptable";

		private const int Yield = 2;

		private const int StackSize = 10;

		private static readonly Color EnrichedTint = new Color(1f, 0.85f, 0.2f);

		private const float EnrichedTintStrength = 0.4f;

		private static readonly Dictionary<string, string> BaseFoodByAnimal = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "Asksvin", "Vineberry" },
			{ "Hen", "Dandelion" },
			{ "Lox", "Cloudberry" },
			{ "Moose", "Lingonberry" },
			{ "Wolf", "RawMeat" }
		};

		private static readonly Dictionary<string, string> PlainFoodByAnimal = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { { "Boar", "MushroomYellow" } };

		public static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += OnPrefabsAvailable;
		}

		private static void OnPrefabsAvailable()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= OnPrefabsAvailable;
			BindKnownAnimals();
			if ((Object)(object)PrefabManager.Instance.GetPrefab("piece_preptable") == (Object)null)
			{
				QuickBreedingPlugin.Log.LogError((object)"Crafting station 'piece_preptable' not found - feed items were not registered.");
				return;
			}
			HashSet<string> hashSet = new HashSet<string>();
			foreach (KeyValuePair<string, string> item in BaseFoodByAnimal)
			{
				if (!QuickBreedingPlugin.Animals.IsExcluded(item.Key) && QuickBreedingPlugin.Animals.ShouldGenerateFeed(item.Key) && hashSet.Add(item.Value))
				{
					AddEnriched(item.Value);
				}
			}
			DescribeEnricher();
		}

		private static void BindKnownAnimals()
		{
			foreach (KeyValuePair<string, string> item in PlainFoodByAnimal)
			{
				if (!QuickBreedingPlugin.Animals.IsExcluded(item.Key))
				{
					QuickBreedingPlugin.Animals.Bind(item.Key, AnimalDisplayName(item.Key), item.Value, offerGeneratedItem: false);
				}
			}
			foreach (KeyValuePair<string, string> item2 in BaseFoodByAnimal)
			{
				if (!QuickBreedingPlugin.Animals.IsExcluded(item2.Key))
				{
					QuickBreedingPlugin.Animals.Bind(item2.Key, AnimalDisplayName(item2.Key), ItemName(item2.Value), offerGeneratedItem: true);
				}
			}
		}

		private static void AddEnriched(string baseFood)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			if ((Object)(object)PrefabManager.Instance.GetPrefab(baseFood) == (Object)null)
			{
				QuickBreedingPlugin.Log.LogWarning((object)("Base food '" + baseFood + "' not found - skipping its feed item."));
				return;
			}
			ItemConfig val = new ItemConfig();
			val.Name = "Enriched " + DisplayName(baseFood);
			val.Description = "Animal feed. Hand-feed a pair to encourage breeding.";
			val.Amount = 2;
			val.StackSize = 10;
			val.CraftingStation = "piece_preptable";
			val.Requirements = (RequirementConfig[])(object)new RequirementConfig[2]
			{
				new RequirementConfig
				{
					Item = baseFood,
					Amount = 1
				},
				new RequirementConfig
				{
					Item = "MushroomYellow",
					Amount = 1
				}
			};
			ItemConfig val2 = val;
			Sprite val3 = IconFor(baseFood, EnrichedTint, 0.4f);
			if ((Object)(object)val3 != (Object)null)
			{
				val2.Icon = val3;
			}
			CustomItem val4 = new CustomItem(ItemName(baseFood), baseFood, val2);
			MakeAnimalFeed(val4);
			ItemManager.Instance.AddItem(val4);
		}

		private static void MakeAnimalFeed(CustomItem item)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			SharedData val = ((item == null) ? null : item.ItemDrop?.m_itemData?.m_shared);
			if (val != null)
			{
				val.m_itemType = (ItemType)1;
				val.m_food = 0f;
				val.m_foodStamina = 0f;
				val.m_foodEitr = 0f;
				val.m_foodBurnTime = 0f;
				val.m_foodRegen = 0f;
				val.m_consumeStatusEffect = null;
			}
		}

		private static void DescribeEnricher()
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab("MushroomYellow");
			SharedData val = ((prefab == null) ? null : prefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared);
			if (val != null)
			{
				Localization instance = Localization.instance;
				string text = ((instance != null) ? instance.Localize(val.m_description) : null) ?? string.Empty;
				if (text.IndexOf("hand-feed", StringComparison.OrdinalIgnoreCase) < 0)
				{
					val.m_description = text + "\n\nHand-feed to a pair of boars to encourage breeding.";
				}
			}
		}

		private static Sprite Tint(Sprite source, Color tint, float strength)
		{
			//IL_0013: 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)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			Texture2D texture = source.texture;
			Rect textureRect = source.textureRect;
			int num = Mathf.Max(1, (int)((Rect)(ref textureRect)).width);
			int num2 = Mathf.Max(1, (int)((Rect)(ref textureRect)).height);
			RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)0);
			RenderTexture active = RenderTexture.active;
			try
			{
				Graphics.Blit((Texture)(object)texture, temporary);
				RenderTexture.active = temporary;
				Texture2D val = new Texture2D(num, num2, (TextureFormat)5, false);
				val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0);
				Color[] pixels = val.GetPixels();
				for (int i = 0; i < pixels.Length; i++)
				{
					Color val2 = pixels[i];
					pixels[i] = new Color(Mathf.Lerp(val2.r, tint.r, strength), Mathf.Lerp(val2.g, tint.g, strength), Mathf.Lerp(val2.b, tint.b, strength), val2.a);
				}
				val.SetPixels(pixels);
				val.Apply();
				return Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num2), new Vector2(0.5f, 0.5f), source.pixelsPerUnit);
			}
			catch (Exception ex)
			{
				QuickBreedingPlugin.Log.LogWarning((object)("Could not tint icon, using the original: " + ex.Message));
				return null;
			}
			finally
			{
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
			}
		}

		private static Sprite IconFor(string prefabName, Color tint, float strength)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			GameObject prefab = PrefabManager.Instance.GetPrefab(prefabName);
			Sprite[] array = ((prefab == null) ? null : prefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_icons);
			if (array != null && array.Length != 0)
			{
				return Tint(array[0], tint, strength);
			}
			return null;
		}

		private static string DisplayName(string prefabName)
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab(prefabName);
			return Localize((prefab == null) ? null : prefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_name) ?? prefabName;
		}

		private static string AnimalDisplayName(string prefabName)
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab(prefabName);
			return Localize((prefab == null) ? null : prefab.GetComponent<Character>()?.m_name);
		}

		private static string Localize(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return null;
			}
			Localization instance = Localization.instance;
			string text = ((instance != null) ? instance.Localize(token) : null);
			if (!string.IsNullOrWhiteSpace(text) && !text.StartsWith("$"))
			{
				return text;
			}
			return null;
		}

		private static string ItemName(string baseFood)
		{
			return "QB_Enriched" + baseFood;
		}
	}
	internal class Config
	{
		public ConfigEntry<bool> EnableMod { get; }

		public ConfigEntry<float> HandFeedCooldown { get; }

		public ConfigEntry<int> RequiredLovePoints { get; }

		public ConfigEntry<float> PregnancyChance { get; }

		public ConfigEntry<float> PregnancyDuration { get; }

		public ConfigEntry<float> CheckInterval { get; }

		public ConfigEntry<float> PartnerCheckRange { get; }

		public ConfigEntry<float> TotalCheckRange { get; }

		public ConfigEntry<int> MaxCreatures { get; }

		public ConfigEntry<bool> BreedingFoodOnly { get; }

		public ConfigEntry<string> ExcludedAnimals { get; }

		public ConfigEntry<bool> DebugLogging { get; }

		private static ConfigurationManagerAttributes Synced => new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		};

		public Config(ConfigFile file)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Expected O, but got Unknown
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Expected O, but got Unknown
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Expected O, but got Unknown
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Expected O, but got Unknown
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Expected O, but got Unknown
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Expected O, but got Unknown
			EnableMod = file.Bind<bool>("1 - General", "EnableMod", true, new ConfigDescription("Master switch. Off = vanilla breeding.", (AcceptableValueBase)null, new object[1] { Synced }));
			HandFeedCooldown = file.Bind<float>("2 - Breeding", "HandFeedCooldown", 60f, new ConfigDescription("Seconds before an animal can be hand-fed into breeding again. 0 = no cooldown.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3600f), new object[1] { Synced }));
			RequiredLovePoints = file.Bind<int>("2 - Breeding", "FeedsRequired", 1, new ConfigDescription("Hand-feeds needed before an animal is ready to breed.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), new object[1] { Synced }));
			PregnancyDuration = file.Bind<float>("2 - Breeding", "PregnancyDuration", 2f, new ConfigDescription("Seconds between conceiving and the baby appearing. Affects ground feeding. 0 = leave vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 600f), new object[1] { Synced }));
			CheckInterval = file.Bind<float>("2 - Breeding", "CheckInterval", 0f, new ConfigDescription("Seconds between breeding checks. Affects ground feeding. 0 = leave vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), new object[1] { Synced }));
			PregnancyChance = file.Bind<float>("2 - Breeding", "BreedChance", 0f, new ConfigDescription("Chance per check of progress toward conceiving. Affects ground feeding. 0 = leave vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { Synced }));
			PartnerCheckRange = file.Bind<float>("3 - Ranges", "PartnerCheckRange", 10f, new ConfigDescription("How far apart two animals can be and still pair up. 0 = leave vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 40f), new object[1] { Synced }));
			TotalCheckRange = file.Bind<float>("3 - Ranges", "TotalCheckRange", 0f, new ConfigDescription("Radius used to count nearby animals against MaxCreatures. 0 = leave vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 60f), new object[1] { Synced }));
			MaxCreatures = file.Bind<int>("3 - Ranges", "MaxCreatures", 0, new ConfigDescription("Population cap before breeding stops. 0 = leave vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), new object[1] { Synced }));
			BreedingFoodOnly = file.Bind<bool>("4 - Breeding food", "BreedingFoodOnly", true, new ConfigDescription("On: only the items assigned to each animal work when hand-fed, even if the animal would not normally eat them. Off: any food the animal normally eats also works.", (AcceptableValueBase)null, new object[1] { Synced }));
			ExcludedAnimals = file.Bind<string>("1 - General", "ExcludedAnimals", "Placeable_HardRock,Wolf_spiritcaller", new ConfigDescription("Comma-separated creatures this mod should leave completely alone. Uses internal names, which the log lists when DebugLogging is on.", (AcceptableValueBase)null, new object[1] { Synced }));
			DebugLogging = file.Bind<bool>("9 - Debug", "DebugLogging", false, "Logs hand-feeding details, including each item's exact name.");
		}
	}
	[BepInPlugin("jelaw.quickbreeding", "Quick Breeding", "1.5.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class QuickBreedingPlugin : BaseUnityPlugin
	{
		public const string Guid = "jelaw.quickbreeding";

		internal static ManualLogSource Log;

		internal static Config Settings;

		internal static QuickBreedingPlugin Instance;

		internal static AnimalOverrides Animals;

		internal static bool Active
		{
			get
			{
				if (Settings != null)
				{
					return Settings.EnableMod.Value;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Settings = new Config(((BaseUnityPlugin)this).Config);
			Animals = new AnimalOverrides(((BaseUnityPlugin)this).Config);
			BreedingItems.Register();
			new Harmony("jelaw.quickbreeding").PatchAll();
		}

		internal static void MakeHungryAfterBirth(Tameable a, Tameable b, float delay)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((MonoBehaviour)Instance).StartCoroutine(HungerRoutine(a, b, delay));
			}
		}

		private static IEnumerator HungerRoutine(Tameable a, Tameable b, float delay)
		{
			yield return (object)new WaitForSeconds(delay);
			TameableAccess.MakeHungry(a);
			TameableAccess.MakeHungry(b);
		}
	}
	internal static class Ownership
	{
		internal static bool Claim(ZNetView view)
		{
			if ((Object)(object)view == (Object)null || !view.IsValid())
			{
				return false;
			}
			if (!view.IsOwner())
			{
				view.ClaimOwnership();
			}
			return view.IsOwner();
		}
	}
	internal static class ProcreationAccess
	{
		private static readonly FieldInfo LoveKeyField = AccessTools.Field(typeof(Procreation), "s_lovePoints");

		private static readonly FieldInfo NViewField = AccessTools.Field(typeof(Procreation), "m_nview");

		private static readonly MethodInfo IsPregnantMethod = AccessTools.Method(typeof(Procreation), "IsPregnant", (Type[])null, (Type[])null);

		private static bool _loveKeyResolved;

		private static int _loveKey;

		private static readonly int LastBredKey = StringExtensionMethods.GetStableHashCode("jelaw_qb_lastBred");

		private static readonly int PrimedKey = StringExtensionMethods.GetStableHashCode("jelaw_qb_primed");

		private static int LoveKey
		{
			get
			{
				if (!_loveKeyResolved)
				{
					_loveKeyResolved = true;
					_loveKey = ((LoveKeyField?.GetValue(null) is int num) ? num : StringExtensionMethods.GetStableHashCode("lovePoints"));
				}
				return _loveKey;
			}
		}

		public static ZNetView View(Procreation p)
		{
			if (!((Object)(object)p == (Object)null))
			{
				object? obj = NViewField?.GetValue(p);
				return (ZNetView)((obj is ZNetView) ? obj : null);
			}
			return null;
		}

		public static bool IsPregnant(Procreation p)
		{
			if ((Object)(object)p == (Object)null || IsPregnantMethod == null)
			{
				return false;
			}
			object obj = IsPregnantMethod.Invoke(p, null);
			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;
		}

		public static int GetLove(Procreation p)
		{
			ZNetView obj = View(p);
			ZDO val = ((obj != null) ? obj.GetZDO() : null);
			if (val != null)
			{
				return val.GetInt(LoveKey, 0);
			}
			return 0;
		}

		public static void SetLove(Procreation p, int value)
		{
			ZNetView val = View(p);
			if (Ownership.Claim(val))
			{
				val.GetZDO().Set(LoveKey, value, false);
			}
		}

		public static int GetPrimed(Procreation p)
		{
			ZNetView obj = View(p);
			ZDO val = ((obj != null) ? obj.GetZDO() : null);
			if (val != null)
			{
				return val.GetInt(PrimedKey, 0);
			}
			return 0;
		}

		public static void SetPrimed(Procreation p, int value)
		{
			ZNetView val = View(p);
			if (Ownership.Claim(val))
			{
				val.GetZDO().Set(PrimedKey, value, false);
			}
		}

		public static double CooldownRemaining(Procreation p, float cooldown)
		{
			if (cooldown <= 0f)
			{
				return 0.0;
			}
			ZNetView obj = View(p);
			ZDO val = ((obj != null) ? obj.GetZDO() : null);
			if (val == null)
			{
				return 0.0;
			}
			long num = val.GetLong(LastBredKey, 0L);
			if (num == 0L)
			{
				return 0.0;
			}
			double totalSeconds = (ZNet.instance.GetTime() - new DateTime(num)).TotalSeconds;
			if (!(totalSeconds >= (double)cooldown))
			{
				return (double)cooldown - totalSeconds;
			}
			return 0.0;
		}

		public static void StampBred(Procreation p)
		{
			ZNetView val = View(p);
			if (Ownership.Claim(val))
			{
				val.GetZDO().Set(LastBredKey, ZNet.instance.GetTime().Ticks);
			}
		}

		public static bool MakePregnant(Procreation p)
		{
			ZNetView val = View(p);
			if (!Ownership.Claim(val))
			{
				return false;
			}
			val.GetZDO().Set(ZDOVars.s_pregnant, ZNet.instance.GetTime().Ticks);
			return true;
		}
	}
	internal static class TameableAccess
	{
		private static readonly MethodInfo OnConsumedItemMethod = AccessTools.Method(typeof(Tameable), "OnConsumedItem", (Type[])null, (Type[])null);

		private static readonly MethodInfo IsHungryMethod = AccessTools.Method(typeof(Tameable), "IsHungry", (Type[])null, (Type[])null);

		private static readonly FieldInfo TameableNViewField = AccessTools.Field(typeof(Tameable), "m_nview");

		public static bool IsHungry(Tameable t)
		{
			if ((Object)(object)t == (Object)null || IsHungryMethod == null)
			{
				return false;
			}
			object obj = IsHungryMethod.Invoke(t, null);
			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;
		}

		public static void MakeHungry(Tameable t)
		{
			if (!((Object)(object)t == (Object)null))
			{
				object? obj = TameableNViewField?.GetValue(t);
				ZNetView val = (ZNetView)((obj is ZNetView) ? obj : null);
				if (Ownership.Claim(val))
				{
					val.GetZDO().Set(ZDOVars.s_tameLastFeeding, 0L);
				}
			}
		}

		public static bool Consume(Tameable tameable, ItemDrop item)
		{
			if ((Object)(object)tameable == (Object)null || (Object)(object)item == (Object)null || OnConsumedItemMethod == null)
			{
				return false;
			}
			ParameterInfo[] parameters = OnConsumedItemMethod.GetParameters();
			if (parameters.Length != 1 || !parameters[0].ParameterType.IsAssignableFrom(typeof(ItemDrop)))
			{
				QuickBreedingPlugin.Log.LogWarning((object)"Tameable.OnConsumedItem has an unexpected signature - falling back to setting love directly.");
				return false;
			}
			OnConsumedItemMethod.Invoke(tameable, new object[1] { item });
			return true;
		}
	}
	internal static class PartnerFinder
	{
		public static Procreation FindPartner(Procreation self, float range, Func<Procreation, bool> accept = null)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)self == (Object)null)
			{
				return null;
			}
			Character component = ((Component)self).GetComponent<Character>();
			if ((Object)(object)component == (Object)null)
			{
				return null;
			}
			string prefabName = Utils.GetPrefabName(((Component)self).gameObject);
			float num = range * range;
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if ((Object)(object)allCharacter == (Object)null || (Object)(object)allCharacter == (Object)(object)component || !allCharacter.IsTamed() || Utils.GetPrefabName(((Component)allCharacter).gameObject) != prefabName)
				{
					continue;
				}
				Vector3 val = ((Component)allCharacter).transform.position - ((Component)component).transform.position;
				if (!(((Vector3)(ref val)).sqrMagnitude > num))
				{
					Procreation component2 = ((Component)allCharacter).GetComponent<Procreation>();
					if (!((Object)(object)component2 == (Object)null) && (accept == null || accept(component2)))
					{
						return component2;
					}
				}
			}
			return null;
		}

		public static int CountNearby(Procreation self, float range)
		{
			//IL_006c: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			Character val = (((Object)(object)self == (Object)null) ? null : ((Component)self).GetComponent<Character>());
			if ((Object)(object)val == (Object)null)
			{
				return 0;
			}
			string prefabName = Utils.GetPrefabName(((Component)self).gameObject);
			float num = range * range;
			int num2 = 0;
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if (!((Object)(object)allCharacter == (Object)null) && !(Utils.GetPrefabName(((Component)allCharacter).gameObject) != prefabName))
				{
					Vector3 val2 = ((Component)allCharacter).transform.position - ((Component)val).transform.position;
					if (((Vector3)(ref val2)).sqrMagnitude <= num)
					{
						num2++;
					}
				}
			}
			return num2;
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ZNetSceneAwakeBindPatch
	{
		private static bool _done;

		private static void Postfix(ZNetScene __instance)
		{
			if (_done || __instance?.m_prefabs == null || QuickBreedingPlugin.Animals == null)
			{
				return;
			}
			_done = true;
			int num = 0;
			foreach (GameObject prefab in __instance.m_prefabs)
			{
				if ((Object)(object)prefab == (Object)null)
				{
					continue;
				}
				Character component = prefab.GetComponent<Character>();
				if ((Object)(object)prefab.GetComponent<Procreation>() == (Object)null || (Object)(object)prefab.GetComponent<Tameable>() == (Object)null || (Object)(object)prefab.GetComponent<BaseAI>() == (Object)null || (Object)(object)component == (Object)null)
				{
					continue;
				}
				string prefabName = Utils.GetPrefabName(prefab);
				if (!QuickBreedingPlugin.Animals.IsExcluded(prefabName) && !QuickBreedingPlugin.Animals.IsBound(prefabName))
				{
					QuickBreedingPlugin.Animals.Bind(prefabName, DisplayName(component), null, offerGeneratedItem: false);
					num++;
					if (QuickBreedingPlugin.Settings.DebugLogging.Value)
					{
						Procreation component2 = prefab.GetComponent<Procreation>();
						QuickBreedingPlugin.Log.LogInfo((object)($"{prefabName}: maxCreatures={component2.m_maxCreatures}, totalCheckRange={component2.m_totalCheckRange}m, " + $"partnerCheckRange={component2.m_partnerCheckRange}m, requiredLove={component2.m_requiredLovePoints}, " + $"pregnancyDuration={component2.m_pregnancyDuration}s, updateInterval={component2.m_updateInterval}s"));
						QuickBreedingPlugin.Log.LogInfo((object)(prefabName + " eats: " + ConsumeList(prefab)));
					}
				}
			}
			if (QuickBreedingPlugin.Settings.DebugLogging.Value)
			{
				QuickBreedingPlugin.Log.LogInfo((object)$"Bound per-animal settings for {num} breedable creature(s).");
			}
		}

		private static string ConsumeList(GameObject prefab)
		{
			List<ItemDrop> list = prefab.GetComponent<MonsterAI>()?.m_consumeItems;
			if (list == null || list.Count == 0)
			{
				return "(none)";
			}
			List<string> list2 = new List<string>();
			foreach (ItemDrop item in list)
			{
				if ((Object)(object)item != (Object)null)
				{
					list2.Add(((Object)item).name);
				}
			}
			if (list2.Count != 0)
			{
				return string.Join(", ", list2.ToArray());
			}
			return "(none)";
		}

		private static string DisplayName(Character character)
		{
			string name = character.m_name;
			if (string.IsNullOrEmpty(name))
			{
				return null;
			}
			Localization instance = Localization.instance;
			string text = ((instance != null) ? instance.Localize(name) : null);
			if (!string.IsNullOrWhiteSpace(text) && !text.StartsWith("$"))
			{
				return text;
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(Procreation), "Awake")]
	internal static class ProcreationAwakePatch
	{
		private static void Prefix(Procreation __instance)
		{
			if (QuickBreedingPlugin.Active && !((Object)(object)__instance == (Object)null) && !QuickBreedingPlugin.Animals.IsExcluded(Utils.GetPrefabName(((Component)__instance).gameObject)))
			{
				Config settings = QuickBreedingPlugin.Settings;
				if (settings.CheckInterval.Value > 0f)
				{
					__instance.m_updateInterval = settings.CheckInterval.Value;
				}
				if (settings.PregnancyDuration.Value > 0f)
				{
					__instance.m_pregnancyDuration = settings.PregnancyDuration.Value;
				}
				float value = settings.PregnancyChance.Value;
				if (value > 0f)
				{
					__instance.m_pregnancyChance = ((value >= 1f) ? (-1f) : (1f - value));
				}
				if (settings.PartnerCheckRange.Value > 0f)
				{
					__instance.m_partnerCheckRange = settings.PartnerCheckRange.Value;
				}
				if (settings.TotalCheckRange.Value > 0f)
				{
					__instance.m_totalCheckRange = settings.TotalCheckRange.Value;
				}
				int num = QuickBreedingPlugin.Animals.MaxCreatures(Utils.GetPrefabName(((Component)__instance).gameObject));
				if (num > 0)
				{
					__instance.m_maxCreatures = num;
				}
				else if (settings.MaxCreatures.Value > 0)
				{
					__instance.m_maxCreatures = settings.MaxCreatures.Value;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "GetHoverText")]
	internal static class TameableHoverTextPatch
	{
		private static void Postfix(Tameable __instance, ref string __result)
		{
			if (!QuickBreedingPlugin.Active || string.IsNullOrEmpty(__result))
			{
				return;
			}
			Procreation component = ((Component)__instance).GetComponent<Procreation>();
			if (!((Object)(object)component == (Object)null))
			{
				int num = Mathf.Max(1, QuickBreedingPlugin.Settings.RequiredLovePoints.Value);
				if (ProcreationAccess.GetPrimed(component) >= num)
				{
					__result += "\nReady to Breed";
				}
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "Interact")]
	internal static class TameableInteractPatch
	{
		internal struct PartnerTally
		{
			public int InRange;

			public int Pregnant;

			public int Capped;

			public int CoolingDown;
		}

		private const float HeartSeconds = 5f;

		private const float HeartInterval = 0.8f;

		private static bool Prefix(Tameable __instance, Humanoid user, bool hold, bool alt, ref bool __result)
		{
			if (!QuickBreedingPlugin.Active)
			{
				return true;
			}
			if (hold || alt || (Object)(object)__instance == (Object)null)
			{
				return true;
			}
			Player val = (Player)(object)((user is Player) ? user : null);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			Character component = ((Component)__instance).GetComponent<Character>();
			if ((Object)(object)component == (Object)null || !component.IsTamed())
			{
				return true;
			}
			Procreation component2 = ((Component)__instance).GetComponent<Procreation>();
			if ((Object)(object)component2 == (Object)null)
			{
				return true;
			}
			if (QuickBreedingPlugin.Animals.IsExcluded(Utils.GetPrefabName(((Component)__instance).gameObject)))
			{
				return true;
			}
			ItemData val2 = FindFood(val, __instance);
			if (val2 == null)
			{
				return true;
			}
			double num = ProcreationAccess.CooldownRemaining(component2, QuickBreedingPlugin.Settings.HandFeedCooldown.Value);
			if (num > 0.0)
			{
				((Character)user).Message((MessageType)2, component.m_name + " is not ready to breed again (" + FormatSeconds(num) + ")", 0, (Sprite)null, false);
				__result = true;
				return false;
			}
			if (AtPopulationCap(component2, out var total, out var cap))
			{
				((Character)user).Message((MessageType)2, $"Max animals in area ({total}/{cap})", 0, (Sprite)null, false);
				__result = true;
				return false;
			}
			int num2 = Mathf.Max(1, QuickBreedingPlugin.Settings.RequiredLovePoints.Value);
			int primed = ProcreationAccess.GetPrimed(component2);
			bool flag = TameableAccess.IsHungry(__instance);
			if (primed >= num2 && !flag)
			{
				((Character)user).Message((MessageType)2, component.m_name + " is already ready to breed", 0, (Sprite)null, false);
				__result = true;
				return false;
			}
			if (CollectEligiblePartners(__instance, component2, out var tally).Count == 0)
			{
				if (QuickBreedingPlugin.Settings.DebugLogging.Value)
				{
					QuickBreedingPlugin.Log.LogInfo((object)("refused " + Utils.GetPrefabName(((Component)__instance).gameObject) + ": no eligible partner " + $"within {component2.m_partnerCheckRange}m " + $"(in range {tally.InRange}, pregnant {tally.Pregnant}, " + $"capped {tally.Capped}, cooling down {tally.CoolingDown})"));
				}
				((Character)user).Message((MessageType)2, (tally.CoolingDown > 0) ? ("No other " + component.m_name + " ready to breed yet") : ("No other " + component.m_name + " close enough to breed with"), 0, (Sprite)null, false);
				__result = true;
				return false;
			}
			((Humanoid)val).GetInventory().RemoveItem(val2, 1);
			GameObject dropPrefab = val2.m_dropPrefab;
			TameableAccess.Consume(__instance, (dropPrefab != null) ? dropPrefab.GetComponent<ItemDrop>() : null);
			int num3 = Mathf.Min(primed + 1, num2);
			ProcreationAccess.SetPrimed(component2, num3);
			bool flag2 = num3 >= num2 && TryBreedNow(__instance, component2, num2);
			if (!flag2 && num3 >= num2)
			{
				ShowEligiblePartners(__instance, component2);
			}
			if (QuickBreedingPlugin.Settings.DebugLogging.Value)
			{
				AtPopulationCap(component2, out var total2, out var cap2);
				QuickBreedingPlugin.Log.LogInfo((object)($"fed {Utils.GetPrefabName(((Component)__instance).gameObject)}: primed {primed} -> {num3}" + $"/{num2}, conceived={flag2}, " + $"vanilla love={ProcreationAccess.GetLove(component2)}/{component2.m_requiredLovePoints}, " + $"hungry {flag} -> {TameableAccess.IsHungry(__instance)}, " + $"alerted={IsAlerted(__instance)}, pregnant={ProcreationAccess.IsPregnant(component2)}, " + $"nearby={total2}/{cap2} incl. young within {component2.m_totalCheckRange}m"));
			}
			((Character)user).Message((MessageType)2, flag2 ? (component.m_name + " is expecting") : ((num3 >= num2) ? (component.m_name + " is ready to breed") : $"{component.m_name} fed ({num3}/{num2})"), 0, (Sprite)null, false);
			__result = true;
			return false;
		}

		private static bool IsAlerted(Tameable tameable)
		{
			BaseAI component = ((Component)tameable).GetComponent<BaseAI>();
			if ((Object)(object)component != (Object)null)
			{
				return component.IsAlerted();
			}
			return false;
		}

		private static string FormatSeconds(double seconds)
		{
			int num = Mathf.CeilToInt((float)seconds);
			if (num < 60)
			{
				return $"{num}s";
			}
			return $"{num / 60}m {num % 60}s";
		}

		private static bool TryBreedNow(Tameable tameable, Procreation procreation, int feedsNeeded)
		{
			if (ProcreationAccess.IsPregnant(procreation))
			{
				return false;
			}
			if (IsAlerted(tameable))
			{
				return false;
			}
			float cooldown = QuickBreedingPlugin.Settings.HandFeedCooldown.Value;
			Procreation val = PartnerFinder.FindPartner(procreation, procreation.m_partnerCheckRange, (Procreation candidate) => !ProcreationAccess.IsPregnant(candidate) && ProcreationAccess.GetPrimed(candidate) >= feedsNeeded && ProcreationAccess.CooldownRemaining(candidate, cooldown) <= 0.0);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if (AtPopulationCap(procreation, out var _, out var _))
			{
				return false;
			}
			if (!ProcreationAccess.MakePregnant(procreation))
			{
				return false;
			}
			ProcreationAccess.SetPrimed(procreation, 0);
			ProcreationAccess.SetPrimed(val, 0);
			ProcreationAccess.StampBred(procreation);
			ProcreationAccess.StampBred(val);
			Tameable component = ((Component)val).GetComponent<Tameable>();
			float delay = procreation.m_pregnancyDuration + 2f;
			QuickBreedingPlugin.MakeHungryAfterBirth(tameable, component, delay);
			return true;
		}

		private static List<Procreation> CollectEligiblePartners(Tameable fed, Procreation self)
		{
			PartnerTally tally;
			return CollectEligiblePartners(fed, self, out tally);
		}

		private static List<Procreation> CollectEligiblePartners(Tameable fed, Procreation self, out PartnerTally tally)
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//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_00ba: Unknown result type (might be due to invalid IL or missing references)
			tally = default(PartnerTally);
			List<Procreation> list = new List<Procreation>();
			Character component = ((Component)fed).GetComponent<Character>();
			if ((Object)(object)component == (Object)null)
			{
				return list;
			}
			if (AtPopulationCap(self, out var total, out var cap))
			{
				return list;
			}
			string prefabName = Utils.GetPrefabName(((Component)fed).gameObject);
			float num = self.m_partnerCheckRange * self.m_partnerCheckRange;
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if ((Object)(object)allCharacter == (Object)null || (Object)(object)allCharacter == (Object)(object)component || !allCharacter.IsTamed() || Utils.GetPrefabName(((Component)allCharacter).gameObject) != prefabName)
				{
					continue;
				}
				Vector3 val = ((Component)allCharacter).transform.position - ((Component)component).transform.position;
				if (((Vector3)(ref val)).sqrMagnitude > num)
				{
					continue;
				}
				Procreation component2 = ((Component)allCharacter).GetComponent<Procreation>();
				if (!((Object)(object)component2 == (Object)null))
				{
					tally.InRange++;
					if (ProcreationAccess.IsPregnant(component2))
					{
						tally.Pregnant++;
					}
					else if (AtPopulationCap(component2, out cap, out total))
					{
						tally.Capped++;
					}
					else if (ProcreationAccess.CooldownRemaining(component2, QuickBreedingPlugin.Settings.HandFeedCooldown.Value) > 0.0)
					{
						tally.CoolingDown++;
					}
					else
					{
						list.Add(component2);
					}
				}
			}
			return list;
		}

		private static void ShowEligiblePartners(Tameable fed, Procreation self)
		{
			List<Procreation> list = CollectEligiblePartners(fed, self);
			if (list.Count != 0)
			{
				list.Add(self);
				if ((Object)(object)QuickBreedingPlugin.Instance != (Object)null)
				{
					((MonoBehaviour)QuickBreedingPlugin.Instance).StartCoroutine(PulseHearts(list));
				}
			}
		}

		private static IEnumerator PulseHearts(List<Procreation> targets)
		{
			for (float elapsed = 0f; elapsed < 5f; elapsed += 0.8f)
			{
				foreach (Procreation target in targets)
				{
					if (!((Object)(object)target == (Object)null))
					{
						Tameable component = ((Component)target).GetComponent<Tameable>();
						if (!((Object)(object)component == (Object)null))
						{
							component.m_sootheEffect.Create(((Component)target).transform.position, ((Component)target).transform.rotation, (Transform)null, 1f, -1, default(ZDOID));
						}
					}
				}
				yield return (object)new WaitForSeconds(0.8f);
			}
		}

		private static bool AtPopulationCap(Procreation procreation, out int total, out int cap)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			total = 0;
			cap = procreation.m_maxCreatures;
			ZNetScene instance = ZNetScene.instance;
			GameObject val = ((instance != null) ? instance.GetPrefab(Utils.GetPrefabName(((Component)procreation).gameObject)) : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			Vector3 position = ((Component)procreation).transform.position;
			float totalCheckRange = procreation.m_totalCheckRange;
			int nrOfInstances = SpawnSystem.GetNrOfInstances(val, position, totalCheckRange, false, false);
			int num = (((Object)(object)procreation.m_offspring != (Object)null) ? SpawnSystem.GetNrOfInstances(procreation.m_offspring, position, totalCheckRange, false, false) : 0);
			total = nrOfInstances + num;
			return total >= cap;
		}

		private static ItemData FindFood(Player player, Tameable tameable)
		{
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return null;
			}
			bool value = QuickBreedingPlugin.Settings.DebugLogging.Value;
			if (QuickBreedingPlugin.Settings.BreedingFoodOnly.Value)
			{
				HashSet<string> hashSet = BreedingFoodNames(Utils.GetPrefabName(((Component)tameable).gameObject));
				foreach (ItemData allItem in inventory.GetAllItems())
				{
					if (allItem != null)
					{
						if (value)
						{
							QuickBreedingPlugin.Log.LogInfo((object)("hand-feed candidate: prefab='" + PrefabName(allItem) + "' token='" + allItem.m_shared?.m_name + "'"));
						}
						if (hashSet.Contains(Normalize(PrefabName(allItem))) || hashSet.Contains(Normalize(allItem.m_shared?.m_name)))
						{
							return allItem;
						}
					}
				}
				return null;
			}
			List<ItemDrop> list = ((Component)tameable).GetComponent<MonsterAI>()?.m_consumeItems;
			if (list == null)
			{
				return null;
			}
			foreach (ItemDrop item in list)
			{
				string text = item?.m_itemData?.m_shared?.m_name;
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				foreach (ItemData allItem2 in inventory.GetAllItems())
				{
					if (allItem2?.m_shared?.m_name == text)
					{
						return allItem2;
					}
				}
			}
			return null;
		}

		private static string PrefabName(ItemData item)
		{
			if (!((Object)(object)item?.m_dropPrefab != (Object)null))
			{
				return null;
			}
			return ((Object)item.m_dropPrefab).name;
		}

		private static string Normalize(string raw)
		{
			if (string.IsNullOrEmpty(raw))
			{
				return string.Empty;
			}
			string text = raw.Trim().ToLowerInvariant();
			if (text.StartsWith("$item_"))
			{
				text = text.Substring("$item_".Length);
			}
			return text.Replace("_", string.Empty);
		}

		private static HashSet<string> BreedingFoodNames(string prefabName)
		{
			string text = QuickBreedingPlugin.Animals.BreedingFoods(prefabName);
			HashSet<string> hashSet = new HashSet<string>();
			if (text == null)
			{
				text = string.Empty;
			}
			string[] array = text.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = Normalize(array[i]);
				if (text2.Length > 0)
				{
					hashSet.Add(text2);
				}
			}
			return hashSet;
		}
	}
}