Decompiled source of Shepherd v0.1.21

plugins/Shepherd/Shepherd.Core.dll

Decompiled 13 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using ExtraPotions.Shepherd.Breeding;
using Microsoft.CodeAnalysis;

[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("ExtraPotions")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (C) 2026 expDARE (ExtraPotions Meadworks)")]
[assembly: AssemblyFileVersion("0.1.21.0")]
[assembly: AssemblyInformationalVersion("0.1.21")]
[assembly: AssemblyProduct("Shepherd.Core")]
[assembly: AssemblyTitle("Shepherd.Core")]
[assembly: AssemblyVersion("0.1.21.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 ExtraPotions.Shepherd
{
	public static class ShepherdCore
	{
		public const string ProductId = "com.meadworks.shepherd";

		public const string Name = "Shepherd";

		public const string Version = "0.1.21";

		public const string Family = "Hearth";

		public const string SupportedGameVersion = "1.0.17";

		public const string KeyPrefix = "shepherd.";
	}
	public static class ShepherdText
	{
		public const string Namespace = "shepherd";

		public const string HerdRoom = "herd_room";

		public const string HerdWaiting = "herd_waiting";

		public const string HerdUnlimited = "herd_unlimited";

		public const string PieceFeedBarrel = "piece_feed_barrel";

		public const string PiecePlankTrough = "piece_plank_trough";

		public const string PieceStoneTrough = "piece_stone_trough";

		public const string PieceTroughDescription = "piece_trough_description";

		private static readonly string[] keys = new string[83]
		{
			"herd_room", "herd_waiting", "herd_unlimited", "piece_feed_barrel", "piece_plank_trough", "piece_stone_trough", "piece_trough_description", "time_seconds", "time_minutes", "time_hours_minutes",
			"lore_taming_gate", "lore_taming", "lore_fed", "lore_content", "lore_love", "lore_pregnant", "lore_due", "lore_generation", "lore_parents", "lore_unknown",
			"lore_growing", "lore_grown_due", "lore_hatching", "lore_hatched_due", "callout_strong", "callout_twins", "book_title", "book_count", "book_close", "book_hungry",
			"book_fed", "book_pregnant", "book_summary", "book_previous", "book_next", "book_rename", "book_rename_reach", "book_empty", "book_empty_title", "book_empty_hint",
			"book_species", "book_stars", "book_variant", "book_state", "book_lineage", "book_generation", "book_born", "book_breeder", "book_mother", "book_sire",
			"book_grandparents", "book_traits", "trough_stock", "trough_last", "trough_no_meal", "trough_foods", "trough_food_only", "piece_land_pen", "piece_land_pen_description", "land_pen_capacity",
			"book_help_previous", "book_help_next", "book_help_close", "book_help_animal", "step_aside_feeding", "step_aside_husbandry", "step_aside_inheritance", "step_aside_containers", "import_done", "command_help",
			"command_off", "command_busy", "command_target", "command_sent", "command_unknown", "command_done", "command_refused", "feed_mark_hint", "feed_mark_on", "feed_mark_off",
			"feed_mark_busy", "feed_mark_refused", "feed_mark_unknown"
		};

		public static IReadOnlyList<string> Keys => keys;

		public static string Token(string key)
		{
			return "$meadworks_shepherd_" + key;
		}
	}
}
namespace ExtraPotions.Shepherd.Yield
{
	public static class HoneyProductionMath
	{
		public static bool Finite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		public static float SecondsPerHoney(float fixedPerDay, bool perPlayer, int online, float daySeconds)
		{
			if (!Finite(daySeconds) || daySeconds <= 0f)
			{
				return 0f;
			}
			float num = (perPlayer ? ((float)Math.Max(1, online)) : (Finite(fixedPerDay) ? Math.Max(0f, Math.Min(1000f, fixedPerDay)) : 0f));
			float num2 = ((num > 0f) ? (daySeconds / num) : 0f);
			if (!Finite(num2) || !(num2 > 0f))
			{
				return 0f;
			}
			return num2;
		}

		public static bool TryRescale(float product, float fromSeconds, float toSeconds, out float scaled)
		{
			scaled = product;
			if (!Finite(product) || product < 0f || !Finite(fromSeconds) || fromSeconds <= 0f || !Finite(toSeconds) || toSeconds <= 0f)
			{
				return false;
			}
			float num = (float)((double)product * (double)toSeconds / (double)fromSeconds);
			if (!Finite(num))
			{
				return false;
			}
			scaled = num;
			return true;
		}

		public static bool TryNativeRemainder(float product, float elapsed, float seconds, out float total, out float remainder)
		{
			total = product + elapsed;
			remainder = product;
			if (!Finite(product) || product < 0f || !Finite(elapsed) || elapsed < 0f || !Finite(seconds) || seconds <= 0f || !Finite(total) || (double)total / (double)seconds >= 2147483647.0)
			{
				return false;
			}
			remainder = ((total > seconds) ? (total - (float)(int)(total / seconds) * seconds) : total);
			if (Finite(remainder))
			{
				return remainder >= 0f;
			}
			return false;
		}
	}
	public enum ProduceStep
	{
		Start,
		Wait,
		Roll
	}
	public readonly struct ProduceTick
	{
		public ProduceStep Step { get; }

		public long NextMs { get; }

		public ProduceTick(ProduceStep step, long nextMs)
		{
			Step = step;
			NextMs = nextMs;
		}
	}
	public static class ProduceClock
	{
		public static ProduceTick Step(long nowMs, long nextMs, double intervalSeconds, double chance)
		{
			long num = (long)Math.Max(1000.0, intervalSeconds * 1000.0);
			if (nextMs == 0L || nextMs - nowMs > num)
			{
				return new ProduceTick(ProduceStep.Start, nowMs + num);
			}
			if (nowMs < nextMs || chance <= 0.0)
			{
				return new ProduceTick(ProduceStep.Wait, nextMs);
			}
			return new ProduceTick(ProduceStep.Roll, nowMs + num);
		}
	}
	public static class YieldMath
	{
		public const int MaxAmount = 100;

		public const double MaxToughness = 0.9;

		public static int Butchered(int amount, double share, IBreedingRandom random)
		{
			if (random == null)
			{
				throw new ArgumentNullException("random");
			}
			if (amount <= 0 || share <= 0.0)
			{
				return amount;
			}
			double num = (double)amount * (1.0 + share);
			int num2 = (int)Math.Floor(num);
			double num3 = num - (double)num2;
			if (num3 > 0.0 && random.Value() < num3)
			{
				num2++;
			}
			return Math.Min(Math.Max(num2, amount), Math.Max(amount, 100));
		}

		public static int PickWeighted(double[] weights, double unit)
		{
			if (weights == null)
			{
				return -1;
			}
			double num = 0.0;
			int num2 = -1;
			for (int i = 0; i < weights.Length; i++)
			{
				if (weights[i] > 0.0)
				{
					num += weights[i];
					num2 = i;
				}
			}
			if (num2 < 0)
			{
				return -1;
			}
			double num3 = Math.Min(Math.Max(unit, 0.0), 1.0) * num;
			for (int j = 0; j < weights.Length; j++)
			{
				if (!(weights[j] <= 0.0))
				{
					num3 -= weights[j];
					if (num3 < 0.0)
					{
						return j;
					}
				}
			}
			return num2;
		}

		public static bool IsProduce(bool trophy, double foodValue, bool cookingInput)
		{
			if (!trophy && foodValue == 0.0)
			{
				return !cookingInput;
			}
			return false;
		}

		public static int ExtraHoney(int count, double share, IBreedingRandom random)
		{
			if (random == null)
			{
				throw new ArgumentNullException("random");
			}
			if (count <= 0 || share <= 0.0)
			{
				return 0;
			}
			int num = 0;
			for (int i = 0; i < count; i++)
			{
				if (random.Value() < share)
				{
					num++;
				}
			}
			return num;
		}

		public static double PackDealt(double share)
		{
			return 1.0 + Math.Max(0.0, share);
		}

		public static double PackTaken(double share)
		{
			return 1.0 - Math.Min(Math.Max(0.0, share), 0.9);
		}
	}
}
namespace ExtraPotions.Shepherd.Troughs
{
	public sealed class TroughPiece
	{
		public string Prefab { get; }

		public string DisplayName { get; }

		public string Description { get; }

		public string SourcePrefab { get; }

		public string? MeshPrefab { get; }

		public int Width { get; }

		public int Height { get; }

		public string Station { get; }

		public string DefaultRecipe { get; }

		public string NameKey { get; }

		public string DescriptionKey => "piece_trough_description";

		public string NameToken => ShepherdText.Token(NameKey);

		public string DescriptionToken => ShepherdText.Token(DescriptionKey);

		public TroughPiece(string prefab, string nameKey, string displayName, string description, string sourcePrefab, string? meshPrefab, int width, int height, string station, string defaultRecipe)
		{
			Prefab = prefab;
			NameKey = nameKey;
			DisplayName = displayName;
			Description = description;
			SourcePrefab = sourcePrefab;
			MeshPrefab = meshPrefab;
			Width = width;
			Height = height;
			Station = station;
			DefaultRecipe = defaultRecipe;
		}
	}
	public static class TroughCatalog
	{
		public const string Workbench = "piece_workbench";

		public const string Stonecutter = "piece_stonecutter";

		private const string Feeds = "Hungry tamed animals, and animals being tamed, come to eat the food you put in it.";

		private static readonly TroughPiece[] All = new TroughPiece[3]
		{
			new TroughPiece("shepherd_feed_barrel", "piece_feed_barrel", "Feed Barrel", "Hungry tamed animals, and animals being tamed, come to eat the food you put in it.", "piece_chest_barrel", null, 4, 2, "piece_workbench", "Wood:10, LeatherScraps:4"),
			new TroughPiece("shepherd_trough_plank", "piece_plank_trough", "Plank Trough", "Hungry tamed animals, and animals being tamed, come to eat the food you put in it.", "piece_chest_wood", "wood_beam_1", 6, 1, "piece_workbench", "Wood:6, Resin:2"),
			new TroughPiece("shepherd_trough_stone", "piece_stone_trough", "Stone Trough", "Hungry tamed animals, and animals being tamed, come to eat the food you put in it.", "piece_chest_wood", "stone_wall_1x1", 6, 1, "piece_stonecutter", "Stone:12, Wood:2")
		};

		public static IReadOnlyList<TroughPiece> Pieces => All;

		public static TroughPiece? Find(string? prefab)
		{
			string text = Canonical(prefab);
			TroughPiece[] all = All;
			foreach (TroughPiece troughPiece in all)
			{
				if (troughPiece.Prefab == text)
				{
					return troughPiece;
				}
			}
			return null;
		}

		public static string? Canonical(string? prefab)
		{
			if (prefab == "grindstone_feeder")
			{
				return "shepherd_feed_barrel";
			}
			TroughPiece[] all = All;
			for (int i = 0; i < all.Length; i++)
			{
				if (all[i].Prefab == prefab)
				{
					return prefab;
				}
			}
			return null;
		}
	}
	public static class TroughSource
	{
		public static readonly IReadOnlyList<string> Fallbacks = new string[5] { "piece_chest_wood", "piece_chest_barrel", "piece_chest", "piece_chest_private", "piece_chest_blackmetal" };

		public static IEnumerable<string> Candidates(string? preferred)
		{
			if (!string.IsNullOrEmpty(preferred))
			{
				yield return preferred;
			}
			foreach (string fallback in Fallbacks)
			{
				if (fallback != preferred)
				{
					yield return fallback;
				}
			}
		}

		public static string? Choose(string? preferred, Func<string, bool> usable)
		{
			foreach (string item in Candidates(preferred))
			{
				if (usable(item))
				{
					return item;
				}
			}
			return null;
		}
	}
	public static class TroughGate
	{
		public const double HiddenAbove = 100.0;

		public static bool MayBuild(double buildLevel, double keeperLevel, bool husbandryActive)
		{
			if (buildLevel > 100.0)
			{
				return false;
			}
			if (buildLevel <= 0.0)
			{
				return true;
			}
			if (husbandryActive)
			{
				return keeperLevel >= buildLevel;
			}
			return false;
		}
	}
	public static class TroughFilter
	{
		public static bool Accepts(string? itemPrefab, ISet<string> edible)
		{
			if (!string.IsNullOrEmpty(itemPrefab) && edible != null)
			{
				return edible.Contains(itemPrefab);
			}
			return false;
		}
	}
	public static class TroughPrefabs
	{
		public const string FeedBarrel = "shepherd_feed_barrel";

		public const string PlankTrough = "shepherd_trough_plank";

		public const string StoneTrough = "shepherd_trough_stone";

		public const string GrindstoneFeeder = "grindstone_feeder";

		public const string FeedRole = "feed";

		private static readonly HashSet<string> Names = new HashSet<string>(StringComparer.Ordinal) { "shepherd_feed_barrel", "shepherd_trough_plank", "shepherd_trough_stone", "grindstone_feeder" };

		public static IReadOnlyCollection<string> All => Names;

		public static bool IsTrough(string? prefabName)
		{
			if (prefabName != null)
			{
				return Names.Contains(prefabName);
			}
			return false;
		}

		public static string? RoleOf(string? prefabName)
		{
			if (!IsTrough(prefabName))
			{
				return null;
			}
			return "feed";
		}
	}
	public readonly struct RecipeEntry
	{
		public string Item { get; }

		public int Amount { get; }

		public RecipeEntry(string item, int amount)
		{
			Item = item;
			Amount = amount;
		}
	}
	public static class TroughRecipe
	{
		public const string Fallback = "Wood:10";

		public static IReadOnlyList<RecipeEntry> Parse(string? text, Func<string, bool> knownItem)
		{
			if (knownItem == null)
			{
				throw new ArgumentNullException("knownItem");
			}
			List<RecipeEntry> list = Read(text, knownItem);
			if (list.Count <= 0)
			{
				return Read("Wood:10", (string _) => true);
			}
			return list;
		}

		private static List<RecipeEntry> Read(string? text, Func<string, bool> knownItem)
		{
			List<RecipeEntry> list = new List<RecipeEntry>();
			string[] array = (text ?? "").Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(':');
				if (array2.Length == 2 && int.TryParse(array2[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result >= 1)
				{
					string text2 = array2[0].Trim();
					if (text2.Length != 0 && knownItem(text2))
					{
						list.Add(new RecipeEntry(text2, result));
					}
				}
			}
			return list;
		}
	}
}
namespace ExtraPotions.Shepherd.Take
{
	public static class TakeProtocol
	{
		public const string TakeRpc = "shepherd.take";

		public const string MealRpc = "shepherd.meal";

		public const double ReplyTimeoutSeconds = 10.0;

		public const double DedupeWindowSeconds = 60.0;

		public const int DedupeCapacity = 256;

		public const int MaxItemNameLength = 128;

		internal const string Version = "v1";

		internal const char Separator = '|';
	}
	public readonly struct NetObjectId : IEquatable<NetObjectId>
	{
		public long User { get; }

		public uint Id { get; }

		public bool IsNone
		{
			get
			{
				if (User == 0L)
				{
					return Id == 0;
				}
				return false;
			}
		}

		public NetObjectId(long user, uint id)
		{
			User = user;
			Id = id;
		}

		public bool Equals(NetObjectId other)
		{
			if (User == other.User)
			{
				return Id == other.Id;
			}
			return false;
		}

		public override bool Equals(object? obj)
		{
			if (obj is NetObjectId other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (User.GetHashCode() * 397) ^ (int)Id;
		}

		public override string ToString()
		{
			return User.ToString(CultureInfo.InvariantCulture) + ":" + Id.ToString(CultureInfo.InvariantCulture);
		}

		public static bool TryParse(string? text, out NetObjectId value)
		{
			value = default(NetObjectId);
			if (!IdText.TryPair(text, out var first, out var second))
			{
				return false;
			}
			value = new NetObjectId(first, second);
			return true;
		}
	}
	public readonly struct TakeRequestId : IEquatable<TakeRequestId>
	{
		public long Issuer { get; }

		public uint Sequence { get; }

		public TakeRequestId(long issuer, uint sequence)
		{
			Issuer = issuer;
			Sequence = sequence;
		}

		public bool Equals(TakeRequestId other)
		{
			if (Issuer == other.Issuer)
			{
				return Sequence == other.Sequence;
			}
			return false;
		}

		public override bool Equals(object? obj)
		{
			if (obj is TakeRequestId other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (Issuer.GetHashCode() * 397) ^ (int)Sequence;
		}

		public override string ToString()
		{
			return Issuer.ToString(CultureInfo.InvariantCulture) + ":" + Sequence.ToString(CultureInfo.InvariantCulture);
		}

		public static bool TryParse(string? text, out TakeRequestId value)
		{
			value = default(TakeRequestId);
			if (!IdText.TryPair(text, out var first, out var second))
			{
				return false;
			}
			value = new TakeRequestId(first, second);
			return true;
		}
	}
	public sealed class TakeRequest
	{
		public TakeRequestId Id { get; }

		public string ItemName { get; }

		public NetObjectId Animal { get; }

		public TakeRequest(TakeRequestId id, string itemName, NetObjectId animal)
		{
			Id = id;
			ItemName = itemName ?? throw new ArgumentNullException("itemName");
			Animal = animal;
		}
	}
	public sealed class MealMessage
	{
		public TakeRequestId Id { get; }

		public string ItemName { get; }

		public MealMessage(TakeRequestId id, string itemName)
		{
			Id = id;
			ItemName = itemName ?? throw new ArgumentNullException("itemName");
		}
	}
	public static class TakeCodec
	{
		private const string TakeKind = "take";

		private const string MealKind = "meal";

		public static string Encode(TakeRequest request)
		{
			if (request == null)
			{
				throw new ArgumentNullException("request");
			}
			RequireItem(request.ItemName);
			return string.Join('|'.ToString(), "v1", "take", request.Id.ToString(), request.Animal.ToString(), request.ItemName);
		}

		public static string Encode(MealMessage meal)
		{
			if (meal == null)
			{
				throw new ArgumentNullException("meal");
			}
			RequireItem(meal.ItemName);
			return string.Join('|'.ToString(), "v1", "meal", meal.Id.ToString(), meal.ItemName);
		}

		public static bool TryDecodeTake(string? text, out TakeRequest? request)
		{
			request = null;
			string[] array = Split(text, "take", 5);
			if (array == null || !TakeRequestId.TryParse(array[2], out var value) || !NetObjectId.TryParse(array[3], out var value2) || !IsItem(array[4]))
			{
				return false;
			}
			request = new TakeRequest(value, array[4], value2);
			return true;
		}

		public static bool TryDecodeMeal(string? text, out MealMessage? meal)
		{
			meal = null;
			string[] array = Split(text, "meal", 4);
			if (array == null || !TakeRequestId.TryParse(array[2], out var value) || !IsItem(array[3]))
			{
				return false;
			}
			meal = new MealMessage(value, array[3]);
			return true;
		}

		public static bool IsItem(string? item)
		{
			if (!string.IsNullOrEmpty(item) && item.Length <= 128)
			{
				return item.IndexOf('|') < 0;
			}
			return false;
		}

		private static void RequireItem(string item)
		{
			if (!IsItem(item))
			{
				throw new ArgumentException("An item name is 1 to " + 128 + " characters without '|'.", "item");
			}
		}

		private static string[]? Split(string? text, string kind, int count)
		{
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			string[] array = text.Split('|');
			if (array.Length != count || !(array[0] == "v1") || !(array[1] == kind))
			{
				return null;
			}
			return array;
		}
	}
	internal static class IdText
	{
		public static bool TryPair(string? text, out long first, out uint second)
		{
			first = 0L;
			second = 0u;
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			int num = text.IndexOf(':');
			if (num <= 0 || num != text.LastIndexOf(':'))
			{
				return false;
			}
			if (long.TryParse(text.Substring(0, num), NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out first))
			{
				return uint.TryParse(text.Substring(num + 1), NumberStyles.None, CultureInfo.InvariantCulture, out second);
			}
			return false;
		}
	}
	public enum MealDecision
	{
		Apply,
		Duplicate,
		NotOwner
	}
	public sealed class TakeRequester
	{
		private readonly long issuer;

		private readonly double timeout;

		private readonly Dictionary<NetObjectId, (TakeRequest Request, double At)> pending = new Dictionary<NetObjectId, (TakeRequest, double)>();

		private readonly HashSet<TakeRequestId> applied = new HashSet<TakeRequestId>();

		private uint sequence;

		public int PendingCount => pending.Count;

		public TakeRequester(long issuer, double timeout = 10.0)
		{
			if (!(timeout > 0.0))
			{
				throw new ArgumentOutOfRangeException("timeout");
			}
			this.issuer = issuer;
			this.timeout = timeout;
		}

		public bool HasPending(NetObjectId animal)
		{
			return pending.ContainsKey(animal);
		}

		public bool IsBlocking(NetObjectId animal, double now)
		{
			if (pending.TryGetValue(animal, out (TakeRequest, double) value))
			{
				return now - value.Item2 < timeout;
			}
			return false;
		}

		public TakeRequest? TryBegin(NetObjectId animal, string itemName, double now)
		{
			if (!TakeCodec.IsItem(itemName))
			{
				throw new ArgumentException("Invalid item name.", "itemName");
			}
			if (pending.TryGetValue(animal, out (TakeRequest, double) value))
			{
				if (now - value.Item2 < timeout)
				{
					return null;
				}
				pending[animal] = (value.Item1, now);
				return value.Item1;
			}
			if (sequence == uint.MaxValue)
			{
				throw new InvalidOperationException("Request sequence exhausted for this session.");
			}
			TakeRequest takeRequest = new TakeRequest(new TakeRequestId(issuer, ++sequence), itemName, animal);
			pending[animal] = (takeRequest, now);
			return takeRequest;
		}

		public IReadOnlyList<TakeRequest> Expire(double now)
		{
			return Array.Empty<TakeRequest>();
		}

		public void Forget(NetObjectId animal)
		{
			pending.Remove(animal);
		}

		public MealDecision OnMeal(MealMessage meal, NetObjectId animal, bool ownedHere, double now)
		{
			if (meal == null)
			{
				throw new ArgumentNullException("meal");
			}
			if (!ownedHere)
			{
				return MealDecision.NotOwner;
			}
			if (!applied.Add(meal.Id))
			{
				return MealDecision.Duplicate;
			}
			if (pending.TryGetValue(animal, out (TakeRequest, double) value) && value.Item1.Id.Equals(meal.Id))
			{
				pending.Remove(animal);
			}
			return MealDecision.Apply;
		}
	}
	public enum TakeRoute
	{
		None,
		Local,
		Remote
	}
	public static class TakeRouting
	{
		public const bool ClaimsOwnership = false;

		public static TakeRoute ForTake(bool troughValid, long troughOwner, long localPeer)
		{
			return Route(troughValid, troughOwner, localPeer);
		}

		public static TakeRoute ForMeal(bool animalValid, long animalOwner, long localPeer)
		{
			return Route(animalValid, animalOwner, localPeer);
		}

		private static TakeRoute Route(bool valid, long owner, long local)
		{
			if (!valid || owner == 0L)
			{
				return TakeRoute.None;
			}
			if (owner != local)
			{
				return TakeRoute.Remote;
			}
			return TakeRoute.Local;
		}
	}
	public sealed class DedupeRing
	{
		private readonly int capacity;

		private readonly double window;

		private readonly Queue<(TakeRequestId Id, double At)> order = new Queue<(TakeRequestId, double)>();

		private readonly Dictionary<TakeRequestId, double> seen = new Dictionary<TakeRequestId, double>();

		public int Count => seen.Count;

		public DedupeRing(int capacity = 256, double window = 60.0)
		{
			if (capacity <= 0)
			{
				throw new ArgumentOutOfRangeException("capacity");
			}
			if (!(window > 0.0))
			{
				throw new ArgumentOutOfRangeException("window");
			}
			this.capacity = capacity;
			this.window = window;
		}

		public bool CheckAndRemember(TakeRequestId id, double now)
		{
			Prune(now);
			if (seen.ContainsKey(id))
			{
				return false;
			}
			while (order.Count >= capacity)
			{
				seen.Remove(order.Dequeue().Id);
			}
			order.Enqueue((id, now));
			seen[id] = now;
			return true;
		}

		public void Forget(TakeRequestId id)
		{
			if (!seen.Remove(id))
			{
				return;
			}
			int count = order.Count;
			for (int i = 0; i < count; i++)
			{
				(TakeRequestId, double) item = order.Dequeue();
				if (!item.Item1.Equals(id))
				{
					order.Enqueue(item);
				}
			}
		}

		private void Prune(double now)
		{
			while (order.Count > 0 && now - order.Peek().At >= window)
			{
				seen.Remove(order.Dequeue().Id);
			}
		}
	}
	public enum TakeVerdict
	{
		Granted,
		Resend,
		Duplicate,
		NotOwner,
		TroughGone,
		TroughDisabled,
		ItemMissing,
		ItemDisallowed
	}
	public static class TakeVerdicts
	{
		public static bool RemovesItem(TakeVerdict verdict)
		{
			return verdict == TakeVerdict.Granted;
		}

		public static bool SendsMeal(TakeVerdict verdict)
		{
			if (verdict != TakeVerdict.Granted)
			{
				return verdict == TakeVerdict.Resend;
			}
			return true;
		}
	}
	public readonly struct TroughFacts
	{
		public bool Exists { get; }

		public bool IsOwner { get; }

		public bool Enabled { get; }

		public bool HasItem { get; }

		public bool Disallowed { get; }

		public TroughFacts(bool exists, bool isOwner, bool enabled, bool hasItem, bool disallowed)
		{
			Exists = exists;
			IsOwner = isOwner;
			Enabled = enabled;
			HasItem = hasItem;
			Disallowed = disallowed;
		}
	}
	public sealed class TakeServer
	{
		private readonly DedupeRing ring;

		private readonly HashSet<TakeRequestId> granted = new HashSet<TakeRequestId>();

		public TakeServer(DedupeRing? ring = null)
		{
			this.ring = ring ?? new DedupeRing();
		}

		public TakeVerdict Decide(TakeRequest request, TroughFacts facts, double now)
		{
			if (request == null)
			{
				throw new ArgumentNullException("request");
			}
			if (!facts.Exists)
			{
				return TakeVerdict.TroughGone;
			}
			if (!facts.IsOwner)
			{
				return TakeVerdict.NotOwner;
			}
			if (granted.Contains(request.Id))
			{
				return TakeVerdict.Resend;
			}
			if (!facts.Enabled)
			{
				return TakeVerdict.TroughDisabled;
			}
			if (facts.Disallowed)
			{
				return TakeVerdict.ItemDisallowed;
			}
			if (!facts.HasItem)
			{
				return TakeVerdict.ItemMissing;
			}
			if (!ring.CheckAndRemember(request.Id, now))
			{
				return TakeVerdict.Duplicate;
			}
			return TakeVerdict.Granted;
		}

		public void Commit(TakeRequestId id)
		{
			granted.Add(id);
		}

		public void Release(TakeRequestId id)
		{
			granted.Remove(id);
			ring.Forget(id);
		}
	}
}
namespace ExtraPotions.Shepherd.Pens
{
	public static class LandPenDefinition
	{
		public const string Prefab = "shepherd_land_pen";

		public const string NativeGate = "wood_gate";

		public const string DefaultRecipe = "Wood:30, Resin:4";

		public const string Station = "piece_workbench";

		public const int DefaultCapacity = 12;

		public const int MaximumCapacity = 100;

		public const float Width = 6f;

		public const float Length = 6f;

		public const float Height = 3f;

		public const float RailHeight = 1.5f;

		public const string NameKey = "piece_land_pen";

		public const string DescriptionKey = "piece_land_pen_description";

		public const string CapacityKey = "land_pen_capacity";

		public static int Capacity(int value)
		{
			if (value >= 0)
			{
				if (value <= 100)
				{
					return value;
				}
				return 100;
			}
			return 0;
		}
	}
	public static class PenCapacity
	{
		public static int Maximum(int native, int? pen)
		{
			if (!pen.HasValue || pen.Value <= 0)
			{
				return native;
			}
			return pen.Value;
		}
	}
}
namespace ExtraPotions.Shepherd.Husbandry
{
	public static class FollowRules
	{
		public static bool Enables(bool active, bool nativelyCommandable, bool summon, bool supportsFollow)
		{
			return active && !nativelyCommandable && !summon && supportsFollow;
		}

		public static bool Restores(bool flippedByShepherd, bool active)
		{
			if (flippedByShepherd)
			{
				return !active;
			}
			return false;
		}

		public static bool PetsForContent(bool nativelyCommandable)
		{
			return !nativelyCommandable;
		}
	}
	public readonly struct HerdSnapshot
	{
		public float TamingLeft { get; }

		public float TamingTime { get; }

		public bool Tamed { get; }

		public long LastFed { get; }

		public int Births { get; }

		public bool BeingTamed
		{
			get
			{
				if (!Tamed)
				{
					return TamingLeft < TamingTime;
				}
				return false;
			}
		}

		public HerdSnapshot(float tamingLeft, float tamingTime, bool tamed, long lastFed, int births)
		{
			TamingTime = Math.Max(1f, tamingTime);
			Tamed = tamed;
			TamingLeft = (tamed ? 0f : tamingLeft);
			LastFed = lastFed;
			Births = births;
		}
	}
	public readonly struct ExperienceRates
	{
		public double Taming { get; }

		public double Tamed { get; }

		public double Discovery { get; }

		public double Feeding { get; }

		public double Birth { get; }

		public ExperienceRates(double taming, double tamed, double discovery, double feeding, double birth)
		{
			Taming = Math.Max(0.0, taming);
			Tamed = Math.Max(0.0, tamed);
			Discovery = Math.Max(1.0, discovery);
			Feeding = Math.Max(0.0, feeding);
			Birth = Math.Max(0.0, birth);
		}
	}
	public static class HerdExperience
	{
		public const int MaxBirthsPerScan = 4;

		public static double Between(HerdSnapshot before, HerdSnapshot now, ExperienceRates rates, Func<bool> firstOfKind)
		{
			if (firstOfKind == null)
			{
				throw new ArgumentNullException("firstOfKind");
			}
			double num = Taming(before, now, rates) + Tamed(before, now, rates, firstOfKind);
			if (now.LastFed != before.LastFed && now.LastFed != 0L && (now.Tamed || now.BeingTamed))
			{
				num += rates.Feeding;
			}
			int num2 = Math.Min(4, Math.Max(0, now.Births - before.Births));
			return num + (double)num2 * rates.Birth;
		}

		private static double Taming(HerdSnapshot before, HerdSnapshot now, ExperienceRates rates)
		{
			if (before.Tamed || now.Tamed || now.TamingLeft >= before.TamingLeft)
			{
				return 0.0;
			}
			return (double)(before.TamingLeft - now.TamingLeft) / (double)now.TamingTime * rates.Taming;
		}

		private static double Tamed(HerdSnapshot before, HerdSnapshot now, ExperienceRates rates, Func<bool> firstOfKind)
		{
			if (!now.Tamed || !before.BeingTamed)
			{
				return 0.0;
			}
			if (!firstOfKind())
			{
				return rates.Tamed;
			}
			return rates.Tamed * rates.Discovery;
		}
	}
	public static class TameDiscovery
	{
		public const string Key = "shepherd.tamed_kinds";

		public const string GrindstoneKey = "grindstone_tamed";

		private const char Separator = ',';

		public static bool HasTamed(IDictionary<string, string> data, string prefab)
		{
			if (data != null && !string.IsNullOrEmpty(prefab))
			{
				if (!Listed(data, "shepherd.tamed_kinds", prefab))
				{
					return Listed(data, "grindstone_tamed", prefab);
				}
				return true;
			}
			return false;
		}

		public static bool TryRecord(IDictionary<string, string> data, string prefab)
		{
			if (data == null || string.IsNullOrEmpty(prefab) || prefab.IndexOf(',') >= 0 || HasTamed(data, prefab))
			{
				return false;
			}
			data.TryGetValue("shepherd.tamed_kinds", out string value);
			data["shepherd.tamed_kinds"] = (string.IsNullOrEmpty(value) ? prefab : (value + "," + prefab));
			return true;
		}

		private static bool Listed(IDictionary<string, string> data, string key, string prefab)
		{
			if (data.TryGetValue(key, out string value))
			{
				return Array.IndexOf((value ?? "").Split(','), prefab) >= 0;
			}
			return false;
		}
	}
	public static class HusbandryIdentity
	{
		public const string Identity = "meadworks_husbandry";

		public const string PublishKey = "meadworks_husbandry_level";

		public const string ImportFrom = "grindstone_husbandry";

		public const string Name = "Husbandry";

		public const string Description = "Tending animals: taming, feeding, breeding and herd care.";

		public const double DefaultKeeperRange = 30.0;
	}
}
namespace ExtraPotions.Shepherd.Feeding
{
	public enum FeederKind
	{
		Trough,
		Container
	}
	public enum ContainerSelectionMode
	{
		AllExceptDenied,
		MarkedOnly
	}
	public readonly struct AnimalFacts
	{
		public bool Tamed { get; }

		public bool BeingTamed { get; }

		public bool Tameable { get; }

		public bool Hungry { get; }

		public bool Dead { get; }

		public bool Disallowed { get; }

		public AnimalFacts(bool tamed, bool beingTamed, bool tameable, bool hungry, bool dead, bool disallowed)
		{
			Tamed = tamed;
			BeingTamed = beingTamed;
			Tameable = tameable;
			Hungry = hungry;
			Dead = dead;
			Disallowed = disallowed;
		}
	}
	public static class NameList
	{
		public static IReadOnlyCollection<string> Parse(string? text)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			string[] array = (text ?? "").Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length > 0)
				{
					hashSet.Add(text2);
				}
			}
			return hashSet;
		}
	}
	public static class FeedingRules
	{
		public static bool Eligible(AnimalFacts animal, bool feedWild)
		{
			if (!animal.Tameable || !animal.Hungry || animal.Dead || animal.Disallowed)
			{
				return false;
			}
			return animal.Tamed || animal.BeingTamed || feedWild;
		}

		public static bool EligibleYoung(AnimalFacts animal, bool feedWild, bool growing, bool nativeEater)
		{
			if (growing && nativeEater && !animal.Tameable && animal.Hungry && !animal.Dead && !animal.Disallowed)
			{
				return animal.Tamed || feedWild;
			}
			return false;
		}

		public static string? FirstFood(IEnumerable<string> consumeItems, Func<string, bool> holds, IReadOnlyCollection<string> disallowed)
		{
			if (consumeItems == null)
			{
				throw new ArgumentNullException("consumeItems");
			}
			if (holds == null)
			{
				throw new ArgumentNullException("holds");
			}
			foreach (string consumeItem in consumeItems)
			{
				if (!string.IsNullOrEmpty(consumeItem) && !IsListed(disallowed, consumeItem) && holds(consumeItem))
				{
					return consumeItem;
				}
			}
			return null;
		}

		public static bool IsListed(IReadOnlyCollection<string>? names, string? name)
		{
			if (names == null || names.Count == 0 || string.IsNullOrEmpty(name))
			{
				return false;
			}
			if (names is ICollection<string> collection)
			{
				return collection.Contains(name);
			}
			foreach (string name2 in names)
			{
				if (string.Equals(name2, name, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}
	}
	public readonly struct ContainerFacts
	{
		public bool IsTrough { get; }

		public bool IsPrivate { get; }

		public bool PlayerBuilt { get; }

		public bool? BurrowFeedSource { get; }

		public bool ShepherdMarked { get; }

		public bool ShepherdDenied { get; }

		public ContainerFacts(bool isTrough, bool isPrivate, bool playerBuilt, bool? burrowFeedSource, bool shepherdMarked, bool shepherdDenied)
		{
			IsTrough = isTrough;
			IsPrivate = isPrivate;
			PlayerBuilt = playerBuilt;
			BurrowFeedSource = burrowFeedSource;
			ShepherdMarked = shepherdMarked;
			ShepherdDenied = shepherdDenied;
		}
	}
	public static class ContainerEligibility
	{
		public const string MarkKey = "shepherd.feed";

		public const string DenyKey = "shepherd.feed_deny";

		public static bool IsFeedSource(ContainerFacts facts, ContainerSelectionMode selection)
		{
			if (facts.IsTrough || facts.IsPrivate || !facts.PlayerBuilt)
			{
				return false;
			}
			if (selection == ContainerSelectionMode.MarkedOnly)
			{
				return facts.BurrowFeedSource ?? facts.ShepherdMarked;
			}
			return !facts.ShepherdDenied;
		}
	}
	public readonly struct FeedSolidSpan
	{
		public double Start { get; }

		public double End { get; }

		public FeedSolidSpan(double start, double end)
		{
			Start = start;
			End = end;
		}
	}
	public static class FeedMath
	{
		public const double EatRiseMetres = 1.0;

		public const int RingBearings = 8;

		public const double SpotRecheckSeconds = 2.0;

		public const double DirectWalkMetres = 6.0;

		public const double DirectWalkRise = 1.0;

		public static double SolidThickness(IEnumerable<FeedSolidSpan> solids)
		{
			List<FeedSolidSpan> list = new List<FeedSolidSpan>();
			foreach (FeedSolidSpan solid in solids)
			{
				if (double.IsNaN(solid.Start) || double.IsNaN(solid.End) || double.IsInfinity(solid.Start) || double.IsInfinity(solid.End) || solid.Start < 0.0 || solid.End < solid.Start)
				{
					return double.PositiveInfinity;
				}
				if (solid.End > solid.Start)
				{
					list.Add(solid);
				}
			}
			list.Sort((FeedSolidSpan a, FeedSolidSpan b) => a.Start.CompareTo(b.Start));
			double num = 0.0;
			double num2 = 0.0;
			foreach (FeedSolidSpan item in list)
			{
				if (!(item.End <= num2))
				{
					num += item.End - Math.Max(num2, item.Start);
					num2 = item.End;
				}
			}
			return num;
		}

		public static bool WallWithinReach(double thickness, double configuredMetres)
		{
			double num = (double.IsNaN(configuredMetres) ? 0.0 : Math.Max(0.0, Math.Min(2.0, configuredMetres)));
			if (thickness != 0.0)
			{
				if (thickness > 0.0 && num > 0.0)
				{
					return thickness <= num + 0.0001;
				}
				return false;
			}
			return true;
		}

		public static double StandOff(double sourceRadius, double animalRadius)
		{
			return sourceRadius + animalRadius;
		}

		public static bool InReach(double distance, double sourceRadius, double animalRadius, double proximity)
		{
			return InReach(distance, sourceRadius, animalRadius, proximity, 0.0);
		}

		public static bool InReach(double distance, double sourceRadius, double animalRadius, double proximity, double rise)
		{
			if (Math.Abs(rise) <= 1.0)
			{
				return distance <= StandOff(sourceRadius, animalRadius) + proximity;
			}
			return false;
		}

		public static bool MayEatFrom(double distance, double sourceRadius, double animalRadius, double proximity, bool requireMove, double range)
		{
			return MayEatFrom(distance, sourceRadius, animalRadius, proximity, requireMove, range, 0.0);
		}

		public static bool MayEatFrom(double distance, double sourceRadius, double animalRadius, double proximity, bool requireMove, double range, double rise)
		{
			if (!requireMove)
			{
				return distance <= range;
			}
			return InReach(distance, sourceRadius, animalRadius, proximity, rise);
		}

		public static bool GaveUp(double since, double now, double giveUpSeconds)
		{
			return now - since > giveUpSeconds;
		}

		public static bool MayWalkDirect(double toSpot, double rise)
		{
			if (toSpot >= 0.0 && toSpot <= 6.0)
			{
				return Math.Abs(rise) <= 1.0;
			}
			return false;
		}

		public static IEnumerable<int> RingOrder(int bearings)
		{
			if (bearings <= 0)
			{
				yield break;
			}
			yield return 0;
			for (int step = 1; step <= bearings / 2; step++)
			{
				yield return step;
				if (bearings - step != step)
				{
					yield return bearings - step;
				}
			}
		}
	}
	public sealed class FeedCandidate
	{
		public string Id { get; }

		public FeederKind Kind { get; }

		public double DistanceSquared { get; }

		public string Food { get; }

		public FeedCandidate(string id, FeederKind kind, double distanceSquared, string food)
		{
			Id = id ?? throw new ArgumentNullException("id");
			Kind = kind;
			DistanceSquared = distanceSquared;
			Food = food ?? throw new ArgumentNullException("food");
		}
	}
	public static class FeedSearch
	{
		public const int PathTries = 3;

		public static FeedCandidate? Choose(IEnumerable<FeedCandidate> candidates, Func<FeedCandidate, bool> havePath)
		{
			if (candidates == null)
			{
				throw new ArgumentNullException("candidates");
			}
			if (havePath == null)
			{
				throw new ArgumentNullException("havePath");
			}
			int num = 0;
			foreach (FeedCandidate item in from c in candidates
				orderby (c.Kind != FeederKind.Trough) ? 1 : 0, c.DistanceSquared
				select c)
			{
				if (havePath(item))
				{
					return item;
				}
				if (++num >= 3)
				{
					return null;
				}
			}
			return null;
		}
	}
	public static class YoungMealPacing
	{
		public const double FallbackSeconds = 600.0;

		public static double Interval(double adultSeconds)
		{
			if (!(adultSeconds > 0.0) || double.IsInfinity(adultSeconds) || double.IsNaN(adultSeconds))
			{
				return 600.0;
			}
			return adultSeconds;
		}

		public static bool Due(long nowTicks, long lastMealTicks, double adultSeconds)
		{
			if (nowTicks <= 0)
			{
				return false;
			}
			if (lastMealTicks <= 0)
			{
				return true;
			}
			if (lastMealTicks > nowTicks)
			{
				return false;
			}
			return (double)(nowTicks - lastMealTicks) / 10000000.0 >= Interval(adultSeconds);
		}
	}
}
namespace ExtraPotions.Shepherd.Conversion
{
	public static class SimpleYaml
	{
		public static Dictionary<string, string> Read(string? text)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			List<(int, string)> list = new List<(int, string)>();
			int num = -1;
			string[] array = (text ?? "").Replace("\r", "").Split('\n');
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = StripComment(array[i]);
				if (text2.Trim().Length == 0)
				{
					continue;
				}
				int num2 = text2.Length - text2.TrimStart(' ').Length;
				string text3 = text2.Trim();
				if (num >= 0)
				{
					if (num2 > num)
					{
						continue;
					}
					num = -1;
				}
				while (list.Count > 0 && list[list.Count - 1].Item1 >= num2)
				{
					list.RemoveAt(list.Count - 1);
				}
				if (text3.StartsWith("-", StringComparison.Ordinal))
				{
					num = num2;
					continue;
				}
				int num3 = text3.IndexOf(':');
				if (num3 > 0)
				{
					string text4 = text3.Substring(0, num3).Trim();
					string text5 = Unquote(text3.Substring(num3 + 1).Trim());
					string key = string.Join(".", list.Select<(int, string), string>(((int Indent, string Key) s) => s.Key).Concat(new string[1] { text4 }));
					if (text5.Length == 0)
					{
						list.Add((num2, text4));
					}
					else
					{
						dictionary[key] = text5;
					}
				}
			}
			return dictionary;
		}

		public static IReadOnlyList<string> List(string? value)
		{
			string text = (value ?? "").Trim();
			if (text.StartsWith("[", StringComparison.Ordinal) && text.EndsWith("]", StringComparison.Ordinal))
			{
				text = text.Substring(1, text.Length - 2);
			}
			return (from p in text.Split(',')
				select Unquote(p.Trim()) into p
				where p.Length > 0
				select p).ToList();
		}

		private static string StripComment(string line)
		{
			char c = '\0';
			for (int i = 0; i < line.Length; i++)
			{
				char c2 = line[i];
				if (c != 0)
				{
					if (c2 == c)
					{
						c = '\0';
					}
					continue;
				}
				switch (c2)
				{
				case '"':
				case '\'':
					c = c2;
					break;
				case '#':
					if (i == 0 || line[i - 1] == ' ')
					{
						return line.Substring(0, i);
					}
					break;
				}
			}
			return line;
		}

		private static string Unquote(string v)
		{
			if (v.Length < 2 || (v[0] != '\'' && v[0] != '"') || v[v.Length - 1] != v[0])
			{
				return v;
			}
			return v.Substring(1, v.Length - 2);
		}
	}
	public readonly struct SourceEntry
	{
		public string Section { get; }

		public string Key { get; }

		public string Value { get; }

		public SourceEntry(string section, string key, string value)
		{
			Section = section;
			Key = key;
			Value = value;
		}
	}
	public static class SourceConfig
	{
		public static IReadOnlyList<SourceEntry> Parse(string? text)
		{
			List<SourceEntry> list = new List<SourceEntry>();
			string section = "";
			string[] array = (text ?? "").Split('\n');
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length == 0 || text2[0] == '#')
				{
					continue;
				}
				if (text2[0] == '[' && text2[text2.Length - 1] == ']')
				{
					section = text2.Substring(1, text2.Length - 2).Trim();
					continue;
				}
				int num = text2.IndexOf('=');
				if (num > 0)
				{
					string text3 = text2.Substring(0, num).Trim();
					if (text3.Length != 0)
					{
						list.Add(new SourceEntry(section, text3, text2.Substring(num + 1).Trim()));
					}
				}
			}
			return list;
		}
	}
	public enum ImportSource
	{
		AutoFeedRedux,
		GrindstoneSkills,
		EliteCreaturesReborn
	}
	public sealed class ImportPlan
	{
		public ImportSource Source { get; }

		public Dictionary<string, string> Values { get; } = new Dictionary<string, string>(StringComparer.Ordinal);

		public List<string> Notes { get; } = new List<string>();

		internal ImportPlan(ImportSource source)
		{
			Source = source;
		}

		public string Report()
		{
			return "Source: " + Source.ToString() + "\n" + string.Join("\n", Values.Select<KeyValuePair<string, string>, string>((KeyValuePair<string, string> v) => "Set " + v.Key + " = " + v.Value).Concat(Notes));
		}
	}
	public static class SourceImport
	{
		private static readonly Dictionary<string, string> mappings = BuildMappings();

		public static string FileName(ImportSource source)
		{
			return source switch
			{
				ImportSource.GrindstoneSkills => "com.GrindstoneSkills.cfg", 
				ImportSource.AutoFeedRedux => "vapok.mods.AutoFeedRedux.cfg", 
				_ => "creature_rules.yml", 
			};
		}

		private static Dictionary<string, string> BuildMappings()
		{
			Dictionary<string, string> map = new Dictionary<string, string>(StringComparer.Ordinal);
			Set("Synced Settings", "Enable Auto Feeder", "2 - Feeding", "Container Feeding");
			Set("Synced Settings", "Feed Range in Meters", "2 - Feeding", "Container Range");
			Set("Synced Settings", "Require Move to Feed", "2 - Feeding", "Require Move To Feed");
			Set("Synced Settings", "Disallow Animal", "2 - Feeding", "Disallow Animals");
			Same("Synced Settings", "2 - Feeding", "Move Proximity|Disallow Feed|Protect Feed Containers");
			Set("23 - Husbandry", "Husbandry Enabled", "1 - General", "Husbandry Enabled");
			Same("23 - Husbandry", "4 - Husbandry", "Keeper Range|Animal Lore Level|Show Callouts");
			Same("24 - Taming", "5 - Taming", "Taming Speed At 100|Fed Duration At 100|Taming Levels|Calm Level|Calm Break Time");
			Same("25 - Breeding", "6 - Breeding", "Breeding Speed At 100|Growth Speed At 100|Better Offspring At 100|Max Offspring Level|Twins At 100|Content Duration|Content Breeding Bonus");
			Set("25 - Breeding", "Herd Size At 100", "7 - Herd", "Herd Size At 100");
			Same("26 - Animal Yield", "8 - Yield", "Butcher Yield At 100|Produce Chance At 100|Produce Interval|Extra Honey At 100");
			Same("27 - Companions", "9 - Companions", "Pack Damage At 100|Pack Toughness At 100");
			Set("27 - Companions", "Feeder Level", "3 - Troughs", "Build Level");
			Set("27 - Companions", "Feeder Range", "2 - Feeding", "Trough Range");
			Set("27 - Companions", "Feeder Recipe", "3 - Troughs", "Feed Barrel Recipe");
			Same("28 - Husbandry Experience", "10 - Experience", "Experience Multiplier|Taming Experience|Tamed Experience|Discovery Multiplier|Feeding Experience|Birth Experience|Petting Experience|Butchering Experience|Honey Experience");
			return map;
			void Same(string section, string target, string names)
			{
				string[] array = names.Split('|');
				foreach (string text in array)
				{
					Set(section, text, target, text);
				}
			}
			void Set(string section, string key, string targetSection, string targetKey)
			{
				map[section + "." + key] = targetSection + "." + targetKey;
			}
		}

		public static ImportPlan Plan(ImportSource source, string text)
		{
			ImportPlan importPlan = new ImportPlan(source);
			if (source == ImportSource.EliteCreaturesReborn)
			{
				foreach (KeyValuePair<string, string> item in SimpleYaml.Read(text))
				{
					if (item.Key == "breeding.enabled")
					{
						if (!bool.TryParse(item.Value, out var result))
						{
							throw new ArgumentException("Invalid breeding.enabled.");
						}
						if (result)
						{
							importPlan.Values["6 - Breeding.Star Inheritance"] = "BestParentUniform";
						}
						else
						{
							importPlan.Notes.Add("Skip breeding.enabled=false: source inheritance is disabled.");
						}
					}
					else if (item.Key == "breeding.mutation chance")
					{
						importPlan.Values["6 - Breeding.Mutation Chance"] = item.Value;
					}
					else
					{
						importPlan.Notes.Add("Skip " + item.Key + ": outside Shepherd mappings.");
					}
				}
				return importPlan;
			}
			foreach (SourceEntry item2 in SourceConfig.Parse(text))
			{
				string text2 = item2.Section + "." + item2.Key;
				if (((source == ImportSource.AutoFeedRedux) ? (item2.Section == "Synced Settings") : (item2.Section != "Synced Settings")) && mappings.TryGetValue(text2, out string value))
				{
					importPlan.Values[value] = item2.Value;
				}
				else
				{
					importPlan.Notes.Add("Skip " + text2 + ": outside Shepherd mappings.");
				}
			}
			return importPlan;
		}
	}
	public sealed class SourceModuleDecision
	{
		public bool Feeding { get; internal set; }

		public bool Husbandry { get; internal set; }

		public bool Inheritance { get; internal set; }

		public bool Containers { get; internal set; }
	}
	public static class SourceModules
	{
		public const string AutoFeedRedux = "vapok.mods.AutoFeedRedux";

		public const string GrindstoneSkills = "com.GrindstoneSkills";

		public const string EliteCreaturesReborn = "gglasgow.elitecreaturesreborn";

		public const string OpenKeep = "milkyteam.openkeep";

		public static SourceModuleDecision Decide(IEnumerable<string> installed, bool? gsHusbandry, bool? ecrBreeding, bool? openKeepPets)
		{
			HashSet<string> hashSet = new HashSet<string>(installed, StringComparer.Ordinal);
			bool flag = hashSet.Contains("com.GrindstoneSkills") && gsHusbandry != false;
			return new SourceModuleDecision
			{
				Feeding = (hashSet.Contains("vapok.mods.AutoFeedRedux") || flag),
				Husbandry = flag,
				Inheritance = (hashSet.Contains("gglasgow.elitecreaturesreborn") && ecrBreeding != false),
				Containers = (hashSet.Contains("milkyteam.openkeep") && openKeepPets != false)
			};
		}
	}
}
namespace ExtraPotions.Shepherd.Breeding
{
	public sealed class BirthInput
	{
		public string Token { get; }

		public LineageRecord? Mother { get; }

		public string MotherName { get; }

		public int MotherLevel { get; }

		public SireRecord? Sire { get; }

		public int MinOffspringLevel { get; }

		public double KeeperLevel { get; }

		public int Day { get; }

		public string Breeder { get; }

		public bool RecordLineage { get; }

		public string Traits { get; }

		public BirthInput(string token, LineageRecord? mother, string motherName, int motherLevel, SireRecord? sire, int minOffspringLevel, double keeperLevel, int day, string breeder, bool recordLineage, string traits)
		{
			Token = token ?? "";
			Mother = mother;
			MotherName = motherName ?? "";
			MotherLevel = motherLevel;
			Sire = sire;
			MinOffspringLevel = minOffspringLevel;
			KeeperLevel = keeperLevel;
			Day = day;
			Breeder = breeder ?? "";
			RecordLineage = recordLineage;
			Traits = traits ?? "";
		}
	}
	public sealed class BirthPlan
	{
		public InheritanceResult Inheritance { get; }

		public int Level => Inheritance.Level;

		public LineageRecord? Lineage { get; }

		public EggRecord Egg { get; }

		public int EggQuality => Inheritance.Level;

		public BirthPlan(InheritanceResult inheritance, LineageRecord? lineage, EggRecord egg)
		{
			Inheritance = inheritance;
			Lineage = lineage;
			Egg = egg;
		}
	}
	public static class BirthPlanner
	{
		public static BirthPlan Plan(BirthInput input, InheritanceSettings settings, IBreedingRandom random)
		{
			if (input == null)
			{
				throw new ArgumentNullException("input");
			}
			InheritanceResult inheritance = StarInheritance.Compute(new InheritanceInput(input.MotherLevel, input.Sire?.Level ?? 0, input.MinOffspringLevel, input.KeeperLevel), settings, random);
			LineageRecord lineageRecord = (input.RecordLineage ? Lineage.Newborn(input.Token, input.Mother, input.MotherName, input.Sire, input.Day, input.Breeder) : null);
			EggRecord egg = ((lineageRecord != null) ? EggRecord.FromNewborn(lineageRecord, input.Traits) : new EggRecord("", "", "", "", 0, 0, "", input.Traits));
			return new BirthPlan(inheritance, lineageRecord, egg);
		}
	}
	public enum BreedingVerb : byte
	{
		Help,
		Breed,
		Stars
	}
	public readonly struct BreedingCommandLine
	{
		public BreedingVerb Verb { get; }

		public int Level { get; }

		private BreedingCommandLine(BreedingVerb verb, int level = 0)
		{
			Verb = verb;
			Level = level;
		}

		public static BreedingCommandLine Parse(IReadOnlyList<string> args, int maxLevel)
		{
			if (args.Count == 1 && args[0].Equals("breed", StringComparison.OrdinalIgnoreCase))
			{
				return new BreedingCommandLine(BreedingVerb.Breed);
			}
			if (args.Count == 2 && args[0].Equals("stars", StringComparison.OrdinalIgnoreCase) && int.TryParse(args[1], NumberStyles.None, CultureInfo.InvariantCulture, out var result) && result < maxLevel)
			{
				return new BreedingCommandLine(BreedingVerb.Stars, result + 1);
			}
			return new BreedingCommandLine(BreedingVerb.Help);
		}
	}
	public readonly struct PaceFields : IEquatable<PaceFields>
	{
		public double PregnancyDuration { get; }

		public double PregnancyChance { get; }

		public int MaxCreatures { get; }

		public PaceFields(double pregnancyDuration, double pregnancyChance, int maxCreatures)
		{
			PregnancyDuration = pregnancyDuration;
			PregnancyChance = pregnancyChance;
			MaxCreatures = maxCreatures;
		}

		public bool Equals(PaceFields other)
		{
			if (PregnancyDuration.Equals(other.PregnancyDuration) && PregnancyChance.Equals(other.PregnancyChance))
			{
				return MaxCreatures == other.MaxCreatures;
			}
			return false;
		}

		public override bool Equals(object? obj)
		{
			if (obj is PaceFields other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (((PregnancyDuration.GetHashCode() * 397) ^ PregnancyChance.GetHashCode()) * 397) ^ MaxCreatures;
		}

		public override string ToString()
		{
			return PregnancyDuration + "/" + PregnancyChance + "/" + MaxCreatures;
		}
	}
	public sealed class PacedCall
	{
		public bool Paced { get; }

		public PaceFields Fields { get; }

		public PaceFields Original { get; }

		public PacedCall(bool paced, PaceFields fields, PaceFields original)
		{
			Paced = paced;
			Fields = fields;
			Original = original;
		}
	}
	public static class BreedingPace
	{
		public static double SpeedFactor(double breedingSpeedAt100, double keeperLevel, bool content, double contentBonusPercent)
		{
			double num = 1.0 + HusbandryShare.Share(breedingSpeedAt100, keeperLevel);
			if (content)
			{
				num += Math.Max(0.0, contentBonusPercent) / 100.0;
			}
			return num;
		}

		public static PacedCall Apply(PaceFields original, double factor, int room)
		{
			if (!(factor > 1.0) && room <= 0)
			{
				return new PacedCall(paced: false, original, original);
			}
			double num = Math.Max(1.0, factor);
			int maxCreatures = ((room > 0 && original.MaxCreatures > int.MaxValue - room) ? int.MaxValue : (original.MaxCreatures + Math.Max(0, room)));
			return new PacedCall(paced: true, new PaceFields(original.PregnancyDuration / num, original.PregnancyChance / num, maxCreatures), original);
		}

		public static double GrowthFactor(double growthSpeedAt100, double keeperLevel)
		{
			return 1.0 + HusbandryShare.Share(growthSpeedAt100, keeperLevel);
		}

		public static double ScaledTime(double time, double factor)
		{
			if (!(factor > 1.0))
			{
				return time;
			}
			return time / factor;
		}

		public static double TwinStartOffset(double pregnancyDuration, double twinDelay)
		{
			return 0.0 - Math.Max(0.0, pregnancyDuration - twinDelay);
		}
	}
	public interface IBreedingRandom
	{
		double Value();

		int Range(int minInclusive, int maxExclusive);
	}
	public sealed class SeededRandom : IBreedingRandom
	{
		private readonly Random random;

		public SeededRandom(int seed)
		{
			random = new Random(seed);
		}

		public double Value()
		{
			return random.NextDouble();
		}

		public int Range(int minInclusive, int maxExclusive)
		{
			return random.Next(minInclusive, maxExclusive);
		}
	}
	public interface IKeyStore
	{
		string GetString(string key);

		int GetInt(string key);

		long GetLong(string key);

		bool GetBool(string key);

		void Set(string key, string value);

		void Set(string key, int value);

		void Set(string key, long value);

		void Set(string key, bool value);
	}
	public static class BreedingKeys
	{
		public const string Instance = "shepherd.instance";

		public const string Mother = "shepherd.mother";

		public const string Sire = "shepherd.sire";

		public const string MotherName = "shepherd.mother_name";

		public const string SireName = "shepherd.sire_name";

		public const string Generation = "shepherd.gen";

		public const string Born = "shepherd.born";

		public const string Breeder = "shepherd.breeder";

		public const string PendingSire = "shepherd.pending_sire";

		public const string PendingSireName = "shepherd.pending_sire_name";

		public const string PendingSireLevel = "shepherd.pending_sire_level";

		public const string PendingSireGeneration = "shepherd.pending_sire_gen";

		public const string PendingSireTraits = "shepherd.pending_sire_traits";

		public const string TwinDue = "shepherd.twin_due";

		public const string IsTwin = "shepherd.is_twin";

		public const string ContentUntil = "shepherd.content_until";

		public const string ProduceNext = "shepherd.produce_next";

		public const string Traits = "shepherd.traits";

		public const string Births = "shepherd.births";

		public const string Egg = "shepherd.egg";

		private static readonly string[] Keys = new string[20]
		{
			"shepherd.instance", "shepherd.mother", "shepherd.sire", "shepherd.mother_name", "shepherd.sire_name", "shepherd.gen", "shepherd.born", "shepherd.breeder", "shepherd.pending_sire", "shepherd.pending_sire_name",
			"shepherd.pending_sire_level", "shepherd.pending_sire_gen", "shepherd.pending_sire_traits", "shepherd.twin_due", "shepherd.is_twin", "shepherd.content_until", "shepherd.produce_next", "shepherd.traits", "shepherd.births", "shepherd.egg"
		};

		public static IReadOnlyList<string> All => Keys;
	}
	public static class BreedingStore
	{
		public static void WriteLineage(IKeyStore store, LineageRecord record)
		{
			if (store == null)
			{
				throw new ArgumentNullException("store");
			}
			if (record == null)
			{
				throw new ArgumentNullException("record");
			}
			store.Set("shepherd.instance", record.Token);
			store.Set("shepherd.mother", record.MotherToken);
			store.Set("shepherd.sire", record.SireToken);
			store.Set("shepherd.mother_name", record.MotherName);
			store.Set("shepherd.sire_name", record.SireName);
			store.Set("shepherd.gen", record.Generation);
			store.Set("shepherd.born", record.BornDay);
			store.Set("shepherd.breeder", record.Breeder);
		}

		public static LineageRecord? ReadLineage(IKeyStore store)
		{
			if (store == null)
			{
				throw new ArgumentNullException("store");
			}
			string text = store.GetString("shepherd.instance");
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			return new LineageRecord(text, store.GetString("shepherd.mother"), store.GetString("shepherd.sire"), store.GetString("shepherd.mother_name"), store.GetString("shepherd.sire_name"), Math.Max(0, store.GetInt("shepherd.gen")), store.GetInt("shepherd.born"), store.GetString("shepherd.breeder"));
		}

		public static void WritePendingSire(IKeyStore store, SireRecord? sire)
		{
			if (store == null)
			{
				throw new ArgumentNullException("store");
			}
			store.Set("shepherd.pending_sire", sire?.Token ?? "");
			store.Set("shepherd.pending_sire_name", sire?.Name ?? "");
			store.Set("shepherd.pending_sire_level", sire?.Level ?? 0);
			store.Set("shepherd.pending_sire_gen", sire?.Generation ?? 0);
			store.Set("shepherd.pending_sire_traits", sire?.Traits ?? "");
		}

		public static SireRecord? ReadPendingSire(IKeyStore store)
		{
			if (store == null)
			{
				throw new ArgumentNullException("store");
			}
			int num = store.GetInt("shepherd.pending_sire_level");
			if (num < 1)
			{
				return null;
			}
			return new SireRecord(store.GetString("shepherd.pending_sire"), store.GetString("shepherd.pending_sire_name"), num, store.GetInt("shepherd.pending_sire_gen"), store.GetString("shepherd.pending_sire_traits"));
		}

		public static void SetTwinDue(IKeyStore store, double worldSeconds)
		{
			SetTime(store, "shepherd.twin_due", worldSeconds);
		}

		public static double GetTwinDue(IKeyStore store)
		{
			return GetTime(store, "shepherd.twin_due");
		}

		public static void SetContentUntil(IKeyStore store, double worldSeconds)
		{
			SetTime(store, "shepherd.content_until", worldSeconds);
		}

		public static double GetContentUntil(IKeyStore store)
		{
			return GetTime(store, "shepherd.content_until");
		}

		public static void SetProduceNext(IKeyStore store, double worldSeconds)
		{
			SetTime(store, "shepherd.produce_next", worldSeconds);
		}

		public static double GetProduceNext(IKeyStore store)
		{
			return GetTime(store, "shepherd.produce_next");
		}

		public static bool IsTwin(IKeyStore store)
		{
			return (store ?? throw new ArgumentNullException("store")).GetBool("shepherd.is_twin");
		}

		public static void SetIsTwin(IKeyStore store, bool value)
		{
			(store ?? throw new ArgumentNullException("store")).Set("shepherd.is_twin", value);
		}

		public static string GetTraits(IKeyStore store)
		{
			return (store ?? throw new ArgumentNullException("store")).GetString("shepherd.traits");
		}

		public static void SetTraits(IKeyStore store, string traits)
		{
			(store ?? throw new ArgumentNullException("store")).Set("shepherd.traits", traits ?? "");
		}

		private static void SetTime(IKeyStore store, string key, double worldSeconds)
		{
			if (store == null)
			{
				throw new ArgumentNullException("store");
			}
			bool flag = !double.IsNaN(worldSeconds) && !double.IsInfinity(worldSeconds) && worldSeconds > 0.0 && worldSeconds < 9223372036854776.0;
			store.Set(key, flag ? ((long)Math.Round(worldSeconds * 1000.0)) : 0);
		}

		private static double GetTime(IKeyStore store, string key)
		{
			if (store == null)
			{
				throw new ArgumentNullException("store");
			}
			return (double)Math.Max(0L, store.GetLong(key)) / 1000.0;
		}
	}
	public sealed class ClaimSlot<T> where T : class
	{
		private T? record;

		private string? prefab;

		public bool Armed => record != null;

		public void Arm(T value, string offspringPrefab)
		{
			record = value ?? throw new ArgumentNullException("value");
			prefab = offspringPrefab ?? throw new ArgumentNullException("offspringPrefab");
		}

		public bool Claims(string? objectPrefab)
		{
			if (record != null && objectPrefab != null)
			{
				return objectPrefab == prefab;
			}
			return false;
		}

		public T? Claim(string? objectPrefab)
		{
			if (!Claims(objectPrefab))
			{
				return null;
			}
			T? result = record;
			Clear();
			return result;
		}

		public void Clear()
		{
			record = null;
			prefab = null;
		}
	}
	public static class Carry
	{
		public static bool GrowsNow(double secondsSinceSpawn, double growTime)
		{
			return secondsSinceSpawn > growTime;
		}

		public static LineageRecord GrowUp(LineageRecord young)
		{
			return Lineage.GrowUp(young);
		}

		public static LineageRecord? Hatch(string? eggText, string token)
		{
			if (!EggCodec.TryDecode(eggText, out EggRecord egg) || egg == null)
			{
				return null;
			}
			return Lineage.Hatch(egg, token);
		}
	}
	public sealed class EcrSire
	{
		public int Level { get; }

		public int Mask { get; }

		internal EcrSire(int level, int mask)
		{
			Level = level;
			Mask = mask;
		}
	}
	public readonly struct EcrEgg
	{
		public int Stars { get; }

		public int Level => Stars + 1;

		public int Mask { get; }

		public int Biome { get; }

		public EcrEgg(int stars, int mask, int biome)
		{
			Stars = stars;
			Mask = mask;
			Biome = biome;
		}
	}
	public static class EcrImport
	{
		public const string SireStarsKey = "ecr_sire_stars";

		public const string SireMaskKey = "ecr_sire_mask";

		public const string EggKey = "ecr_egg";

		public const string SireImportedKey = "shepherd.imported.ecr_sire";

		public const string StarUpKey = "grindstone_star_up";

		public static EcrSire? ReadSire(int sireStarsValue, int mask)
		{
			if (sireStarsValue > 0)
			{
				return new EcrSire(sireStarsValue, Math.Max(0, mask));
			}
			return null;
		}

		public static bool ImportPendingSire(IKeyStore store, out int mask)
		{
			if (store == null)
			{
				throw new ArgumentNullException("store");
			}
			mask = 0;
			EcrSire ecrSire = ReadSire(store.GetInt("ecr_sire_stars"), store.GetInt("ecr_sire_mask"));
			if (ecrSire == null || store.GetInt("shepherd.imported.ecr_sire") != 0 || BreedingStore.ReadPendingSire(store) != null)
			{
				return false;
			}
			BreedingStore.WritePendingSire(store, new SireRecord("", "", ecrSire.Level, 0, ""));
			store.Set("shepherd.imported.ecr_sire", 1);
			mask = ecrSire.Mask;
			return true;
		}

		public static bool TryParseEgg(string? text, out EcrEgg egg)
		{
			egg = default(EcrEgg);
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			string[] array = text.Split(',');
			if (array.Length < 3 || !Int(array[0], out var value) || value == int.MaxValue || !Int(array[1], out var value2) || !Int(array[2], out var value3))
			{
				return false;
			}
			egg = new EcrEgg(value, value2, value3);
			return true;
		}

		private static bool Int(string text, out int value)
		{
			if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
			{
				return value >= 0;
			}
			return false;
		}
	}
	public static class EggCodec
	{
		public const int MaxLength = 1024;

		public const int TrimmedNameLength = 64;

		private const string Version = "v1";

		private const int FieldCount = 9;

		public static string Encode(EggRecord egg)
		{
			if (egg == null)
			{
				throw new ArgumentNullException("egg");
			}
			string text = Join(egg, egg.Traits, int.MaxValue);
			if (text.Length > 1024)
			{
				text = Join(egg, "", int.MaxValue);
			}
			if (text.Length > 1024)
			{
				text = Join(egg, "", 64);
			}
			if (text.Length > 1024)
			{
				throw new ArgumentException("The egg's parent tokens do not fit in " + 1024 + " characters.", "egg");
			}
			return text;
		}

		public static bool TryDecode(string? text, out EggRecord? egg)
		{
			egg = null;
			if (string.IsNullOrEmpty(text) || text.Length > 1024)
			{
				return false;
			}
			List<string> list = Split(text);
			if (list == null || list.Count != 9 || list[0] != "v1")
			{
				return false;
			}
			if (!NonNegative(list[5], out var value) || !NonNegative(list[6], out var value2))
			{
				return false;
			}
			egg = new EggRecord(list[1], list[2], list[3], list[4], value, value2, list[7], list[8]);
			return true;
		}

		private static string Join(EggRecord egg, string traits, int nameLength)
		{
			StringBuilder stringBuilder = new StringBuilder("v1");
			string[] array = new string[8]
			{
				egg.MotherToken,
				egg.SireToken,
				Trim(egg.MotherName, nameLength),
				Trim(egg.SireName, nameLength),
				egg.Generation.ToString(CultureInfo.InvariantCulture),
				egg.BornDay.ToString(CultureInfo.InvariantCulture),
				Trim(egg.Breeder, nameLength),
				traits
			};
			foreach (string obj in array)
			{
				stringBuilder.Append(';');
				string text = obj;
				foreach (char c in text)
				{
					if (c == '\\' || c == ';')
					{
						stringBuilder.Append('\\');
					}
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		private static string Trim(string text, int length)
		{
			if (text.Length > length)
			{
				return text.Substring(0, length);
			}
			return text;
		}

		private static List<string>? Split(string text)
		{
			List<string> list = new List<string>();
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				switch (c)
				{
				case '\\':
					if (i + 1 >= text.Length || (text[i + 1] != '\\' && text[i + 1] != ';'))
					{
						return null;
					}
					stringBuilder.Append(text[++i]);
					break;
				case ';':
					list.Add(stringBuilder.ToString());
					stringBuilder.Clear();
					break;
				default:
					stringBuilder.Append(c);
					break;
				}
			}
			list.Add(stringBuilder.ToString());
			return list;
		}

		private static bool NonNegative(string text, out int value)
		{
			return int.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out value);
		}
	}
	public readonly struct HerdInput
	{
		public int VanillaMax { get; }

		public int Count { get; }

		public double HerdSizeAt100 { get; }

		public double KeeperLevel { get; }

		public bool Unlimited { get; }

		public bool Strict { get; }

		public HerdInput(int vanillaMax, int count, double herdSizeAt100, double keeperLevel, bool unlimited, bool strict)
		{
			VanillaMax = Math.Max(0, vanillaMax);
			Count = Math.Max(0, count);
			HerdSizeAt100 = herdSizeAt100;
			KeeperLevel = keeperLevel;
			Unlimited = unlimited;
			Strict = strict;
		}
	}
	public sealed class HerdVerdict
	{
		public int Bonus { get; }

		public int Limit { get; }

		public bool Unlimited { get; }

		public bool CanConceive { get; }

		public bool BirthMayProceed { get; }

		public bool WaitingForRoom => !BirthMayProceed;

		public int Room { get; }

		public int ExtraMax
		{
			get
			{
				if (!Unlimited)
				{
					return Bonus;
				}
				return int.MaxValue;
			}
		}

		internal HerdVerdict(int bonus, int limit, int count, bool unlimited, bool strict)
		{
			Bonus = bonus;
			Limit = limit;
			Unlimited = unlimited;
			CanConceive = unlimited || count < limit;
			BirthMayProceed = unlimited || !strict || count < limit;
			Room = (unlimited ? int.MaxValue : Math.Max(0, limit - count));
		}
	}
	public readonly struct HerdLine
	{
		public string Key { get; }

		public int Room { get; }

		public int Limit { get; }

		public HerdLine(string key, int room, int limit)
		{
			Key = key;
			Room = room;
			Limit = limit;
		}
	}
	public static class HerdLimit
	{
		public static HerdVerdict Evaluate(HerdInput input)
		{
			int num = HusbandryShare.ExtraRoom(input.HerdSizeAt100, input.KeeperLevel);
			int limit = (int)(input.Unlimited ? int.MaxValue : Math.Min(2147483646L, (long)input.VanillaMax + (long)num));
			return new HerdVerdict(num, limit, input.Count, input.Unlimited, input.Strict);
		}

		public static bool HoldsBirth(HerdVerdict verdict, bool pregnant, bool due)
		{
			if (verdict != null && pregnant && due)
			{
				return !verdict.BirthMayProceed;
			}
			return false;
		}

		public static HerdLine Describe(HerdVerdict verdict, bool pregnant, bool due)
		{
			if (verdict == null)
			{
				throw new ArgumentNullException("verdict");
			}
			if (HoldsBirth(verdict, pregnant, due))
			{
				return new HerdLine("herd_waiting", 0, verdict.Limit);
			}
			if (verdict.Unlimited)
			{
				return new HerdLine("herd_unlimited", 0, 0);
			}
			return new HerdLine("herd_room", verdict.Room, verdict.Limit);
		}
	}
	public static class HusbandryShare
	{
		public const double MaxLevel = 100.0;

		public static double Share(double percentAt100, double level)
		{
			return Math.Max(0.0, percentAt100) / 100.0 * Clamp01(level / 100.0);
		}

		public static bool Rolls(double percentAt100, double level, IBreedingRandom random)
		{
			if (random == null)
			{
				throw new ArgumentNullException("random");
			}
			double num = Share(percentAt100, level);
			if (num > 0.0)
			{
				return random.Value() < num;
			}
			return false;
		}

		public static bool RollsFlat(double percent, IBreedingRandom random)
		{
			if (random == null)
			{
				throw new ArgumentNullException("random");
			}
			double num = Math.Max(0.0, percent) / 100.0;
			if (num > 0.0)
			{
				return random.Value() < num;
			}
			return false;
		}

		public static int ExtraRoom(double herdSizeAt100, double level)
		{
			return (int)Math.Floor(Math.Max(0.0, herdSizeAt100) * Clamp01(level / 100.0) + 0.5);
		}

		private static double Clamp01(double value)
		{
			if (!double.IsNaN(value))
			{
				return Math.Min(1.0, Math.Max(0.0, value));
			}
			return 0.0;
		}
	}
	public sealed class LineageRecord
	{
		public string Token { get; }

		public string MotherToken { get; }

		public string SireToken { get; }

		public string MotherName { get; }

		public string SireName { get; }

		public int Generation { get; }

		public int BornDay { get; }

		public string Breeder { get; }

		public LineageRecord(string token, string motherToken, string sireToken, string motherName, string sireName, int generation, int bornDay, string breeder)
		{
			if (generation < 0)
			{
				throw new ArgumentOutOfRangeException("generation");
			}
			Token = token ?? "";
			MotherToken = motherToken ?? "";
			SireToken = sireToken ?? "";
			MotherName = motherName ?? "";
			SireName = sireName ?? "";
			Generation = generation;
			BornDay = Math.Max(0, bornDay);
			Breeder = breeder ?? "";
		}

		public LineageRecord WithToken(string token)
		{
			return new LineageRecord(token, MotherToken, SireToken, MotherName, SireName, Generation, BornDay, Breeder);
		}
	}
	public static class Lineage
	{
		public static LineageRecord Wild(string token)
		{
			return new LineageRecord(token, "", "", "", "", 0, 0, "");
		}

		public static LineageRecord Newborn(string token, LineageRecord? mother, string motherName, SireRecord? sire, int day, string breeder)
		{
			int generation = Math.Max(mother?.Generation ?? 0, sire?.Generation ?? 0) + 1;
			return new LineageRecord(token, mother?.Token ?? "", sire?.Token ?? "", motherName ?? "", sire?.Name ?? "", generation, day, breeder ?? "");
		}

		public static LineageRecord GrowUp(LineageRecord young)
		{
			if (young == null)
			{
				throw new ArgumentNullException("young");
			}
			return young.WithToken(young.Token);
		}

		public static LineageRecord Hatch(EggRecord egg, string token)
		{
			if (egg == null)
			{
				throw new ArgumentNullException("egg");
			}
			return new LineageRecord(token, egg.MotherToken, egg.SireToken, egg.MotherName, egg.SireName, egg.Generation, egg.BornDay, egg.Breeder);
		}
	}
	public sealed class EggRecord
	{
		public string MotherToken { get; }

		public string SireToken { get; }

		public string MotherName { get; }

		public string SireName { get; }

		public int Generation { get; }

		public int BornDay { get; }

		public string Breeder { get; }

		public string Traits { get; }

		public EggRecord(string motherToken, string sireToken, string motherName, string sireName, int generation, int bornDay, string breeder, string traits)
		{
			if (generation < 0)
			{
				throw new ArgumentOutOfRangeException("generation");
			}
			if (bornDay < 0)
			{
				throw new ArgumentOutOfRangeException("bornDay");
			}
			MotherToken = motherToken ?? "";
			SireToken = sireToken ?? "";
			MotherName = motherName ?? "";
			SireName = sireName ?? "";
			Generation = generation;
			BornDay = bornDay;
			Breeder = breeder ?? "";
			Traits = traits ?? "";
		}

		public static EggRecord FromNewborn(LineageRecord newborn, string traits)
		{
			if (newborn == null)
			{
				throw new ArgumentNullException("newborn");
			}
			return new EggRecord(newborn.MotherToken, newborn.SireToken, newborn.MotherName, newborn.SireName, newborn.Generation, newborn.BornDay, newborn.Breeder, traits);
		}
	}
	public readonly struct SeasonBreedRate
	{
		public bool Active { get; }

		public float Rate { get; }

		public bool Stop { get; }

		public SeasonBreedRate(bool active, float rate)
		{
			if (!active || float.IsNaN(rate) || float.IsInfinity(rate) || rate < 0f)
			{
				Active = false;
				Rate = 1f;
				Stop = false;
				return;
			}
			Active = true;
			Stop = rate <= 0f;
			if (Stop)
			{
				Rate = 0f;
			}
			else if (rate < 0.25f)
			{
				Rate = 0.25f;
			}
			else if (rate > 3f)
			{
				Rate = 3f;
			}
			else
			{
				Rate = rate;
			}
		}
	}
	public readonly struct SeasonEdit
	{
		public bool Changed { get; }

		public bool Stop { get; }

		public double Duration { get; }

		public double Chance { get; }

		public double PartnerRange { get; }

		public double TotalRange { get; }

		public SeasonEdit(bool changed, bool stop, double duration, double chance, double partnerRange, double totalRange)
		{
			Changed = changed;
			Stop = stop;
			Duration = duration;
			Chance = chance;
			PartnerRange = partnerRange;
			TotalRange = totalRange;
		}
	}
	public static class SeasonBreeding
	{
		public const string Id = "meadworks.seasons.facts";

		public static readonly Version Version = new Version(1, 0);

		public const float MinRate = 0.25f;

		public const float MaxRate = 3f;

		public const int MaxLength = 8192;

		public static SeasonBreedRate Read(Func<string>? provider)
		{
			try
			{
				SeasonBreedRate rate;
				return (provider != null && TryParse(provider(), out rate)) ? rate : default(SeasonBreedRate);
			}
			catch (Exception)
			{
				return default(SeasonBreedRate);
			}
		}

		public static bool TryParse(string? text, out SeasonBreedRate rate)
		{
			rate = default(SeasonBreedRate);
			if (!Fields(text, out Dictionary<string, string> fields) || !Ready(fields) || !Number(fields, "breed", out var value) || value < 0f)
			{
				return false;
			}
			rate = new SeasonBreedRate(active: true, value);
			return rate.Active;
		}

		public static SeasonEdit Edit(double duration, double chance, double partner, double total, SeasonBreedRate rate)
		{
			if (!rate.Active || rate.Rate == 1f)
			{
				return new SeasonEdit(changed: false, stop: false, duration, chance, partner, total);
			}
			if (rate.Stop)
			{
				return new SeasonEdit(changed: true, stop: true, duration, 1.0, partner, total);
			}
			double duration2 = ((duration > 0.0) ? Math.Max(1.0, duration / (double)rate.Rate) : duration);
			double num = (1.0 - chance) * (double)rate.Rate;
			if (num < 0.0)
			{
				num = 0.0;
			}
			else if (num > 1.0)
			{
				num = 1.0;
			}
			double partnerRange = partner * (double)rate.Rate;
			double totalRange = ((total > 0.0) ? Math.Max(0.5, total / (double)rate.Rate) : total);
			return new SeasonEdit(changed: true, stop: false, duration2, 1.0 - num, partnerRange, totalRange);
		}

		public static string Prefix(long worldId, string sessionId)
		{
			return "1|" + worldId.ToString(CultureInfo.InvariantCulture) + "|" + Convert.ToBase64String(Encoding.UTF8.GetBytes(sessionId ?? "")) + "|";
		}

		public static string Wrap(long worldId, string sessionId, string? facts)
		{
			return Prefix(worldId, sessionId) + facts;
		}

		public static bool TryUnwrap(string? carrier, long worldId, string sessionId, out string facts)
		{
			facts = "";
			if (string.IsNullOrEmpty(carrier))
			{
				return false;
			}
			string text = Prefix(worldId, sessionId);
			if (!carrier.StartsWith(text, StringComparison.Ordinal))
			{
				return false;
			}
			facts = carrier.Substring(text.Length);
			return true;
		}

		private static bool Ready(Dictionary<string, string> fields)
		{
			if (!Integer(fields, "effects", out var value) || value != 1)
			{
				return false;
			}
			if (!Integer(fields, "season", out var value2) || value2 < 0 || value2 > 3)
			{
				return false;
			}
			if (Integer(fields, "day", out var value3) && Integer(fields, "length", out var value4) && value4 >= 1 && value3 >= 0)
			{
				return value3 <= value4;
			}
			return false;
		}

		private static bool Fields(string? text, out Dictionary<string, string> fields)
		{
			fields = new Dictionary<string, string>(StringComparer.Ordinal);
			if (string.IsNullOrEmpty(text) || text.Length > 8192)
			{
				return false;
			}
			string[] array = text.Split(';');
			foreach (string text2 in array)
			{
				int num = text2.IndexOf('=');
				if (num <= 0)
				{
					continue;
				}
				string text3 = text2.Substring(0, num);
				if (!(text3 != "effects") || !(text3 != "season") || !(text3 != "day") || !(text3 != "length") || !(text3 != "breed"))
				{
					if (fields.ContainsKey(text3))
					{
						return false;
					}
					fields.Add(text3, text2.Substring(num + 1));
				}
			}
			return true;
		}

		private static bool Integer(Dictionary<string, string> fields, string key, out int value)
		{
			value = 0;
			if (fields.TryGetValue(key, out string value2))
			{
				return int.TryParse(value2, NumberStyles.Integer, CultureInfo.InvariantCulture, out value);
			}
			return false;
		}

		private static bool Number(Dictionary<string, string> fields, string key, out float value)
		{
			value = 0f;
			if (fields.TryGetValue(key, out string value2) && float.TryParse(value2, NumberStyles.Float, CultureInfo.InvariantCulture, out value) && !float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}
	}
	public sealed class PartnerCandidate
	{
		public string Token { get; }

		public string Name { get; }

		public string PrefabName { get; }

		public int Level { get; }

		public int Generation { get; }

		public string Traits { get; }

		public double Distance { get; }

		public bool IsSelf { get; }

		public bool IsTamed { get; }

		public bool IsReady { get; }

		public PartnerCandidate(string token, string name, string prefabName, int level, int generation, string traits, double distance, bool isSelf, bool isTamed, bool isReady)
		{
			Token = token ?? "";
			Name = name ?? "";
			PrefabName = prefabName ?? "";
			Level = level;
			Generation = generation;
			Traits = traits ?? "";
			Distance = distance;
			IsSelf = isSelf;
			IsTamed = isTamed;
			IsReady = isReady;
		}
	}
	public sealed class SireRecord
	{
		public string Token { get; }

		public string Name { get; }

		public int Level { get; }

		public int Generation { get; }

		public string Traits { get; }

		public SireRecord(string token, string name, int level, int generation, string traits)
		{
			if (level < 1)
			{
				throw new ArgumentOutOfRangeException("level", "levels start at 1");
			}
			Token = token ?? "";
			Name = name ?? "";
			Level = level;
			Generation = Math.Max(0, generation);
			Traits = traits ?? "";
		}
	}
	public static class SireCapture
	{
		public static SireRecord? Choose(string partnerPrefab, double partnerRange, IEnumerable<PartnerCandidate> candidates)
		{
			if (candidates == null)
			{
				throw new ArgumentNullException("candidates");
			}
			if (string.IsNullOrEmpty(partnerPrefab))
			{
				return null;
			}
			PartnerCandidate partnerCandidate = null;
			foreach (PartnerCandidate candidate in candidates)
			{
				if (candidate != null && !candidate.IsSelf && candidate.IsTamed && candidate.IsReady && string.Equals(candidate.PrefabName, partnerPrefab, StringComparison.Ordinal) && candidate.Distance <= partnerRange && (partnerCandidate == null || candidate.Distance < partnerCandidate.Distance))
				{
					partnerCandidate = candidate;
				}
			}
			if (partnerCandidate != null)
			{
				return new SireRecord(partnerCandidate.Token, partnerCandidate.Name, Math.Max(1, partnerCandidate.Level), partnerCandidate.Generation, partnerCandidate.Traits);
			}
			return null;
		}
	}
	public enum InheritanceMode
	{
		Vanilla,
		BestParentUniform,
		ParentMean
	}
	public sealed class InheritanceSettings
	{
		public static InheritanceSettings Default { get; } = new InheritanceSettings(InheritanceMode.ParentMean, 1, 3, 25.0, 0.0);

		public InheritanceMode Mode { get; }

		public int MaxAboveBestParent { get; }

		public int MaxOffspringLevel { get; }

		public double BetterOffspringAt100 { get; }

		public double BirthStarChance { get; }

		public bool TamedStars { get; }

		public InheritanceSettings(InheritanceMode mode, int maxAboveBestParent, int maxOffspringLevel, double betterOffspringAt100, double birthStarChance, bool tamedStars = true)
		{
			if (!Enum.IsDefined(typeof(InheritanceMode), mode))
			{
				throw new ArgumentOutOfRangeException("mode");
			}
			if (maxAboveBestParent < 0 || maxAboveBestParent > 2)
			{
				throw new ArgumentOutOfRangeException("maxAboveBestParent", "0 to 2");
			}
			if (maxOffspringLevel < 1 || maxOffspringLevel > 10)
			{
				throw new ArgumentOutOfRangeException("maxOffspringLevel", "1 to 10");
			}
			if (!(betterOffspringAt100 >= 0.0) || !(betterOffspringAt100 <= 100.0))
			{
				throw new ArgumentOutOfRangeException("betterOffspringAt100", "0 to 100");
			}
			if (!(birthStarChance >= 0.0) || !(birthStarChance <= 100.0))
			{
				throw new ArgumentOutOfRangeException("birthStarChance", "0 to 100");
			}
			Mode = mode;
			MaxAboveBestParent = maxAboveBestParent;
			MaxOffspringLevel = maxOffspringLevel;
			BetterOffspringAt100 = betterOffspringAt100;
			BirthStarChance = birthStarChance;
			TamedStars = tamedStars;
		}
	}
	public readonly struct InheritanceInput
	{
		public int MotherLevel { get; }

		public int SireLevel { get; }

		public int MinOffspringLevel { get; }

		public double KeeperLevel { get; }

		public bool HasSire => SireLevel > 0;

		public InheritanceInput(int motherLevel, int sireLevel, int minOffspringLevel, double keeperLevel)
		{
			if (motherLevel < 1)
			{
				throw new ArgumentOutOfRangeException("motherLevel", "levels start at 1");
			}
			if (sireLevel < 0)
			{
				throw new ArgumentOutOfRangeException("sireLevel", "0 means no sire");
			}
			MotherLevel = motherLevel;
			SireLevel = sireLevel;
			MinOffspringLevel = Math.Max(0, minOffspringLevel);
			KeeperLevel = keeperLevel;
		}
	}
	public sealed class InheritanceResult
	{
		public int Base { get; }

		public int Best { get; }

		public int Cap { get; }

		public int Level { get; }

		public bool BetterOffspring { get; }

		public bool BirthStar { get; }

		public bool StrongOffspring => Level > Best;

		internal InheritanceResult(int @base, int best, int cap, int level, bool betterOffspring, bool birthStar)
		{
			Base = @base;
			Best = best;
			Cap = cap;
			Level = level;
			BetterOffspring = betterOffspring;
			BirthStar = birthStar;
		}
	}
	public static class StarInheritance
	{
		public static InheritanceResult Compute(InheritanceInput input, InheritanceSettings settings, IBreedingRandom random)
		{
			if (settings == null)
			{
				throw new ArgumentNullException("settings");
			}
			if (random == null)
			{
				throw new ArgumentNullException("random");
			}
			int motherLevel = input.MotherLevel;
			int num = (input.HasSire ? input.SireLevel : motherLevel);
			if (!settings.TamedStars)
			{
				int num2 = Math.Max(1, motherLevel);
				return new InheritanceResult(num2, Math.Max(motherLevel, num), num2, num2, betterOffspring: false, birthStar: false);
			}
			int num3 = Math.Max(motherLevel, num);
			int val = Math.Max(1, input.MinOffspringLevel);
			int num4 = Math.Max(val, Math.Min(num3 + settings.MaxAboveBestParent, settings.MaxOffspringLevel));
			int num5 = Math.Max(val, BaseLevel(settings.Mode, motherLevel, num, num3, random));
			int num6 = num5;
			bool flag = HusbandryShare.Rolls(settings.BetterOffspringAt100, input.KeeperLevel, random) && num5 < num4;
			if (flag)
			{
				num5++;
			}
			bool flag2 = HusbandryShare.RollsFlat(settings.BirthStarChance, random) && num5 < num4;
			if (flag2)
			{
				num5++;
			}
			return new InheritanceResult(num6, num3, num4, num5, flag, flag2);
		}

		private static int BaseLevel(InheritanceMode mode, int mother, int sire, int best, IBreedingRandom random)
		{
			return mode switch
			{
				InheritanceMode.Vanilla => mother, 
				InheritanceMode.BestParentUniform => 1 + random.Range(0, best), 
				_ => (mother + sire + 1) / 2, 
			};
		}
	}
	public sealed class TraitsConsumer
	{
		public const string Id = "meadworks.creatures.traits";

		public static readonly Version Version = new Version(1, 0);

		private readonly Tuple<Func<object, string>, Func<string, string, int, float, int, string>, Action<object, string>, Func<string, string>, Func<string, string>>? provider;

		public bool Available => provider != null;

		public TraitsConsumer(Tuple<Func<object, string>, Func<string, string, int, float, int, string>, Action<object, string>, Func<string, string>, Func<string, string>>? provider)
		{
			this.provider = provider;
		}

		public string Read(object? target, string fallback = "")
		{
			if (target == null)
			{
				return fallback;
			}
			try
			{
				return provider?.Item1(target) ?? fallback;
			}
			catch (Exception)
			{
				return fallback;
			}
		}

		public BirthPlan Inherit(BirthPlan plan, string mother, string sire, int seed, float mutationChance = 100f)
		{
			float arg = (float.IsNaN(mutationChance) ? 0f : Math.Max(0f, Math.Min(100f, mutationChance)));
			string traits;
			try
			{
				traits = provider?.Item2(mother, sire, plan.Level, arg, seed) ?? "";
			}
			catch (Exception)
			{
				traits = "";
			}
			return new BirthPlan(plan.Inheritance, plan.Lineage, WithTraits(plan.Egg, traits));
		}

		public void Apply(object target, string traits)
		{
			try
			{
				provider?.Item3(target, traits);
			}
			catch (Exception)
			{
			}
		}

		public string EncodeEgg(EggRecord egg)
		{
			string traits;
			try
			{
				traits = provider?.Item4(egg.Traits) ?? egg.Traits;
			}
			catch (Exception)
			{
				traits = egg.Traits;
			}
			return EggCodec.Encode(WithTraits(egg, traits));
		}

		public OffspringCarry Hatch(EggRecord egg, string token)
		{
			string traits;
			try
			{
				traits = provider?.Item5(egg.Traits) ?? egg.Traits;
			}
			catch (Exception)
			{
				traits = egg.Traits;
			}
			return new OffspringCarry((egg.Generation != 0 || egg.BornDay != 0 || egg.MotherToken.Length != 0 || egg.SireToken.Length != 0 || egg.MotherName.Length != 0 || egg.SireName.Length != 0 || egg.Breeder.Length != 0) ? Lineage.Hatch(egg, token) : null, traits);
		}

		public string DecodeLegacyEgg(string text)
		{
			try
			{
				return provider?.Item5(text) ?? "";
			}
			catch (Exception)
			{
				return "";
			}
		}

		private static EggRecord WithTraits(EggRecord egg, string traits)
		{
			return new EggRecord(egg.MotherToken, egg.SireToken, egg.MotherName, egg.SireName, egg.Generation, egg.BornDay, egg.Breeder, traits);
		}
	}
	public sealed class OffspringCarry
	{
		public LineageRecord? Lineage { get; }

		public string Traits { get; }

		public OffspringCarry(LineageRecord? lineage, string traits)
		{
			Lineage = lineage;
			Traits = traits ?? "";
		}
	}
	public static class TwinRules
	{
		public const double DefaultDelaySeconds = 30.0;

		public const double MinDelaySeconds = 5.0;

		public const double MaxDelaySeconds = 300.0;

		public static bool RollTwin(bool birthWasTwin, double twinsAt100, double keeperLevel, IBreedingRandom random)
		{
			if (random == null)
			{
				throw new ArgumentNullException("random");
			}
			if (!birthWasTwin)
			{
				return HusbandryShare.Rolls(twinsAt100, keeperLevel, random);
			}
			return false;
		}

		public static double DueAt(double now, double delaySeconds)
		{
			double num = (double.IsNaN(delaySeconds) ? 30.0 : Math.Min(300.0, Math.Max(5.0, delaySeconds)));
			return now + num;
		}

		public static bool IsDue(double twinDue, double now)
		{
			if (twinDue > 0.0)
			{
				return now >= twinDue;
			}
			return false;
		}
	}
}

plugins/Shepherd/Shepherd.dll

Decompiled 13 hours ago
using System;
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.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExtraPotions.Meadworks.Crucible;
using ExtraPotions.Meadworks.Crucible.UI;
using ExtraPotions.Meadworks.OriginalArt;
using ExtraPotions.Shepherd.Breeding;
using ExtraPotions.Shepherd.Conversion;
using ExtraPotions.Shepherd.Feeding;
using ExtraPotions.Shepherd.Husbandry;
using ExtraPotions.Shepherd.Pens;
using ExtraPotions.Shepherd.Runtime.Adopted.Husbandry;
using ExtraPotions.Shepherd.Runtime.Breeding;
using ExtraPotions.Shepherd.Runtime.Companions;
using ExtraPotions.Shepherd.Runtime.Feeding;
using ExtraPotions.Shepherd.Runtime.Integration;
using ExtraPotions.Shepherd.Runtime.Pens;
using ExtraPotions.Shepherd.Runtime.Skills;
using ExtraPotions.Shepherd.Runtime.UI;
using ExtraPotions.Shepherd.Take;
using ExtraPotions.Shepherd.Troughs;
using ExtraPotions.Shepherd.Yield;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ExtraPotions")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (C) 2026 expDARE (ExtraPotions Meadworks)")]
[assembly: AssemblyFileVersion("0.1.21.0")]
[assembly: AssemblyInformationalVersion("0.1.21")]
[assembly: AssemblyProduct("Shepherd")]
[assembly: AssemblyTitle("Shepherd")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.21.0")]
[module: UnverifiableCode]
[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 ExtraPotions.Meadworks.OriginalArt
{
	internal static class OriginalItemArt
	{
		[Serializable]
		private sealed class Catalog
		{
			public Entry[] assets;

			public Surface[] materials;
		}

		[Serializable]
		private sealed class Entry
		{
			public string id;

			public string[] prefabs;
		}

		[Serializable]
		private sealed class Surface
		{
			public string id;

			public string nativePrefab;
		}

		private static AssetBundle bundle;

		private static Dictionary<string, string> ids;

		private static Dictionary<string, string> nativeMaterials;

		private static readonly List<Material> ownedMaterials = new List<Material>();

		private static readonly Dictionary<string, GameObject> models = new Dictionary<string, GameObject>(StringComparer.Ordinal);

		private static void Load()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Invalid comparison between Unknown and I4
			if ((Object)(object)bundle != (Object)null)
			{
				return;
			}
			Assembly assembly = typeof(OriginalItemArt).Assembly;
			string platform = (((int)Application.platform == 13 || (int)Application.platform == 43) ? "linux" : "windows");
			string text = assembly.GetManifestResourceNames().Single((string n) => n.EndsWith(".original-items." + platform, StringComparison.Ordinal));
			using (Stream stream = assembly.GetManifestResourceStream(text))
			{
				using MemoryStream memoryStream = new MemoryStream();
				stream.CopyTo(memoryStream);
				bundle = AssetBundle.LoadFromMemory(memoryStream.ToArray());
			}
			if ((Object)(object)bundle == (Object)null)
			{
				throw new InvalidOperationException("Original item art bundle did not load: " + text);
			}
			using Stream stream2 = assembly.GetManifestResourceStream("MeadWorks.OriginalItems.catalog.json");
			using StreamReader streamReader = new StreamReader(stream2);
			ids = new Dictionary<string, string>(StringComparer.Ordinal);
			Catalog catalog = JsonConvert.DeserializeObject<Catalog>(streamReader.ReadToEnd());
			if (catalog == null || catalog.assets == null || catalog.assets.Length == 0)
			{
				throw new InvalidDataException("Original item catalog contains no assets");
			}
			nativeMaterials = new Dictionary<string, string>(StringComparer.Ordinal);
			Surface[] array = catalog.materials ?? Array.Empty<Surface>();
			foreach (Surface surface in array)
			{
				if (!string.IsNullOrEmpty(surface.nativePrefab))
				{
					nativeMaterials.Add(surface.id, surface.nativePrefab);
				}
			}
			Entry[] assets = catalog.assets;
			foreach (Entry entry in assets)
			{
				ids.Add(entry.id, entry.id);
				string[] array2 = entry.prefabs ?? Array.Empty<string>();
				foreach (string text2 in array2)
				{
					if (text2 != entry.id)
					{
						ids.Add(text2, entry.id);
					}
				}
			}
		}

		internal static Sprite Icon(string prefab)
		{
			if (MeadworksHeadless.IsHeadless)
			{
				return null;
			}
			Load();
			if (!ids.TryGetValue(prefab, out string value))
			{
				throw new KeyNotFoundException("Original icon missing: " + prefab);
			}
			return bundle.LoadAsset<Sprite>(value + "_icon") ?? throw new InvalidDataException("Original icon sprite missing: " + value);
		}

		internal static GameObject Model(ZNetScene scene, string prefab)
		{
			if (MeadworksHeadless.IsHeadless)
			{
				return null;
			}
			GameObject val = (((Object)(object)scene != (Object)null) ? (scene.GetPrefab("SerpentScale") ?? scene.GetPrefab("TrollHide")) : null);
			if ((Object)(object)val == (Object)null && (Object)(object)ObjectDB.instance != (Object)null)
			{
				val = ObjectDB.instance.GetItemPrefab("SerpentScale") ?? ObjectDB.instance.GetItemPrefab("TrollHide");
			}
			return ModelCore(val, prefab, scene);
		}

		internal static GameObject Model(GameObject native, string prefab)
		{
			if (MeadworksHeadless.IsHeadless)
			{
				return null;
			}
			return ModelCore(native, prefab, ZNetScene.instance);
		}

		private static bool ActiveBelowRoot(Renderer renderer, Transform root)
		{
			Transform val = ((Component)renderer).transform;
			while ((Object)(object)val != (Object)(object)root)
			{
				if (!((Component)val).gameObject.activeSelf)
				{
					return false;
				}
				val = val.parent;
			}
			return true;
		}

		internal static Material NativeBaseMaterial(GameObject source)
		{
			Material? obj = (((Object)(object)source != (Object)null) ? (from renderer in source.GetComponentsInChildren<Renderer>(true)
				where (renderer is MeshRenderer || renderer is SkinnedMeshRenderer) && renderer.enabled && ActiveBelowRoot(renderer, source.transform)
				select renderer).SelectMany((Renderer renderer) => renderer.sharedMaterials).FirstOrDefault((Func<Material, bool>)((Material candidate) => (Object)(object)candidate != (Object)null && (Object)(object)candidate.shader != (Object)null && ((Object)candidate.shader).name.IndexOf("Snow", StringComparison.OrdinalIgnoreCase) < 0 && candidate.renderQueue <= 2500 && candidate.HasProperty("_MainTex") && (Object)(object)candidate.GetTexture("_MainTex") != (Object)null)) : null);
			if ((Object)(object)obj == (Object)null)
			{
				throw new InvalidOperationException("Native opaque base material with albedo unavailable: " + (((Object)(object)source != (Object)null) ? ((Object)source).name : "<null>"));
			}
			return obj;
		}

		private static GameObject ModelCore(GameObject native, string prefab, ZNetScene scene)
		{
			Load();
			if (!ids.TryGetValue(prefab, out string value))
			{
				throw new KeyNotFoundException("Original model missing: " + prefab);
			}
			if (models.TryGetValue(value, out GameObject value2) && (Object)(object)value2 != (Object)null)
			{
				return value2;
			}
			GameObject obj = bundle.LoadAsset<GameObject>(value) ?? throw new InvalidDataException("Original model prefab missing: " + value);
			Material nativeMaterial = NativeBaseMaterial(native);
			GameObject val = Object.Instantiate<GameObject>(obj);
			((Object)val).name = value;
			val.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)val);
			Dictionary<Material, Material> dress = new Dictionary<Material, Material>();
			Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer obj2 in componentsInChildren)
			{
				obj2.sharedMaterials = ((IEnumerable<Material>)obj2.sharedMaterials).Select((Func<Material, Material>)delegate(Material original)
				{
					//IL_0088: 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)
					//IL_00a4: Expected O, but got Unknown
					//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
					//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
					//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
					//IL_0242: Unknown result type (might be due to invalid IL or missing references)
					//IL_0218: Unknown result type (might be due to invalid IL or missing references)
					if (dress.TryGetValue(original, out Material value3))
					{
						return value3;
					}
					Material val2 = nativeMaterial;
					if (nativeMaterials.TryGetValue(((Object)original).name.Replace(" (Instance)", ""), out string value4))
					{
						GameObject val3 = (((Object)(object)scene != (Object)null) ? scene.GetPrefab(value4) : null);
						if ((Object)(object)val3 == (Object)null && (Object)(object)ObjectDB.instance != (Object)null)
						{
							val3 = ObjectDB.instance.GetItemPrefab(value4);
						}
						val2 = NativeBaseMaterial(val3);
					}
					Material val4 = new Material(val2)
					{
						name = "MW_" + ((Object)original).name
					};
					if (val4.HasProperty("_MainTex"))
					{
						val4.SetTexture("_MainTex", original.mainTexture);
					}
					if (val4.HasProperty("_Color"))
					{
						val4.SetColor("_Color", original.color);
					}
					val4.mainTextureScale = Vector2.one;
					val4.mainTextureOffset = Vector2.zero;
					if (val4.HasProperty("_BumpMap"))
					{
						val4.SetTexture("_BumpMap", (Texture)null);
					}
					string[] array = new string[3] { "_MetallicGlossMap", "_EmissionMap", "_StyleTex" };
					foreach (string text in array)
					{
						if (val4.HasProperty(text))
						{
							val4.SetTexture(text, (Texture)null);
						}
					}
					if (val4.HasProperty("_UseStyles"))
					{
						val4.SetFloat("_UseStyles", 0f);
					}
					val4.DisableKeyword("_USESTYLES_ON");
					if (val4.HasProperty("_Glossiness"))
					{
						val4.SetFloat("_Glossiness", original.GetFloat("_Glossiness"));
					}
					if (val4.HasProperty("_Metallic"))
					{
						val4.SetFloat("_Metallic", original.GetFloat("_Metallic"));
					}
					if (val4.HasProperty("_MetalGloss"))
					{
						val4.SetFloat("_MetalGloss", 0f);
					}
					if (val4.HasProperty("_EmissionColor") && original.IsKeywordEnabled("_EMISSION"))
					{
						val4.EnableKeyword("_EMISSION");
						val4.SetColor("_EmissionColor", original.GetColor("_EmissionColor"));
					}
					else if (val4.HasProperty("_EmissionColor"))
					{
						val4.DisableKeyword("_EMISSION");
						val4.SetColor("_EmissionColor", Color.black);
					}
					ownedMaterials.Add(val4);
					dress.Add(original, val4);
					return val4;
				}).ToArray();
			}
			models[value] = val;
			return val;
		}

		internal static GameObject Instantiate(ZNetScene scene, string prefab, Transform parent)
		{
			GameObject val = Model(scene, prefab);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject obj = Object.Instantiate<GameObject>(val, parent, false);
			((Object)obj).name = "meadworks_original_model";
			obj.SetActive(true);
			return obj;
		}

		internal static GameObject Instantiate(GameObject nativeMaterialItem, string prefab, Transform parent)
		{
			GameObject val = Model(nativeMaterialItem, prefab);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject obj = Object.Instantiate<GameObject>(val, parent, false);
			((Object)obj).name = "meadworks_original_model";
			obj.SetActive(true);
			return obj;
		}

		internal static void Shutdown()
		{
			foreach (GameObject value in models.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
			}
			models.Clear();
			foreach (Material ownedMaterial in ownedMaterials)
			{
				if ((Object)(object)ownedMaterial != (Object)null)
				{
					Object.Destroy((Object)(object)ownedMaterial);
				}
			}
			ownedMaterials.Clear();
			if ((Object)(object)bundle != (Object)null)
			{
				bundle.Unload(false);
			}
			bundle = null;
			ids = null;
			nativeMaterials = null;
		}
	}
}
namespace ExtraPotions.Shepherd.Runtime
{
	[BepInPlugin("com.meadworks.shepherd", "Shepherd", "0.1.21")]
	[BepInDependency("com.meadworks.crucible", "0.3.32")]
	[BepInDependency("com.meadworks.crucible.ui", "0.3.21")]
	[BepInDependency("com.jotunn.jotunn", "2.30.2")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.meadworks.shepherd";

		public const string Name = "Shepherd";

		public const string Version = "0.1.21";

		public const string Family = "Hearth";

		private ProductRegistration? registration;

		private MeadworksSkill? husbandry;

		private MeadworksLog? log;

		private ShepherdImport? sourceImport;

		public static bool Ready { get; private set; }

		public static bool AllowsUi { get; private set; }

		public static MeadworksSkill? Husbandry { get; private set; }

		private void Awake()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			log = MeadworksLog.For(((BaseUnityPlugin)this).Logger, "Shepherd");
			try
			{
				if (!Plugin.IsReady)
				{
					throw new InvalidOperationException("Required Crucible is not ready");
				}
				registration = Plugin.Services.Register(new ProductMetadata("com.meadworks.shepherd", "Shepherd", new Version("0.1.21"), new Version(0, 1), new Version(0, 1), (MultiplayerPolicy)2, "Hearth"));
				AllowsUi = MeadworksHeadless.AllowsUi;
				ContainerRoleCapability.Register(registration);
				BreedingActivityCapability.Register(registration);
				LivestockPens.Register(registration);
				ShepherdLocalization.Initialize(((BaseUnityPlugin)this).Info.Metadata, ((BaseUnityPlugin)this).Logger);
				husbandry = ExtraPotions.Shepherd.Runtime.Skills.HusbandrySkill.Register();
				Husbandry = husbandry;
				NativeHusbandry.Initialize(((BaseUnityPlugin)this).Config, log);
				ShepherdSeasons.Initialize(((BaseUnityPlugin)this).Config);
				ShepherdSources.Initialize();
				sourceImport = new ShepherdImport(((BaseUnityPlugin)this).Config, log);
				NativeFeeding.Initialize(log);
				ContainerFeedMark.Initialize(registration);
				NativeBreeding.Initialize(log);
				NativeCheats.Initialize();
				BreedingCommands.Initialize(registration);
				FollowCommand.Initialize();
				LandPenPieces.Initialize(() => ShepherdSettings.LandPenCapacity.Value, () => ShepherdSettings.LandPenRecipe.Value);
				TroughHeader.Initialize();
				Ready = true;
				NativeHusbandry.Tick();
				ShepherdSources.Tick();
				NativeFeeding.Tick();
				ContainerFeedMark.Tick();
				NativeBreeding.Tick();
				NativeCheats.Tick();
				BreedingCommands.Tick();
				FollowCommand.Tick();
				log.Info("Shepherd registered; Husbandry taming and petting, troughs, owner-routed feeding and breeding core available.");
			}
			catch (Exception ex)
			{
				Shutdown();
				log.Error((object)("Shepherd initialization rejected: " + ex.GetType().Name + ": " + ex.Message));
			}
		}

		private void OnDestroy()
		{
			Shutdown();
		}

		private void Update()
		{
			if (Ready)
			{
				NativeHusbandry.Run("season facts", ShepherdSeasons.Tick);
				NativeHusbandry.Run("Husbandry lifecycle", NativeHusbandry.Tick);
				NativeHusbandry.Run("source compatibility", ShepherdSources.Tick);
				NativeFeeding.Run("Feeding lifecycle", NativeFeeding.Tick);
				NativeFeeding.Run("container feed marking", ContainerFeedMark.Tick);
				NativeBreeding.Run("Breeding lifecycle", NativeBreeding.Tick);
				NativeBreeding.Run("cheat lifecycle", NativeCheats.Tick);
				NativeBreeding.Run("breeding commands", BreedingCommands.Tick);
				NativeHusbandry.Run("Follow Command lifecycle", FollowCommand.Tick);
				NativeHusbandry.Run("herd watch", HerdWatch.Tick);
				NativeHusbandry.Run("localization", ShepherdLocalization.Tick);
				NativeHusbandry.Run("herd book", HerdBook.Tick);
				NativeHusbandry.Run("trough header", TroughHeader.Tick);
				NativeHusbandry.Run("land pen", LandPenPieces.Tick);
			}
		}

		private void Shutdown()
		{
			Ready = false;
			ShepherdSeasons.Shutdown();
			HerdBook.Shutdown();
			TroughHeader.Shutdown();
			LandPenPieces.Shutdown();
			FollowCommand.Shutdown();
			BreedingCommands.Shutdown();
			NativeCheats.Shutdown();
			NativeBreeding.Shutdown();
			LivestockPens.Clear();
			ContainerFeedMark.Shutdown();
			NativeFeeding.Shutdown();
			sourceImport?.Dispose();
			sourceImport = null;
			ShepherdSources.Shutdown();
			NativeHusbandry.Shutdown();
			HerdWatch.Clear();
			ShepherdLocalization.Shutdown();
			Husbandry = null;
			MeadworksSkill? obj = husbandry;
			if (obj != null)
			{
				obj.Dispose();
			}
			husbandry = null;
			ExtraPotions.Shepherd.Runtime.Skills.HusbandrySkill.ShutdownIcon();
			ProductRegistration? obj2 = registration;
			if (obj2 != null)
			{
				obj2.Dispose();
			}
			registration = null;
		}
	}
}
namespace ExtraPotions.Shepherd.Runtime.UI
{
	internal static class HerdBook
	{
		private const int PageSize = 8;

