Decompiled source of Smolkr Pen Gender Targets v1.1.1

SmolkrPenGenderTargets.Core.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;

[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("SmolkrPenGenderTargets.Core")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+6af857529bfa1b02257de924d3cff2337dd12044")]
[assembly: AssemblyProduct("SmolkrPenGenderTargets.Core")]
[assembly: AssemblyTitle("SmolkrPenGenderTargets.Core")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace SmolkrPenGenderTargets.Core;

public enum CullReason
{
	WithinLimit,
	BelowMinimumPopulation,
	NoAdults,
	FemaleChosen,
	MaleChosen,
	NoSurplusAdults
}
public readonly struct CullDecision
{
	public int VictimIndex { get; }

	public CullReason Reason { get; }

	public HerdCensus Census { get; }

	public HerdTargets Targets { get; }

	public bool HasVictim => VictimIndex >= 0;

	public CullDecision(int victimIndex, CullReason reason, HerdCensus census, HerdTargets targets)
	{
		VictimIndex = victimIndex;
		Reason = reason;
		Census = census;
		Targets = targets;
	}

	public string Describe()
	{
		return Reason switch
		{
			CullReason.WithinLimit => $"Nothing - the pen holds {Census.Total} of {Targets.SlaughterLimit} allowed.", 
			CullReason.BelowMinimumPopulation => "Nothing - the pen is below its minimum population.", 
			CullReason.NoAdults => "Nothing - over the limit, but only pups are left.", 
			CullReason.NoSurplusAdults => "Nothing - the surplus gender has no adult available to slaughter.", 
			CullReason.FemaleChosen => $"An adult female ({Census.AdultFemales + Census.FemalePups} females for {Targets.FemalesToKeep} wanted, " + $"{Census.AdultMales + Census.MalePups} males for {Targets.MalesToKeep} wanted, young included).", 
			CullReason.MaleChosen => $"An adult male ({Census.AdultMales + Census.MalePups} males for {Targets.MalesToKeep} wanted, " + $"{Census.AdultFemales + Census.FemalePups} females for {Targets.FemalesToKeep} wanted, young included).", 
			_ => Reason.ToString(), 
		};
	}
}
public static class CullPlanner
{
	public static CullDecision Decide(IReadOnlyList<PenAnimal> animals, HerdTargets targets, int penPopulation, int minimumPopulation)
	{
		HerdCensus census = HerdCensus.Count(animals);
		if (penPopulation <= targets.SlaughterLimit)
		{
			return None(CullReason.WithinLimit, census, targets);
		}
		if (penPopulation < minimumPopulation)
		{
			return None(CullReason.BelowMinimumPopulation, census, targets);
		}
		if (census.AdultFemales == 0 && census.AdultMales == 0)
		{
			return None(CullReason.NoAdults, census, targets);
		}
		int num = census.AdultFemales + census.FemalePups - targets.FemalesToKeep;
		int num2 = census.AdultMales + census.MalePups - targets.MalesToKeep;
		bool flag = num > 0 && census.AdultFemales > 0;
		bool flag2 = num2 > 0 && census.AdultMales > 0;
		if (!flag && !flag2)
		{
			return None(CullReason.NoSurplusAdults, census, targets);
		}
		bool flag3 = flag && (!flag2 || num > num2);
		int victimIndex = FindLastAdult(animals, flag3);
		CullReason reason = (flag3 ? CullReason.FemaleChosen : CullReason.MaleChosen);
		return new CullDecision(victimIndex, reason, census, targets);
	}

	private static int FindLastAdult(IReadOnlyList<PenAnimal> animals, bool female)
	{
		for (int num = animals.Count - 1; num >= 0; num--)
		{
			if (animals[num].IsMature && animals[num].IsFemale == female)
			{
				return num;
			}
		}
		return -1;
	}

	private static CullDecision None(CullReason reason, HerdCensus census, HerdTargets targets)
	{
		return new CullDecision(-1, reason, census, targets);
	}
}
public readonly struct HerdCensus
{
	public int AdultFemales { get; }

	public int AdultMales { get; }

	public int FemalePups { get; }

	public int MalePups { get; }

	public int Total => AdultFemales + AdultMales + FemalePups + MalePups;

	private HerdCensus(int adultFemales, int adultMales, int femalePups, int malePups)
	{
		AdultFemales = adultFemales;
		AdultMales = adultMales;
		FemalePups = femalePups;
		MalePups = malePups;
	}

	public static HerdCensus Count(IReadOnlyList<PenAnimal> animals)
	{
		int num = 0;
		int num2 = 0;
		int num3 = 0;
		int num4 = 0;
		if (animals == null)
		{
			return new HerdCensus(0, 0, 0, 0);
		}
		foreach (PenAnimal animal in animals)
		{
			if (animal.IsMature && animal.IsFemale)
			{
				num++;
			}
			else if (animal.IsMature)
			{
				num2++;
			}
			else if (animal.IsFemale)
			{
				num3++;
			}
			else
			{
				num4++;
			}
		}
		return new HerdCensus(num, num2, num3, num4);
	}

	public int Adults(bool female)
	{
		if (!female)
		{
			return AdultMales;
		}
		return AdultFemales;
	}

	public int Pups(bool female)
	{
		if (!female)
		{
			return MalePups;
		}
		return FemalePups;
	}
}
public readonly struct HerdTargets
{
	public int SlaughterLimit { get; }

	public int FemalesToKeep { get; }

	public int MalesToKeep => SlaughterLimit - FemalesToKeep;

	public static HerdTargets Create(int slaughterLimit, int femalesToKeep)
	{
		int num = Math.Max(0, slaughterLimit);
		int femalesToKeep2 = Math.Min(Math.Max(0, femalesToKeep), num);
		return new HerdTargets(num, femalesToKeep2);
	}

	private HerdTargets(int slaughterLimit, int femalesToKeep)
	{
		SlaughterLimit = slaughterLimit;
		FemalesToKeep = femalesToKeep;
	}

	public int ToKeep(bool female)
	{
		if (!female)
		{
			return MalesToKeep;
		}
		return FemalesToKeep;
	}
}
public readonly struct PenAnimal
{
	public bool IsFemale { get; }

	public bool IsMature { get; }

	public static PenAnimal AdultFemale => new PenAnimal(isFemale: true, isMature: true);

	public static PenAnimal AdultMale => new PenAnimal(isFemale: false, isMature: true);

	public static PenAnimal FemalePup => new PenAnimal(isFemale: true, isMature: false);

	public static PenAnimal MalePup => new PenAnimal(isFemale: false, isMature: false);

	public PenAnimal(bool isFemale, bool isMature)
	{
		IsFemale = isFemale;
		IsMature = isMature;
	}
}

SmolkrPenGenderTargets.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 System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.Reflection;
using Microsoft.CodeAnalysis;
using SSSGame;
using SSSGame.AI;
using SSSGame.UI;
using SandSailorStudio.Inventory;
using SandSailorStudio.Storage;
using SandSailorStudio.UI;
using SmolkrPenGenderTargets.Core;
using SmolkrPenGenderTargets.Runtime;
using SmolkrPenGenderTargets.UI;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("SmolkrPenGenderTargets")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+6af857529bfa1b02257de924d3cff2337dd12044")]
[assembly: AssemblyProduct("SmolkrPenGenderTargets")]
[assembly: AssemblyTitle("SmolkrPenGenderTargets")]
[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 SmolkrPenGenderTargets
{
	[BepInPlugin("aska.smolkr.pen.gender.targets", "Smolkr and Kyckling Pen Gender Limits", "1.1.1")]
	public sealed class Plugin : BasePlugin
	{
		public const string PluginGuid = "aska.smolkr.pen.gender.targets";

		public const string PluginName = "Smolkr and Kyckling Pen Gender Limits";

		public const string PluginVersion = "1.1.1";

		private Harmony _harmony;

		internal static ManualLogSource Log { get; private set; }

		internal static ConfigEntry<bool> Enabled { get; private set; }

		internal static ConfigEntry<bool> ShowRow { get; private set; }

		internal static ConfigEntry<float> RowOffsetX { get; private set; }

		internal static ConfigEntry<float> RowOffsetY { get; private set; }

		public override void Load()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			Log = ((BasePlugin)this).Log;
			BindConfig();
			InstallPatches();
			ManualLogSource log = Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(20, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Smolkr and Kyckling Pen Gender Limits");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.1.1");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded (enabled=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(Enabled.Value);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(").");
			}
			log.LogInfo(val);
		}

		public override bool Unload()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			return true;
		}

		private void BindConfig()
		{
			Enabled = ((BasePlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When false, every smolkr and kyckling pen slaughters exactly as in vanilla, whatever each pen's gender targets are set to. The targets themselves are kept.");
			ShowRow = ((BasePlugin)this).Config.Bind<bool>("Interface", "ShowRow", true, "Add a 'Females to keep' row under the slaughter limit in a smolkr or kyckling pen's slaughter task. Turning this off hides the row only; pens keep using the targets they already have.");
			RowOffsetX = ((BasePlugin)this).Config.Bind<float>("Interface", "RowOffsetX", 0f, "Moves the 'Females to keep' row sideways, in UI units. Only needed if the row overlaps something after a game update; the default places it directly under the slaughter limit.");
			RowOffsetY = ((BasePlugin)this).Config.Bind<float>("Interface", "RowOffsetY", 0f, "Moves the 'Females to keep' row up (positive) or down (negative), in UI units. Only needed if the row overlaps something after a game update.");
		}

		private void InstallPatches()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			try
			{
				_harmony = new Harmony("aska.smolkr.pen.gender.targets");
				_harmony.PatchAll();
				Log.LogInfo((object)"Harmony patches installed.");
			}
			catch (Exception value)
			{
				Log.LogError((object)("Failed to install Harmony patches - smolkr and kyckling pens will behave as vanilla. This usually means ASKA updated and the interop assemblies need regenerating. " + $"Details: {value}"));
			}
		}
	}
}
namespace SmolkrPenGenderTargets.UI
{
	internal static class FemalesToKeepRow
	{
		private sealed class RowState
		{
			internal GameObject Row;

			internal IncreaseDecreasePanel Control;

			internal TMP_Text Title;

			internal TaskDataPanel Panel;

			internal AnimalPen Pen;
		}

		private const int OffValue = -1;

		private const float RowSpacing = 6f;

		private static readonly Dictionary<IntPtr, RowState> RowsByPanel = new Dictionary<IntPtr, RowState>();

		private static readonly Dictionary<IntPtr, RowState> RowsByControl = new Dictionary<IntPtr, RowState>();

		private static bool _layoutLogged;

		internal static void OnQuantitySet(TaskDataPanel panel, WorkstationTaskData task)
		{
			object obj;
			if (task == null)
			{
				obj = null;
			}
			else
			{
				AnimalSlaughterTaskData obj2 = ((Il2CppObjectBase)task).TryCast<AnimalSlaughterTaskData>();
				obj = ((obj2 != null) ? obj2.SmolkrPen : null);
			}
			AnimalPen val = (AnimalPen)obj;
			if ((Object)(object)val == (Object)null || !Plugin.ShowRow.Value)
			{
				if (RowsByPanel.TryGetValue(((Il2CppObjectBase)panel).Pointer, out var value))
				{
					Hide(value);
				}
				return;
			}
			RowState orBuild = GetOrBuild(panel);
			if (orBuild != null)
			{
				Show(orBuild, val);
			}
		}

		internal static void OnLimitChanged(TaskDataPanel panel)
		{
			if (RowsByPanel.TryGetValue(((Il2CppObjectBase)panel).Pointer, out var value) && !((Object)(object)value.Pen == (Object)null) && !((Object)(object)value.Row == (Object)null))
			{
				Show(value, value.Pen);
			}
		}

		internal static void OnControlTextRefreshed(IncreaseDecreasePanel control)
		{
			if (RowsByControl.TryGetValue(((Il2CppObjectBase)control).Pointer, out var _))
			{
				string text = ((control.Value <= -1) ? "Off" : control.Value.ToString());
				if ((Object)(object)control.ValueText != (Object)null)
				{
					((TMP_Text)control.ValueText).text = text;
				}
				if ((Object)(object)control.InputField != (Object)null)
				{
					control.InputField.SetTextWithoutNotify(text);
				}
			}
		}

		private static void Show(RowState state, AnimalPen pen)
		{
			state.Pen = pen;
			int num = CurrentLimit(state);
			int femalesToKeep;
			int num2 = (PenTargetStore.TryGet(pen, out femalesToKeep) ? Math.Min(femalesToKeep, num) : (-1));
			state.Row.SetActive(true);
			Place(state);
			state.Control.MinValue = -1;
			state.Control.MaxValue = num;
			state.Control.SetValue(num2, true);
			RefreshTitle(state);
		}

		private static void Hide(RowState state)
		{
			state.Pen = null;
			if ((Object)(object)state.Row != (Object)null)
			{
				state.Row.SetActive(false);
			}
		}

		private static int CurrentLimit(RowState state)
		{
			IncreaseDecreasePanel quantityControlPanel = state.Panel._quantityControlPanel;
			if (!((Object)(object)quantityControlPanel != (Object)null))
			{
				return 0;
			}
			return Math.Max(0, quantityControlPanel.Value);
		}

		private static void RefreshTitle(RowState state)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)state.Title == (Object)null))
			{
				if (state.Control.Value <= -1)
				{
					state.Title.text = "Females to keep  (off - vanilla 50/50)";
					return;
				}
				HerdTargets val = HerdTargets.Create(CurrentLimit(state), state.Control.Value);
				state.Title.text = $"Females to keep  (males: {((HerdTargets)(ref val)).MalesToKeep})";
			}
		}

		private static void OnValueChanged(RowState state, int value)
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			try
			{
				AnimalPen pen = state.Pen;
				if (!((Object)(object)pen == (Object)null))
				{
					if (value <= -1)
					{
						PenTargetStore.Clear(pen);
					}
					else
					{
						PenTargetStore.Set(pen, value);
					}
					RefreshTitle(state);
					SlaughterLog.Write("targets_changed", $"{SlaughterLog.DescribePen(pen)} keep_f={((value <= -1) ? "off" : value.ToString())} limit={CurrentLimit(state)}");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(37, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("SPGT event=row_change_failed details=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}

		private static RowState GetOrBuild(TaskDataPanel panel)
		{
			if (RowsByPanel.TryGetValue(((Il2CppObjectBase)panel).Pointer, out var value))
			{
				if ((Object)(object)value.Row != (Object)null && (Object)(object)value.Control != (Object)null)
				{
					return value;
				}
				RowsByPanel.Remove(((Il2CppObjectBase)panel).Pointer);
				if (value.Control != null)
				{
					RowsByControl.Remove(((Il2CppObjectBase)value.Control).Pointer);
				}
			}
			value = Build(panel);
			if (value == null)
			{
				return null;
			}
			RowsByPanel[((Il2CppObjectBase)panel).Pointer] = value;
			RowsByControl[((Il2CppObjectBase)value.Control).Pointer] = value;
			return value;
		}

		private static RowState Build(TaskDataPanel panel)
		{
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Expected O, but got Unknown
			GameObject quantityDiv = panel._quantityDiv;
			IncreaseDecreasePanel quantityControlPanel = panel._quantityControlPanel;
			if ((Object)(object)quantityDiv == (Object)null || (Object)(object)quantityControlPanel == (Object)null)
			{
				SlaughterLog.Write("row_unavailable", "reason=task_panel_has_no_quantity_row");
				return null;
			}
			Transform parent = quantityDiv.transform.parent;
			string text = RelativePath(quantityDiv.transform, ((Component)quantityControlPanel).transform);
			string text2 = (((Object)(object)panel._quantityDivTitle != (Object)null) ? RelativePath(quantityDiv.transform, panel._quantityDivTitle.transform) : null);
			if (text == null)
			{
				SlaughterLog.Write("row_unavailable", "reason=limit_control_is_not_inside_its_div");
				return null;
			}
			GameObject val = new GameObject("SPGT_RowHolder");
			val.SetActive(false);
			val.transform.SetParent(parent, false);
			GameObject val2 = Object.Instantiate<GameObject>(quantityDiv, val.transform);
			((Object)val2).name = "SPGT_FemalesToKeepRow";
			Transform obj = FindRelative(val2.transform, text);
			IncreaseDecreasePanel val3 = ((obj != null) ? ((Component)obj).GetComponent<IncreaseDecreasePanel>() : null);
			object obj2;
			if (text2 == null)
			{
				obj2 = null;
			}
			else
			{
				Transform obj3 = FindRelative(val2.transform, text2);
				obj2 = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null);
			}
			TMP_Text val4 = (TMP_Text)obj2;
			if ((Object)(object)val3 == (Object)null)
			{
				Object.Destroy((Object)(object)val);
				SlaughterLog.Write("row_unavailable", "reason=cloned_control_not_found");
				return null;
			}
			HideClonedMaterials(panel, quantityDiv, val2);
			val3.group = null;
			SilencePersistentListeners((UnityEventBase)(object)val3.OnValueChanged);
			SilencePersistentListeners((UnityEventBase)(object)val3.OnIncrease);
			SilencePersistentListeners((UnityEventBase)(object)val3.OnDecrease);
			if ((Object)(object)val4 != (Object)null)
			{
				RemoveLocalizers(((Component)val4).gameObject);
			}
			RowState state = new RowState
			{
				Row = val2,
				Control = val3,
				Title = val4,
				Panel = panel
			};
			((UnityEvent<int>)(object)val3.OnValueChanged).AddListener(DelegateSupport.ConvertDelegate<UnityAction<int>>((Delegate)(Action<int>)delegate(int value)
			{
				OnValueChanged(state, value);
			}));
			val2.transform.SetParent(parent, false);
			val2.transform.SetSiblingIndex(quantityDiv.transform.GetSiblingIndex() + 1);
			Object.Destroy((Object)(object)val);
			if (!_layoutLogged)
			{
				_layoutLogged = true;
				LogLayout(quantityDiv, val4);
			}
			SlaughterLog.Write("row_built", $"panel={((Il2CppObjectBase)panel).Pointer.ToInt64():X}");
			return state;
		}

		private static void Place(RowState state)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			GameObject quantityDiv = state.Panel._quantityDiv;
			if ((Object)(object)quantityDiv == (Object)null)
			{
				return;
			}
			Transform parent = quantityDiv.transform.parent;
			if (!((Object)(object)parent != (Object)null) || !((Object)(object)((Component)parent).GetComponent<LayoutGroup>() != (Object)null))
			{
				RectTransform component = quantityDiv.GetComponent<RectTransform>();
				RectTransform component2 = state.Row.GetComponent<RectTransform>();
				if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null))
				{
					Rect rect = component.rect;
					float height = ((Rect)(ref rect)).height;
					component2.anchoredPosition = component.anchoredPosition + new Vector2(Plugin.RowOffsetX.Value, 0f - (height + 6f) + Plugin.RowOffsetY.Value);
				}
			}
		}

		private static void HideClonedMaterials(TaskDataPanel panel, GameObject templateDiv, GameObject row)
		{
			GameObject materialsDiv = panel._materialsDiv;
			if ((Object)(object)materialsDiv == (Object)null)
			{
				return;
			}
			string text = RelativePath(templateDiv.transform, materialsDiv.transform);
			if (!string.IsNullOrEmpty(text))
			{
				Transform val = FindRelative(row.transform, text);
				if ((Object)(object)val != (Object)null)
				{
					((Component)val).gameObject.SetActive(false);
				}
			}
		}

		private static void SilencePersistentListeners(UnityEventBase unityEvent)
		{
			if (unityEvent != null)
			{
				int persistentEventCount = unityEvent.GetPersistentEventCount();
				for (int i = 0; i < persistentEventCount; i++)
				{
					unityEvent.SetPersistentListenerState(i, (UnityEventCallState)0);
				}
			}
		}

		private static void RemoveLocalizers(GameObject titleObject)
		{
			foreach (Component component in titleObject.GetComponents<Component>())
			{
				if (((MemberInfo)((Object)component).GetIl2CppType()).Name.IndexOf("Locali", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					Behaviour val = ((Il2CppObjectBase)component).TryCast<Behaviour>();
					if ((Object)(object)val != (Object)null)
					{
						val.enabled = false;
					}
					Object.Destroy((Object)(object)component);
				}
			}
		}

		private static string RelativePath(Transform ancestor, Transform descendant)
		{
			List<string> list = new List<string>();
			Transform val = descendant;
			while ((Object)(object)val != (Object)null)
			{
				if (((Il2CppObjectBase)val).Pointer == ((Il2CppObjectBase)ancestor).Pointer)
				{
					list.Reverse();
					return string.Join("/", list);
				}
				list.Add(((Object)val).name);
				val = val.parent;
			}
			return null;
		}

		private static Transform FindRelative(Transform root, string path)
		{
			if (path.Length != 0)
			{
				return root.Find(path);
			}
			return root;
		}

		private static void LogLayout(GameObject templateDiv, TMP_Text title)
		{
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Transform parent = templateDiv.transform.parent;
				LayoutGroup val = ((parent != null) ? ((Component)parent).GetComponent<LayoutGroup>() : null);
				StringBuilder stringBuilder = new StringBuilder();
				StringBuilder stringBuilder2 = stringBuilder;
				StringBuilder stringBuilder3 = stringBuilder2;
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(21, 2, stringBuilder2);
				handler.AppendLiteral("parent=");
				handler.AppendFormatted((parent != null) ? ((Object)parent).name : null);
				handler.AppendLiteral(" layout_group=");
				handler.AppendFormatted(((Object)(object)val != (Object)null) ? ((MemberInfo)((Object)val).GetIl2CppType()).Name : "none");
				stringBuilder3.Append(ref handler);
				if ((Object)(object)parent != (Object)null)
				{
					for (int i = 0; i < parent.childCount; i++)
					{
						Transform child = parent.GetChild(i);
						RectTransform component = ((Component)child).GetComponent<RectTransform>();
						stringBuilder2 = stringBuilder;
						StringBuilder stringBuilder4 = stringBuilder2;
						handler = new StringBuilder.AppendInterpolatedStringHandler(14, 3, stringBuilder2);
						handler.AppendLiteral(" | [");
						handler.AppendFormatted(i);
						handler.AppendLiteral("] ");
						handler.AppendFormatted(((Object)child).name);
						handler.AppendLiteral(" active=");
						handler.AppendFormatted(((Component)child).gameObject.activeSelf);
						stringBuilder4.Append(ref handler);
						if ((Object)(object)component != (Object)null)
						{
							stringBuilder2 = stringBuilder;
							StringBuilder stringBuilder5 = stringBuilder2;
							handler = new StringBuilder.AppendInterpolatedStringHandler(11, 2, stringBuilder2);
							handler.AppendLiteral(" pos=");
							handler.AppendFormatted<Vector2>(component.anchoredPosition);
							handler.AppendLiteral(" size=");
							Rect rect = component.rect;
							handler.AppendFormatted<Vector2>(((Rect)(ref rect)).size);
							stringBuilder5.Append(ref handler);
						}
					}
				}
				if ((Object)(object)title != (Object)null)
				{
					stringBuilder.Append(" | title_components=");
					foreach (Component component2 in ((Component)title).GetComponents<Component>())
					{
						stringBuilder.Append(((MemberInfo)((Object)component2).GetIl2CppType()).Name).Append(',');
					}
				}
				SlaughterLog.Write("row_layout", stringBuilder.ToString());
			}
			catch (Exception ex)
			{
				SlaughterLog.Write("row_layout", "unavailable=" + ex.Message);
			}
		}
	}
}
namespace SmolkrPenGenderTargets.Runtime
{
	internal static class PenReader
	{
		internal sealed class PenSnapshot
		{
			internal readonly List<PenAnimal> Animals = new List<PenAnimal>();

