Decompiled source of BreedingInPen v1.0.0

plugins/BreedingInPen.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("BreedingInPen")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a132911eeaa2f387033c9213b83b8d67d0146b7f")]
[assembly: AssemblyProduct("BreedingInPen")]
[assembly: AssemblyTitle("BreedingInPen")]
[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;
		}
	}
}
[BepInPlugin("Tie.BreedingInPen", "BreedingInPen", "1.0.0")]
public class BreedingInPenPlugin : BaseUnityPlugin
{
	private sealed class Breeder
	{
		public string Name;

		public ConfigEntry<int> MaxCreatures;

		public int Default;

		public float SpawnOffset;

		public float SpawnOffsetMax;

		public float PartnerRange;
	}

	public const string Guid = "Tie.BreedingInPen";

	public const string Version = "1.0.0";

	private static readonly int s_hasFields = StringExtensionMethods.GetStableHashCode("HasFields");

	private static readonly int s_hasProcreationFields = StringExtensionMethods.GetStableHashCode("HasFieldsProcreation");

	private static readonly int s_maxCreaturesField = StringExtensionMethods.GetStableHashCode("Procreation.m_maxCreatures");

	private static readonly int s_spawnOffsetField = StringExtensionMethods.GetStableHashCode("Procreation.m_spawnOffset");

	private static readonly int s_spawnOffsetMaxField = StringExtensionMethods.GetStableHashCode("Procreation.m_spawnOffsetMax");

	private static readonly int KeyPlaced = StringExtensionMethods.GetStableHashCode("BreedingInPen_placed");

	private ConfigEntry<float> _tickSeconds;

	private ConfigEntry<bool> _debugLog;

	private ConfigEntry<bool> _birthAtParent;

	private ConfigEntry<bool> _birthBetweenParents;

	private ConfigEntry<float> _newbornSeconds;

	private readonly Dictionary<int, Breeder> _breeders = new Dictionary<int, Breeder>();

	private readonly Dictionary<int, List<int>> _parentsOf = new Dictionary<int, List<int>>();

	private readonly List<ZDO> _sectorObjects = new List<ZDO>();

	private readonly HashSet<ZDOID> _seen = new HashSet<ZDOID>();

	private readonly List<ZDO> _adults = new List<ZDO>();

	private readonly List<ZDO> _young = new List<ZDO>();

	private bool _resolved;

	private float _timer;