		private const string MenuId = "shepherd";

		private static IDisposable? menuEntry;

		private static KitWindow? window;

		private static KitStatSheet? sheet;

		private static KitEmptyState? empty;

		private static TMP_Text? title;

		private static TMP_Text? count;

		private static Button? previous;

		private static Button? next;

		private static Button? rename;

		private static Button? close;

		private static readonly List<Button> buttons = new List<Button>();

		private static readonly List<Tameable> animals = new List<Tameable>();

		private static ZDOID selected;

		private static Player? actor;

		private static ZNet? network;

		private static long generation = -1L;

		private static int page;

		private static float refresh;

		private static string language = "";

		internal static bool Active
		{
			get
			{
				if (Plugin.Ready && Plugin.AllowsUi && NativeHusbandry.Active && (Object)(object)Player.m_localPlayer != (Object)null && !((Character)Player.m_localPlayer).IsDead() && (Object)(object)((Character)Player.m_localPlayer).m_nview != (Object)null)
				{
					return ((Character)Player.m_localPlayer).m_nview.IsOwner();
				}
				return false;
			}
		}

		private static string Text(string key)
		{
			return ShepherdLocalization.Text(key);
		}

		private static string Local(string token)
		{
			return LoreText.Literal((Localization.instance != null) ? Localization.instance.Localize(token) : token);
		}

