Decompiled source of HeyBooBoo v1.1.0

plugins\HeyBooBoo\TameableBears.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("TameableBears")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("TameableBears")]
[assembly: AssemblyTitle("TameableBears")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace TameableBears
{
	[DisallowMultipleComponent]
	public class BearBabySizer : MonoBehaviour
	{
		public static ConfigEntry<float> BabyScale;

		public static ConfigEntry<float> GrowTime;

		private const string KeyBabyStart = "bear_baby_start";

		private bool _decided;

		private Vector3 _babyScale = Vector3.one;

		private void Awake()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			_babyScale = Vector3.one * Mathf.Max(0.05f, BabyScale?.Value ?? 0.3f);
		}

		private void Update()
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			if (!_decided)
			{
				Decide();
			}
			ZNetView component = ((Component)this).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return;
			}
			long num = component.GetZDO().GetLong("bear_baby_start", 0L);
			if (num != 0L)
			{
				float num2 = Mathf.Max(1f, GrowTime?.Value ?? 1800f);
				float num3 = Mathf.Clamp01((float)((ZNet.instance.GetTime() - new DateTime(num)).TotalSeconds / (double)num2));
				Vector3 val = ((num3 <= 0f) ? _babyScale : Vector3.Lerp(_babyScale, Vector3.one, num3));
				if (((Component)this).transform.localScale != val)
				{
					((Component)this).transform.localScale = val;
				}
				if (num3 >= 1f)
				{
					Debug.Log((object)("[TameableBears] [BabySizer] " + ((Object)((Component)this).gameObject).name + ": finished growing to full size."));
					Object.Destroy((Object)(object)this);
				}
			}
		}

		private void Decide()
		{
			Tameable component = ((Component)this).GetComponent<Tameable>();
			BaseAI component2 = ((Component)this).GetComponent<BaseAI>();
			ZNetView component3 = ((Component)this).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null || !component3.IsValid())
			{
				return;
			}
			TimeSpan timeSinceSpawned = component2.GetTimeSinceSpawned();
			bool flag = component.IsTamed();
			if (component3.GetZDO().GetLong("bear_baby_start", 0L) != 0L)
			{
				_decided = true;
				Debug.Log((object)("[TameableBears] [BabySizer] " + ((Object)((Component)this).gameObject).name + ": born earlier (zdo key set), resuming growth from started ticks."));
			}
			else if (flag && timeSinceSpawned.TotalSeconds <= 30.0)
			{
				if (component3.IsOwner())
				{
					component3.GetZDO().Set("bear_baby_start", ZNet.instance.GetTime().Ticks);
				}
				_decided = true;
				Debug.Log((object)$"[TameableBears] [BabySizer] {((Object)((Component)this).gameObject).name}: newborn detected (age={timeSinceSpawned.TotalSeconds:F1}s, tamed=true), shrinking to baby size.");
			}
			else if (timeSinceSpawned.TotalSeconds > 30.0)
			{
				Debug.Log((object)$"[TameableBears] [BabySizer] {((Object)((Component)this).gameObject).name}: adult bear (age={timeSinceSpawned.TotalSeconds:F1}s, tamed={flag}), leaving full size.");
				Object.Destroy((Object)(object)this);
			}
		}
	}
	internal static class BreedingConfig
	{
		public static ConfigEntry<bool> Enabled;

		public static ConfigEntry<float> FedDuration;

		public static ConfigEntry<int> MaxCreatures;

		public static ConfigEntry<float> TotalCheckRange;

		public static ConfigEntry<float> PartnerCheckRange;

		public static ConfigEntry<float> PregnancyChance;

		public static ConfigEntry<int> RequiredLovePoints;

		public static ConfigEntry<float> PregnancyDuration;

		public static ConfigEntry<float> UpdateInterval;

		public static ConfigEntry<bool> Debug;
	}
	public static class Breeding
	{
		public static string TargetPrefabName;

		public static void ApplyOverrides(GameObject bear, Tameable tameable, Procreation procreation)
		{
			if (BreedingConfig.Enabled != null && BreedingConfig.Enabled.Value)
			{
				tameable.m_fedDuration = BreedingConfig.FedDuration.Value;
				procreation.m_updateInterval = BreedingConfig.UpdateInterval.Value;
				procreation.m_totalCheckRange = BreedingConfig.TotalCheckRange.Value;
				procreation.m_maxCreatures = BreedingConfig.MaxCreatures.Value;
				procreation.m_partnerCheckRange = BreedingConfig.PartnerCheckRange.Value;
				procreation.m_pregnancyChance = BreedingConfig.PregnancyChance.Value;
				procreation.m_pregnancyDuration = BreedingConfig.PregnancyDuration.Value;
				procreation.m_requiredLovePoints = BreedingConfig.RequiredLovePoints.Value;
			}
		}
	}
	[HarmonyPatch(typeof(Procreation), "Procreate")]
	internal static class Procreate_DebugPatch
	{
		private static readonly Dictionary<int, float> LastLog = new Dictionary<int, float>();

		private const float ThrottleSeconds = 20f;

		private static void Postfix(Procreation __instance)
		{
			//IL_00e1: 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)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			if (BreedingConfig.Debug == null || !BreedingConfig.Debug.Value)
			{
				return;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid())
			{
				return;
			}
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(component.GetZDO().GetPrefab()) : null);
			string text = (((Object)(object)val != (Object)null) ? ((Object)val).name : null);
			if (string.IsNullOrEmpty(Breeding.TargetPrefabName) || text != Breeding.TargetPrefabName)
			{
				return;
			}
			Tameable component2 = ((Component)__instance).GetComponent<Tameable>();
			if (!((Object)(object)component2 == (Object)null) && component2.IsTamed())
			{
				float time = Time.time;
				if (!LastLog.TryGetValue(((Object)__instance).GetInstanceID(), out var value) || !(time - value < 20f))
				{
					LastLog[((Object)__instance).GetInstanceID()] = time;
					BaseAI component3 = ((Component)__instance).GetComponent<BaseAI>();
					Vector3 position = ((Component)__instance).transform.position;
					long num = component.GetZDO().GetLong(ZDOVars.s_pregnant, 0L);
					bool flag = num != 0;
					bool flag2 = flag && (ZNet.instance.GetTime() - new DateTime(num)).TotalSeconds > (double)__instance.m_pregnancyDuration;
					int num2 = (((Object)(object)val != (Object)null) ? SpawnSystem.GetNrOfInstances(val, position, __instance.m_totalCheckRange, false, false) : (-1));
					int num3 = (((Object)(object)val != (Object)null) ? SpawnSystem.GetNrOfInstances(val, position, __instance.m_partnerCheckRange, false, true) : (-1));
					Debug.Log((object)$"[TameableBears] [Breeding] {text}: owner={component.IsOwner()} tamed={true} hungry={component2.IsHungry()} alert={(Object)(object)component3 != (Object)null && component3.IsAlerted()} love={__instance.GetLovePoints()}/{__instance.m_requiredLovePoints} pregnant={flag} due={flag2} pair={num3} total={num2}/{__instance.m_maxCreatures} (tcr={__instance.m_totalCheckRange} pcr={__instance.m_partnerCheckRange})");
				}
			}
		}
	}
	[BepInPlugin("wayfarers.tameablebears", "HeyBooBoo!", "1.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "wayfarers.tameablebears";

		public const string Name = "HeyBooBoo!";

		public const string Version = "1.1.0";

		private void Awake()
		{
			BearBabySizer.BabyScale = ((BaseUnityPlugin)this).Config.Bind<float>("Appearance", "BabyScale", 0.3f, "Spawn scale of newborn (bred) bears. 1.0 = adult size.");
			BearBabySizer.GrowTime = ((BaseUnityPlugin)this).Config.Bind<float>("Growth", "GrowTime", 1800f, "Seconds for a baby bear to grow to full size. 1800 = one Valheim day.");
			BreedingConfig.Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Breeding", "Enabled", true, "Enable bear breeding.");
			BreedingConfig.FedDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "FedDuration", 7200f, "Seconds a bear stays 'fed' after eating (breeding is blocked while hungry).");
			BreedingConfig.MaxCreatures = ((BaseUnityPlugin)this).Config.Bind<int>("Breeding", "MaxCreatures", 30, "Max bears (tamed+wild, incl. cubs) allowed within TotalCheckRange before breeding stops.");
			BreedingConfig.TotalCheckRange = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "TotalCheckRange", 20f, "Radius used for the total-bear count.");
			BreedingConfig.PartnerCheckRange = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "PartnerCheckRange", 30f, "Radius a second tamed bear must be within for a pair.");
			BreedingConfig.PregnancyChance = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "PregnancyChance", 0.25f, "Chance per tick to gain a love point (0..1).");
			BreedingConfig.RequiredLovePoints = ((BaseUnityPlugin)this).Config.Bind<int>("Breeding", "RequiredLovePoints", 5, "Love points needed before the bear gets pregnant.");
			BreedingConfig.PregnancyDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "PregnancyDuration", 1800f, "Seconds a bear stays pregnant before giving birth. 1800 = one Valheim day.");
			BreedingConfig.UpdateInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Breeding", "UpdateInterval", 2f, "Seconds between breeding checks.");
			BreedingConfig.Debug = ((BaseUnityPlugin)this).Config.Bind<bool>("Breeding", "DebugLog", true, "Log one breeding status line per tamed bear every ~20 seconds.");
			Harmony.CreateAndPatchAll(typeof(Plugin).Assembly, (string)null);
			PrefabManager.OnVanillaPrefabsAvailable += MakeBearsTameable;
		}

		private void OnDestroy()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= MakeBearsTameable;
		}

		private void MakeBearsTameable()
		{
			GameObject prefab = Cache.GetPrefab<GameObject>("Wolf");
			GameObject val = null;
			string text = null;
			string[] array = new string[2] { "Bjorn", "Bear" };
			foreach (string text2 in array)
			{
				GameObject prefab2 = Cache.GetPrefab<GameObject>(text2);
				if ((Object)(object)prefab2 != (Object)null && (Object)(object)prefab2.GetComponent<MonsterAI>() != (Object)null)
				{
					val = prefab2;
					text = text2;
					break;
				}
			}
			if ((Object)(object)prefab == (Object)null || (Object)(object)val == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"Missing prefabs (wolf={(Object)(object)prefab != (Object)null} bear={(Object)(object)val != (Object)null})");
				return;
			}
			Tameable component = prefab.GetComponent<Tameable>();
			MonsterAI component2 = prefab.GetComponent<MonsterAI>();
			MonsterAI component3 = val.GetComponent<MonsterAI>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"Missing components (wolfTameable={(Object)(object)component != (Object)null} wolfAI={(Object)(object)component2 != (Object)null} bearAI={(Object)(object)component3 != (Object)null})");
				return;
			}
			component3.m_consumeItems = new List<ItemDrop>(component2.m_consumeItems);
			component3.m_consumeRange = component2.m_consumeRange;
			component3.m_consumeSearchRange = component2.m_consumeSearchRange;
			component3.m_consumeSearchInterval = component2.m_consumeSearchInterval;
			if ((Object)(object)val.GetComponent<Tameable>() != (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Bear already has a Tameable component; nothing to do.");
				return;
			}
			Tameable val2 = val.AddComponent<Tameable>();
			val2.m_tamingTime = component.m_tamingTime;
			val2.m_fedDuration = component.m_fedDuration;
			val2.m_commandable = component.m_commandable;
			val2.m_tameText = component.m_tameText;
			val2.m_nameBeforeText = component.m_nameBeforeText;
			val2.m_tamingSpeedMultiplierRange = component.m_tamingSpeedMultiplierRange;
			val2.m_tamingBoostMultiplier = component.m_tamingBoostMultiplier;
			val2.m_tamedEffect = component.m_tamedEffect;
			val2.m_sootheEffect = component.m_sootheEffect;
			val2.m_petEffect = component.m_petEffect;
			val2.m_randomStartingName = new List<string>(component.m_randomStartingName);
			Procreation component4 = prefab.GetComponent<Procreation>();
			Procreation component5 = val.GetComponent<Procreation>();
			if ((Object)(object)component4 != (Object)null && (Object)(object)component5 == (Object)null)
			{
				component5 = val.AddComponent<Procreation>();
				component5.m_updateInterval = component4.m_updateInterval;
				component5.m_totalCheckRange = component4.m_totalCheckRange;
				component5.m_maxCreatures = component4.m_maxCreatures;
				component5.m_partnerCheckRange = component4.m_partnerCheckRange;
				component5.m_pregnancyChance = component4.m_pregnancyChance;
				component5.m_pregnancyDuration = component4.m_pregnancyDuration;
				component5.m_requiredLovePoints = component4.m_requiredLovePoints;
				component5.m_offspring = val;
				component5.m_minOffspringLevel = component4.m_minOffspringLevel;
				component5.m_spawnOffset = component4.m_spawnOffset;
				component5.m_spawnOffsetMax = component4.m_spawnOffsetMax;
				component5.m_spawnRandomDirection = component4.m_spawnRandomDirection;
				component5.m_birthEffects = component4.m_birthEffects;
				component5.m_loveEffects = component4.m_loveEffects;
				Breeding.TargetPrefabName = text;
				Breeding.ApplyOverrides(val, val2, component5);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Bears can now breed (pairs of fed, tamed bears produce cubs).");
			}
			if ((Object)(object)val.GetComponent<BearBabySizer>() == (Object)null)
			{
				val.AddComponent<BearBabySizer>();
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Baby bears spawn small and grow to full size (" + text + ")."));
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Bears are now tameable! Feed them raw meat, drop it near them, and wait (like wolves).");
		}
	}
}