	private void Awake()
	{
		_tickSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "TickSeconds", 2f, "How often (seconds) creatures near players are checked. Newborns are moved on the first check after birth.");
		_debugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLog", false, "Log every creature changed or newborn moved.");
		_birthAtParent = ((BaseUnityPlugin)this).Config.Bind<bool>("Pen", "BirthAtParent", true, "Babies appear where the mother stands instead of up to 2 m behind her, so they never start on the other side of a pen fence.");
		_birthBetweenParents = ((BaseUnityPlugin)this).Config.Bind<bool>("Pen", "BirthBetweenParents", true, "A newborn is moved between its mother and her nearest tamed partner a moment after birth (it may visibly jump once). Both parents are inside the pen, so the baby is too.");
		_newbornSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Pen", "NewbornSeconds", 20f, "Only tamed babies younger than this are moved, so babies that already walked around are left alone.");
	}

	private void Update()
	{
		if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null)
		{
			_resolved = false;
			return;
		}
		_timer += Time.deltaTime;
		if (_timer < Mathf.Max(0.5f, _tickSeconds.Value))
		{
			return;
		}
		_timer = 0f;
		try
		{
			if (!_resolved)
			{
				Resolve();
			}
			Tick();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)ex);
		}
	}

	private void Resolve()
	{
		_resolved = true;
		_breeders.Clear();
		_parentsOf.Clear();
		foreach (GameObject item in ZNetScene.instance.m_prefabs.OrderBy<GameObject, string>((GameObject g) => ((Object)g).name, StringComparer.Ordinal))
		{
			Procreation component = item.GetComponent<Procreation>();
			if ((Object)(object)component == (Object)null || (Object)(object)item.GetComponent<Character>() == (Object)null || (Object)(object)item.GetComponent<Tameable>() == (Object)null || (Object)(object)item.GetComponent<ZNetView>() == (Object)null)
			{
				continue;
			}
			_breeders[StringExtensionMethods.GetStableHashCode(((Object)item).name)] = new Breeder
			{
				Name = ((Object)item).name,
				MaxCreatures = ((BaseUnityPlugin)this).Config.Bind<int>("MaxCreatures", ((Object)item).name, -1, $"Tamed {((Object)item).name} stop breeding when this many {((Object)item).name} and their young are within {component.m_totalCheckRange:0.#} m (the game's check). -1 keeps the game's value, {component.m_maxCreatures}."),
				Default = component.m_maxCreatures,
				SpawnOffset = component.m_spawnOffset,
				SpawnOffsetMax = component.m_spawnOffsetMax,
				PartnerRange = component.m_partnerCheckRange
			};
			GameObject val = (((Object)(object)component.m_offspring == (Object)null) ? null : ZNetScene.instance.GetPrefab(((Object)component.m_offspring).name));
			if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)item && (Object)(object)val.GetComponent<Character>() != (Object)null)
			{
				int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)val).name);
				if (!_parentsOf.TryGetValue(stableHashCode, out var value))
				{
					value = (_parentsOf[stableHashCode] = new List<int>());
				}
				value.Add(StringExtensionMethods.GetStableHashCode(((Object)item).name));
			}
		}
		string text = string.Join(", ", (from b in _breeders.Values
			where b.MaxCreatures.Value >= 0
			select b.Name + " " + b.MaxCreatures.Value).DefaultIfEmpty("game values"));
		((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} breeding creature(s): {1}. Limits: {2}. Birth at parent: {3}, between parents: {4}.", _breeders.Count, string.Join(", ", _breeders.Values.Select((Breeder b) => b.Name)), text, _birthAtParent.Value, _birthBetweenParents.Value));
	}

	private void Tick()
	{
		if (_breeders.Count == 0)
		{
			return;
		}
		Collect();
		foreach (ZDO adult in _adults)
		{
			ApplyOverrides(adult);
		}
		if (!_birthBetweenParents.Value)
		{
			return;
		}
		foreach (ZDO item in _young)
		{
			PlaceNewborn(item);
		}
	}

	private void Collect()
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		_adults.Clear();
		_young.Clear();
		_seen.Clear();
		SimulationDistance syncedSimulationDistance = ZNet.instance.GetSyncedSimulationDistance();
		SimulationDistance val = default(SimulationDistance);
		((SimulationDistance)(ref val))..ctor(((SimulationDistance)(ref syncedSimulationDistance)).NearSimulationDistance, 0, ((SimulationDistance)(ref syncedSimulationDistance)).IsClassic);
		List<Vector3> list = (from p in ZNet.instance.GetPeers()
			select p.GetRefPos()).ToList();
		if (!ZNet.instance.IsDedicated())
		{
			list.Add(ZNet.instance.GetReferencePosition());
		}
		foreach (Vector3 item in list)
		{
			_sectorObjects.Clear();
			ZDOMan.instance.FindSectorObjects(ZoneSystem.GetZone(item), val, _sectorObjects, (List<ZDO>)null);
			foreach (ZDO sectorObject in _sectorObjects)
			{
				if (sectorObject.IsValid() && _seen.Add(sectorObject.m_uid) && sectorObject.GetBool(ZDOVars.s_tamed, false))
				{
					int prefab = sectorObject.GetPrefab();
					if (_breeders.ContainsKey(prefab))
					{
						_adults.Add(sectorObject);
					}
					else if (_parentsOf.ContainsKey(prefab))
					{
						_young.Add(sectorObject);
					}
				}
			}
		}
	}

	private void ApplyOverrides(ZDO zdo)
	{
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
		//IL_011e: Unknown result type (might be due to invalid IL or missing references)
		Breeder breeder = _breeders[zdo.GetPrefab()];
		bool value = _birthAtParent.Value;
		if (Override(zdo, s_maxCreaturesField, (breeder.MaxCreatures.Value >= 0) ? new int?(breeder.MaxCreatures.Value) : ((int?)null), breeder.Default) | Override(zdo, s_spawnOffsetField, value ? new float?(0f) : ((float?)null), breeder.SpawnOffset) | Override(zdo, s_spawnOffsetMaxField, value ? new float?(0f) : ((float?)null), breeder.SpawnOffsetMax))
		{
			zdo.Set(s_hasFields, true);
			zdo.Set(s_hasProcreationFields, true);
			ZDO val = Replace(zdo, zdo.GetPosition());
			Debug($"{breeder.Name} {zdo.m_uid}: breeding limit {zdo.GetInt(s_maxCreaturesField, breeder.Default)}, birth at parent {value}; replaced by {val.m_uid}.");
		}
	}

	private static bool Override(ZDO zdo, int key, int? wanted, int gameValue)
	{
		int num = default(int);
		bool flag = zdo.GetInt(key, ref num);
		int num2 = wanted ?? gameValue;
		if ((!wanted.HasValue && !flag) || (flag && num == num2))
		{
			return false;
		}
		zdo.Set(key, num2, false);
		return true;
	}

	private static bool Override(ZDO zdo, int key, float? wanted, float gameValue)
	{
		float num = default(float);
		bool flag = zdo.GetFloat(key, ref num);
		float num2 = wanted ?? gameValue;
		if ((!wanted.HasValue && !flag) || (flag && num == num2))
		{
			return false;
		}
		zdo.Set(key, num2);
		return true;
	}

	private void PlaceNewborn(ZDO baby)
	{
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//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_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_020d: Unknown result type (might be due to invalid IL or missing references)
		//IL_021b: Unknown result type (might be due to invalid IL or missing references)
		//IL_022b: Unknown result type (might be due to invalid IL or missing references)
		long num = baby.GetLong(ZDOVars.s_spawnTime, 0L);
		if (num == 0L || !baby.GetBool(ZDOVars.s_tamed, false) || baby.GetBool(KeyPlaced, false) || (ZNet.instance.GetTime() - new DateTime(num)).TotalSeconds > (double)_newbornSeconds.Value)
		{
			return;
		}
		Vector3 pos = baby.GetPosition();
		List<int> parents = _parentsOf[baby.GetPrefab()];
		ZDO mother = _adults.Where(delegate(ZDO z)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (parents.Contains(z.GetPrefab()) && z.GetBool(ZDOVars.s_tamed, false))
			{
				Vector3 val4 = z.GetPosition() - pos;
				return ((Vector3)(ref val4)).sqrMagnitude <= 16f;
			}
			return false;
		}).OrderBy(delegate(ZDO z)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val4 = z.GetPosition() - pos;
			return ((Vector3)(ref val4)).sqrMagnitude;
		}).FirstOrDefault();
		if (mother == null)
		{
			return;
		}
		Vector3 at = mother.GetPosition();
		float range = Mathf.Max(_breeders[mother.GetPrefab()].PartnerRange, 3f) + 5f;
		ZDO val = _adults.Where(delegate(ZDO z)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (z != mother && z.GetPrefab() == mother.GetPrefab() && z.GetBool(ZDOVars.s_tamed, false))
			{
				Vector3 val4 = z.GetPosition() - at;
				return ((Vector3)(ref val4)).sqrMagnitude <= range * range;
			}
			return false;
		}).OrderBy(delegate(ZDO z)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val4 = z.GetPosition() - at;
			return ((Vector3)(ref val4)).sqrMagnitude;
		}).FirstOrDefault();
		baby.Set(KeyPlaced, true);
		if (val != null)
		{
			Vector3 val2 = Vector3.Lerp(at, val.GetPosition(), Random.Range(0.3f, 0.7f));
			val2.y = Mathf.Max(at.y, val.GetPosition().y) + 0.5f;
			ZDO val3 = Replace(baby, val2);
			Debug($"{((Object)ZNetScene.instance.GetPrefab(baby.GetPrefab())).name} {baby.m_uid} born at ({pos.x:0}, {pos.y:0}, {pos.z:0}) moved between its parents to ({val2.x:0}, {val2.y:0}, {val2.z:0}) as {val3.m_uid}.");
		}
	}

	private static ZDO Replace(ZDO zdo, Vector3 pos)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Expected O, but got Unknown
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		ZPackage val = new ZPackage();
		zdo.Serialize(val);
		val.SetPos(0);
		ZDO obj = ZDOMan.instance.CreateNewZDO(pos, zdo.GetPrefab());
		obj.Deserialize(val);
		obj.SetPosition(pos);
		obj.SetOwner(0L);
		zdo.SetOwnerInternal(ZDOMan.GetSessionID());
		ZDOMan.instance.DestroyZDO(zdo);
		return obj;
	}

	private void Debug(string text)
	{
		if (_debugLog.Value)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)text);
		}
	}
}