		private static bool Valid(Tameable tameable)
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)tameable != (Object)null && tameable.IsTamed() && (Object)(object)tameable.m_character != (Object)null && !tameable.m_character.IsDead() && (Object)(object)tameable.m_nview != (Object)null && tameable.m_nview.IsValid() && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				Vector3 val = ((Component)tameable).transform.position - ((Component)Player.m_localPlayer).transform.position;
				return ((Vector3)(ref val)).sqrMagnitude <= ShepherdSettings.BookRange.Value * ShepherdSettings.BookRange.Value;
			}
			return false;
		}

		private static Tameable? Selection()
		{
			return ((IEnumerable<Tameable>)animals).FirstOrDefault((Func<Tameable, bool>)((Tameable t) => Valid(t) && t.m_nview.GetZDO().m_uid == selected));
		}

		internal static void Tick()
		{
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.Ready && Plugin.AllowsUi && menuEntry == null)
			{
				menuEntry = MeadworksMenu.Register("shepherd", (Func<string>)(() => Text("book_title")), (Action)OpenFromMenu, (Func<bool>)(() => Active && (Object)(object)KitCanvas.Font != (Object)null), 100);
			}
			if (!Active)
			{
				Clear();
				return;
			}
			if ((Object)(object)actor != (Object)(object)Player.m_localPlayer || (Object)(object)network != (Object)(object)ZNet.instance || generation != Plugin.Session.Generation || (window != null && (Object)(object)window.Panel != (Object)null && (Object)(object)((Transform)window.Panel).parent != (Object)(object)KitCanvas.Front))
			{
				Clear();
			}
			actor = Player.m_localPlayer;
			network = ZNet.instance;
			generation = Plugin.Session.Generation;
			KitWindow? obj = window;
			InputContext val = (InputContext)((obj != null && obj.IsOpen) ? 1 : 0);
			KitWindow? obj2 = window;
			RectTransform val2 = ((obj2 != null) ? obj2.Panel : null);
			if ((window == null || !window.IsOpen || ((Object)(object)val2 != (Object)null && (Object)(object)((Transform)val2).parent != (Object)null && ((Transform)val2).GetSiblingIndex() == ((Transform)val2).parent.childCount - 1)) && KitAlmanacDialog.Active == null && (MeadworksInput.Pressed(ShepherdSettings.BookKey.Entry, val) || (MeadworksInput.Allows(val) && PadPressed(ShepherdSettings.BookPadChord.Value))))
			{
				KitWindow? obj3 = window;
				if (obj3 != null && obj3.IsOpen)
				{
					window.Close();
				}
				else
				{
					Open();
				}
			}
			KitWindow? obj4 = window;
			if (obj4 != null && obj4.IsOpen)
			{
				if (Time.unscaledTime >= refresh || language != MeadworksBlockedOptions.Language)
				{
					refresh = Time.unscaledTime + 1f;
					language = MeadworksBlockedOptions.Language;
					Scan();
					Draw();
				}
				Tameable val3 = Selection();
				if ((Object)(object)rename != (Object)null)
				{
					((Selectable)rename).interactable = CanRename(val3);
				}
				KitStatSheet? obj5 = sheet;
				if (obj5 != null)
				{
					obj5.Refresh((long)(((Object)(object)val3 != (Object)null) ? ((object)Unsafe.As<ZDOID, ZDOID>(ref val3.m_nview.GetZDO().m_uid)/*cast due to .constrained prefix*/).GetHashCode() : 0), (Action<KitSheet>)Fill);
				}
			}
		}

		private static bool PadPressed(string text)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			if (!MeadworksInput.GamepadActive || string.IsNullOrWhiteSpace(text) || text.Length > 128)
			{
				return false;
			}
			string[] array = (from s in text.Split('+')
				select s.Trim()).Distinct<string>(StringComparer.Ordinal).ToArray();
			List<PadButton> list = new List<PadButton>();
			string[] array2 = array;
			PadButton item = default(PadButton);
			for (int num = 0; num < array2.Length; num++)
			{
				if (!GamepadMap.TryParse(array2[num], ref item))
				{
					return false;
				}
				list.Add(item);
			}
			if (list.Count == 0 || !((IEnumerable<PadButton>)list).All((Func<PadButton, bool>)MeadworksInput.PadHeld) || !((IEnumerable<PadButton>)list).Any((Func<PadButton, bool>)MeadworksInput.PadDown))
			{
				return false;
			}
			foreach (PadButton item2 in list)
			{
				MeadworksInput.PadConsume(item2);
			}
			return true;
		}

		private static void OpenFromMenu()
		{
			if (Menu.IsVisible())
			{
				Menu instance = Menu.instance;
				if (instance != null)
				{
					instance.OnClose();
				}
			}
			KitWindow? obj = window;
			if (obj == null || !obj.IsOpen)
			{
				Open();
			}
		}

		internal static void Open()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0291: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0347: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_039e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_040d: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || (Object)(object)KitCanvas.Font == (Object)null || MeadworksInput.Typing || Menu.IsVisible())
			{
				return;
			}
			if (window == null)
			{
				window = KitWindow.Create("Shepherd_HerdBook", new Vector2(850f, 570f), (Transform)null, false, false);
				if (window == null)
				{
					return;
				}
				title = KitAlmanacDialog.Label((Transform)(object)window.Panel, "Title", "", new Vector2(20f, -15f), new Vector2(800f, 34f), 23f);
				if ((Object)(object)KitCanvas.Heading != (Object)null)
				{
					title.font = KitCanvas.Heading;
				}
				count = KitAlmanacDialog.Label((Transform)(object)window.Panel, "Count", "", new Vector2(20f, -52f), new Vector2(800f, 30f), 15f);
				for (int i = 0; i < 8; i++)
				{
					int index = i;
					Button val = KitButton.Create(window.Panel, "Animal" + i, "", (Action)delegate
					{
						Select(index);
					}, new Vector2(20f, (float)(-90 - i * 48)), new Vector2(375f, 44f));
					buttons.Add(val);
					window.Focusable((Selectable)(object)val, 0, i);
					TMP_Text[] componentsInChildren = ((Component)val).GetComponentsInChildren<TMP_Text>(true);
					foreach (TMP_Text obj in componentsInChildren)
					{
						obj.richText = false;
						obj.fontSize = 13f;
					}
				}
				RectTransform component = new GameObject("EmptyArea", new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
				((Component)component).gameObject.layer = ((Component)window.Panel).gameObject.layer;
				((Transform)component).SetParent((Transform)(object)window.Panel, false);
				Vector2 val2 = default(Vector2);
				((Vector2)(ref val2))..ctor(0f, 1f);
				component.pivot = val2;
				Vector2 anchorMin = (component.anchorMax = val2);
				component.anchorMin = anchorMin;
				component.anchoredPosition = new Vector2(20f, -90f);
				component.sizeDelta = new Vector2(810f, 385f);
				empty = KitForged.EmptyState(component, "Empty", KitForgedArt.EmptyBoar, "", "", 220f);
				sheet = KitStatSheet.Create(window.Panel, "AnimalDetails", new Vector2(415f, -90f), new Vector2(415f, 385f));
				previous = KitButton.Create(window.Panel, "Previous", "", (Action)delegate
				{
					page = Math.Max(0, page - 1);
					Draw();
				}, new Vector2(20f, -495f), new Vector2(180f, 42f));
				next = KitButton.Create(window.Panel, "Next", "", (Action)delegate
				{
					page++;
					Draw();
				}, new Vector2(215f, -495f), new Vector2(180f, 42f));
				rename = KitButton.Create(window.Panel, "Rename", "", (Action)Rename, new Vector2(415f, -495f), new Vector2(200f, 42f));
				close = KitButton.Create(window.Panel, "Close", Text("book_close"), (Action)delegate
				{
					KitWindow? obj2 = window;
					if (obj2 != null)
					{
						obj2.Close();
					}
				}, new Vector2(630f, -495f), new Vector2(200f, 42f));
				window.Focusable((Selectable)(object)previous, 0, 8);
				window.Focusable((Selectable)(object)next, 1, 8);
				window.Focusable((Selectable)(object)rename, 2, 8);
				window.Focusable((Selectable)(object)close, 3, 8);
			}
			actor = Player.m_localPlayer;
			network = ZNet.instance;
			generation = Plugin.Session.Generation;
			Scan();
			Draw();
			window.Open();
		}

		private static void Scan()
		{
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			animals.Clear();
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if (!((Object)(object)allCharacter == (Object)null) && !allCharacter.IsPlayer())
				{
					Tameable val = Herd.TameableOf(allCharacter);
					if ((Object)(object)val != (Object)null && Valid(val))
					{
						animals.Add(val);
					}
				}
			}
			animals.Sort((Tameable a, Tameable b) => Vector3.SqrMagnitude(((Component)a).transform.position - ((Component)actor).transform.position).CompareTo(Vector3.SqrMagnitude(((Component)b).transform.position - ((Component)actor).transform.position)));
			if ((Object)(object)Selection() == (Object)null)
			{
				selected = ((animals.Count > 0) ? animals[0].m_nview.GetZDO().m_uid : ZDOID.None);
			}
		}

		private static string State(Tameable animal)
		{
			string text = Text(animal.IsHungry() ? "book_hungry" : "book_fed");
			Procreation component = ((Component)animal).GetComponent<Procreation>();
			if (!((Object)(object)component != (Object)null) || !component.IsPregnant())
			{
				return text;
			}
			return text + " · " + Text("book_pregnant");
		}

		private static string Variant(Tameable animal)
		{
			VisEquipment component = ((Component)animal).GetComponent<VisEquipment>();
			if (!((Object)(object)component != (Object)null))
			{
				return Text("lore_unknown");
			}
			return component.GetModelIndex().ToString();
		}

		private static void Draw()
		{
			if (window == null)
			{
				return;
			}
			page = Mathf.Clamp(page, 0, Math.Max(0, (animals.Count - 1) / 8));
			title.text = Text("book_title");
			count.text = ShepherdLocalization.Format("book_count", animals.Count, ShepherdSettings.BookRange.Value, page + 1, Math.Max(1, (animals.Count + 8 - 1) / 8));
			for (int i = 0; i < buttons.Count; i++)
			{
				int num = page * 8 + i;
				((Component)buttons[i]).gameObject.SetActive(num < animals.Count);
				if (num < animals.Count)
				{
					Tameable val = animals[num];
					string text = LoreText.Literal(val.GetHoverName()) + " · " + Local(val.m_character.m_name) + "\n" + ShepherdLocalization.Format("book_summary", Math.Max(0, val.m_character.GetLevel() - 1), Variant(val), State(val));
					GameButtons.Caption(((Component)buttons[i]).gameObject, text);
					KitTooltip.Set(((Component)buttons[i]).gameObject, Local(val.m_character.m_name), Text("book_help_animal") + "\n" + State(val));
				}
			}
			bool flag = animals.Count == 0;
			KitEmptyState? obj = empty;
			if (obj != null)
			{
				obj.Words(Text("book_empty_title"), Text("book_empty_hint"));
			}
			KitEmptyState? obj2 = empty;
			if (obj2 != null)
			{
				obj2.Show(flag);
			}
			if (sheet != null)
			{
				((Component)sheet.Area).gameObject.SetActive(!flag);
			}
			((Component)rename).gameObject.SetActive(!flag);
			((Selectable)previous).interactable = page > 0;
			((Selectable)next).interactable = (page + 1) * 8 < animals.Count;
			GameButtons.Caption(((Component)previous).gameObject, Text("book_previous"));
			GameButtons.Caption(((Component)next).gameObject, Text("book_next"));
			GameButtons.Caption(((Component)rename).gameObject, Text("book_rename"));
			GameButtons.Caption(((Component)close).gameObject, Text("book_close"));
			KitTooltip.Set(((Component)previous).gameObject, Text("book_previous"), Text("book_help_previous"));
			KitTooltip.Set(((Component)next).gameObject, Text("book_next"), Text("book_help_next"));
			KitTooltip.Set(((Component)close).gameObject, Text("book_close"), Text("book_help_close"));
			KitTooltip.Set(((Component)rename).gameObject, Text("book_rename"), Text("book_rename_reach"));
			KitStatSheet? obj3 = sheet;
			if (obj3 != null)
			{
				obj3.Invalidate();
			}
		}

		private static void Select(int index)
		{
			//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)
			int num = page * 8 + index;
			if (Active && num >= 0 && num < animals.Count && Valid(animals[num]))
			{
				selected = animals[num].m_nview.GetZDO().m_uid;
				KitStatSheet? obj = sheet;
				if (obj != null)
				{
					obj.Invalidate();
				}
			}
		}

		private static bool CanRename(Tameable? animal)
		{
			//IL_001e: 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)
			if (Active && (Object)(object)animal != (Object)null && Valid(animal))
			{
				return Vector3.Distance(((Component)animal).transform.position, ((Component)Player.m_localPlayer).transform.position) <= 5f;
			}
			return false;
		}

		private static void Rename()
		{
			Tameable val = Selection();
			if (CanRename(val) && !MeadworksInput.Typing && !Menu.IsVisible())
			{
				val.Interact((Humanoid)(object)Player.m_localPlayer, false, true);
			}
		}

		private static void Fill(KitSheet target)
		{
			Tameable val = Selection();
			if ((Object)(object)val == (Object)null)
			{
				target.Add(Text("book_empty"), "", (string)null);
				return;
			}
			target.Section(LoreText.Literal(val.GetHoverName()));
			target.Add(Text("book_species"), Local(val.m_character.m_name), (string)null);
			target.Add(Text("book_stars"), Math.Max(0, val.m_character.GetLevel() - 1).ToString(), (string)null);
			target.Add(Text("book_variant"), Variant(val), (string)null);
			target.Add(Text("book_state"), State(val), (string)null);
			string text = WildbloodLabels(val);
			if (text.Length > 0)
			{
				target.Add(Text("book_traits"), text, (string)null);
			}
			LineageRecord val2 = BreedingStore.ReadLineage((IKeyStore)(object)new ZdoKeyStore(val.m_nview.GetZDO()));
			if (val2 == null)
			{
				target.Add(Text("book_lineage"), Text("lore_unknown"), (string)null);
				return;
			}
			target.Section(Text("book_lineage"));
			target.Add(Text("book_generation"), val2.Generation.ToString(), (string)null);
			target.Add(Text("book_born"), (val2.BornDay > 0) ? val2.BornDay.ToString() : Text("lore_unknown"), (string)null);
			target.Add(Text("book_breeder"), (val2.Breeder.Length > 0) ? LoreText.Literal(val2.Breeder) : Text("lore_unknown"), (string)null);
			Parent(target, "book_mother", val2.MotherToken, val2.MotherName);
			Parent(target, "book_sire", val2.SireToken, val2.SireName);
		}

		private static string WildbloodLabels(Tameable animal)
		{
			try
			{
				CapabilityRegistry capabilities = Plugin.Services.Capabilities;
				IReadOnlyList<CapabilityMetadata> readOnlyList = capabilities.Providers("meadworks.creatures.trait_labels");
				Func<object, string> func = default(Func<object, string>);
				if (readOnlyList.Count != 1 || readOnlyList[0].Owner != "com.meadworks.wildblood" || !capabilities.TryResolve<Func<object, string>>("meadworks.creatures.trait_labels", new Version(1, 0), ref func) || func == null)
				{
					return "";
				}
				string text = func(animal.m_character) ?? "";
				text = text.Replace('<', '‹').Replace('>', '›').Replace('\n', ' ')
					.Replace('\r', ' ');
				return (text.Length <= 1024) ? text : text.Substring(0, 1024);
			}
			catch
			{
				return "";
			}
		}

		private static void Parent(KitSheet target, string key, string token, string name)
		{
			target.Add(Text(key), (name.Length > 0) ? Local(name) : Text("lore_unknown"), (string)null);
			if (token.Length == 0)
			{
				return;
			}
			Character[] array = (from character in Character.GetAllCharacters()
				where (Object)(object)character != (Object)null && (Object)(object)character.m_nview != (Object)null && character.m_nview.IsValid() && character.m_nview.GetZDO().GetString("shepherd.instance", "") == token
				select character).Take(2).ToArray();
			if (array.Length == 1)
			{
				LineageRecord val = BreedingStore.ReadLineage((IKeyStore)(object)new ZdoKeyStore(array[0].m_nview.GetZDO()));
				if (val != null && (val.MotherName.Length > 0 || val.SireName.Length > 0))
				{
					target.Add(Text("book_grandparents"), Local(val.MotherName) + " / " + Local(val.SireName), (string)null);
				}
			}
		}

		internal static void Shutdown()
		{
			menuEntry?.Dispose();
			menuEntry = null;
			Clear();
		}

		internal static void Clear()
		{
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			EventSystem current = EventSystem.current;
			GameObject val = (((Object)(object)current != (Object)null) ? current.currentSelectedGameObject : null);
			if ((Object)(object)val != (Object)null)
			{
				KitWindow? obj = window;
				if ((Object)(object)((obj != null) ? obj.Panel : null) != (Object)null && val.transform.IsChildOf((Transform)(object)window.Panel))
				{
					current.SetSelectedGameObject((GameObject)null);
				}
			}
			KitWindow? obj2 = window;
			if (obj2 != null)
			{
				obj2.Close();
			}
			KitWindow? obj3 = window;
			if (obj3 != null)
			{
				obj3.Destroy();
			}
			window = null;
			sheet = null;
			empty = null;
			title = (count = null);
			previous = (next = (rename = (close = null)));
			buttons.Clear();
			animals.Clear();
			selected = ZDOID.None;
			actor = null;
			network = null;
			generation = -1L;
			page = 0;
			refresh = 0f;
			language = "";
		}
	}
	internal static class TroughHeader
	{
		[HarmonyPatch(typeof(InventoryGrid), "UpdateGamepad")]
		private sealed class GridInput
		{
			[HarmonyPrefix]
			private static bool Prefix(InventoryGrid __instance)
			{
				//IL_0130: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance != (Object)(object)grid || !Available || (Object)(object)book == (Object)null || !((Selectable)book).interactable || !__instance.m_uiGroup.IsActive || !MeadworksInput.GamepadActive || ZInput.IsTouchActive() || !MeadworksInput.Allows((InputContext)1) || KitAlmanacDialog.Active != null)
				{
					return true;
				}
				EventSystem current = EventSystem.current;
				if ((Object)(object)current == (Object)null)
				{
					return true;
				}
				bool flag = ZInput.GetButtonDown("JoyDPadDown") || ZInput.GetButtonDown("JoyLStickDown");
				bool flag2 = ZInput.GetButtonDown("JoyDPadUp") || ZInput.GetButtonDown("JoyLStickUp");
				if ((Object)(object)current.currentSelectedGameObject == (Object)(object)((Component)book).gameObject)
				{
					if (MeadworksInput.PadDown((PadButton)0))
					{
						MeadworksInput.PadConsume((PadButton)0);
						((UnityEvent)book.onClick).Invoke();
					}
					else if (flag2)
					{
						ZInput.ResetButtonStatus("JoyDPadUp");
						ZInput.ResetButtonStatus("JoyLStickUp");
						RectTransform gamepadSelectedElement = __instance.GetGamepadSelectedElement();
						if ((Object)(object)gamepadSelectedElement != (Object)null)
						{
							current.SetSelectedGameObject(((Component)gamepadSelectedElement).gameObject);
						}
					}
					else if (flag)
					{
						ZInput.ResetButtonStatus("JoyDPadDown");
						ZInput.ResetButtonStatus("JoyLStickDown");
						__instance.OnMoveToLowerInventoryGrid?.Invoke(__instance.SelectionGridPosition);
					}
					return false;
				}
				if (flag && __instance.jumpToNextContainer && __instance.m_selected.y == __instance.m_height - 1)
				{
					ZInput.ResetButtonStatus("JoyDPadDown");
					ZInput.ResetButtonStatus("JoyLStickDown");
					current.SetSelectedGameObject(((Component)book).gameObject);
					return false;
				}
				return true;
			}
		}

		internal const string LastFeed = "shepherd.last_feed_sent";

		private static Harmony? harmony;

		private static RectTransform? panel;

		private static TMP_Text? stock;

		private static TMP_Text? last;

		private static Button? book;

		private static InventoryGrid? grid;

		private static Container? source;

		private static readonly List<KitIconButton> species = new List<KitIconButton>();

		private static float next;

		private static ZNetScene? speciesScene;

		private static int prefabCount;

		private static string speciesLanguage = "";

		private static string speciesFilter = "";

		private static string language = "";

		private static bool Available
		{
			get
			{
				if (Plugin.Ready && Plugin.AllowsUi && NativeFeeding.FeedingActive && InventoryGui.IsVisible() && (Object)(object)InventoryGui.instance != (Object)null && (Object)(object)InventoryGui.instance.m_currentContainer != (Object)null && TroughPieces.IsTrough(InventoryGui.instance.m_currentContainer))
				{
					return FeedSources.IsUsable(InventoryGui.instance.m_currentContainer);
				}
				return false;
			}
		}

		private static string Text(string key)
		{
			return ShepherdLocalization.Text(key);
		}

		private static string Local(string token)
		{
			return LoreText.Literal((Localization.instance != null) ? Localization.instance.Localize(token) : token);
		}

		internal static void Initialize()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			Shutdown();
			harmony = new Harmony("com.meadworks.shepherd.trough_header");
			harmony.CreateClassProcessor(typeof(GridInput)).Patch();
		}

		internal static void Tick()
		{
			//IL_0087: 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)
			//IL_0091: 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_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: 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_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			if (!Available)
			{
				Clear();
				return;
			}
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)source != (Object)(object)instance.m_currentContainer || (Object)(object)grid != (Object)(object)instance.m_containerGrid || (Object)(object)panel == (Object)null)
			{
				Clear();
				source = instance.m_currentContainer;
				grid = instance.m_containerGrid;
				if ((Object)(object)grid == (Object)null || (Object)(object)KitCanvas.Font == (Object)null)
				{
					return;
				}
				Rect rect = ((RectTransform)((Component)grid).transform).rect;
				float num = Mathf.Clamp(((Rect)(ref rect)).width, 400f, 700f);
				panel = KitPanel.Create(((Component)grid).transform, "Shepherd_TroughHeader", new Vector2(num, 88f), false);
				if ((Object)(object)panel == (Object)null)
				{
					return;
				}
				RectTransform? obj = panel;
				RectTransform? obj2 = panel;
				Vector2 val = default(Vector2);
				((Vector2)(ref val))..ctor(0f, 1f);
				obj2.anchorMax = val;
				obj.anchorMin = val;
				panel.pivot = Vector2.zero;
				panel.anchoredPosition = new Vector2(0f, 18f);
				stock = KitAlmanacDialog.Label((Transform)(object)panel, "Stock", "", new Vector2(10f, -6f), new Vector2(num - 190f, 24f), 14f);
				last = KitAlmanacDialog.Label((Transform)(object)panel, "LastFeed", "", new Vector2(10f, -31f), new Vector2(num - 20f, 23f), 12f);
				TMP_Text? obj3 = stock;
				bool richText = (last.richText = false);
				obj3.richText = richText;
				book = KitButton.Create(panel, "HerdBook", "", (Action)OpenBook, new Vector2(num - 175f, -4f), new Vector2(165f, 30f));
				Navigation navigation = ((Selectable)book).navigation;
				((Navigation)(ref navigation)).mode = (Mode)0;
				((Selectable)book).navigation = navigation;
				next = 0f;
			}
			if ((Object)(object)book != (Object)null)
			{
				((Selectable)book).interactable = HerdBook.Active;
			}
			if (!(Time.unscaledTime < next) || !(language == MeadworksBlockedOptions.Language))
			{
				next = Time.unscaledTime + 1f;
				language = MeadworksBlockedOptions.Language;
				Refresh();
			}
		}

		private static void OpenBook()
		{
			if (Available && HerdBook.Active && !MeadworksInput.Typing && !Menu.IsVisible())
			{
				HerdBook.Open();
			}
		}

		private static void Refresh()
		{
			//IL_0360: Unknown result type (might be due to invalid IL or missing references)
			//IL_0365: Unknown result type (might be due to invalid IL or missing references)
			//IL_03db: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null || !FeedSources.IsUsable(source) || (Object)(object)panel == (Object)null || (Object)(object)book == (Object)null)
			{
				return;
			}
			int num = source.GetInventory().GetAllItems().Sum((ItemData item) => item.m_stack);
			stock.text = ShepherdLocalization.Format("trough_stock", num);
			long num2 = source.m_nview.GetZDO().GetLong("shepherd.last_feed_sent", 0L);
			double num3 = ((num2 > 0) ? ((double)(Herd.Now.Ticks - num2) / 10000000.0) : (-1.0));
			last.text = ((num3 >= 0.0) ? ShepherdLocalization.Format("trough_last", Duration(num3)) : Text("trough_no_meal"));
			GameButtons.Caption(((Component)book).gameObject, Text("book_title"));
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			string text = ShepherdSettings.DisallowFeed.Value + "\n" + ShepherdSettings.DisallowAnimals.Value;
			if ((Object)(object)speciesScene == (Object)(object)instance && prefabCount == instance.m_prefabs.Count && speciesLanguage == language && speciesFilter == text)
			{
				return;
			}
			speciesScene = instance;
			prefabCount = instance.m_prefabs.Count;
			speciesLanguage = language;
			speciesFilter = text;
			foreach (KitIconButton item in species)
			{
				if ((Object)(object)item.Button != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)item.Button).gameObject);
				}
			}
			species.Clear();
			MonsterAI[] array = (from p in instance.m_prefabs
				where (Object)(object)p != (Object)null
				select p.GetComponent<MonsterAI>() into ai
				where (Object)(object)ai != (Object)null && (Object)(object)((Component)ai).GetComponent<Character>() != (Object)null && (Object)(object)((Component)ai).GetComponent<Tameable>() != (Object)null && ai.m_consumeItems != null && !NativeFeeding.AnimalDisallowed(Utils.GetPrefabName(((Component)ai).gameObject)) && ai.m_consumeItems.Any((ItemDrop food) => (Object)(object)food != (Object)null && !NativeFeeding.FoodDisallowed(Utils.GetPrefabName(((Component)food).gameObject)))
				group ai by Utils.GetPrefabName(((Component)ai).gameObject) into g
				select g.First()).OrderBy<MonsterAI, string>((MonsterAI ai) => Local(((Component)ai).GetComponent<Character>().m_name), StringComparer.Ordinal).ToArray();
			string text2 = string.Join("\n", array.Select(Details));
			KitTooltip.Set(((Component)panel).gameObject, Text("trough_foods"), (text2.Length <= 8192) ? text2 : text2.Substring(0, 8192));
			Rect rect = panel.rect;
			int count = Math.Max(1, Math.Min(12, (int)(((Rect)(ref rect)).width - 20f) / 32));
			foreach (MonsterAI item2 in array.Take(count))
			{
				KitIconButton val = KitIconButton.Create(panel, "Species" + species.Count, (KitGlyph)2, new Vector2((float)(10 + species.Count * 32), -57f), 26f, (Action<KitClickKind>)null);
				if (val != null)
				{
					CharacterDrop component = ((Component)item2).GetComponent<CharacterDrop>();
					ItemDrop val2 = (((Object)(object)component != (Object)null) ? component.m_drops.Select((Drop d) => (!((Object)(object)d.m_prefab != (Object)null)) ? null : d.m_prefab.GetComponent<ItemDrop>()).FirstOrDefault((Func<ItemDrop, bool>)((ItemDrop d) => (Object)(object)d != (Object)null && (int)d.m_itemData.m_shared.m_itemType == 13)) : null);
					ItemDrop val3 = (ItemDrop)(((Object)(object)val2 != (Object)null) ? ((object)val2) : ((object)((IEnumerable<ItemDrop>)item2.m_consumeItems).FirstOrDefault((Func<ItemDrop, bool>)((ItemDrop d) => (Object)(object)d != (Object)null))));
					if ((Object)(object)val3 != (Object)null)
					{
						val.SetSprite(val3.m_itemData.GetIcon(), false);
					}
					val.Tooltip(Local(((Component)item2).GetComponent<Character>().m_name), Details(item2));
					((Selectable)val.Button).interactable = false;
					species.Add(val);
				}
			}
			static string Details(MonsterAI ai)
			{
				return Local(((Component)ai).GetComponent<Character>().m_name) + ": " + string.Join(", ", (from food in ai.m_consumeItems
					where (Object)(object)food != (Object)null && !NativeFeeding.FoodDisallowed(Utils.GetPrefabName(((Component)food).gameObject))
					select Local(food.m_itemData.m_shared.m_name)).Distinct());
			}
		}

		private static string Duration(double seconds)
		{
			int num = (int)Math.Min(2147483647.0, Math.Max(0.0, seconds));
			if (num >= 60)
			{
				if (num >= 3600)
				{
					return ShepherdLocalization.Format("time_hours_minutes", num / 3600, num / 60 % 60);
				}
				return ShepherdLocalization.Format("time_minutes", num / 60);
			}
			return ShepherdLocalization.Format("time_seconds", num);
		}

		private static void Clear()
		{
			EventSystem current = EventSystem.current;
			if ((Object)(object)current != (Object)null && (Object)(object)panel != (Object)null && (Object)(object)current.currentSelectedGameObject != (Object)null && current.currentSelectedGameObject.transform.IsChildOf((Transform)(object)panel))
			{
				current.SetSelectedGameObject((GameObject)null);
			}
			if ((Object)(object)panel != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)panel).gameObject);
			}
			panel = null;
			stock = (last = null);
			book = null;
			grid = null;
			source = null;
			species.Clear();
			language = "";
			speciesScene = null;
			prefabCount = 0;
			speciesLanguage = (speciesFilter = "");
		}

		internal static void Shutdown()
		{
			Harmony? obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			harmony = null;
			Clear();
		}
	}
}
namespace ExtraPotions.Shepherd.Runtime.Skills
{
	public static class HusbandrySkill
	{
		private static Sprite? embedded;

