Decompiled source of TameCraft v1.1.3

BepInEx\plugins\TameCraft\TameCraft.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
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 Microsoft.CodeAnalysis;
using TameCraft.Common;
using TameCraft.Configuration;
using TameCraft.Core;
using TameCraft.Subsystems.Affection;
using TameCraft.Subsystems.Breeding;
using TameCraft.Subsystems.Genetics;
using TameCraft.Subsystems.Offspring;
using TameCraft.Subsystems.Pregnancy;
using TameCraft.Subsystems.Taming;
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("momos3939")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A configurable Valheim 1.0 animal husbandry overhaul focused on making taming, affection, breeding, pregnancy, and offspring growth faster and more convenient while preserving vanilla behavior when disabled.")]
[assembly: AssemblyFileVersion("1.1.3.0")]
[assembly: AssemblyInformationalVersion("1.1.3")]
[assembly: AssemblyProduct("TameCraft")]
[assembly: AssemblyTitle("TameCraft")]
[assembly: AssemblyVersion("1.1.3.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 TameCraft
{
	[BepInPlugin("com.tamecraft.valheim", "TameCraft", "1.1.3")]
	public class TameCraftPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.tamecraft.valheim";

		public const string PluginName = "TameCraft";

		public const string PluginVersion = "1.1.3";

		private Harmony? _harmony;

		public static TameCraftPlugin? Instance { get; private set; }

		private void Awake()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			Instance = this;
			ModConfig.Initialize(((BaseUnityPlugin)this).Config);
			SubsystemLogger.Initialize(((BaseUnityPlugin)this).Logger, () => ModConfig.DebugLogging?.Value ?? false);
			if (!ModConfig.Enabled.Value)
			{
				SubsystemLogger.LogInfo(Subsystem.Husbandry, "TameCraft v1.1.3 is disabled in configuration.");
				return;
			}
			_harmony = new Harmony("com.tamecraft.valheim");
			_harmony.PatchAll();
			SubsystemLogger.LogInfo(Subsystem.Husbandry, "TameCraft v1.1.3 initialized and patched successfully.");
			if (ModConfig.DebugLogging.Value)
			{
				SubsystemLogger.LogDebug(Subsystem.Husbandry, "Verbose debug logging is enabled.");
			}
		}

		private void OnDestroy()
		{
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			_harmony = null;
			SubsystemLogger.LogInfo(Subsystem.Husbandry, "TameCraft unloaded.");
			Instance = null;
		}
	}
}
namespace TameCraft.Subsystems.Taming
{
	public static class TamingSubsystem
	{
		private static readonly HashSet<int> _configuredCreatureZdos = new HashSet<int>();

		public static void ConfigureCreature(Tameable tameable, CreatureProfile profile)
		{
			if ((Object)(object)tameable == (Object)null || profile == null || !ModConfig.Enabled.Value || !ModConfig.Taming.Enabled.Value)
			{
				return;
			}
			string prefabName = profile.PrefabName;
			if (ModConfig.Taming.Advanced.TryGetTamingEnabledOverride(prefabName, out var value) && !value)
			{
				return;
			}
			ZNetView component = ((Component)tameable).GetComponent<ZNetView>();
			int item = (((Object)(object)component != (Object)null && component.IsValid()) ? ((object)Unsafe.As<ZDOID, ZDOID>(ref component.GetZDO().m_uid)/*cast due to .constrained prefix*/).GetHashCode() : ((Object)tameable).GetInstanceID());
			float orCreateTamingTime = VanillaBaselineCache.GetOrCreateTamingTime(prefabName, tameable.m_tamingTime);
			float num;
			if (ModConfig.Taming.Advanced.TryGetTameDurationOverride(prefabName, out var value2))
			{
				num = value2;
			}
			else
			{
				float num2 = Mathf.Max(0.01f, ModConfig.Taming.TamingSpeedMultiplier.Value);
				num = orCreateTamingTime / num2;
			}
			tameable.m_tamingTime = num;
			if ((Object)(object)component != (Object)null && component.IsValid() && component.IsOwner() && !tameable.IsTamed())
			{
				ZDO zDO = component.GetZDO();
				float num3 = zDO.GetFloat(ZDOVars.s_tameTimeLeft, -1f);
				if (num3 < 0f || num3 > num)
				{
					zDO.Set(ZDOVars.s_tameTimeLeft, num);
				}
			}
			float orCreateFedDuration = VanillaBaselineCache.GetOrCreateFedDuration(prefabName, tameable.m_fedDuration);
			float fedDuration;
			if (ModConfig.Taming.Advanced.TryGetFeedingIntervalOverride(prefabName, out var value3))
			{
				fedDuration = value3;
			}
			else
			{
				float num4 = Mathf.Max(0.01f, ModConfig.Taming.FeedingIntervalMultiplier.Value);
				fedDuration = orCreateFedDuration / num4;
			}
			tameable.m_fedDuration = fedDuration;
			MonsterAI component2 = ((Component)tameable).GetComponent<MonsterAI>();
			if ((Object)(object)component2 != (Object)null)
			{
				ConfigureAllowedFoods(component2, profile);
			}
			if (_configuredCreatureZdos.Add(item))
			{
				bool value4;
				bool flag = (ModConfig.Taming.Advanced.TryGetAllowTamingWhileAlertedOverride(prefabName, out value4) ? value4 : ModConfig.Taming.AllowTamingWhileAlerted.Value);
				bool flag2 = ModConfig.Taming.Advanced.IsHungerIgnored(prefabName);
				SubsystemLogger.LogDebug(Subsystem.Taming, $"Configured {profile.DisplayName}: duration={tameable.m_tamingTime:F1}s, consumptionInterval={tameable.m_fedDuration:F1}s, alertTaming={flag}, ignoreHunger={flag2}");
			}
		}

		public static void ConfigureAllowedFoods(MonsterAI monsterAI, CreatureProfile profile)
		{
			if ((Object)(object)ObjectDB.instance == (Object)null || (Object)(object)monsterAI == (Object)null)
			{
				return;
			}
			List<ItemDrop> orCreateNativeConsumeItems = VanillaBaselineCache.GetOrCreateNativeConsumeItems(profile.PrefabName, monsterAI.m_consumeItems);
			if (ModConfig.Taming.Advanced.TryGetAllowedFoodsOverride(profile.PrefabName, out List<string> foods) && foods != null && foods.Count > 0)
			{
				List<ItemDrop> list = new List<ItemDrop>();
				foreach (string item in foods)
				{
					GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item.Trim());
					if ((Object)(object)itemPrefab != (Object)null)
					{
						ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
						if ((Object)(object)component != (Object)null)
						{
							list.Add(component);
						}
					}
				}
				if (list.Count > 0)
				{
					monsterAI.m_consumeItems = list;
				}
			}
			else if (orCreateNativeConsumeItems != null && orCreateNativeConsumeItems.Count > 0)
			{
				monsterAI.m_consumeItems = new List<ItemDrop>(orCreateNativeConsumeItems);
			}
		}

		public static void OnFeedAccepted(Tameable tameable, CreatureProfile profile, ItemDrop? item)
		{
			if (!((Object)(object)tameable == (Object)null) && profile != null && ModConfig.Enabled.Value && ModConfig.Taming.Enabled.Value && PersistenceSystem.TryGetState(((Component)tameable).GetComponent<Character>(), out CreatureState state) && state != null && state.IsOwner)
			{
				int value = ModConfig.Affection.AffectionPerFeed.Value;
				if (value > 0)
				{
					AffectionSubsystem.RecordFeeding(state, profile, item, value);
				}
			}
		}
	}
}
namespace TameCraft.Subsystems.Pregnancy
{
	public static class PregnancySubsystem
	{
		public static float GetRemainingGestationSeconds(CreatureState? state)
		{
			if (state == null || !state.IsPregnant || state.PregnancyStart <= 0)
			{
				return 0f;
			}
			if ((Object)(object)ZNet.instance == (Object)null)
			{
				return 0f;
			}
			double num = ZNet.instance.GetTimeSeconds() - (double)state.PregnancyStart;
			double num2 = (double)state.PregnancyDuration - num;
			if (!(num2 > 0.0))
			{
				return 0f;
			}
			return (float)num2;
		}

