Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Shepherd v0.1.21
plugins/Shepherd/Shepherd.Core.dll
Decompiled 13 hours agousing 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
The result has been truncated due to the large size, download it to view full contents!
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[