		private static bool triedEmbedded;

		public static SkillDefinition Definition()
		{
			return GrindstoneSkillsMap.Definition("grindstone_husbandry", "com.meadworks.shepherd", "Husbandry", "Tending animals: taming, feeding, breeding and herd care.", 1f, (string)null, (string)null);
		}

		public static MeadworksSkill Register()
		{
			SkillDefinition val = Definition();
			if (val.Identity != "meadworks_husbandry" || val.PublishKey != "meadworks_husbandry_level")
			{
				throw new InvalidOperationException("Crucible mapped Husbandry to " + val.Identity + " / " + val.PublishKey + "; Shepherd expects meadworks_husbandry / meadworks_husbandry_level.");
			}
			return MeadworksSkills.Register(val, (Func<Sprite>)Icon, (ProductTranslations)null);
		}

		private static Sprite? Icon()
		{
			if (MeadworksHeadless.IsHeadless)
			{
				return null;
			}
			if (!triedEmbedded)
			{
				triedEmbedded = true;
				embedded = EmbeddedSprite.Load(typeof(HusbandrySkill).Assembly, "Shepherd.skill_husbandry.png", "shepherd_husbandry");
			}
			if (!((Object)(object)embedded != (Object)null))
			{
				return TrophyIcon();
			}
			return embedded;
		}