		public static void OnConceptionDetected(Procreation procreation, CreatureProfile profile)
		{
			if (!((Object)(object)procreation == (Object)null) && profile != null && PersistenceSystem.TryGetState(((Component)procreation).GetComponent<Character>(), out CreatureState state) && state != null && state.IsOwner)
			{
				string text = ((object)Unsafe.As<ZDOID, ZDOID>(ref state.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown";
				long pregnancyStart = (long)(((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : 0.0);
				float pregnancyDuration = procreation.m_pregnancyDuration;
				string text2 = ResolveMatingPartnerId(procreation, profile);
				state.IsPregnant = true;
				state.PregnancyStart = pregnancyStart;
				state.PregnancyDuration = pregnancyDuration;
				state.ParentId = text2;
				string text3 = (string.IsNullOrEmpty(text2) ? "<none/ambiguous>" : text2);
				SubsystemLogger.LogInfo(Subsystem.Pregnancy, $"{profile.DisplayName} <{text}> conception detected. Sire={text3} Duration={pregnancyDuration:0.#}s");
			}
		}

		public static void OnBirthDetected(Procreation procreation, CreatureProfile profile)
		{
			if (!((Object)(object)procreation == (Object)null) && profile != null && PersistenceSystem.TryGetState(((Component)procreation).GetComponent<Character>(), out CreatureState state) && state != null && state.IsOwner)
			{
				string text = ((object)Unsafe.As<ZDOID, ZDOID>(ref state.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown";
				state.IsPregnant = false;
				state.PregnancyStart = 0L;
				state.PregnancyDuration = 0f;
				SubsystemLogger.LogInfo(Subsystem.Pregnancy, profile.DisplayName + " <" + text + "> birth detected. Native pregnancy completed.");
			}
		}

		public static void OnMotherDeath(Character character)
		{
			if (!((Object)(object)character == (Object)null) && CreatureRegistry.TryGetProfile(((Component)character).gameObject, out CreatureProfile profile) && profile != null && PersistenceSystem.TryGetState(character, out CreatureState state) && state != null && state.IsOwner && state.IsPregnant)
			{
				string text = ((object)Unsafe.As<ZDOID, ZDOID>(ref state.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown";
				state.IsPregnant = false;
				state.PregnancyStart = 0L;
				state.PregnancyDuration = 0f;
				state.ParentId = string.Empty;
				SubsystemLogger.LogInfo(Subsystem.Pregnancy, "Mother " + profile.DisplayName + " <" + text + "> died; pregnancy metadata cleared.");
			}
		}

		public static void SynchronizeState(Procreation procreation, CreatureProfile profile)
		{
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)procreation == (Object)null || profile == null || !PersistenceSystem.TryGetState(((Component)procreation).GetComponent<Character>(), out CreatureState state) || state == null || !state.IsOwner)
			{
				return;
			}
			ZNetView component = ((Component)procreation).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return;
			}
			long num = component.GetZDO().GetLong(ZDOVars.s_pregnant, 0L);
			bool flag = num > 0;
			if (flag && !state.IsPregnant)
			{
				long num2 = (long)((double)new DateTime(num).Ticks / 10000000.0);
				if (num2 <= 0 && (Object)(object)ZNet.instance != (Object)null)
				{
					num2 = (long)ZNet.instance.GetTimeSeconds();
				}
				state.IsPregnant = true;
				state.PregnancyStart = num2;
				state.PregnancyDuration = procreation.m_pregnancyDuration;
				SubsystemLogger.LogDebug(Subsystem.Pregnancy, $"{profile.DisplayName} <{state.ZDO?.m_uid}> state restored from native ZDO.");
			}
			else if (!flag && state.IsPregnant)
			{
				state.IsPregnant = false;
				state.PregnancyStart = 0L;
				state.PregnancyDuration = 0f;
				SubsystemLogger.LogDebug(Subsystem.Pregnancy, $"{profile.DisplayName} <{state.ZDO?.m_uid}> state cleared (native is not pregnant).");
			}
		}

		public static void LogGestationProgress(Procreation procreation, CreatureProfile profile)
		{
			if (!((Object)(object)procreation == (Object)null) && profile != null && PersistenceSystem.TryGetState(((Component)procreation).GetComponent<Character>(), out CreatureState state) && state != null)
			{
				float remainingGestationSeconds = GetRemainingGestationSeconds(state);
				string text = ((object)Unsafe.As<ZDOID, ZDOID>(ref state.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown";
				string text2 = (string.IsNullOrEmpty(state.ParentId) ? "<none/ambiguous>" : state.ParentId);
				SubsystemLogger.LogDebug(Subsystem.Pregnancy, $"{profile.DisplayName} <{text}> gestation: {remainingGestationSeconds:0.0}s / {state.PregnancyDuration:0.0}s remaining (Sire: {text2})");
			}
		}

		public static string ResolveMatingPartnerId(Procreation procreation, CreatureProfile profile)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)procreation == (Object)null || profile == null)
			{
				return string.Empty;
			}
			Vector3 position = ((Component)procreation).transform.position;
			float partnerCheckRange = procreation.m_partnerCheckRange;
			List<Character> list = new List<Character>();
			List<BaseAI> baseAIInstances = BaseAI.BaseAIInstances;
			if (baseAIInstances != null)
			{
				for (int i = 0; i < baseAIInstances.Count; i++)
				{
					BaseAI val = baseAIInstances[i];
					if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)(object)((Component)procreation).gameObject || !((Object)((Component)val).gameObject).name.StartsWith(profile.PrefabName, StringComparison.OrdinalIgnoreCase) || Vector3.Distance(position, ((Component)val).transform.position) > partnerCheckRange)
					{
						continue;
					}
					Procreation component = ((Component)val).GetComponent<Procreation>();
					if (!((Object)(object)component != (Object)null) || component.ReadyForProcreation())
					{
						Character component2 = ((Component)val).GetComponent<Character>();
						if ((Object)(object)component2 != (Object)null && !component2.IsDead())
						{
							list.Add(component2);
						}
					}
				}
			}
			if (list.Count == 1)
			{
				ZNetView component3 = ((Component)list[0]).GetComponent<ZNetView>();
				if ((Object)(object)component3 != (Object)null && component3.IsValid())
				{
					return ((object)Unsafe.As<ZDOID, ZDOID>(ref component3.GetZDO()?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? string.Empty;
				}
			}
			if (list.Count > 1)
			{
				SubsystemLogger.LogDebug(Subsystem.Pregnancy, $"Ambiguous sire detection for {profile.DisplayName}: {list.Count} eligible partners within {partnerCheckRange}m. Leaving ParentId empty to prevent incorrect lineage.");
			}
			return string.Empty;
		}
	}
}
namespace TameCraft.Subsystems.Offspring
{
	public class JuvenileSnapshot
	{
		public string ZdoId { get; set; } = string.Empty;

		public int Generation { get; set; }

		public int Affection { get; set; }

		public string MotherId { get; set; } = string.Empty;

		public string ParentId { get; set; } = string.Empty;

		public int GeneticStarLevel { get; set; }

		public int GeneticGeneration { get; set; }

		public string GeneticTraits { get; set; } = string.Empty;

		public CreatureProfile? Profile { get; set; }
	}
	public static class OffspringContext
	{
		[ThreadStatic]
		public static Character? ActiveMother;

		[ThreadStatic]
		public static Character? CapturedNewborn;

		[ThreadStatic]
		public static CreatureState? ActiveMaturingJuvenile;

		[ThreadStatic]
		public static JuvenileSnapshot? ActiveJuvenileSnapshot;

		[ThreadStatic]
		public static Character? CapturedAdult;

		public static bool IsInBirthOrMaturityTransition
		{
			get
			{
				if (!((Object)(object)ActiveMother != (Object)null) && ActiveMaturingJuvenile == null)
				{
					return ActiveJuvenileSnapshot != null;
				}
				return true;
			}
		}
	}
	public static class OffspringSubsystem
	{
		public static void ConfigureGrowup(Growup growup)
		{
			if ((Object)(object)growup == (Object)null || !ModConfig.Enabled.Value || !ModConfig.Offspring.Enabled.Value)
			{
				return;
			}
			string cleanPrefabName = VanillaBaselineCache.GetCleanPrefabName(((Component)growup).gameObject);
			if (!ModConfig.Offspring.Advanced.TryGetOffspringEnabledOverride(cleanPrefabName, out var value) || value)
			{
				float orCreateGrowTime = VanillaBaselineCache.GetOrCreateGrowTime(cleanPrefabName, growup.m_growTime);
				float num;
				if (ModConfig.Offspring.Advanced.TryGetGrowTimeOverride(cleanPrefabName, out var value2))
				{
					num = value2;
				}
				else
				{
					float num2 = Mathf.Max(0.01f, ModConfig.Offspring.GrowthSpeedMultiplier.Value);
					num = orCreateGrowTime / num2;
				}
				growup.m_growTime = num;
				SubsystemLogger.LogDebug(Subsystem.Offspring, $"[Offspring] Growth configured for {cleanPrefabName}: growTime={num:F1}s (Vanilla: {orCreateGrowTime:F1}s)");
			}
		}

		public static float GetRemainingGrowthSeconds(Growup growup)
		{
			if ((Object)(object)growup == (Object)null)
			{
				return 0f;
			}
			BaseAI component = ((Component)growup).GetComponent<BaseAI>();
			if ((Object)(object)component == (Object)null)
			{
				return 0f;
			}
			TimeSpan timeSinceSpawned = component.GetTimeSinceSpawned();
			return Mathf.Max(0f, growup.m_growTime - (float)timeSinceSpawned.TotalSeconds);
		}

		public static void OnOffspringBorn(Character offspringChar, Character motherChar)
		{
			if ((Object)(object)offspringChar == (Object)null || (Object)(object)motherChar == (Object)null)
			{
				return;
			}
			PersistenceSystem.TryGetState(motherChar, out CreatureState state);
			if (CreatureRegistry.TryGetProfile(offspringChar, out CreatureProfile profile) && profile != null && profile.Enabled)
			{
				CreatureState creatureState = PersistenceSystem.OnCreatureLoaded(offspringChar, profile);
				if (creatureState != null && creatureState.IsValid)
				{
					string text = ((object)Unsafe.As<ZDOID, ZDOID>(ref state?.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? string.Empty;
					string text2 = state?.ParentId ?? string.Empty;
					int num = state?.Generation ?? 0;
					int num2 = num + 1;
					float value;
					float num3 = (ModConfig.Offspring.Advanced.TryGetInheritAffectionPercentageOverride(profile.PrefabName, out value) ? value : ModConfig.Offspring.InheritAffectionPercentage.Value);
					int value2 = ModConfig.Affection.MaxAffection.Value;
					int num4 = state?.Affection ?? 0;
					int num5 = Mathf.Clamp(Mathf.RoundToInt((float)num4 * num3), 0, value2);
					creatureState.StateVersion = 1;
					creatureState.MotherId = text;
					creatureState.ParentId = text2;
					creatureState.Generation = num2;
					creatureState.Affection = num5;
					creatureState.IsPregnant = false;
					creatureState.PregnancyStart = 0L;
					creatureState.PregnancyDuration = 0f;
					GeneticsSubsystem.ApplyGeneticsToNewborn(offspringChar, motherChar);
					string text3 = ((object)Unsafe.As<ZDOID, ZDOID>(ref creatureState.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown";
					SubsystemLogger.LogInfo(Subsystem.Offspring, "[Offspring] Birth detected: " + profile.DisplayName + " offspring <" + text3 + "> born from mother <" + text + ">.");
					SubsystemLogger.LogInfo(Subsystem.Offspring, string.Format("[Offspring] Generation assigned: {0} (Mother: {1}), Sire: <{2}>.", num2, num, string.IsNullOrEmpty(text2) ? "<none/ambiguous>" : text2));
					SubsystemLogger.LogInfo(Subsystem.Offspring, $"[Offspring] Affection inherited: {num5}/{value2} (Mother: {num4}, {num3:P0}).");
				}
			}
		}

		public static void OnAdulthoodReached(JuvenileSnapshot juvenileSnapshot, Character adultChar)
		{
			if (juvenileSnapshot == null || (Object)(object)adultChar == (Object)null)
			{
				return;
			}
			CreatureProfile profile = juvenileSnapshot.Profile;
			if (profile == null)
			{
				CreatureRegistry.TryGetProfile(adultChar, out profile);
			}
			if (profile != null && profile.Enabled)
			{
				CreatureState creatureState = PersistenceSystem.OnCreatureLoaded(adultChar, profile);
				if (creatureState != null && creatureState.IsValid)
				{
					creatureState.StateVersion = 1;
					creatureState.Generation = juvenileSnapshot.Generation;
					creatureState.Affection = juvenileSnapshot.Affection;
					creatureState.MotherId = juvenileSnapshot.MotherId;
					creatureState.ParentId = juvenileSnapshot.ParentId;
					GeneticsSubsystem.TransferGeneticsToAdult(juvenileSnapshot, adultChar);
					creatureState.IsPregnant = false;
					creatureState.PregnancyStart = 0L;
					creatureState.PregnancyDuration = 0f;
					string zdoId = juvenileSnapshot.ZdoId;
					string text = ((object)Unsafe.As<ZDOID, ZDOID>(ref creatureState.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown";
					SubsystemLogger.LogInfo(Subsystem.Offspring, "[Offspring] Maturity detected: " + profile.DisplayName + " juvenile <" + zdoId + "> matured into adult <" + text + ">.");
					SubsystemLogger.LogInfo(Subsystem.Offspring, $"[Offspring] Metadata transferred: Generation: {creatureState.Generation}, Affection: {creatureState.Affection}, Mother: <{creatureState.MotherId}>, Sire: <{creatureState.ParentId}>.");
				}
			}
		}

		public static void OnAdulthoodReached(CreatureState juvenileState, Character adultChar)
		{
			if (juvenileState != null && !((Object)(object)adultChar == (Object)null))
			{
				OnAdulthoodReached(new JuvenileSnapshot
				{
					ZdoId = (((object)Unsafe.As<ZDOID, ZDOID>(ref juvenileState.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown"),
					Generation = juvenileState.Generation,
					Affection = juvenileState.Affection,
					MotherId = juvenileState.MotherId,
					ParentId = juvenileState.ParentId,
					GeneticStarLevel = juvenileState.GeneticStarLevel,
					GeneticGeneration = juvenileState.GeneticGeneration,
					GeneticTraits = juvenileState.GeneticTraits,
					Profile = juvenileState.Profile
				}, adultChar);
			}
		}

		public static Character? ResolveFallbackNewborn(Procreation procreation, CreatureProfile profile)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)procreation == (Object)null || profile == null)
			{
				return null;
			}
			Vector3 position = ((Component)procreation).transform.position;
			string offspringPrefabName = profile.OffspringPrefabName;
			if (string.IsNullOrEmpty(offspringPrefabName))
			{
				return null;
			}
			float num = 2.5f;
			int num2 = 0;
			Character val = null;
			List<Character> allCharacters = Character.GetAllCharacters();
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val2 = allCharacters[i];
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)null) && val2.IsTamed() && string.Equals(Utils.GetPrefabName(((Component)val2).gameObject), offspringPrefabName, StringComparison.OrdinalIgnoreCase) && !(Vector3.Distance(position, ((Component)val2).transform.position) > num))
				{
					BaseAI component = ((Component)val2).GetComponent<BaseAI>();
					if ((Object)(object)component != (Object)null && component.GetTimeSinceSpawned().TotalSeconds < 3.0)
					{
						val = val2;
						num2++;
					}
				}
			}
			if (num2 == 1 && (Object)(object)val != (Object)null)
			{
				ZNetView component2 = ((Component)val).GetComponent<ZNetView>();
				string text = ((component2 == null) ? null : ((object)Unsafe.As<ZDOID, ZDOID>(ref component2.GetZDO()?.m_uid)/*cast due to .constrained prefix*/).ToString()) ?? "unknown";
				object[] obj = new object[4] { profile.DisplayName, null, null, null };
				ZNetView component3 = ((Component)procreation).GetComponent<ZNetView>();
				obj[1] = ((component3 == null) ? ((ZDOID?)null) : component3.GetZDO()?.m_uid);
				obj[2] = ((Object)val).name;
				obj[3] = text;
				SubsystemLogger.LogWarning(Subsystem.Offspring, string.Format("[Offspring] WARNING: fallback spatial offspring resolution used for mother {0} <{1}>. Found unique newborn {2} <{3}>.", obj));
				return val;
			}
			if (num2 > 1)
			{
				SubsystemLogger.LogWarning(Subsystem.Offspring, $"[Offspring] WARNING: Rejected ambiguous spatial offspring resolution: {num2} matching newborns found within {num:F1}m of mother. Lineage not assigned to prevent corruption.");
			}
			return null;
		}

		public static Character? ResolveFallbackAdult(Growup growup, CreatureProfile profile)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)growup == (Object)null || profile == null)
			{
				return null;
			}
			Vector3 position = ((Component)growup).transform.position;
			string prefabName = profile.PrefabName;
			float num = 2f;
			int num2 = 0;
			Character val = null;
			List<Character> allCharacters = Character.GetAllCharacters();
			for (int i = 0; i < allCharacters.Count; i++)
			{
				Character val2 = allCharacters[i];
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)null) && val2.IsTamed() && string.Equals(Utils.GetPrefabName(((Component)val2).gameObject), prefabName, StringComparison.OrdinalIgnoreCase) && !(Vector3.Distance(position, ((Component)val2).transform.position) > num))
				{
					BaseAI component = ((Component)val2).GetComponent<BaseAI>();
					if ((Object)(object)component != (Object)null && component.GetTimeSinceSpawned().TotalSeconds < 3.0)
					{
						val = val2;
						num2++;
					}
				}
			}
			if (num2 == 1 && (Object)(object)val != (Object)null)
			{
				ZNetView component2 = ((Component)val).GetComponent<ZNetView>();
				string text = ((component2 == null) ? null : ((object)Unsafe.As<ZDOID, ZDOID>(ref component2.GetZDO()?.m_uid)/*cast due to .constrained prefix*/).ToString()) ?? "unknown";
				SubsystemLogger.LogWarning(Subsystem.Offspring, "[Offspring] WARNING: fallback spatial adult resolution used for maturing juvenile. Found unique adult " + ((Object)val).name + " <" + text + ">.");
				return val;
			}
			if (num2 > 1)
			{
				SubsystemLogger.LogWarning(Subsystem.Offspring, $"[Offspring] WARNING: Rejected ambiguous spatial adult resolution: {num2} matching adults found within {num:F1}m of transformation point. Lineage not transferred to prevent corruption.");
			}
			return null;
		}
	}
}
namespace TameCraft.Subsystems.Genetics
{
	public class GeneticsState
	{
		public string MotherZdoId { get; set; } = string.Empty;