			internal readonly List<DomesticSmolkr> Smolkr = new List<DomesticSmolkr>();

			internal int SlaughterLimit;

			internal int MinimumPopulation;

			internal int OwnedPetCount;
		}

		internal static PenSnapshot Read(AnimalPen pen)
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			List<PetWrapper> ownedPets = ((Kennel)pen)._ownedPets;
			AnimalSlaughterTaskData slaughterTaskData = pen._slaughterTaskData;
			ItemInfoQuantity val = ((slaughterTaskData != null) ? ((WorkstationTaskData)slaughterTaskData).itemInfoQuantity : null);
			if (ownedPets == null || val == null)
			{
				return null;
			}
			PenSnapshot penSnapshot = new PenSnapshot
			{
				SlaughterLimit = val.quantity,
				MinimumPopulation = pen.minimumPetPopulation,
				OwnedPetCount = ownedPets.Count
			};
			for (int i = 0; i < ownedPets.Count; i++)
			{
				PetWrapper obj = ownedPets[i];
				Pet val2 = ((obj != null) ? obj.pet : null);
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)null))
				{
					DomesticSmolkr component = ((Component)val2).GetComponent<DomesticSmolkr>();
					if (!((Object)(object)component == (Object)null))
					{
						penSnapshot.Animals.Add(new PenAnimal(component.isFemale, val2._mature));
						penSnapshot.Smolkr.Add(component);
					}
				}
			}
			return penSnapshot;
		}

		internal static CullDecision? Plan(AnimalPen pen, int femalesToKeep, out DomesticSmolkr victim)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			victim = null;
			PenSnapshot penSnapshot = Read(pen);
			if (penSnapshot == null)
			{
				return null;
			}
			HerdTargets val = HerdTargets.Create(penSnapshot.SlaughterLimit, femalesToKeep);
			CullDecision value = CullPlanner.Decide((IReadOnlyList<PenAnimal>)penSnapshot.Animals, val, penSnapshot.OwnedPetCount, penSnapshot.MinimumPopulation);
			if (((CullDecision)(ref value)).HasVictim)
			{
				victim = penSnapshot.Smolkr[((CullDecision)(ref value)).VictimIndex];
			}
			return value;
		}
	}
	internal static class PenTargetStore
	{
		private static readonly Dictionary<IntPtr, int> FemalesToKeepByPen = new Dictionary<IntPtr, int>();

		internal static bool TryGet(AnimalPen pen, out int femalesToKeep)
		{
			femalesToKeep = 0;
			if ((Object)(object)pen != (Object)null)
			{
				return FemalesToKeepByPen.TryGetValue(((Il2CppObjectBase)pen).Pointer, out femalesToKeep);
			}
			return false;
		}

		internal static void Set(AnimalPen pen, int femalesToKeep)
		{
			if (!((Object)(object)pen == (Object)null))
			{
				FemalesToKeepByPen[((Il2CppObjectBase)pen).Pointer] = Math.Max(0, femalesToKeep);
			}
		}

		internal static void Clear(AnimalPen pen)
		{
			if (!((Object)(object)pen == (Object)null))
			{
				FemalesToKeepByPen.Remove(((Il2CppObjectBase)pen).Pointer);
			}
		}

		internal static void Forget(IntPtr penPointer)
		{
			FemalesToKeepByPen.Remove(penPointer);
		}
	}
	internal static class SlaughterLog
	{
		private static readonly Dictionary<IntPtr, IntPtr> SelectedSmolkrByPen = new Dictionary<IntPtr, IntPtr>();

		private static bool _failureReported;

		internal static void Write(string eventName, string details)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(12, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("SPGT event=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(eventName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(details);
				}
				log.LogInfo(val);
			}
		}

		internal static string DescribePen(AnimalPen pen)
		{
			return $"pen={((Il2CppObjectBase)pen).Pointer.ToInt64():X} kind={(pen.kycklingPen ? "kyckling" : "smolkr")}";
		}

		internal static void Selected(AnimalPen pen, CullDecision decision, DomesticSmolkr victim)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			IntPtr intPtr = ((victim != null) ? ((Il2CppObjectBase)victim).Pointer : IntPtr.Zero);
			if (!SelectedSmolkrByPen.TryGetValue(((Il2CppObjectBase)pen).Pointer, out var value) || !(value == intPtr))
			{
				SelectedSmolkrByPen[((Il2CppObjectBase)pen).Pointer] = intPtr;
				HerdCensus census = ((CullDecision)(ref decision)).Census;
				HerdTargets targets = ((CullDecision)(ref decision)).Targets;
				Write(((Object)(object)victim != (Object)null) ? "slaughter_selected" : "slaughter_declined", $"{DescribePen(pen)} reason={((CullDecision)(ref decision)).Reason} victim_female={(((Object)(object)victim != (Object)null) ? victim.isFemale.ToString() : "-")} adults_f={((HerdCensus)(ref census)).AdultFemales} adults_m={((HerdCensus)(ref census)).AdultMales} pups_f={((HerdCensus)(ref census)).FemalePups} pups_m={((HerdCensus)(ref census)).MalePups} keep_f={((HerdTargets)(ref targets)).FemalesToKeep} keep_m={((HerdTargets)(ref targets)).MalesToKeep} limit={((HerdTargets)(ref targets)).SlaughterLimit}");
			}
		}

		internal static void Died(AnimalPen pen, DomesticSmolkr smolkr)
		{
			int num;
			object eventName;
			if (SelectedSmolkrByPen.TryGetValue(((Il2CppObjectBase)pen).Pointer, out var value))
			{
				num = ((value == ((Il2CppObjectBase)smolkr).Pointer) ? 1 : 0);
				if (num != 0)
				{
					eventName = "slaughter_confirmed";
					goto IL_0032;
				}
			}
			else
			{
				num = 0;
			}
			eventName = "smolkr_died_unselected";
			goto IL_0032;
			IL_0032:
			Write((string)eventName, $"{DescribePen(pen)} female={smolkr.isFemale}");
			if (num != 0)
			{
				SelectedSmolkrByPen.Remove(((Il2CppObjectBase)pen).Pointer);
			}
		}

		internal static void Failed(Exception exception)
		{
			if (!_failureReported)
			{
				_failureReported = true;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("SPGT event=selection_failed - the vanilla slaughter choice is used whenever this " + $"happens; later failures are not reported again. Details: {exception}"));
				}
			}
		}

		internal static void Forget(IntPtr penPointer)
		{
			SelectedSmolkrByPen.Remove(penPointer);
		}
	}
}
namespace SmolkrPenGenderTargets.Patches
{
	[HarmonyPatch(typeof(Kennel), "OnDestroy")]
	internal static class KennelDestroyPatch
	{
		private static void Prefix(Kennel __instance)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				PenTargetStore.Forget(((Il2CppObjectBase)__instance).Pointer);
				SlaughterLog.Forget(((Il2CppObjectBase)__instance).Pointer);
			}
		}
	}
	internal static class PenSaveKeys
	{
		internal const string FemalesToKeep = "spgt_femalesToKeep";
	}
	[HarmonyPatch(typeof(AnimalPen), "SerializeTaskData")]
	internal static class PenSerializePatch
	{
		private static void Postfix(AnimalPen __instance, DataObject __result)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			try
			{
				if (__result != null && PenTargetStore.TryGet(__instance, out var femalesToKeep))
				{
					__result.AddElement("spgt_femalesToKeep", (DataElement)new DataElementInt(femalesToKeep));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(74, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("SPGT event=save_failed - this pen's gender target was not saved. Details: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				log.LogError(val);
			}
		}
	}
	[HarmonyPatch(typeof(AnimalPen), "DeserializeTaskData")]
	internal static class PenDeserializePatch
	{
		private static void Postfix(AnimalPen __instance, DataObject __0)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			try
			{
				DataElement val = default(DataElement);
				if (__0 != null && __0.TryGetElement("spgt_femalesToKeep", ref val))
				{
					DataElementInt val2 = ((val != null) ? ((Il2CppObjectBase)val).TryCast<DataElementInt>() : null);
					if (val2 != null)
					{
						PenTargetStore.Set(__instance, val2.value);
						SlaughterLog.Write("targets_loaded", $"{SlaughterLog.DescribePen(__instance)} keep_f={val2.value}");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(74, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("SPGT event=load_failed - this pen will use vanilla slaughtering. Details: ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Exception>(ex);
				}
				log.LogError(val3);
			}
		}
	}
	[HarmonyPatch(typeof(AnimalPen), "GetSmolkrReadyForSlaughter")]
	internal static class SlaughterSelectionPatch
	{
		private static bool Prefix(AnimalPen __instance, ref DomesticSmolkr __0, ref bool __result)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Enabled.Value)
			{
				return true;
			}
			if (!PenTargetStore.TryGet(__instance, out var femalesToKeep))
			{
				return true;
			}
			try
			{
				DomesticSmolkr victim;
				CullDecision? val = PenReader.Plan(__instance, femalesToKeep, out victim);
				if (!val.HasValue)
				{
					return true;
				}
				__0 = victim;
				__result = (Object)(object)victim != (Object)null;
				SlaughterLog.Selected(__instance, val.Value, victim);
				return false;
			}
			catch (Exception exception)
			{
				SlaughterLog.Failed(exception);
				return true;
			}
		}
	}
	[HarmonyPatch(typeof(DomesticSmolkr), "_HandleCreatureDead")]
	internal static class SmolkrDeathPatch
	{
		private static void Prefix(DomesticSmolkr __instance)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			try
			{
				object obj;
				if (__instance == null)
				{
					obj = null;
				}
				else
				{
					Kennel kennel = __instance._kennel;
					obj = ((kennel != null) ? ((Il2CppObjectBase)kennel).TryCast<AnimalPen>() : null);
				}
				AnimalPen val = (AnimalPen)obj;
				if (!((Object)(object)val == (Object)null) && PenTargetStore.TryGet(val, out var _))
				{
					SlaughterLog.Died(val, __instance);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(36, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("SPGT event=death_log_failed details=");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
				}
				log.LogWarning(val2);
			}
		}
	}
	[HarmonyPatch(typeof(TaskDataPanel), "_SetQuantity")]
	internal static class TaskDataPanelSetQuantityPatch
	{
		private static void Postfix(TaskDataPanel __instance, WorkstationTaskData __0)
		{
			RowGuard.Run(delegate
			{
				FemalesToKeepRow.OnQuantitySet(__instance, __0);
			});
		}
	}
	[HarmonyPatch(typeof(TaskDataPanel), "_onQuantityChanged")]
	internal static class TaskDataPanelQuantityChangedPatch
	{
		private static void Postfix(TaskDataPanel __instance)
		{
			RowGuard.Run(delegate
			{
				FemalesToKeepRow.OnLimitChanged(__instance);
			});
		}
	}
	[HarmonyPatch(typeof(IncreaseDecreasePanel), "RefreshAutomaticText")]
	internal static class IncreaseDecreaseTextPatch
	{
		private static void Postfix(IncreaseDecreasePanel __instance)
		{
			RowGuard.Run(delegate
			{
				FemalesToKeepRow.OnControlTextRefreshed(__instance);
			});
		}
	}
	internal static class RowGuard
	{
		private static bool _failureReported;

		internal static void Run(Action action)
		{
			try
			{
				action();
			}
			catch (Exception value)
			{
				if (!_failureReported)
				{
					_failureReported = true;
					Plugin.Log.LogError((object)("SPGT event=row_failed - the 'Females to keep' row may be missing or stale; pens keep " + $"their saved targets. Details: {value}"));
				}
			}
		}
	}
}