		public static void ShutdownIcon()
		{
			if ((Object)(object)embedded != (Object)null)
			{
				Texture2D texture = embedded.texture;
				Object.Destroy((Object)(object)embedded);
				if ((Object)(object)texture != (Object)null)
				{
					Object.Destroy((Object)(object)texture);
				}
			}
			embedded = null;
			triedEmbedded = false;
		}

		private static Sprite? TrophyIcon()
		{
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("TrophyBoar") : null);
			ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
			if (!((Object)(object)val2 != (Object)null))
			{
				return null;
			}
			return val2.m_itemData.GetIcon();
		}
	}
}
namespace ExtraPotions.Shepherd.Runtime.Pens
{
	public static class LandPenPieces
	{
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private sealed class SceneAwake
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				Install();
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private sealed class DatabaseAwake
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				Install();
			}
		}

		[HarmonyPatch(typeof(Door), "GetHoverText")]
		private sealed class GateHover
		{
			[HarmonyPostfix]
			private static void Postfix(Door __instance, ref string __result)
			{
				if (Active && (Object)(object)((Component)__instance).GetComponent<LandPenRegistration>() != (Object)null)
				{
					__result = __result + "\n" + ShepherdLocalization.Format("land_pen_capacity", Capacity);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
		{
			typeof(Piece),
			typeof(RequirementMode)
		})]
		private sealed class Requirements
		{
			[HarmonyPostfix]
			private static void Postfix(Piece piece, ref bool __result)
			{
				if ((Object)(object)prefab != (Object)null && (Object)(object)piece == (Object)(object)prefab.GetComponent<Piece>() && !Active)
				{
					__result = false;
				}
			}
		}

		private static Func<int>? capacity;

		private static Func<string>? recipe;

		private static Harmony? harmony;

		private static GameObject? holder;

		private static GameObject? prefab;

		private static string appliedRecipe = "";

		private static bool failed;

		private static double retryAt;

		public static bool Active
		{
			get
			{
				if (harmony != null && Plugin.Ready)
				{
					return NativeFeeding.ProductActive;
				}
				return false;
			}
		}

		public static bool Ready => (Object)(object)prefab != (Object)null;

		internal static int Capacity => LandPenDefinition.Capacity(capacity?.Invoke() ?? 12);

		public static void Initialize(Func<int> readCapacity, Func<string> readRecipe)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			Shutdown();
			capacity = readCapacity ?? throw new ArgumentNullException("readCapacity");
			recipe = readRecipe ?? throw new ArgumentNullException("readRecipe");
			harmony = new Harmony("com.meadworks.shepherd.land_pen");
			Type[] array = new Type[4]
			{
				typeof(SceneAwake),
				typeof(DatabaseAwake),
				typeof(GateHover),
				typeof(Requirements)
			};
			foreach (Type type in array)
			{
				harmony.CreateClassProcessor(type).Patch();
			}
			Install();
		}

		public static void Tick()
		{
			if (harmony == null)
			{
				return;
			}
			try
			{
				if ((Object)(object)prefab == (Object)null && Time.realtimeSinceStartupAsDouble >= retryAt)
				{
					retryAt = Time.realtimeSinceStartupAsDouble + 1.0;
					Install();
				}
				if ((Object)(object)prefab != (Object)null)
				{
					prefab.GetComponent<Piece>().m_enabled = Active;
					ApplyRecipe();
				}
			}
			catch (Exception error)
			{
				if (!failed)
				{
					Warn("land pen refresh", error);
				}
				failed = true;
			}
		}

		public static void Shutdown()
		{
			LandPenRegistration.Clear();
			Harmony? obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			harmony = null;
			capacity = null;
			recipe = null;
			if ((Object)(object)prefab != (Object)null)
			{
				prefab.GetComponent<Piece>().m_enabled = false;
			}
		}

		public static void Install()
		{
			if (harmony == null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			try
			{
				if ((Object)(object)prefab == (Object)null)
				{
					Build(ZNetScene.instance);
				}
				if ((Object)(object)prefab == (Object)null)
				{
					return;
				}
				ZNetScene instance = ZNetScene.instance;
				int stableHashCode = StringExtensionMethods.GetStableHashCode("shepherd_land_pen");
				if (instance.m_namedPrefabs.TryGetValue(stableHashCode, out var value) && (Object)(object)value != (Object)(object)prefab)
				{
					throw new InvalidOperationException("land pen prefab name already registered");
				}
				if (!instance.m_prefabs.Contains(prefab))
				{
					instance.m_prefabs.Add(prefab);
				}
				instance.m_namedPrefabs[stableHashCode] = prefab;
				if (!((Object)(object)ObjectDB.instance == (Object)null))
				{
					ApplyRecipe();
					GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hammer");
					ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
					PieceTable val2 = (((Object)(object)val != (Object)null) ? val.m_itemData.m_shared.m_buildPieces : null);
					if ((Object)(object)val2 != (Object)null && !val2.m_pieces.Contains(prefab))
					{
						val2.m_pieces.Add(prefab);
					}
					failed = false;
				}
			}
			catch (Exception error)
			{
				if (!failed)
				{
					Warn("land pen installation", error);
				}
				failed = true;
			}
		}

		private static void Build(ZNetScene scene)
		{
			//IL_009b: 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_00a3: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Expected O, but got Unknown
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0337: Unknown result type (might be due to invalid IL or missing references)
			//IL_0365: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_037b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0380: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = scene.GetPrefab("wood_gate");
			GameObject obj = scene.GetPrefab("wood_pole");
			MeshFilter val2 = ((obj != null) ? obj.GetComponentInChildren<MeshFilter>(true) : null);
			GameObject obj2 = scene.GetPrefab("wood_beam");
			MeshFilter val3 = ((obj2 != null) ? obj2.GetComponentInChildren<MeshFilter>(true) : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<Door>() == (Object)null || (Object)(object)val.GetComponent<ZNetView>() == (Object)null || (Object)(object)val.GetComponent<Piece>() == (Object)null || (Object)(object)val.GetComponent<WearNTear>() == (Object)null || !Usable(val2) || !Usable(val3))
			{
				throw new InvalidOperationException("native gate/wood parts missing or invalid");
			}
			Bounds val4 = GateBox(val);
			if (((Bounds)(ref val4)).size.x < 1f || ((Bounds)(ref val4)).size.x > 5.5f || ((Bounds)(ref val4)).size.z > 1.5f || ((Bounds)(ref val4)).size.y < 0.8f || ((Bounds)(ref val4)).size.y > 5f)
			{
				throw new InvalidOperationException("native gate orientation/extent is outside the measured construction bounds");
			}
			if ((Object)(object)holder == (Object)null)
			{
				holder = new GameObject("Shepherd_LandPen_Prefabs");
				holder.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)holder);
			}
			GameObject val5 = Object.Instantiate<GameObject>(val, holder.transform, false);
			((Object)val5).name = "shepherd_land_pen";
			try
			{
				Piece component = val5.GetComponent<Piece>();
				component.m_name = ShepherdText.Token("piece_land_pen");
				component.m_description = ShepherdText.Token("piece_land_pen_description");
				component.m_category = (PieceCategory)4;
				GameObject obj3 = scene.GetPrefab("piece_workbench");
				component.m_craftingStation = ((obj3 != null) ? obj3.GetComponent<CraftingStation>() : null);
				val5.GetComponent<Door>().m_name = component.m_name;
				float x = ((Bounds)(ref val4)).center.x;
				float z = ((Bounds)(ref val4)).center.z;
				float y = ((Bounds)(ref val4)).min.y;
				float num = 3f;
				float num2 = 6f;
				float num3 = 1.5f;
				float num4 = ((Bounds)(ref val4)).size.x / 2f;
				float num5 = num - num4;
				float[] array = new float[2] { -1f, 1f };
				foreach (float num6 in array)
				{
					float[] array2 = new float[2]
					{
						z,
						z + num2
					};
					foreach (float num7 in array2)
					{
						Member(val5.transform, val2, new Vector3(x + num6 * num, y + num3 / 2f, num7), Vector3.up, num3, 0.16f);
					}
					Fence(val5.transform, val3, new Vector3(x + num6 * num, y + num3 / 2f, z + num2 / 2f), num2, num3, alongZ: true);
					Fence(val5.transform, val3, new Vector3(x + num6 * (num4 + num5 / 2f), y + num3 / 2f, z), num5, num3, alongZ: false);
				}
				Fence(val5.transform, val3, new Vector3(x, y + num3 / 2f, z + num2), 6f, num3, alongZ: false);
				val5.AddComponent<LandPenRegistration>().LocalBox = new Bounds(new Vector3(x, y + 1.5f, z + num2 / 2f), new Vector3(6f, 3f, num2));
				prefab = val5;
			}
			catch
			{
				Object.Destroy((Object)(object)val5);
				throw;
			}
		}

		private static Bounds GateBox(GameObject source)
		{
			//IL_0002: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			Bounds result = default(Bounds);
			bool flag = true;
			MeshFilter[] componentsInChildren = source.GetComponentsInChildren<MeshFilter>(true);
			foreach (MeshFilter val in componentsInChildren)
			{
				if (!Usable(val))
				{
					continue;
				}
				Bounds bounds = val.sharedMesh.bounds;
				float[] array = new float[2]
				{
					((Bounds)(ref bounds)).min.x,
					((Bounds)(ref bounds)).max.x
				};
				foreach (float num in array)
				{
					float[] array2 = new float[2]
					{
						((Bounds)(ref bounds)).min.y,
						((Bounds)(ref bounds)).max.y
					};
					foreach (float num2 in array2)
					{
						float[] array3 = new float[2]
						{
							((Bounds)(ref bounds)).min.z,
							((Bounds)(ref bounds)).max.z
						};
						foreach (float num3 in array3)
						{
							Vector3 val2 = source.transform.InverseTransformPoint(((Component)val).transform.TransformPoint(new Vector3(num, num2, num3)));
							if (flag)
							{
								((Bounds)(ref result))..ctor(val2, Vector3.zero);
								flag = false;
							}
							else
							{
								((Bounds)(ref result)).Encapsulate(val2);
							}
						}
					}
				}
			}
			if (flag || !Finite(((Bounds)(ref result)).center) || !Finite(((Bounds)(ref result)).size))
			{
				throw new InvalidOperationException("native gate geometry unavailable");
			}
			return result;
		}

		private static bool Finite(Vector3 v)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (!float.IsNaN(v.x) && !float.IsInfinity(v.x) && !float.IsNaN(v.y) && !float.IsInfinity(v.y) && !float.IsNaN(v.z))
			{
				return !float.IsInfinity(v.z);
			}
			return false;
		}

		private static bool Usable(MeshFilter? filter)
		{
			//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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)filter != (Object)null && (Object)(object)filter.sharedMesh != (Object)null && (Object)(object)((Component)filter).GetComponent<MeshRenderer>() != (Object)null)
			{
				Bounds bounds = filter.sharedMesh.bounds;
				if (Finite(((Bounds)(ref bounds)).size))
				{
					bounds = filter.sharedMesh.bounds;
					if (((Bounds)(ref bounds)).size.x > 0f)
					{
						bounds = filter.sharedMesh.bounds;
						if (((Bounds)(ref bounds)).size.y > 0f)
						{
							bounds = filter.sharedMesh.bounds;
							return ((Bounds)(ref bounds)).size.z > 0f;
						}
					}
				}
			}
			return false;
		}

		private static void Member(Transform parent, MeshFilter source, Vector3 center, Vector3 direction, float length, float thickness)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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)
			//IL_0050: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			Mesh sharedMesh = source.sharedMesh;
			Bounds bounds = sharedMesh.bounds;
			int num = ((!(((Bounds)(ref bounds)).size.x >= ((Bounds)(ref bounds)).size.y) || !(((Bounds)(ref bounds)).size.x >= ((Bounds)(ref bounds)).size.z)) ? ((((Bounds)(ref bounds)).size.y >= ((Bounds)(ref bounds)).size.z) ? 1 : 2) : 0);
			Vector3 val = (Vector3)(num switch
			{
				1 => Vector3.up, 
				0 => Vector3.right, 
				_ => Vector3.forward, 
			});
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(thickness / ((Bounds)(ref bounds)).size.x, thickness / ((Bounds)(ref bounds)).size.y, thickness / ((Bounds)(ref bounds)).size.z);
			Vector3 size = ((Bounds)(ref bounds)).size;
			((Vector3)(ref val2))[num] = length / ((Vector3)(ref size))[num];
			GameObject val3 = new GameObject("Shepherd pen wood");
			val3.transform.SetParent(parent, false);
			val3.transform.localRotation = Quaternion.FromToRotation(val, direction);
			val3.transform.localScale = val2;
			val3.transform.localPosition = center - val3.transform.localRotation * Vector3.Scale(((Bounds)(ref bounds)).center, val2);
			val3.AddComponent<MeshFilter>().sharedMesh = sharedMesh;
			((Renderer)val3.AddComponent<MeshRenderer>()).sharedMaterials = ((Renderer)((Component)source).GetComponent<MeshRenderer>()).sharedMaterials;
		}

		private static void Fence(Transform parent, MeshFilter mesh, Vector3 center, float length, float height, bool alongZ)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: 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)
			Vector3 direction = (alongZ ? Vector3.forward : Vector3.right);
			Member(parent, mesh, center + Vector3.up * height * 0.25f, direction, length, 0.14f);
			Member(parent, mesh, center - Vector3.up * height * 0.25f, direction, length, 0.14f);
			GameObject val = new GameObject("Shepherd pen collision");
			val.transform.SetParent(parent, false);
			val.layer = LayerMask.NameToLayer("piece");
			val.transform.localPosition = center;
			val.AddComponent<BoxCollider>().size = (alongZ ? new Vector3(0.14f, height, length) : new Vector3(length, height, 0.14f));
		}

		private static void ApplyRecipe()
		{
			if ((Object)(object)prefab == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			string text = recipe?.Invoke() ?? "Wood:30, Resin:4";
			if (!(appliedRecipe == text) || prefab.GetComponent<Piece>().m_resources.Length == 0)
			{
				Requirement[] array = (from e in TroughRecipe.Parse(text, (Func<string, bool>)((string name) => (Object)(object)Item(name) != (Object)null))
					where (Object)(object)Item(((RecipeEntry)(ref e)).Item) != (Object)null
					select e).Select((Func<RecipeEntry, Requirement>)((RecipeEntry e) => new Requirement
				{
					m_resItem = Item(((RecipeEntry)(ref e)).Item),
					m_amount = ((RecipeEntry)(ref e)).Amount,
					m_recover = true
				})).ToArray();
				if (array.Length == 0)
				{
					throw new InvalidOperationException("land pen recipe has no native materials");
				}
				prefab.GetComponent<Piece>().m_resources = array;
				appliedRecipe = text;
			}
			static ItemDrop? Item(string name)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(name);
				if (itemPrefab == null)
				{
					return null;
				}
				return itemPrefab.GetComponent<ItemDrop>();
			}
		}

		internal static void Warn(string context, Exception error)
		{
			NativeFeeding.Warn(context + ": " + error.GetType().Name + ": " + error.Message);
		}
	}
	internal sealed class LandPenRegistration : MonoBehaviour
	{
		private static readonly HashSet<LandPenRegistration> instances = new HashSet<LandPenRegistration>();

		[SerializeField]
		internal Bounds LocalBox;

		private ZNetView? view;

		private IDisposable? lease;

		private ZNet? network;

		private long generation = -1L;

		private int capacity = -1;

		private Vector3 scale;

		private double next;

		private bool warned;

		private void Awake()
		{
			view = ((Component)this).GetComponent<ZNetView>();
			instances.Add(this);
		}

		private void Update()
		{
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: 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)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if (!LandPenPieces.Active || !NativeBreeding.HerdOn || (Object)(object)view == (Object)null || !view.IsValid())
			{
				Release();
			}
			else
			{
				if (Time.realtimeSinceStartupAsDouble < next)
				{
					return;
				}
				next = Time.realtimeSinceStartupAsDouble + 0.5;
				int num = LandPenPieces.Capacity;
				long num2 = Plugin.Session.Generation;
				if (lease != null && capacity == num && generation == num2 && network == ZNet.instance && scale == ((Component)this).transform.lossyScale)
				{
					return;
				}
				Release();
				try
				{
					lease = LivestockPens.RegisterPen(view, LocalBox, num);
					capacity = num;
					generation = num2;
					network = ZNet.instance;
					scale = ((Component)this).transform.lossyScale;
				}
				catch (Exception error)
				{
					if (!warned)
					{
						LandPenPieces.Warn("land pen registration", error);
					}
					warned = true;
				}
			}
		}

		private void Release()
		{
			try
			{
				lease?.Dispose();
			}
			catch (Exception error)
			{
				if (!warned)
				{
					LandPenPieces.Warn("land pen disposal", error);
				}
				warned = true;
			}
			lease = null;
			network = null;
		}

		private void OnDisable()
		{
			Release();
		}

		private void OnDestroy()
		{
			Release();
			instances.Remove(this);
		}

		internal static void Clear()
		{
			foreach (LandPenRegistration item in new List<LandPenRegistration>(instances))
			{
				if ((Object)(object)item != (Object)null)
				{
					item.Release();
				}
			}
		}
	}
}
namespace ExtraPotions.Shepherd.Runtime.Integration
{
	public static class BreedingActivityCapability
	{
		public const string Id = "meadworks.husbandry.breeding";