		public int MotherStar { get; set; }

		public string SireZdoId { get; set; } = string.Empty;

		public int SireStar { get; set; }

		public StarInheritanceMode InheritanceMode { get; set; }

		public float MotherWeight { get; set; }

		public float SireWeight { get; set; }

		public float InheritanceRoll { get; set; }

		public string SelectedParent { get; set; } = string.Empty;

		public int InheritedStar { get; set; }

		public bool MutationEnabled { get; set; }

		public float MutationChance { get; set; }

		public float MutationRoll { get; set; }

		public bool MutationTriggered { get; set; }

		public int MutationDelta { get; set; }

		public int MutatedStar { get; set; }

		public int FinalGeneticStar { get; set; }

		public int FinalVisibleLevel { get; set; }

		public int Generation { get; set; }

		public string GeneticTraits { get; set; } = string.Empty;
	}
	public static class GeneticsSubsystem
	{
		private static readonly Random _random = new Random();

		public static bool TryParseZDOID(string? str, out ZDOID zdoid)
		{
			//IL_0001: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			zdoid = ZDOID.None;
			if (string.IsNullOrEmpty(str))
			{
				return false;
			}
			string[] array = str.Split(':');
			if (array.Length == 2 && long.TryParse(array[0], out var result) && uint.TryParse(array[1], out var result2))
			{
				zdoid = new ZDOID(result, result2);
				return true;
			}
			return false;
		}

		public static void ResolveParentStars(CreatureState motherState, IGeneticsConfig config, out int motherStar, out int sireStar, out string sireId, out bool sireFallbackApplied)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if (motherState == null)
			{
				throw new ArgumentNullException("motherState");
			}
			if (config == null)
			{
				throw new ArgumentNullException("config");
			}
			sireFallbackApplied = false;
			sireId = motherState.ParentId;
			if (!motherState.HasGeneticData)
			{
				InitializeLegacyCreature(motherState);
			}
			motherStar = motherState.GeneticStarLevel;
			bool flag = false;
			sireStar = 0;
			if (!string.IsNullOrEmpty(sireId) && TryParseZDOID(sireId, out var zdoid))
			{
				ZDOMan instance = ZDOMan.instance;
				ZDO val = ((instance != null) ? instance.GetZDO(zdoid) : null);
				if (val != null)
				{
					int num = val.GetInt(ZDOKeys.GeneticStarLevelHash, -1);
					if (num >= 0)
					{
						sireStar = num;
						flag = true;
					}
					else
					{
						int num2 = val.GetInt(ZDOVars.s_level, 1);
						sireStar = Math.Max(0, num2 - 1);
						flag = true;
					}
				}
			}
			if (!flag)
			{
				sireFallbackApplied = true;
				GeneticsParentResolutionFallback parentResolutionFallback = config.ParentResolutionFallback;
				SubsystemLogger.LogWarning(Subsystem.Genetics, $"WARNING: Sire <{sireId}> could not be resolved; using configured fallback {parentResolutionFallback}.");
				switch (parentResolutionFallback)
				{
				case GeneticsParentResolutionFallback.FallbackToMother:
					sireStar = motherStar;
					break;
				case GeneticsParentResolutionFallback.FallbackToLowerParent:
					sireStar = Math.Min(motherStar, 0);
					break;
				case GeneticsParentResolutionFallback.AbortInheritance:
					sireStar = 0;
					break;
				default:
					sireStar = motherStar;
					break;
				}
			}
		}

		public static GeneticsState DetermineOffspringGenetics(CreatureState motherState, int motherStar, int sireStar, string sireId, bool sireFallbackApplied, IGeneticsConfig config)
		{
			GeneticsState geneticsState = new GeneticsState
			{
				MotherZdoId = (((object)Unsafe.As<ZDOID, ZDOID>(ref motherState.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown"),
				MotherStar = motherStar,
				SireZdoId = (string.IsNullOrEmpty(sireId) ? "none" : sireId),
				SireStar = sireStar,
				InheritanceMode = config.StarInheritanceMode,
				Generation = motherState.GeneticGeneration + 1,
				GeneticTraits = string.Empty
			};
			if (sireFallbackApplied && config.ParentResolutionFallback == GeneticsParentResolutionFallback.AbortInheritance)
			{
				geneticsState.SelectedParent = "AbortInheritance";
				geneticsState.InheritedStar = 0;
				geneticsState.InheritanceRoll = 0f;
				geneticsState.FinalGeneticStar = 0;
				geneticsState.FinalVisibleLevel = 1;
				return geneticsState;
			}
			config.GetNormalizedWeights(out var normMotherWeight, out var normSireWeight);
			geneticsState.MotherWeight = normMotherWeight;
			geneticsState.SireWeight = normSireWeight;
			switch (config.StarInheritanceMode)
			{
			case StarInheritanceMode.Vanilla:
				geneticsState.InheritedStar = motherStar;
				geneticsState.SelectedParent = "Mother";
				geneticsState.InheritanceRoll = 0f;
				break;
			case StarInheritanceMode.HigherParent:
				if (motherStar >= sireStar)
				{
					geneticsState.InheritedStar = motherStar;
					geneticsState.SelectedParent = "Mother";
				}
				else
				{
					geneticsState.InheritedStar = sireStar;
					geneticsState.SelectedParent = "Sire";
				}
				geneticsState.InheritanceRoll = 0f;
				break;
			case StarInheritanceMode.LowerParent:
				if (motherStar <= sireStar)
				{
					geneticsState.InheritedStar = motherStar;
					geneticsState.SelectedParent = "Mother";
				}
				else
				{
					geneticsState.InheritedStar = sireStar;
					geneticsState.SelectedParent = "Sire";
				}
				geneticsState.InheritanceRoll = 0f;
				break;
			default:
			{
				if (motherStar == sireStar)
				{
					geneticsState.InheritedStar = motherStar;
					geneticsState.SelectedParent = "BothEqual";
					geneticsState.InheritanceRoll = 50f;
					break;
				}
				float num = (geneticsState.InheritanceRoll = (float)(_random.NextDouble() * 100.0));
				if (num < normMotherWeight)
				{
					geneticsState.InheritedStar = motherStar;
					geneticsState.SelectedParent = "Mother";
				}
				else
				{
					geneticsState.InheritedStar = sireStar;
					geneticsState.SelectedParent = "Sire";
				}
				break;
			}
			}
			geneticsState.MutationEnabled = config.MutationEnabled;
			geneticsState.MutationChance = Mathf.Clamp01(config.MutationChance);
			geneticsState.MutatedStar = geneticsState.InheritedStar;
			if (geneticsState.MutationEnabled && geneticsState.MutationChance > 0f)
			{
				float num3 = (geneticsState.MutationRoll = (float)_random.NextDouble());
				if (num3 <= geneticsState.MutationChance)
				{
					geneticsState.MutationTriggered = true;
					if (config.MutationDirection == MutationDirection.Bidirectional)
					{
						int num5 = (geneticsState.MutationDelta = ((_random.NextDouble() < 0.5) ? 1 : (-1)));
						geneticsState.MutatedStar = geneticsState.InheritedStar + num5;
					}
					else
					{
						geneticsState.MutationDelta = 1;
						geneticsState.MutatedStar = geneticsState.InheritedStar + 1;
					}
				}
			}
			int val = 2;
			int val2 = Math.Min(config.MutationMaxStar, val);
			val2 = Math.Max(0, val2);
			geneticsState.FinalGeneticStar = Math.Clamp(geneticsState.MutatedStar, 0, val2);
			geneticsState.FinalVisibleLevel = geneticsState.FinalGeneticStar + 1;
			return geneticsState;
		}

		public static void ApplyGeneticsToNewborn(Character newbornChar, Character motherChar)
		{
			if ((Object)(object)newbornChar == (Object)null || (Object)(object)motherChar == (Object)null)
			{
				return;
			}
			if ((!CreatureState.TryGet(newbornChar, out CreatureState state) || state == null) && CreatureRegistry.TryGetProfile(newbornChar, out CreatureProfile profile) && profile != null)
			{
				state = CreatureState.GetOrCreate(newbornChar, profile);
			}
			if (state == null || !state.IsValid || !state.IsOwner || state.HasGeneticData)
			{
				return;
			}
			if ((!CreatureState.TryGet(motherChar, out CreatureState state2) || state2 == null) && CreatureRegistry.TryGetProfile(motherChar, out CreatureProfile profile2) && profile2 != null)
			{
				state2 = CreatureState.GetOrCreate(motherChar, profile2);
			}
			if (state2 == null || !state2.IsValid)
			{
				return;
			}
			IGeneticsConfig genetics = ModConfig.Genetics;
			if (!genetics.Enabled)
			{
				int geneticStarLevel = Math.Max(0, newbornChar.GetLevel() - 1);
				state.GeneticStarLevel = geneticStarLevel;
				state.GeneticGeneration = state2.GeneticGeneration + 1;
				state.GeneticTraits = string.Empty;
				return;
			}
			ResolveParentStars(state2, genetics, out int motherStar, out int sireStar, out string sireId, out bool sireFallbackApplied);
			GeneticsState geneticsState = DetermineOffspringGenetics(state2, motherStar, sireStar, sireId, sireFallbackApplied, genetics);
			state.GeneticStarLevel = geneticsState.FinalGeneticStar;
			state.GeneticGeneration = geneticsState.Generation;
			state.GeneticTraits = geneticsState.GeneticTraits;
			newbornChar.SetLevel(geneticsState.FinalVisibleLevel);
			if (ModConfig.DebugLogging.Value)
			{
				SubsystemLogger.LogInfo(Subsystem.Genetics, $"Parents:\nMother=<{geneticsState.MotherZdoId}>\nMotherStar={geneticsState.MotherStar}\nSire=<{geneticsState.SireZdoId}>\nSireStar={geneticsState.SireStar}");
				SubsystemLogger.LogInfo(Subsystem.Genetics, $"Inheritance:\nMode={geneticsState.InheritanceMode}\nMotherWeight={geneticsState.MotherWeight:0.##}\nSireWeight={geneticsState.SireWeight:0.##}\nRoll={geneticsState.InheritanceRoll:F2}\nSelected={geneticsState.SelectedParent}\nResultStar={geneticsState.InheritedStar}");
				SubsystemLogger.LogInfo(Subsystem.Genetics, $"Mutation:\nEnabled={geneticsState.MutationEnabled.ToString().ToLowerInvariant()}\nResultStar={geneticsState.FinalGeneticStar}");
				SubsystemLogger.LogInfo(Subsystem.Genetics, $"Final:\nGeneticStar={geneticsState.FinalGeneticStar}\nVisibleLevel={geneticsState.FinalVisibleLevel}");
			}
		}

		public static void TransferGeneticsToAdult(JuvenileSnapshot snapshot, Character adultChar)
		{
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			if (snapshot == null || (Object)(object)adultChar == (Object)null || !CreatureRegistry.TryGetProfile(adultChar, out CreatureProfile profile) || profile == null)
			{
				return;
			}
			CreatureState orCreate = CreatureState.GetOrCreate(adultChar, profile);
			if (orCreate.IsValid && orCreate.IsOwner)
			{
				orCreate.GeneticStarLevel = snapshot.GeneticStarLevel;
				orCreate.GeneticGeneration = snapshot.GeneticGeneration;
				orCreate.GeneticTraits = snapshot.GeneticTraits;
				adultChar.SetLevel(snapshot.GeneticStarLevel + 1);
				if (ModConfig.DebugLogging.Value)
				{
					SubsystemLogger.LogInfo(Subsystem.Genetics, $"Adulthood: Transferred {snapshot.GeneticStarLevel}★ (Gen {snapshot.GeneticGeneration}) to adult {profile.DisplayName} <{adultChar.GetZDOID()}>");
				}
			}
		}

		public static void TransferGeneticsToAdult(CreatureState juvenileState, Character adultChar)
		{
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			if (juvenileState == null || (Object)(object)adultChar == (Object)null || !CreatureRegistry.TryGetProfile(adultChar, out CreatureProfile profile) || profile == null)
			{
				return;
			}
			CreatureState orCreate = CreatureState.GetOrCreate(adultChar, profile);
			if (orCreate.IsValid && orCreate.IsOwner)
			{
				orCreate.GeneticStarLevel = juvenileState.GeneticStarLevel;
				orCreate.GeneticGeneration = juvenileState.GeneticGeneration;
				orCreate.GeneticTraits = juvenileState.GeneticTraits;
				adultChar.SetLevel(juvenileState.GeneticStarLevel + 1);
				if (ModConfig.DebugLogging.Value)
				{
					SubsystemLogger.LogInfo(Subsystem.Genetics, $"Adulthood: Transferred {juvenileState.GeneticStarLevel}★ (Gen {juvenileState.GeneticGeneration}) to adult {profile.DisplayName} <{adultChar.GetZDOID()}>");
				}
			}
		}

		public static void InitializeLegacyCreature(CreatureState state)
		{
			if (state != null && state.IsValid && state.IsOwner)
			{
				int num = (state.GeneticStarLevel = Math.Max(0, state.Character.GetLevel() - 1));
				state.GeneticGeneration = state.Generation;
				state.GeneticTraits = string.Empty;
				SubsystemLogger.LogInfo(Subsystem.Genetics, $"Legacy creature initialized from vanilla star level: {num}★");
			}
		}
	}
}
namespace TameCraft.Subsystems.Breeding
{
	public static class BreedingSubsystem
	{
		private static readonly HashSet<int> _configuredProcreationInstances = new HashSet<int>();

		private static readonly Func<Procreation, bool>? s_isPregnant = AccessTools.MethodDelegate<Func<Procreation, bool>>(AccessTools.Method(typeof(Procreation), "IsPregnant", (Type[])null, (Type[])null), (object)null, true);

		public static void ConfigureCreature(Procreation procreation, CreatureProfile profile)
		{
			if ((Object)(object)procreation == (Object)null || profile == null || !ModConfig.Enabled.Value || !ModConfig.Breeding.Enabled.Value)
			{
				return;
			}
			string prefabName = profile.PrefabName;
			if (!ModConfig.Breeding.Advanced.TryGetBreedingEnabledOverride(prefabName, out var value) || value)
			{
				float orCreateCheckInterval = VanillaBaselineCache.GetOrCreateCheckInterval(prefabName, procreation.m_updateInterval);
				if (ModConfig.Breeding.Advanced.TryGetUpdateIntervalOverride(prefabName, out var value2))
				{
					procreation.m_updateInterval = value2;
				}
				else
				{
					float num = Mathf.Max(0.01f, ModConfig.Breeding.BreedingCheckSpeedMultiplier.Value);
					procreation.m_updateInterval = orCreateCheckInterval / num;
				}
				float orCreatePregnancyDuration = VanillaBaselineCache.GetOrCreatePregnancyDuration(prefabName, procreation.m_pregnancyDuration);
				if (ModConfig.Breeding.Advanced.TryGetPregnancyDurationOverride(prefabName, out var value3))
				{
					procreation.m_pregnancyDuration = value3;
				}
				else if (orCreatePregnancyDuration > 0f)
				{
					float num2 = Mathf.Max(0.01f, ModConfig.Breeding.PregnancySpeedMultiplier.Value);
					procreation.m_pregnancyDuration = orCreatePregnancyDuration / num2;
				}
				else
				{
					procreation.m_pregnancyDuration = 0f;
				}
				if (ModConfig.Breeding.Advanced.TryGetPregnancyChanceOverride(prefabName, out var value4))
				{
					procreation.m_pregnancyChance = value4;
				}
				else
				{
					procreation.m_pregnancyChance = ModConfig.Breeding.PregnancyChance.Value;
				}
				if (ModConfig.Breeding.Advanced.TryGetRequiredLovePointsOverride(prefabName, out var value5))
				{
					procreation.m_requiredLovePoints = value5;
				}
				else
				{
					procreation.m_requiredLovePoints = ModConfig.Breeding.RequiredLovePoints.Value;
				}
				float orCreatePartnerCheckRange = VanillaBaselineCache.GetOrCreatePartnerCheckRange(prefabName, procreation.m_partnerCheckRange);
				if (ModConfig.Breeding.Advanced.TryGetPartnerCheckRangeOverride(prefabName, out var value6))
				{
					procreation.m_partnerCheckRange = value6;
				}
				else
				{
					float num3 = Mathf.Max(0.01f, ModConfig.Breeding.PartnerCheckRangeMultiplier.Value);
					procreation.m_partnerCheckRange = orCreatePartnerCheckRange * num3;
				}
				float orCreateEnclosureCheckRange = VanillaBaselineCache.GetOrCreateEnclosureCheckRange(prefabName, procreation.m_totalCheckRange);
				if (ModConfig.Breeding.Advanced.TryGetEnclosureCheckRangeOverride(prefabName, out var value7))
				{
					procreation.m_totalCheckRange = value7;
				}
				else
				{
					float num4 = Mathf.Max(0.01f, ModConfig.Breeding.EnclosureCheckRangeMultiplier.Value);
					procreation.m_totalCheckRange = orCreateEnclosureCheckRange * num4;
				}
				int orCreateCreatureLimit = VanillaBaselineCache.GetOrCreateCreatureLimit(prefabName, procreation.m_maxCreatures);
				if (ModConfig.Breeding.Advanced.TryGetCreatureLimitOverride(prefabName, out var value8))
				{
					procreation.m_maxCreatures = value8;
				}
				else
				{
					float num5 = Mathf.Max(0.01f, ModConfig.Breeding.CreatureLimitMultiplier.Value);
					procreation.m_maxCreatures = Mathf.Max(1, Mathf.RoundToInt((float)orCreateCreatureLimit * num5));
				}
				int instanceID = ((Object)procreation).GetInstanceID();
				if (_configuredProcreationInstances.Add(instanceID))
				{
					SubsystemLogger.LogDebug(Subsystem.Breeding, $"Configured {profile.DisplayName} Procreation: interval={procreation.m_updateInterval:F1}s, chance={procreation.m_pregnancyChance * 100f:0}%, lovePointsReq={procreation.m_requiredLovePoints}, gestation={procreation.m_pregnancyDuration:F1}s, partnerRange={procreation.m_partnerCheckRange:F1}m, enclosureRange={procreation.m_totalCheckRange:F1}m, limit={procreation.m_maxCreatures}");
				}
			}
		}

		public static bool IsPregnant(Procreation procreation)
		{
			if ((Object)(object)procreation == (Object)null)
			{
				return false;
			}
			if (s_isPregnant != null)
			{
				return s_isPregnant(procreation);
			}
			ZNetView component = ((Component)procreation).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid())
			{
				return component.GetZDO().GetLong(ZDOVars.s_pregnant, 0L) > 0;
			}
			return false;
		}

		public static bool CheckBreedingEligibility(Procreation procreation, CreatureProfile profile)
		{
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)procreation == (Object)null || profile == null)
			{
				return true;
			}
			if (!PersistenceSystem.TryGetState(((Component)procreation).GetComponent<Character>(), out CreatureState state) || state == null)
			{
				return true;
			}
			string text = ((object)Unsafe.As<ZDOID, ZDOID>(ref state.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown";
			if (ModConfig.Breeding.RequireAffectionForBreeding.Value)
			{
				bool num = AffectionSubsystem.IsAffectionSufficientForBreeding(state, profile);
				int affection = state.Affection;
				int value = ModConfig.Breeding.BreedingAffectionThreshold.Value;
				if (!num)
				{
					SubsystemLogger.LogDebug(Subsystem.Breeding, $"{profile.DisplayName} <{text}> breeding blocked: Affection={affection}/{value} (Insufficient Affection)");
					return false;
				}
			}
			if (ModConfig.DebugLogging.Value)
			{
				Vector3 position = ((Component)procreation).transform.position;
				Tameable component = ((Component)procreation).GetComponent<Tameable>();
				BaseAI component2 = ((Component)procreation).GetComponent<BaseAI>();
				bool flag = (Object)(object)component != (Object)null && !component.IsHungry();
				bool flag2 = (Object)(object)component2 != (Object)null && component2.IsAlerted();
				GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(profile.PrefabName) : null);
				int num2 = (((Object)(object)val != (Object)null) ? SpawnSystem.GetNrOfInstances(val, position, procreation.m_partnerCheckRange, false, false) : 0);
				int num3 = (((Object)(object)val != (Object)null) ? SpawnSystem.GetNrOfInstances(val, position, procreation.m_totalCheckRange, false, false) : 0);
				int value2 = ModConfig.Breeding.BreedingAffectionThreshold.Value;
				SubsystemLogger.LogDebug(Subsystem.Breeding, $"{profile.DisplayName} <{text}> check: Affection={state.Affection}/{value2}, Partner={num2 >= 2}, Fed={flag}, Alerted={flag2}, Population={num3}/{procreation.m_maxCreatures}");
			}
			return true;
		}

		public static void OnProcreationCompleted(Procreation procreation, CreatureProfile profile, int oldLovePoints, bool wasPregnant)
		{
			if ((Object)(object)procreation == (Object)null || profile == null)
			{
				return;
			}
			ZNetView component = ((Component)procreation).GetComponent<ZNetView>();
			string text = ((component == null) ? null : ((object)Unsafe.As<ZDOID, ZDOID>(ref component.GetZDO()?.m_uid)/*cast due to .constrained prefix*/).ToString()) ?? "unknown";
			if (IsPregnant(procreation) && !wasPregnant)
			{
				SubsystemLogger.LogInfo(Subsystem.Breeding, profile.DisplayName + " <" + text + "> conceived successfully! Native pregnancy initiated.");
				return;
			}
			int lovePoints = procreation.GetLovePoints();
			if (lovePoints > oldLovePoints)
			{
				SubsystemLogger.LogInfo(Subsystem.Breeding, $"{profile.DisplayName} <{text}> mated with partner; love points {oldLovePoints} -> {lovePoints}/{procreation.m_requiredLovePoints}.");
			}
		}
	}
}
namespace TameCraft.Subsystems.Affection
{
	public static class AffectionSubsystem
	{
		public static AffectionTier GetTier(CreatureState state, CreatureProfile profile)
		{
			if (state == null || profile == null)
			{
				return AffectionTier.Distant;
			}
			int affection = state.Affection;
			if (affection < ModConfig.Affection.NeutralThreshold.Value)
			{
				return AffectionTier.Distant;
			}
			if (affection < ModConfig.Affection.BondedThreshold.Value)
			{
				return AffectionTier.Neutral;
			}
			if (affection < ModConfig.Affection.DevotedThreshold.Value)
			{
				return AffectionTier.Bonded;
			}
			return AffectionTier.Devoted;
		}

		public static bool IsAffectionSufficient(CreatureState state, int requiredPoints)
		{
			if (state == null)
			{
				return false;
			}
			return state.Affection >= requiredPoints;
		}

		public static bool IsAffectionSufficientForBreeding(CreatureState state, CreatureProfile profile)
		{
			if (state == null || profile == null)
			{
				return false;
			}
			return state.Affection >= ModConfig.Breeding.BreedingAffectionThreshold.Value;
		}

		public static void OnPetInteraction(Tameable tameable, CreatureProfile profile, Humanoid user)
		{
			if ((Object)(object)tameable == (Object)null || profile == null || (Object)(object)user == (Object)null || !ModConfig.Enabled.Value || !ModConfig.Affection.Enabled.Value || !ModConfig.Affection.PettingAffectionEnabled.Value || !PersistenceSystem.TryGetState(((Component)tameable).GetComponent<Character>(), out CreatureState state) || state == null)
			{
				return;
			}
			ZNetView component = ((Component)tameable).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid())
			{
				string hoverName = ((Character)user).GetHoverName();
				if (component.IsOwner())
				{
					RecordPetting(state, profile, hoverName);
					return;
				}
				component.InvokeRPC("TameCraft_Pet", new object[1] { hoverName });
			}
		}