		public static readonly Version ContractVersion = new Version(1, 0);

		public static readonly Func<bool> Provider = Active;

		public static void Register(ProductRegistration registration)
		{
			if (registration == null)
			{
				throw new ArgumentNullException("registration");
			}
			registration.AddCapability<Func<bool>>("meadworks.husbandry.breeding", ContractVersion, Provider);
		}

		private static bool Active()
		{
			try
			{
				return NativeBreeding.Active;
			}
			catch (Exception)
			{
				return false;
			}
		}
	}
	public static class ContainerRoleCapability
	{
		public const string Id = "meadworks.containers.role";

		public static readonly Version ContractVersion = new Version(1, 0);

		public static readonly Func<object, string> Provider = RoleOf;

		public static void Register(ProductRegistration registration)
		{
			if (registration == null)
			{
				throw new ArgumentNullException("registration");
			}
			registration.AddCapability<Func<object, string>>("meadworks.containers.role", ContractVersion, Provider);
		}

		private static string RoleOf(object container)
		{
			try
			{
				Container val = (Container)((container is Container) ? container : null);
				return (val != null && (Object)(object)val != (Object)null) ? TroughPrefabs.RoleOf(Utils.GetPrefabName(((Component)val).gameObject)) : null;
			}
			catch (Exception)
			{
				return null;
			}
		}
	}
	public static class LivestockPens
	{
		private sealed class CountScope : IDisposable
		{
			private readonly Procreation parent;

			private readonly Procreation? previous;

			private bool disposed;

			internal CountScope(Procreation parent)
			{
				this.parent = parent;
				previous = counting;
				counting = parent;
			}

			public void Dispose()
			{
				if (!disposed)
				{
					disposed = true;
					if ((Object)(object)counting == (Object)(object)parent)
					{
						counting = previous;
					}
				}
			}
		}

		private sealed class Pen : IDisposable
		{
			internal readonly ZNetView View;

			internal readonly Bounds Box;

			internal readonly int Limit;

			private readonly ZNet network;

			internal bool Disposed;

			internal bool Valid
			{
				get
				{
					if ((Object)(object)View != (Object)null && View.IsValid())
					{
						return ZNet.instance == network;
					}
					return false;
				}
			}

			internal bool Moving
			{
				get
				{
					//IL_0029: Unknown result type (might be due to invalid IL or missing references)
					//IL_002e: Unknown result type (might be due to invalid IL or missing references)
					Ship component = ((Component)View).GetComponent<Ship>();
					if ((Object)(object)component != (Object)null && (Object)(object)component.m_body != (Object)null)
					{
						Vector3 linearVelocity = component.m_body.linearVelocity;
						return ((Vector3)(ref linearVelocity)).sqrMagnitude > 1f;
					}
					return false;
				}
			}