		public static void RecordPetting(CreatureState state, CreatureProfile profile, string playerName)
		{
			if (state == null || profile == null || !state.IsOwner || !ModConfig.Enabled.Value || !ModConfig.Affection.Enabled.Value || !ModConfig.Affection.PettingAffectionEnabled.Value)
			{
				return;
			}
			long num = (long)(((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetTimeSeconds() : 0.0);
			float value = ModConfig.Affection.PettingCooldownSeconds.Value;
			long lastPetTime = state.LastPetTime;
			if (lastPetTime > 0 && (float)(num - lastPetTime) < value)
			{
				return;
			}
			state.LastPetTime = num;
			int value2 = ModConfig.Affection.AffectionPerPet.Value;
			if (value2 > 0)
			{
				int value3 = ModConfig.Affection.MaxAffection.Value;
				int affection = state.Affection;
				AffectionTier tier = GetTier(state, profile);
				state.Affection = Mathf.Clamp(affection + value2, 0, value3);
				AffectionTier tier2 = GetTier(state, profile);
				string text = ((object)Unsafe.As<ZDOID, ZDOID>(ref state.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown";
				SubsystemLogger.LogDebug(Subsystem.Affection, $"{profile.DisplayName} <{text}> petted by {playerName}; affection {affection} -> {state.Affection} (Tier: {tier2})");
				if (tier2 > tier)
				{
					SubsystemLogger.LogInfo(Subsystem.Affection, $"{profile.DisplayName} <{text}> reached {tier2} affection tier ({state.Affection} points)!");
				}
			}
		}

		public static void RecordFeeding(CreatureState state, CreatureProfile profile, ItemDrop? item, int gain)
		{
			if (state != null && profile != null && state.IsOwner)
			{
				int value = ModConfig.Affection.MaxAffection.Value;
				int affection = state.Affection;
				AffectionTier tier = GetTier(state, profile);
				state.Affection = Mathf.Clamp(affection + gain, 0, value);
				AffectionTier tier2 = GetTier(state, profile);
				string text = item?.m_itemData?.m_shared?.m_name ?? ((item != null) ? ((Object)item).name : null) ?? "Food";
				string text2 = ((object)Unsafe.As<ZDOID, ZDOID>(ref state.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown";
				SubsystemLogger.LogDebug(Subsystem.Affection, $"{profile.DisplayName} <{text2}> fed with {text}; affection {affection} -> {state.Affection} (Tier: {tier2})");
				if (tier2 > tier)
				{
					SubsystemLogger.LogInfo(Subsystem.Affection, $"{profile.DisplayName} <{text2}> reached {tier2} affection tier ({state.Affection} points)!");
				}
			}
		}
	}
	public enum AffectionTier
	{
		Distant,
		Neutral,
		Bonded,
		Devoted
	}
}
namespace TameCraft.Patches
{
	[HarmonyPatch(typeof(Tameable), "Interact")]
	public static class TameableInteractPatch
	{
		[HarmonyPostfix]
		public static void Postfix(Tameable __instance, Humanoid user, bool hold, bool alt, bool __result)
		{
			if (__result && !((Object)(object)__instance == (Object)null) && !((Object)(object)user == (Object)null) && !hold && !alt && ModConfig.Enabled.Value && ModConfig.Affection.Enabled.Value && ModConfig.Affection.PettingAffectionEnabled.Value && __instance.IsTamed() && !__instance.HaveRider() && CreatureRegistry.TryGetProfile(((Component)__instance).gameObject, out CreatureProfile profile) && profile != null && profile.Enabled && (!((Object)(object)((Component)__instance).GetComponent<Growup>() != (Object)null) || (ModConfig.Offspring.Advanced.TryGetJuvenilePettingAllowedOverride(profile.PrefabName, out var value) ? value : ModConfig.Offspring.JuvenilePettingAllowed.Value)))
			{
				AffectionSubsystem.OnPetInteraction(__instance, profile, user);
			}
		}
	}
	[HarmonyPatch(typeof(Character), "Awake")]
	public static class CharacterLifecyclePatches
	{
		[HarmonyPostfix]
		public static void AwakePostfix(Character __instance)
		{
			if (ModConfig.Enabled.Value && !((Object)(object)__instance == (Object)null))
			{
				CreatureProfile profile;
				if ((Object)(object)OffspringContext.ActiveMother != (Object)null && (Object)(object)OffspringContext.CapturedNewborn == (Object)null)
				{
					OffspringContext.CapturedNewborn = __instance;
				}
				else if (OffspringContext.ActiveMaturingJuvenile != null && (Object)(object)OffspringContext.CapturedAdult == (Object)null)
				{
					OffspringContext.CapturedAdult = __instance;
				}
				else if (CreatureRegistry.TryGetProfile(__instance, out profile) && profile != null && profile.Enabled)
				{
					PersistenceSystem.OnCreatureLoaded(__instance, profile);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Character), "OnDeath")]
	public static class CharacterDeathPatch
	{
		[HarmonyPostfix]
		public static void Postfix(Character __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && ModConfig.Enabled.Value)
			{
				PregnancySubsystem.OnMotherDeath(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Growup), "Start")]
	public static class GrowupStartPatch
	{
		[HarmonyPostfix]
		public static void Postfix(Growup __instance)
		{
			if (ModConfig.Enabled.Value && ModConfig.Offspring.Enabled.Value && !((Object)(object)__instance == (Object)null))
			{
				OffspringSubsystem.ConfigureGrowup(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Growup), "GrowUpdate")]
	public static class GrowupGrowUpdatePatch
	{
		[HarmonyPrefix]
		public static bool Prefix(Growup __instance, out (bool willMature, JuvenileSnapshot? juvenileSnapshot) __state)
		{
			__state = (willMature: false, juvenileSnapshot: null);
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			if (!ModConfig.Enabled.Value || !ModConfig.Offspring.Enabled.Value)
			{
				return true;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner())
			{
				return true;
			}
			BaseAI component2 = ((Component)__instance).GetComponent<BaseAI>();
			if ((Object)(object)component2 == (Object)null)
			{
				return true;
			}
			TimeSpan timeSinceSpawned = component2.GetTimeSinceSpawned();
			if (timeSinceSpawned.TotalSeconds > (double)__instance.m_growTime)
			{
				PersistenceSystem.TryGetState(((Component)__instance).GetComponent<Character>(), out CreatureState state);
				JuvenileSnapshot juvenileSnapshot = null;
				if (state != null && state.IsValid)
				{
					juvenileSnapshot = new JuvenileSnapshot
					{
						ZdoId = (((object)Unsafe.As<ZDOID, ZDOID>(ref state.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown"),
						Generation = state.Generation,
						Affection = state.Affection,
						MotherId = state.MotherId,
						ParentId = state.ParentId,
						GeneticStarLevel = state.GeneticStarLevel,
						GeneticGeneration = state.GeneticGeneration,
						GeneticTraits = state.GeneticTraits,
						Profile = state.Profile
					};
				}
				__state = (willMature: true, juvenileSnapshot: juvenileSnapshot);
				OffspringContext.ActiveMaturingJuvenile = state;
				OffspringContext.ActiveJuvenileSnapshot = juvenileSnapshot;
				OffspringContext.CapturedAdult = null;
				string arg = juvenileSnapshot?.ZdoId ?? ((object)Unsafe.As<ZDOID, ZDOID>(ref state?.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown";
				SubsystemLogger.LogDebug(Subsystem.Offspring, $"[Offspring] Juvenile <{arg}> ready to mature ({timeSinceSpawned.TotalSeconds:F1}s > {__instance.m_growTime:F1}s). Arming adult capture...");
			}
			else if (ModConfig.DebugLogging.Value)
			{
				float num = Mathf.Max(0f, __instance.m_growTime - (float)timeSinceSpawned.TotalSeconds);
				string text = ((object)Unsafe.As<ZDOID, ZDOID>(ref component.GetZDO()?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown";
				SubsystemLogger.LogDebug(Subsystem.Offspring, $"[Offspring] Growth update: {((Object)((Component)__instance).gameObject).name} <{text}>: {num:F1}s / {__instance.m_growTime:F1}s remaining.");
			}
			return true;
		}

		[HarmonyPostfix]
		public static void Postfix(Growup __instance, (bool willMature, JuvenileSnapshot? juvenileSnapshot) __state)
		{
			try
			{
				if (ModConfig.Enabled.Value && ModConfig.Offspring.Enabled.Value && __state.willMature && __state.juvenileSnapshot != null)
				{
					Character val = OffspringContext.CapturedAdult;
					if ((Object)(object)val == (Object)null && (Object)(object)__instance != (Object)null && __state.juvenileSnapshot.Profile != null)
					{
						val = OffspringSubsystem.ResolveFallbackAdult(__instance, __state.juvenileSnapshot.Profile);
					}
					if ((Object)(object)val != (Object)null)
					{
						OffspringSubsystem.OnAdulthoodReached(__state.juvenileSnapshot, val);
					}
				}
			}
			finally
			{
				OffspringContext.ActiveMaturingJuvenile = null;
				OffspringContext.ActiveJuvenileSnapshot = null;
				OffspringContext.CapturedAdult = null;
			}
		}
	}
	[HarmonyPatch(typeof(Procreation), "Awake")]
	public static class ProcreationAwakePatch
	{
		[HarmonyPrefix]
		public static void Prefix(Procreation __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && ModConfig.Enabled.Value && ModConfig.Breeding.Enabled.Value && CreatureRegistry.TryGetProfile(((Component)__instance).gameObject, out CreatureProfile profile) && profile != null && profile.Enabled)
			{
				BreedingSubsystem.ConfigureCreature(__instance, profile);
			}
		}
	}
	[HarmonyPatch(typeof(Procreation), "Procreate")]
	public static class ProcreationProcreatePatch
	{
		[HarmonyPrefix]
		public static bool Prefix(Procreation __instance, out (int lovePoints, bool isPregnant) __state)
		{
			__state = (lovePoints: 0, isPregnant: false);
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			__state = (lovePoints: __instance.GetLovePoints(), isPregnant: BreedingSubsystem.IsPregnant(__instance));
			if (!ModConfig.Enabled.Value || !ModConfig.Breeding.Enabled.Value)
			{
				return true;
			}
			if (!CreatureRegistry.TryGetProfile(((Component)__instance).gameObject, out CreatureProfile profile) || profile == null || !profile.Enabled)
			{
				return true;
			}
			BreedingSubsystem.ConfigureCreature(__instance, profile);
			PregnancySubsystem.SynchronizeState(__instance, profile);
			if (BreedingSubsystem.IsPregnant(__instance))
			{
				if (ModConfig.DebugLogging.Value)
				{
					PregnancySubsystem.LogGestationProgress(__instance, profile);
				}
				OffspringContext.ActiveMother = ((Component)__instance).GetComponent<Character>();
				OffspringContext.CapturedNewborn = null;
				return true;
			}
			if (!BreedingSubsystem.CheckBreedingEligibility(__instance, profile))
			{
				return false;
			}
			return true;
		}

		[HarmonyPostfix]
		public static void Postfix(Procreation __instance, (int lovePoints, bool isPregnant) __state)
		{
			try
			{
				if ((Object)(object)__instance == (Object)null || !ModConfig.Enabled.Value || !ModConfig.Breeding.Enabled.Value || !CreatureRegistry.TryGetProfile(((Component)__instance).gameObject, out CreatureProfile profile) || profile == null || !profile.Enabled)
				{
					return;
				}
				bool item = __state.isPregnant;
				bool flag = BreedingSubsystem.IsPregnant(__instance);
				if (item && !flag)
				{
					PregnancySubsystem.OnBirthDetected(__instance, profile);
					Character val = OffspringContext.CapturedNewborn;
					if ((Object)(object)val == (Object)null)
					{
						val = OffspringSubsystem.ResolveFallbackNewborn(__instance, profile);
					}
					if ((Object)(object)val != (Object)null)
					{
						Character component = ((Component)__instance).GetComponent<Character>();
						OffspringSubsystem.OnOffspringBorn(val, component);
					}
				}
				else if (!item && flag)
				{
					PregnancySubsystem.OnConceptionDetected(__instance, profile);
				}
				else
				{
					BreedingSubsystem.OnProcreationCompleted(__instance, profile, __state.lovePoints, __state.isPregnant);
				}
			}
			finally
			{
				OffspringContext.ActiveMother = null;
				OffspringContext.CapturedNewborn = null;
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "Awake")]
	public static class TameableAwakePatch
	{
		[HarmonyPostfix]
		public static void Postfix(Tameable __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && ModConfig.Enabled.Value && ModConfig.Taming.Enabled.Value && CreatureRegistry.TryGetProfile(((Component)__instance).gameObject, out CreatureProfile profile) && profile != null && profile.Enabled)
			{
				TamingSubsystem.ConfigureCreature(__instance, profile);
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "OnConsumedItem")]
	public static class TameableOnConsumedItemPatch
	{
		[HarmonyPostfix]
		public static void Postfix(Tameable __instance, ItemDrop item)
		{
			if (!((Object)(object)__instance == (Object)null) && ModConfig.Enabled.Value && ModConfig.Taming.Enabled.Value && CreatureRegistry.TryGetProfile(((Component)__instance).gameObject, out CreatureProfile profile) && profile != null && profile.Enabled)
			{
				TamingSubsystem.OnFeedAccepted(__instance, profile, item);
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "TamingUpdate")]
	public static class TameableTamingUpdatePatch
	{
		private static readonly Action<Tameable, float>? s_decreaseRemainingTime = AccessTools.MethodDelegate<Action<Tameable, float>>(AccessTools.Method(typeof(Tameable), "DecreaseRemainingTime", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Func<Tameable, float>? s_getRemainingTime = AccessTools.MethodDelegate<Func<Tameable, float>>(AccessTools.Method(typeof(Tameable), "GetRemainingTime", (Type[])null, (Type[])null), (object)null, true);

		private static readonly Action<Tameable>? s_tame = AccessTools.MethodDelegate<Action<Tameable>>(AccessTools.Method(typeof(Tameable), "Tame", (Type[])null, (Type[])null), (object)null, true);

		[HarmonyPrefix]
		public static bool Prefix(Tameable __instance)
		{
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: 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_0193: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.Enabled.Value || !ModConfig.Taming.Enabled.Value)
			{
				return true;
			}
			if (!CreatureRegistry.TryGetProfile(((Component)__instance).gameObject, out CreatureProfile profile) || profile == null || !profile.Enabled)
			{
				return true;
			}
			TamingSubsystem.ConfigureCreature(__instance, profile);
			bool value;
			bool flag = (ModConfig.Taming.Advanced.TryGetAllowTamingWhileAlertedOverride(profile.PrefabName, out value) ? value : ModConfig.Taming.AllowTamingWhileAlerted.Value);
			bool flag2 = ModConfig.Taming.Advanced.IsHungerIgnored(profile.PrefabName);
			if (!flag && !flag2)
			{
				return true;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner())
			{
				return false;
			}
			if (__instance.IsTamed())
			{
				return false;
			}
			if (__instance.IsHungry() && !flag2)
			{
				return false;
			}
			MonsterAI component2 = ((Component)__instance).GetComponent<MonsterAI>();
			if (!flag && (Object)(object)component2 != (Object)null && ((BaseAI)component2).IsAlerted())
			{
				return false;
			}
			if (component2 != null)
			{
				component2.SetDespawnInDay(false);
			}
			if (component2 != null)
			{
				component2.SetEventCreature(false);
			}
			if (s_decreaseRemainingTime != null)
			{
				s_decreaseRemainingTime(__instance, 3f);
			}
			if (((s_getRemainingTime != null) ? s_getRemainingTime(__instance) : 0f) <= 0f)
			{
				if (s_tame != null)
				{
					s_tame(__instance);
				}
				SubsystemLogger.LogDebug(Subsystem.Taming, profile.DisplayName + " completed taming!");
			}
			else
			{
				EffectList sootheEffect = __instance.m_sootheEffect;
				if (sootheEffect != null)
				{
					sootheEffect.Create(((Component)__instance).transform.position, ((Component)__instance).transform.rotation, (Transform)null, 1f, -1, default(ZDOID));
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(MonsterAI), "UpdateAI")]
	public static class MonsterAIUpdateAIPatch
	{
		private static readonly Func<MonsterAI, Humanoid, float, bool>? s_updateConsumeItem = AccessTools.MethodDelegate<Func<MonsterAI, Humanoid, float, bool>>(AccessTools.Method(typeof(MonsterAI), "UpdateConsumeItem", (Type[])null, (Type[])null), (object)null, true);

		[HarmonyPostfix]
		public static void Postfix(MonsterAI __instance, float dt)
		{
			if ((Object)(object)__instance == (Object)null || !ModConfig.Enabled.Value || !ModConfig.Taming.Enabled.Value || !CreatureRegistry.TryGetProfile(((Component)__instance).gameObject, out CreatureProfile profile) || profile == null || !profile.Enabled || !(ModConfig.Taming.Advanced.TryGetAllowTamingWhileAlertedOverride(profile.PrefabName, out var value) ? value : ModConfig.Taming.AllowTamingWhileAlerted.Value) || !((BaseAI)__instance).IsAlerted())
			{
				return;
			}
			Tameable component = ((Component)__instance).GetComponent<Tameable>();
			if ((Object)(object)component != (Object)null && component.IsHungry())
			{
				Humanoid component2 = ((Component)__instance).GetComponent<Humanoid>();
				if ((Object)(object)component2 != (Object)null)
				{
					s_updateConsumeItem?.Invoke(__instance, component2, dt);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Tameable), "Tame")]
	public static class TameableTamePatch
	{
		[HarmonyPostfix]
		public static void Postfix(Tameable __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && CreatureRegistry.TryGetProfile(((Component)__instance).gameObject, out CreatureProfile profile) && profile != null && profile.Enabled)
			{
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				string text = ((component == null) ? null : ((object)Unsafe.As<ZDOID, ZDOID>(ref component.GetZDO()?.m_uid)/*cast due to .constrained prefix*/).ToString()) ?? "unknown";
				SubsystemLogger.LogInfo(Subsystem.Taming, "Creature " + profile.DisplayName + " <" + text + "> became tamed.");
			}
		}
	}
}
namespace TameCraft.Core
{
	public class CreatureProfile
	{
		public string PrefabName { get; }

		public string? OffspringPrefabName { get; }

		public string DisplayName { get; }

		public bool Enabled { get; set; }

		public bool IsMammalianProcreation { get; }

		public bool IsEggLayer { get; }

		public CreatureProfile(string prefabName, string displayName, bool enabled = true, bool isMammalianProcreation = true, bool isEggLayer = false, string? offspringPrefabName = null)
		{
			PrefabName = prefabName ?? throw new ArgumentNullException("prefabName");
			DisplayName = displayName ?? throw new ArgumentNullException("displayName");
			Enabled = enabled;
			IsMammalianProcreation = isMammalianProcreation;
			IsEggLayer = isEggLayer;
			OffspringPrefabName = offspringPrefabName;
		}

		public override string ToString()
		{
			return $"CreatureProfile[{PrefabName} ({DisplayName}), Enabled={Enabled}, Mammal={IsMammalianProcreation}, Egg={IsEggLayer}]";
		}
	}
	public static class CreatureRegistry
	{
		private static readonly Dictionary<string, CreatureProfile> _profilesByName;

		private static readonly Dictionary<string, CreatureProfile> _profilesByOffspringName;

		static CreatureRegistry()
		{
			_profilesByName = new Dictionary<string, CreatureProfile>(StringComparer.OrdinalIgnoreCase);
			_profilesByOffspringName = new Dictionary<string, CreatureProfile>(StringComparer.OrdinalIgnoreCase);
			InitializeDefaultProfiles();
		}

		private static void InitializeDefaultProfiles()
		{
			RegisterProfile(new CreatureProfile("Boar", "Boar", enabled: true, isMammalianProcreation: true, isEggLayer: false, "Boar_piggy"));
			RegisterProfile(new CreatureProfile("Wolf", "Wolf", enabled: true, isMammalianProcreation: true, isEggLayer: false, "Wolf_cub"));
			RegisterProfile(new CreatureProfile("Lox", "Lox", enabled: true, isMammalianProcreation: true, isEggLayer: false, "Lox_calf"));
			RegisterProfile(new CreatureProfile("Hen", "Hen", enabled: true, isMammalianProcreation: false, isEggLayer: true, "Chicken"));
			RegisterProfile(new CreatureProfile("Asksvin", "Asksvin", enabled: true, isMammalianProcreation: false, isEggLayer: true, "Asksvin_hatchling"));
		}

		public static void RegisterProfile(CreatureProfile profile)
		{
			if (profile == null)
			{
				throw new ArgumentNullException("profile");
			}
			lock (_profilesByName)
			{
				_profilesByName[profile.PrefabName] = profile;
				if (!string.IsNullOrEmpty(profile.OffspringPrefabName))
				{
					_profilesByOffspringName[profile.OffspringPrefabName] = profile;
				}
			}
		}

		public static bool TryGetProfileByOffspring(string? offspringPrefab, out CreatureProfile? profile)
		{
			profile = null;
			if (string.IsNullOrEmpty(offspringPrefab))
			{
				return false;
			}
			lock (_profilesByName)
			{
				return _profilesByOffspringName.TryGetValue(offspringPrefab, out profile);
			}
		}

		public static bool TryGetProfile(string? prefabName, out CreatureProfile? profile)
		{
			profile = null;
			if (string.IsNullOrEmpty(prefabName))
			{
				return false;
			}
			lock (_profilesByName)
			{
				if (_profilesByName.TryGetValue(prefabName, out profile))
				{
					return true;
				}
				if (_profilesByOffspringName.TryGetValue(prefabName, out profile))
				{
					return true;
				}
				profile = new CreatureProfile(prefabName, prefabName);
				_profilesByName[prefabName] = profile;
				return true;
			}
		}

		public static bool TryGetProfile(GameObject? gameObject, out CreatureProfile? profile)
		{
			profile = null;
			if ((Object)(object)gameObject == (Object)null)
			{
				return false;
			}
			return TryGetProfile(Utils.GetPrefabName(gameObject), out profile);
		}

		public static bool TryGetProfile(Character? character, out CreatureProfile? profile)
		{
			profile = null;
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			return TryGetProfile(((Component)character).gameObject, out profile);
		}

		public static bool IsSupported(string? prefabName)
		{
			if (TryGetProfile(prefabName, out CreatureProfile profile) && profile != null)
			{
				return profile.Enabled;
			}
			return false;
		}

		public static bool IsSupported(GameObject? gameObject)
		{
			if (TryGetProfile(gameObject, out CreatureProfile profile) && profile != null)
			{
				return profile.Enabled;
			}
			return false;
		}

		public static bool IsSupported(Character? character)
		{
			if (TryGetProfile(character, out CreatureProfile profile) && profile != null)
			{
				return profile.Enabled;
			}
			return false;
		}
	}
	public class CreatureState
	{
		private static readonly ConditionalWeakTable<Character, CreatureState> _stateCache = new ConditionalWeakTable<Character, CreatureState>();

		public Character Character { get; }

		public ZNetView? NetView { get; }

		public CreatureProfile Profile { get; }

		public ZDO? ZDO
		{
			get
			{
				if (!((Object)(object)NetView != (Object)null) || !NetView.IsValid())
				{
					return null;
				}
				return NetView.GetZDO();
			}
		}

		public bool IsValid
		{
			get
			{
				if ((Object)(object)NetView != (Object)null && NetView.IsValid())
				{
					return ZDO != null;
				}
				return false;
			}
		}

		public bool IsOwner
		{
			get
			{
				if ((Object)(object)NetView != (Object)null && NetView.IsValid())
				{
					return NetView.IsOwner();
				}
				return false;
			}
		}

		public bool IsRpcRegistered { get; set; }

		public int StateVersion
		{
			get
			{
				ZDO? zDO = ZDO;
				if (zDO == null)
				{
					return 0;
				}
				return zDO.GetInt(ZDOKeys.StateVersionHash, 0);
			}
			set
			{
				if (IsOwner)
				{
					ZDO? zDO = ZDO;
					if (zDO != null)
					{
						zDO.Set(ZDOKeys.StateVersionHash, value, false);
					}
				}
			}
		}

		public int Affection
		{
			get
			{
				ZDO? zDO = ZDO;
				if (zDO == null)
				{
					return 0;
				}
				return zDO.GetInt(ZDOKeys.AffectionHash, 0);
			}
			set
			{
				if (IsOwner)
				{
					ZDO? zDO = ZDO;
					if (zDO != null)
					{
						zDO.Set(ZDOKeys.AffectionHash, value, false);
					}
				}
			}
		}

		public bool IsPregnant
		{
			get
			{
				ZDO? zDO = ZDO;
				if (zDO == null)
				{
					return false;
				}
				return zDO.GetBool(ZDOKeys.IsPregnantHash, false);
			}
			set
			{
				if (IsOwner)
				{
					ZDO? zDO = ZDO;
					if (zDO != null)
					{
						zDO.Set(ZDOKeys.IsPregnantHash, value);
					}
				}
			}
		}

		public long PregnancyStart
		{
			get
			{
				ZDO? zDO = ZDO;
				if (zDO == null)
				{
					return 0L;
				}
				return zDO.GetLong(ZDOKeys.PregnancyStartHash, 0L);
			}
			set
			{
				if (IsOwner)
				{
					ZDO? zDO = ZDO;
					if (zDO != null)
					{
						zDO.Set(ZDOKeys.PregnancyStartHash, value);
					}
				}
			}
		}

		public float PregnancyDuration
		{
			get
			{
				ZDO? zDO = ZDO;
				if (zDO == null)
				{
					return 0f;
				}
				return zDO.GetFloat(ZDOKeys.PregnancyDurationHash, 0f);
			}
			set
			{
				if (IsOwner)
				{
					ZDO? zDO = ZDO;
					if (zDO != null)
					{
						zDO.Set(ZDOKeys.PregnancyDurationHash, value);
					}
				}
			}
		}

		public string ParentId
		{
			get
			{
				ZDO? zDO = ZDO;
				return ((zDO != null) ? zDO.GetString(ZDOKeys.ParentIdHash, string.Empty) : null) ?? string.Empty;
			}
			set
			{
				if (IsOwner)
				{
					ZDO? zDO = ZDO;
					if (zDO != null)
					{
						zDO.Set(ZDOKeys.ParentIdHash, value ?? string.Empty);
					}
				}
			}
		}

		public string MotherId
		{
			get
			{
				ZDO? zDO = ZDO;
				return ((zDO != null) ? zDO.GetString(ZDOKeys.MotherIdHash, string.Empty) : null) ?? string.Empty;
			}
			set
			{
				if (IsOwner)
				{
					ZDO? zDO = ZDO;
					if (zDO != null)
					{
						zDO.Set(ZDOKeys.MotherIdHash, value ?? string.Empty);
					}
				}
			}
		}

		public int Generation
		{
			get
			{
				ZDO? zDO = ZDO;
				if (zDO == null)
				{
					return 0;
				}
				return zDO.GetInt(ZDOKeys.GenerationHash, 0);
			}
			set
			{
				if (IsOwner)
				{
					ZDO? zDO = ZDO;
					if (zDO != null)
					{
						zDO.Set(ZDOKeys.GenerationHash, value, false);
					}
				}
			}
		}

		public long LastPetTime
		{
			get
			{
				ZDO? zDO = ZDO;
				if (zDO == null)
				{
					return 0L;
				}
				return zDO.GetLong(ZDOKeys.LastPetTimeHash, 0L);
			}
			set
			{
				if (IsOwner)
				{
					ZDO? zDO = ZDO;
					if (zDO != null)
					{
						zDO.Set(ZDOKeys.LastPetTimeHash, value);
					}
				}
			}
		}

		public bool HasGeneticData
		{
			get
			{
				if (ZDO != null)
				{
					return ZDO.GetInt(ZDOKeys.GeneticStarLevelHash, -1) >= 0;
				}
				return false;
			}
		}

		public int GeneticStarLevel
		{
			get
			{
				ZDO? zDO = ZDO;
				int num = ((zDO != null) ? zDO.GetInt(ZDOKeys.GeneticStarLevelHash, -1) : (-1));
				if (num >= 0)
				{
					return num;
				}
				return Math.Max(0, Character.GetLevel() - 1);
			}
			set
			{
				if (IsOwner)
				{
					ZDO? zDO = ZDO;
					if (zDO != null)
					{
						zDO.Set(ZDOKeys.GeneticStarLevelHash, value, false);
					}
				}
			}
		}

		public int GeneticGeneration
		{
			get
			{
				ZDO? zDO = ZDO;
				if (zDO == null)
				{
					return Generation;
				}
				return zDO.GetInt(ZDOKeys.GeneticGenerationHash, Generation);
			}
			set
			{
				if (IsOwner)
				{
					ZDO? zDO = ZDO;
					if (zDO != null)
					{
						zDO.Set(ZDOKeys.GeneticGenerationHash, value, false);
					}
				}
			}
		}

		public string GeneticTraits
		{
			get
			{
				ZDO? zDO = ZDO;
				return ((zDO != null) ? zDO.GetString(ZDOKeys.GeneticTraitsHash, string.Empty) : null) ?? string.Empty;
			}
			set
			{
				if (IsOwner)
				{
					ZDO? zDO = ZDO;
					if (zDO != null)
					{
						zDO.Set(ZDOKeys.GeneticTraitsHash, value ?? string.Empty);
					}
				}
			}
		}

		public CreatureState(Character character, ZNetView? netView, CreatureProfile profile)
		{
			Character = character ?? throw new ArgumentNullException("character");
			NetView = netView;
			Profile = profile ?? throw new ArgumentNullException("profile");
		}

		public static bool TryGet(Character? character, out CreatureState? state)
		{
			state = null;
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			return _stateCache.TryGetValue(character, out state);
		}

		public static CreatureState GetOrCreate(Character character, CreatureProfile profile)
		{
			if ((Object)(object)character == (Object)null)
			{
				throw new ArgumentNullException("character");
			}
			if (_stateCache.TryGetValue(character, out CreatureState value))
			{
				return value;
			}
			ZNetView component = ((Component)character).GetComponent<ZNetView>();
			CreatureState creatureState = new CreatureState(character, component, profile);
			_stateCache.Add(character, creatureState);
			return creatureState;
		}
	}
	public static class PersistenceSystem
	{
		public const int CurrentStateVersion = 1;

		public static CreatureState? OnCreatureLoaded(Character character, CreatureProfile profile)
		{
			if ((Object)(object)character == (Object)null || profile == null)
			{
				return null;
			}
			CreatureState state = CreatureState.GetOrCreate(character, profile);
			if (!state.IsValid)
			{
				return state;
			}
			if (!state.IsRpcRegistered && (Object)(object)state.NetView != (Object)null && state.NetView.IsValid())
			{
				try
				{
					state.NetView.Register<string>("TameCraft_Pet", (Action<long, string>)delegate(long sender, string playerName)
					{
						if (state.IsOwner)
						{
							AffectionSubsystem.RecordPetting(state, profile, playerName);
						}
					});
				}
				catch (ArgumentException)
				{
				}
				state.IsRpcRegistered = true;
			}
			string text = ((object)Unsafe.As<ZDOID, ZDOID>(ref state.ZDO?.m_uid)/*cast due to .constrained prefix*/).ToString() ?? "unknown";
			if (state.StateVersion == 0)
			{
				if (state.IsOwner)
				{
					state.StateVersion = 1;
					state.Affection = 0;
					state.IsPregnant = false;
					state.PregnancyStart = 0L;
					state.PregnancyDuration = 0f;
					state.ParentId = string.Empty;
					state.Generation = 0;
					state.LastPetTime = 0L;
					SubsystemLogger.LogDebug(Subsystem.Persistence, $"Initialized {profile.DisplayName} <{text}> with state version {1}");
				}
			}
			else
			{
				SubsystemLogger.LogDebug(Subsystem.Persistence, $"Loaded {profile.DisplayName} <{text}>: affection={state.Affection} lastPet={state.LastPetTime} pregnancy={state.IsPregnant} generation={state.Generation}");
			}
			if (state.IsOwner && !state.HasGeneticData && !OffspringContext.IsInBirthOrMaturityTransition)
			{
				GeneticsSubsystem.InitializeLegacyCreature(state);
			}
			return state;
		}

		public static bool TryGetState(Character? character, out CreatureState? state)
		{
			state = null;
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			if (CreatureState.TryGet(character, out state))
			{
				return true;
			}
			if (CreatureRegistry.TryGetProfile(character, out CreatureProfile profile) && profile != null && profile.Enabled)
			{
				state = CreatureState.GetOrCreate(character, profile);
				return true;
			}
			return false;
		}
	}
	public static class VanillaBaselineCache
	{
		private static readonly object _lock = new object();

		private static readonly Dictionary<string, float> _tamingTimes = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, float> _fedDurations = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, float> _checkIntervals = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, float> _pregnancyDurations = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, float> _growTimes = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, float> _partnerCheckRanges = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, float> _enclosureCheckRanges = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, int> _creatureLimits = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, List<ItemDrop>> _nativeConsumeItems = new Dictionary<string, List<ItemDrop>>(StringComparer.OrdinalIgnoreCase);

		public static string GetCleanPrefabName(GameObject? obj)
		{
			if ((Object)(object)obj == (Object)null)
			{
				return string.Empty;
			}
			return Utils.GetPrefabName(obj);
		}

		public static float GetOrCreateTamingTime(string prefabName, float originalValue)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				if (!(originalValue > 0f))
				{
					return 1800f;
				}
				return originalValue;
			}
			lock (_lock)
			{
				if (!_tamingTimes.TryGetValue(prefabName, out var value))
				{
					value = ((originalValue > 0f) ? originalValue : 1800f);
					_tamingTimes[prefabName] = value;
				}
				return value;
			}
		}

		public static float GetOrCreateFedDuration(string prefabName, float originalValue)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				if (!(originalValue > 0f))
				{
					return 120f;
				}
				return originalValue;
			}
			lock (_lock)
			{
				if (!_fedDurations.TryGetValue(prefabName, out var value))
				{
					value = ((originalValue > 0f) ? originalValue : 120f);
					_fedDurations[prefabName] = value;
				}
				return value;
			}
		}

		public static float GetOrCreateCheckInterval(string prefabName, float originalValue)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				if (!(originalValue > 0f))
				{
					return 30f;
				}
				return originalValue;
			}
			lock (_lock)
			{
				if (!_checkIntervals.TryGetValue(prefabName, out var value))
				{
					value = ((originalValue > 0f) ? originalValue : 30f);
					_checkIntervals[prefabName] = value;
				}
				return value;
			}
		}

		public static float GetOrCreatePregnancyDuration(string prefabName, float originalValue)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return Mathf.Max(0f, originalValue);
			}
			lock (_lock)
			{
				if (!_pregnancyDurations.TryGetValue(prefabName, out var value))
				{
					value = Mathf.Max(0f, originalValue);
					_pregnancyDurations[prefabName] = value;
				}
				return value;
			}
		}

		public static float GetOrCreateGrowTime(string prefabName, float originalValue)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				if (!(originalValue > 0f))
				{
					return 3000f;
				}
				return originalValue;
			}
			lock (_lock)
			{
				if (!_growTimes.TryGetValue(prefabName, out var value))
				{
					value = ((originalValue > 0f) ? originalValue : 3000f);
					_growTimes[prefabName] = value;
				}
				return value;
			}
		}

		public static float GetOrCreatePartnerCheckRange(string prefabName, float originalValue)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				if (!(originalValue > 0f))
				{
					return 3f;
				}
				return originalValue;
			}
			lock (_lock)
			{
				if (!_partnerCheckRanges.TryGetValue(prefabName, out var value))
				{
					value = ((originalValue > 0f) ? originalValue : 3f);
					_partnerCheckRanges[prefabName] = value;
				}
				return value;
			}
		}

		public static float GetOrCreateEnclosureCheckRange(string prefabName, float originalValue)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				if (!(originalValue > 0f))
				{
					return 10f;
				}
				return originalValue;
			}
			lock (_lock)
			{
				if (!_enclosureCheckRanges.TryGetValue(prefabName, out var value))
				{
					value = ((originalValue > 0f) ? originalValue : 10f);
					_enclosureCheckRanges[prefabName] = value;
				}
				return value;
			}
		}

		public static int GetOrCreateCreatureLimit(string prefabName, int originalValue)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				if (originalValue <= 0)
				{
					return 5;
				}
				return originalValue;
			}
			lock (_lock)
			{
				if (!_creatureLimits.TryGetValue(prefabName, out var value))
				{
					value = ((originalValue > 0) ? originalValue : 5);
					_creatureLimits[prefabName] = value;
				}
				return value;
			}
		}

		public static List<ItemDrop> GetOrCreateNativeConsumeItems(string prefabName, List<ItemDrop>? originalItems)
		{
			if (string.IsNullOrEmpty(prefabName))
			{
				return originalItems ?? new List<ItemDrop>();
			}
			lock (_lock)
			{
				if (!_nativeConsumeItems.TryGetValue(prefabName, out List<ItemDrop> value))
				{
					value = ((originalItems != null) ? new List<ItemDrop>(originalItems) : new List<ItemDrop>());
					_nativeConsumeItems[prefabName] = value;
				}
				return value;
			}
		}
	}
}
namespace TameCraft.Configuration
{
	public class GlobalAffectionConfig
	{
		private const string Section = "Affection";

		public ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<bool> PettingAffectionEnabled { get; }

		public ConfigEntry<float> PettingCooldownSeconds { get; }

		public ConfigEntry<int> AffectionPerFeed { get; }

		public ConfigEntry<int> AffectionPerPet { get; }

		public ConfigEntry<int> MaxAffection { get; }

		public ConfigEntry<int> NeutralThreshold { get; }

		public ConfigEntry<int> BondedThreshold { get; }

		public ConfigEntry<int> DevotedThreshold { get; }

		public ConfigEntry<float> AffectionDecayIntervalSeconds { get; }

		public GlobalAffectionConfig(ConfigFile config)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Expected O, but got Unknown
			if (config == null)
			{
				throw new ArgumentNullException("config");
			}
			Enabled = config.Bind<bool>("Affection", "Enabled", true, "Master switch for the Affection subsystem. If false, affection mechanics remain inactive.");
			PettingAffectionEnabled = config.Bind<bool>("Affection", "PettingAffectionEnabled", true, "Enables persistent affection gain when petting a tamed creature.");
			PettingCooldownSeconds = config.Bind<float>("Affection", "PettingCooldownSeconds", 15f, new ConfigDescription("Cooldown in seconds between petting interactions for a creature. (Default: 15s).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 300f), Array.Empty<object>()));
			AffectionPerFeed = config.Bind<int>("Affection", "AffectionPerFeed", 2, new ConfigDescription("Affection points awarded each time a creature consumes food. (Default: 2).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), Array.Empty<object>()));
			AffectionPerPet = config.Bind<int>("Affection", "AffectionPerPet", 2, new ConfigDescription("Affection points awarded each time a creature is petted. (Default: 2).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), Array.Empty<object>()));
			MaxAffection = config.Bind<int>("Affection", "MaxAffection", 20, new ConfigDescription("Maximum affection score a creature can accumulate. (Default: 20).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>()));
			NeutralThreshold = config.Bind<int>("Affection", "NeutralThreshold", 1, "Affection score required to reach Neutral tier.");
			BondedThreshold = config.Bind<int>("Affection", "BondedThreshold", 5, "Affection score required to reach Bonded tier.");
			DevotedThreshold = config.Bind<int>("Affection", "DevotedThreshold", 10, "Affection score required to reach Devoted tier.");
			AffectionDecayIntervalSeconds = config.Bind<float>("Affection", "AffectionDecayIntervalSeconds", 0f, "World seconds of neglect after which affection decreases by 1 point. Set to 0 to disable affection decay entirely (stress-free default).");
		}
	}
	public class GlobalBreedingConfig
	{
		private const string Section = "Breeding";

		public ConfigEntry<bool> Enabled { get; }

		public ConfigEntry<float> BreedingCheckSpeedMultiplier { get; }

		public ConfigEntry<float> PregnancySpeedMultiplier { get; }

		public ConfigEntry<float> PregnancyChance { get; }

		public ConfigEntry<int> RequiredLovePoints { get; }

		public ConfigEntry<bool> RequireAffectionForBreeding { get; }

		public ConfigEntry<int> BreedingAffectionThreshold { get; }

		public ConfigEntry<float> PartnerCheckRangeMultiplier { get; }

		public ConfigEntry<float> EnclosureCheckRangeMultiplier { get; }

		public ConfigEntry<float> CreatureLimitMultiplier { get; }

		public BreedingAdvancedConfig Advanced { get; }

		public GlobalBreedingConfig(ConfigFile config)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Expected O, but got Unknown
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Expected O, but got Unknown
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Expected O, but got Unknown
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Expected O, but got Unknown
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Expected O, but got Unknown
			if (config == null)
			{
				throw new ArgumentNullException("config");
			}
			Enabled = config.Bind<bool>("Breeding", "Enabled", true, "Master switch for TameCraft breeding subsystem. If false, vanilla Procreation runs completely unaltered.");
			BreedingCheckSpeedMultiplier = config.Bind<float>("Breeding", "BreedingCheckSpeedMultiplier", 2f, new ConfigDescription("Speed multiplier for how frequently creatures check for partners and attempt to breed. 1.0 = vanilla (~30s check interval). 2.0 = twice as frequent (~15s check interval).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
			PregnancySpeedMultiplier = config.Bind<float>("Breeding", "PregnancySpeedMultiplier", 2f, new ConfigDescription("Speed multiplier for pregnancy/gestation duration relative to each creature's native Valheim pregnancy duration. 1.0 = native Valheim value (Boar/Wolf 60s, Lox 120s; egg-layers preserved at 0s). 2.0 = approximately twice as fast (Boar/Wolf ~30s, Lox ~60s).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
			PregnancyChance = config.Bind<float>("Breeding", "PregnancyChance", 0.8f, new ConfigDescription("Probability (0.0 to 1.0) of a breeding interaction progressing when conditions are satisfied. (Vanilla: 0.33, TameCraft default: 0.80).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			RequiredLovePoints = config.Bind<int>("Breeding", "RequiredLovePoints", 2, new ConfigDescription("Number of successful love-point interactions required to trigger pregnancy. (Vanilla: Boar/Wolf/Hen/Asksvin 3, Lox 4; TameCraft default: 2).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
			RequireAffectionForBreeding = config.Bind<bool>("Breeding", "RequireAffectionForBreeding", true, "Whether creatures require reaching the breeding affection threshold before they can procreate.");
			BreedingAffectionThreshold = config.Bind<int>("Breeding", "BreedingAffectionThreshold", 5, new ConfigDescription("Minimum affection score required for creatures to mate when RequireAffectionForBreeding is enabled. (Default: 5).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			PartnerCheckRangeMultiplier = config.Bind<float>("Breeding", "PartnerCheckRangeMultiplier", 1f, new ConfigDescription("Multiplier for partner mating search radius relative to creature native baseline (Native: Boar 3m, Wolf 3m, Hen 4m, Asksvin 4m, Lox 8m). 1.0 = native baseline.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
			EnclosureCheckRangeMultiplier = config.Bind<float>("Breeding", "EnclosureCheckRangeMultiplier", 1f, new ConfigDescription("Multiplier for enclosure population check radius relative to creature native baseline (Native: Boar/Wolf/Hen/Asksvin 10m, Lox 20m). 1.0 = native baseline.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
			CreatureLimitMultiplier = config.Bind<float>("Breeding", "CreatureLimitMultiplier", 1f, new ConfigDescription("Multiplier for maximum creatures of this species allowed in enclosure check range before breeding stops (Native: Boar 5, Wolf 4, Lox 4, Hen 10, Asksvin 10). 1.0 = native baseline.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), Array.Empty<object>()));
			Advanced = new BreedingAdvancedConfig(config);
		}
	}
	public class BreedingAdvancedConfig
	{
		private const string Section = "Breeding.Advanced";

		public ConfigEntry<string> PartnerCheckRangeOverrides { get; }

		public ConfigEntry<string> EnclosureCheckRangeOverrides { get; }

		public ConfigEntry<string> CreatureLimitOverrides { get; }

		public ConfigEntry<string> BreedingEnabledOverrides { get; }

		public ConfigEntry<string> UpdateIntervalOverrides { get; }

		public ConfigEntry<string> PregnancyDurationOverrides { get; }

		public ConfigEntry<string> PregnancyChanceOverrides { get; }

		public ConfigEntry<string> RequiredLovePointsOverrides { get; }

		public BreedingAdvancedConfig(ConfigFile config)
		{
			if (config == null)
			{
				throw new ArgumentNullException("config");
			}
			PartnerCheckRangeOverrides = config.Bind<string>("Breeding.Advanced", "PartnerCheckRangeOverrides", string.Empty, "Per-creature mating partner search radius overrides in meters (e.g. 'Boar:6,Wolf:6,Lox:10,Asksvin:6').\nConfigures the maximum distance checked for a partner (native Procreation.m_partnerCheckRange; Vanilla: Boar/Wolf 3m, Hen/Asksvin 4m, Lox 8m).\nSupported canonical creature keys: Boar, Wolf, Lox, Asksvin, Hen (use 'Hen', not 'Chicken').\nCompatible modded creatures with Procreation are supported using their exact registered prefab name.\nFormat: 'CreatureA:Distance,CreatureB:Distance'. Overrides global PartnerCheckRangeMultiplier when set.");
			EnclosureCheckRangeOverrides = config.Bind<string>("Breeding.Advanced", "EnclosureCheckRangeOverrides", string.Empty, "Per-creature enclosure check radius overrides in meters (e.g. 'Boar:15,Lox:25,Wolf:15,Asksvin:15').\nConfigures the radius checked for local population density (native Procreation.m_totalCheckRange; Vanilla: Boar/Wolf/Hen/Asksvin 10m, Lox 20m).\nSupported canonical creature keys: Boar, Wolf, Lox, Asksvin, Hen (use 'Hen', not 'Chicken').\nCompatible modded creatures with Procreation are supported using their exact registered prefab name.\nFormat: 'CreatureA:Distance,CreatureB:Distance'. Overrides global EnclosureCheckRangeMultiplier when set.");
			CreatureLimitOverrides = config.Bind<string>("Breeding.Advanced", "CreatureLimitOverrides", string.Empty, "Per-creature maximum population limit within the enclosure radius (e.g. 'Boar:20,Lox:6,Wolf:20,Asksvin:8').\nIf the number of creatures of this species within the enclosure radius reaches this limit, breeding pauses.\nSupported canonical creature keys: Boar, Wolf, Lox, Asksvin, Hen (use 'Hen', not 'Chicken').\nCompatible modded creatures with Procreation are supported using their exact registered prefab name.\nFormat: 'CreatureA:Count,CreatureB:Count'. Overrides global CreatureLimitMultiplier when set.");
			BreedingEnabledOverrides = config.Bind<string>("Breeding.Advanced", "BreedingEnabledOverrides", string.Empty, "Per-creature breeding enabled overrides (e.g. 'Hen:false,Boar:true').\nSet to false to disable TameCraft breeding modifications for a specific creature and leave it 100% vanilla.\nSupported canonical creature keys: Boar, Wolf, Lox, Asksvin, Hen (use 'Hen', not 'Chicken').\nCompatible modded creatures with Procreation are supported using their exact registered prefab name.\nFormat: 'CreatureA:false,CreatureB:true'.");
			UpdateIntervalOverrides = config.Bind<string>("Breeding.Advanced", "UpdateIntervalOverrides", string.Empty, "Per-creature breeding evaluation frequency in seconds (e.g. 'Boar:15,Wolf:15,Lox:15').\nConfigures seconds between partner and condition checks (native Procreation.m_updateInterval; Vanilla: 30s).\nSupported canonical creature keys: Boar, Wolf, Lox, Asksvin, Hen (use 'Hen', not 'Chicken').\nCompatible modded creatures with Procreation are supported using their exact registered prefab name.\nFormat: 'CreatureA:Seconds,CreatureB:Seconds'. Overrides global BreedingCheckSpeedMultiplier when set.");
			PregnancyDurationOverrides = config.Bind<string>("Breeding.Advanced", "PregnancyDurationOverrides", string.Empty, "Per-creature gestation duration overrides in seconds from conception to birth (e.g. 'Boar:30,Wolf:30,Lox:60').\nConfigures gestation duration (native Procreation.m_pregnancyDuration; Vanilla: Boar 60s, Wolf 60s, Lox 120s).\nApplies to mammalian live-gestation species with native Procreation. Preserved at 0 for egg-layers (Hen, Asksvin).\nSupported canonical creature keys: Boar, Wolf, Lox (and compatible modded live-breeders).\nCompatible modded creatures are supported using their exact registered prefab name.\nFormat: 'CreatureA:Seconds,CreatureB:Seconds'. Overrides global PregnancySpeedMultiplier when set.");
			PregnancyChanceOverrides = config.Bind<string>("Breeding.Advanced", "PregnancyChanceOverrides", string.Empty, "Per-creature conception probability overrides [0.0 to 1.0] when mating conditions are satisfied (e.g. 'Boar:0.8,Wolf:0.8,Lox:0.5').\nConfigures the probability of progressing towards pregnancy each check (native Procreation.m_pregnancyChance).\nSupported canonical creature keys: Boar, Wolf, Lox, Asksvin, Hen (use 'Hen', not 'Chicken').\nCompatible modded creatures with Procreation are supported using their exact registered prefab name.\nFormat: 'CreatureA:Chance,CreatureB:Chance'. Overrides global PregnancyChance when set.");
			RequiredLovePointsOverrides = config.Bind<string>("Breeding.Advanced", "Re