			internal Pen(ZNetView view, Bounds box, int limit, ZNet network)
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				View = view;
				Box = box;
				Limit = limit;
				this.network = network;
			}

			internal bool Contains(Vector3 position)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: 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)
				if (Valid)
				{
					Bounds box = Box;
					return ((Bounds)(ref box)).Contains(((Component)View).transform.InverseTransformPoint(position));
				}
				return false;
			}

			public void Dispose()
			{
				MainThread();
				if (!Disposed)
				{
					Disposed = true;
					pens.Remove(this);
				}
			}
		}

		public const string Id = "meadworks.livestock.pens";

		private static readonly List<Pen> pens = new List<Pen>();

		private static readonly int thread = Thread.CurrentThread.ManagedThreadId;

		[ThreadStatic]
		private static Procreation? counting;

		public static void Register(ProductRegistration registration)
		{
			registration.AddCapability<Tuple<Func<ZNetView, Bounds, int, IDisposable>, Func<Vector3, Tuple<ZNetView, int, bool>>>>("meadworks.livestock.pens", new Version(1, 0), Tuple.Create<Func<ZNetView, Bounds, int, IDisposable>, Func<Vector3, Tuple<ZNetView, int, bool>>>(RegisterPen, PenOf));
		}

		private static void MainThread()
		{
			if (Thread.CurrentThread.ManagedThreadId != thread)
			{
				throw new InvalidOperationException("Pens require the native main thread.");
			}
		}

		private static bool Finite(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		private static bool Finite(Vector3 value)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if (Finite(value.x) && Finite(value.y))
			{
				return Finite(value.z);
			}
			return false;
		}

		private static void Prune()
		{
			pens.RemoveAll((Pen p) => p.Disposed || !p.Valid);
		}

		public static IDisposable RegisterPen(ZNetView view, Bounds box, int herdLimit)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			MainThread();
			Prune();
			if (Plugin.Ready && !((Object)(object)view == (Object)null) && view.IsValid() && !((Object)(object)ZNet.instance == (Object)null) && Finite(((Bounds)(ref box)).center) && Finite(((Bounds)(ref box)).size) && !(((Bounds)(ref box)).size.x <= 0f) && !(((Bounds)(ref box)).size.y <= 0f) && !(((Bounds)(ref box)).size.z <= 0f))
			{
				Vector3 size = ((Bounds)(ref box)).size;
				if (!(((Vector3)(ref size)).sqrMagnitude > 16384f) && herdLimit >= 0 && herdLimit <= 1000 && pens.Count < 256 && !pens.Any((Pen p) => (Object)(object)p.View == (Object)(object)view))
				{
					Pen pen = new Pen(view, box, herdLimit, ZNet.instance);
					pens.Add(pen);
					return pen;
				}
			}
			throw new ArgumentException("Invalid or duplicate pen registration.");
		}

		private static Pen? Find(Vector3 position)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			MainThread();
			Prune();
			if (!Plugin.Ready || !NativeBreeding.HerdOn || !Finite(position))
			{
				return null;
			}
			return pens.Where((Pen p) => p.Contains(position)).OrderBy(delegate(Pen p)
			{
				//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_0009: Unknown result type (might be due to invalid IL or missing references)
				//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_001c: 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_0030: Unknown result type (might be due to invalid IL or missing references)
				Bounds box = p.Box;
				float x = ((Bounds)(ref box)).size.x;
				box = p.Box;
				float num = x * ((Bounds)(ref box)).size.y;
				box = p.Box;
				return num * ((Bounds)(ref box)).size.z;
			}).ThenBy<Pen, string>((Pen p) => ((object)Unsafe.As<ZDOID, ZDOID>(ref p.View.GetZDO().m_uid)/*cast due to .constrained prefix*/).ToString(), StringComparer.Ordinal)
				.FirstOrDefault();
		}

		public static Tuple<ZNetView, int, bool> PenOf(Vector3 position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			Pen pen = Find(position);
			if (pen != null)
			{
				return Tuple.Create<ZNetView, int, bool>(pen.View, pen.Limit, pen.Moving);
			}
			return null;
		}

		internal static int Maximum(Procreation parent, int fallback)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!ShepherdSettings.PenMode.Value)
			{
				return fallback;
			}
			return PenCapacity.Maximum(fallback, Find(((Component)parent).transform.position)?.Limit);
		}

		internal static bool HoldsMoving(Procreation parent)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (NativeBreeding.HerdOn && ShepherdSettings.PauseMovingShips.Value)
			{
				return Find(((Component)parent).transform.position)?.Moving ?? false;
			}
			return false;
		}

		internal static int? Count(GameObject prefab, Vector3 position)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!ShepherdSettings.PenMode.Value || (Object)(object)prefab == (Object)null)
			{
				return null;
			}
			Pen pen = Find(position);
			if (pen == null)
			{
				return null;
			}
			string name = Utils.GetPrefabName(prefab);
			if ((Object)(object)prefab.GetComponent<BaseAI>() != (Object)null)
			{
				return BaseAI.BaseAIInstances.Count((BaseAI ai) => (Object)(object)ai != (Object)null && Utils.GetPrefabName(((Component)ai).gameObject) == name && pen.Contains(((Component)ai).transform.position));
			}
			return GameObject.FindGameObjectsWithTag("spawned").Count((GameObject item) => (Object)(object)item != (Object)null && Utils.GetPrefabName(item) == name && pen.Contains(item.transform.position));
		}

		internal static IDisposable EnterCount(Procreation parent)
		{
			return new CountScope(parent);
		}

		internal static bool TryNativeCount(GameObject prefab, Vector3 position, float range, bool eventOnly, bool procreationOnly, out int count)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			count = 0;
			Procreation val = counting;
			if (!((Object)(object)val == (Object)null || !NativeBreeding.HerdOn || eventOnly || procreationOnly) && range == val.m_totalCheckRange)
			{
				Vector3 val2 = position - ((Component)val).transform.position;
				if (!(((Vector3)(ref val2)).sqrMagnitude > 0.0001f) && (!((Object)(object)prefab != (Object)(object)val.m_myPrefab) || !((Object)(object)prefab != (Object)(object)val.m_offspringPrefab)))
				{
					int? num = Count(prefab, position);
					if (!num.HasValue)
					{
						return false;
					}
					count = num.Value;
					return true;
				}
			}
			return false;
		}

		public static void Clear()
		{
			foreach (Pen pen in pens)
			{
				pen.Disposed = true;
			}
			pens.Clear();
			counting = null;
		}
	}
	public sealed class ShepherdImport : IDisposable
	{
		private sealed class CheckedTarget : IValidatedConversionTarget, IConversionTarget
		{
			private readonly ShepherdImport owner;

			private readonly PreviewDocument preview;

			private readonly IConversionTarget target;

			public int SchemaVersion => target.SchemaVersion;

			internal CheckedTarget(ShepherdImport owner, PreviewDocument preview)
			{
				this.owner = owner;
				this.preview = preview;
				target = MeadworksConversion.Target(owner.config);
			}

			public void Validate(IReadOnlyDictionary<string, object> values)
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				owner.Admission(preview);
				((IValidatedConversionTarget)target).Validate(values);
				foreach (KeyValuePair<string, object> value in values)
				{
					ConfigEntryBase val = owner.Entry(value.Key);
					object obj = (val.SettingType.IsInstanceOfType(value.Value) ? value.Value : TomlTypeConverter.ConvertToValue(Convert.ToString(value.Value, CultureInfo.InvariantCulture), val.SettingType));
					if (val.Description.AcceptableValues != null && !val.Description.AcceptableValues.IsValid(obj))
					{
						throw new ArgumentException("Invalid target: " + value.Key);
					}
				}
			}

			public void Backup()
			{
				owner.Admission(preview);
				if (!File.Exists(owner.config.ConfigFilePath))
				{
					throw new IOException("Save Shepherd config before importing.");
				}
				target.Backup();
			}

			public void WriteAtomic(IReadOnlyDictionary<string, object> values)
			{
				owner.Admission(preview);
				target.WriteAtomic(values);
			}
		}

		public sealed class PreviewDocument
		{
			internal ShepherdImport Owner { get; }

			internal ConfigConverter Converter { get; }

			internal long Generation { get; }

			public ImportPlan Plan { get; }

			public ConversionPreview Conversion { get; }

			public string SourceSha256 { get; }

			public string TargetSha256 { get; }

			internal PreviewDocument(ShepherdImport owner, ImportPlan plan, ConfigConverter converter, ConversionPreview conversion, string source, string target, long generation)
			{
				Owner = owner;
				Plan = plan;
				Converter = converter;
				Conversion = conversion;
				SourceSha256 = source;
				TargetSha256 = target;
				Generation = generation;
			}

			public override string ToString()
			{
				return Plan.Report() + "\nActual target values (after native bounds):\n" + string.Join("\n", from v in Conversion.Values
					where v.TargetId != "Import.Imported Sources"
					select v.TargetId + " = " + Convert.ToString(v.Value, CultureInfo.InvariantCulture)) + "\n" + string.Join("\n", Conversion.Errors.Concat(Conversion.BindingConflicts.Select((ConversionConflict c) => "Binding collision: " + c.TargetId))) + "\nSource SHA256: " + SourceSha256 + "\nTarget SHA256: " + TargetSha256;
			}
		}

		public const string Section = "Import";

		private readonly ConfigFile config;

		private readonly MeadworksLog log;

		private readonly ConfigEntry<string> marker;

		private readonly List<IDisposable> registrations = new List<IDisposable>();

		private readonly int thread = Thread.CurrentThread.ManagedThreadId;

		private bool disposed;

		private static string Id(ConfigEntryBase entry)
		{
			return entry.Definition.Section + "." + entry.Definition.Key;
		}

		private ConfigEntryBase Entry(string id)
		{
			return config[config.Keys.Single((ConfigDefinition k) => k.Section + "." + k.Key == id)];
		}

		private static string SourcePath(ImportSource source)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return Path.Combine(Paths.ConfigPath, SourceImport.FileName(source));
		}

		public ShepherdImport(ConfigFile config, MeadworksLog log)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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)
			//IL_0086: 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)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected O, but got Unknown
			this.config = config;
			this.log = log;
			marker = MeadworksConfig.BindHidden<string>(config, "Import", "Imported Sources", "", "Managed by Shepherd: sources already imported.", (ConfigScope)0, (AcceptableValueBase)null);
			foreach (ImportSource value in Enum.GetValues(typeof(ImportSource)))
			{
				ImportSource s = value;
				SourceMod val2 = ShepherdSources.Source(s);
				registrations.Add(MeadworksConversion.Register(new ConversionRegistration("shepherd." + ((object)Unsafe.As<ImportSource, ImportSource>(ref s)/*cast due to .constrained prefix*/).ToString().ToLowerInvariant(), "com.meadworks.shepherd", val2.Guid, val2.Name, (Func<bool>)(() => !disposed && File.Exists(SourcePath(s)) && !marker.Value.Split(',').Contains<string>(((object)Unsafe.As<ImportSource, ImportSource>(ref s)/*cast due to .constrained prefix*/).ToString())), (Func<object>)(() => Preview(s)), (Func<object, IReadOnlyDictionary<string, string>, bool, object>)((object document, IReadOnlyDictionary<string, string> resolutions, bool backup) => Apply((document as PreviewDocument) ?? throw new ArgumentException("Wrong Shepherd preview."), resolutions, backup)))));
			}
		}

		private void Check()
		{
			if (disposed || thread != Thread.CurrentThread.ManagedThreadId || !Plugin.Ready || !Plugin.IsReady)
			{
				throw new InvalidOperationException("Shepherd importer is unavailable on this thread.");
			}
		}

		private static string Read(string path, out string hash)
		{
			using FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
			if (fileStream.Length > 1048576)
			{
				throw new IOException("Reference config exceeds 1 MiB.");
			}
			using (SHA256 sHA = SHA256.Create())
			{
				hash = BitConverter.ToString(sHA.ComputeHash(fileStream)).Replace("-", "");
			}
			fileStream.Position = 0L;
			using StreamReader streamReader = new StreamReader(fileStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true), detectEncodingFromByteOrderMarks: true);
			return streamReader.ReadToEnd();
		}

		private string TargetHash()
		{
			string hash;
			string text = (File.Exists(config.ConfigFilePath) ? Read(config.ConfigFilePath, out hash) : "missing");
			string text2 = string.Join("\n", from k in config.Keys.OrderBy<ConfigDefinition, string>((ConfigDefinition k) => k.Section, StringComparer.Ordinal).ThenBy<ConfigDefinition, string>((ConfigDefinition k) => k.Key, StringComparer.Ordinal)
				select k.Section + "." + k.Key + "=" + config[k].GetSerializedValue());
			using SHA256 sHA = SHA256.Create();
			return BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(text + "\n" + text2))).Replace("-", "");
		}

		public unsafe PreviewDocument Preview(ImportSource source)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Expected O, but got Unknown
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Expected O, but got Unknown
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Expected O, but got Unknown
			Check();
			string hash;
			string text = Read(SourcePath(source), out hash);
			ImportPlan val = SourceImport.Plan(source, text);
			Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.Ordinal);
			foreach (KeyValuePair<string, string> value in val.Values)
			{
				ConfigEntryBase val2 = Entry(value.Key);
				object obj = TomlTypeConverter.ConvertToValue(value.Value, val2.SettingType);
				if (val2.Description.AcceptableValues != null)
				{
					obj = val2.Description.AcceptableValues.Clamp(obj);
				}
				dictionary[Id(val2)] = obj;
			}
			if (dictionary.Count > 0)
			{
				dictionary[