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 Manger v1.0.2
plugins\Manger.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Manger.Commands; using Manger.Config; using Manger.Content; using Manger.Feed; using Manger.Util; using Microsoft.CodeAnalysis; using UnityEngine; [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("Manger")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2")] [assembly: AssemblyProduct("Manger")] [assembly: AssemblyTitle("Manger")] [assembly: AssemblyVersion("1.0.2.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Manger { internal static class ModInfo { internal const string Guid = "dafini.manger"; internal const string Name = "Manger"; internal const string Version = "1.0.2"; internal const string PieceName = "manger_trough"; } [BepInPlugin("dafini.manger", "Manger", "1.0.2")] [BepInProcess("valheim.exe")] [BepInProcess("valheim_server.exe")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "dafini.manger"; public const string PluginName = "Manger"; public const string PluginVersion = "1.0.2"; private Harmony _harmony; private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Log.Bind(((BaseUnityPlugin)this).Logger); MangerConfig.Bind(((BaseUnityPlugin)this).Config); try { _harmony = new Harmony("dafini.manger"); _harmony.PatchAll(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Manger failed to patch and is disabled for this session: " + ex)); return; } MangerCommand.Register(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Manger 1.0.2 loaded."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } PrefabShelf.Drop(); } } } namespace Manger.Util { internal static class Log { private static ManualLogSource _source; internal static void Bind(ManualLogSource source) { _source = source; } internal static void Info(string message) { ManualLogSource source = _source; if (source != null) { source.LogInfo((object)message); } } internal static void Warn(string message) { ManualLogSource source = _source; if (source != null) { source.LogWarning((object)message); } } internal static void Error(string message) { ManualLogSource source = _source; if (source != null) { source.LogError((object)message); } } internal static void Debug(string message) { if (MangerConfig.Verbose != null && MangerConfig.Verbose.Value) { ManualLogSource source = _source; if (source != null) { source.LogInfo((object)message); } } } } } namespace Manger.Feed { internal static class Bowl { internal const float Height = 0.35f; internal static int Placed { get; private set; } internal static void ResetForTests() { Placed = 0; } internal static ItemDrop Place(ItemData template, int amount, Vector3 at, Quaternion rotation) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (template == null || amount <= 0) { return null; } ItemDrop val = ItemDrop.DropItem(template, amount, at, rotation); if ((Object)(object)val == (Object)null) { Log.Debug("manger: the game would not spawn the feed item"); return null; } Pin(val); Placed++; return val; } internal static void Pin(ItemDrop drop) { //IL_001b: 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) if (!((Object)(object)drop == (Object)null)) { Rigidbody component = ((Component)drop).GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { component.velocity = Vector3.zero; component.angularVelocity = Vector3.zero; component.isKinematic = true; } drop.m_autoPickup = false; } } internal static Vector3 Rest(Vector3 troughPosition) { //IL_0000: 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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) return new Vector3(troughPosition.x, troughPosition.y + 0.35f, troughPosition.z); } internal static ItemDrop Find(ZDOID id) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (((ZDOID)(ref id)).IsNone() || (Object)(object)ZNetScene.instance == (Object)null) { return null; } GameObject val = ZNetScene.instance.FindInstance(id); if (!((Object)(object)val == (Object)null)) { return val.GetComponent<ItemDrop>(); } return null; } internal static int StackOf(ItemDrop drop) { if (drop?.m_itemData != null) { return drop.m_itemData.m_stack; } return 0; } } internal enum Sight { Findable, WrongLayer, NoBody, NotNetworked, NotFood } internal static class Findable { internal const string Layer = "item"; internal static Sight Judge(bool onItemLayer, bool hasBody, bool networked, bool edible) { if (!onItemLayer) { return Sight.WrongLayer; } if (!hasBody) { return Sight.NoBody; } if (!networked) { return Sight.NotNetworked; } if (!edible) { return Sight.NotFood; } return Sight.Findable; } internal static bool Can(bool onItemLayer, bool hasBody, bool networked, bool edible) { return Judge(onItemLayer, hasBody, networked, edible) == Sight.Findable; } } internal static class Fodder { private static readonly HashSet<string> Menu = new HashSet<string>(StringComparer.Ordinal); internal static int Count => Menu.Count; internal static IEnumerable<string> All => Menu; internal static bool Ready => Menu.Count > 0; internal static void Clear() { Menu.Clear(); } internal static void Learn(IEnumerable<string> itemNames) { if (itemNames == null) { return; } foreach (string itemName in itemNames) { if (!string.IsNullOrEmpty(itemName)) { Menu.Add(itemName); } } } internal static bool Accepts(string itemName) { if (!string.IsNullOrEmpty(itemName)) { return Menu.Contains(itemName); } return false; } } internal enum Source { Chosen, Bag, Nearby, None } internal static class Forage { internal static ItemData First(IEnumerable<ItemData> items, Func<ItemData, bool> edible, string alreadyHolding) { if (items == null || edible == null) { return null; } foreach (ItemData item in items) { if (item?.m_shared != null && item.m_stack > 0 && edible(item) && (string.IsNullOrEmpty(alreadyHolding) || string.Equals(item.m_shared.m_name, alreadyHolding, StringComparison.Ordinal))) { return item; } } return null; } internal static bool MayTakeFrom(bool isPublic, bool inUse, bool admitted, bool hasItems) { return isPublic && !inUse && admitted && hasItems; } internal static bool WithinReach(float distance, float reach) { if (distance >= 0f) { return distance <= reach; } return false; } internal static ItemData Find(Player player, Vector3 at, string alreadyHolding, Func<ItemData, bool> edible, out Source source, out Inventory from) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Invalid comparison between Unknown and I4 //IL_007a: Unknown result type (might be due to invalid IL or missing references) source = Source.None; from = null; if ((Object)(object)player == (Object)null) { return null; } Inventory inventory = ((Humanoid)player).GetInventory(); ItemData val = ((inventory == null) ? null : First(inventory.GetAllItems(), edible, alreadyHolding)); if (val != null) { source = Source.Bag; from = inventory; return val; } foreach (Container item in Chests(at)) { Inventory inventory2 = item.GetInventory(); if (inventory2 == null) { continue; } List<ItemData> allItems = inventory2.GetAllItems(); if (MayTakeFrom((int)item.m_privacy == 2, item.IsInUse(), PrivateArea.CheckAccess(((Component)item).transform.position, 0f, false, true), allItems != null && allItems.Count > 0)) { ItemData val2 = First(allItems, edible, alreadyHolding); if (val2 != null) { source = Source.Nearby; from = inventory2; return val2; } } } return null; } private static IEnumerable<Container> Chests(Vector3 at) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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) float value = MangerConfig.Reach.Value; List<Container> list = new List<Container>(); Collider[] array = Physics.OverlapSphere(at, value); foreach (Collider val in array) { if (!((Object)(object)val == (Object)null)) { Container componentInParent = ((Component)val).GetComponentInParent<Container>(); if (!((Object)(object)componentInParent == (Object)null) && !list.Contains(componentInParent) && WithinReach(Vector3.Distance(at, ((Component)componentInParent).transform.position), value)) { list.Add(componentInParent); } } } return list; } internal static string Sentence(Source source, int amount, string food) { switch (source) { case Source.Chosen: case Source.Bag: return $"Stocked {amount} {food}"; case Source.Nearby: return $"Stocked {amount} {food} from a chest nearby"; default: return "Nothing here that any of your animals would eat"; } } } internal enum Filling { Ok, NotFood, Mixed, Full, Warded } internal static class Portion { internal static int Moved(int offered, int alreadyIn, int capacity) { if (offered <= 0) { return 0; } int num = capacity - alreadyIn; if (num <= 0) { return 0; } if (offered >= num) { return num; } return offered; } internal static Filling Judge(bool edible, bool warded, string holding, string current, int alreadyIn, int capacity) { if (!edible) { return Filling.NotFood; } if (warded) { return Filling.Warded; } if (!string.IsNullOrEmpty(current) && !string.Equals(current, holding, StringComparison.Ordinal)) { return Filling.Mixed; } if (alreadyIn >= capacity) { return Filling.Full; } return Filling.Ok; } internal static int Emptied(int inTrough) { if (inTrough <= 0) { return 0; } return inTrough; } } internal class Trough : MonoBehaviour, Interactable, Hoverable { internal const string BowlKey = "manger.bowl"; private ZNetView _view; private bool Ready { get { if ((Object)(object)_view != (Object)null) { return _view.IsValid(); } return false; } } private void Awake() { _view = ((Component)this).GetComponent<ZNetView>(); } internal ItemDrop Food() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!Ready) { return null; } return Bowl.Find(_view.GetZDO().GetZDOID("manger.bowl")); } internal int Amount() { return Bowl.StackOf(Food()); } internal string FoodName() { ItemDrop val = Food(); if (val?.m_itemData?.m_shared != null) { return val.m_itemData.m_shared.m_name; } return string.Empty; } private void Remember(ItemDrop item) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (Ready) { _view.ClaimOwnership(); ZNetView val = (((Object)(object)item == (Object)null) ? null : Networked(item)); _view.GetZDO().Set("manger.bowl", ((Object)(object)val == (Object)null) ? ZDOID.None : val.GetZDO().m_uid); } } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold) { return false; } if (!Ready) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null) { return false; } if (!alt) { return Scrounge(val); } return Empty(val); } public bool UseItem(Humanoid user, ItemData item) { if (!Ready || item?.m_shared == null) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null) { return false; } Put(val, item, ((Humanoid)val).GetInventory(), Source.Chosen); return true; } private bool Scrounge(Player player) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) Source source; Inventory from; ItemData val = Forage.Find(player, ((Component)this).transform.position, FoodName(), Edible, out source, out from); if (val == null) { ((Character)player).Message((MessageType)2, Forage.Sentence(Source.None, 0, string.Empty), 0, (Sprite)null, true); return false; } Put(player, val, from, source); return true; } private static bool Edible(ItemData item) { if (item?.m_shared != null) { return Fodder.Accepts(PrefabNameOf(item)); } return false; } private void Put(Player player, ItemData item, Inventory from, Source source) { //IL_0020: 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_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) string name = item.m_shared.m_name; ItemDrop val = Food(); int num = Bowl.StackOf(val); bool warded = !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, true); Filling filling = Portion.Judge(Edible(item), warded, name, FoodName(), num, MangerConfig.Capacity.Value); if (filling != Filling.Ok) { ((Character)player).Message((MessageType)2, Complaint(filling), 0, (Sprite)null, true); return; } int num2 = Portion.Moved(item.m_stack, num, MangerConfig.Capacity.Value); if (num2 <= 0) { return; } if ((Object)(object)val != (Object)null) { ZNetView obj = Networked(val); if (obj != null) { obj.ClaimOwnership(); } val.SetStack(num + num2); Bowl.Pin(val); } else { ItemDrop val2 = Bowl.Place(item, num2, Bowl.Rest(((Component)this).transform.position), ((Component)this).transform.rotation); if ((Object)(object)val2 == (Object)null) { return; } Remember(val2); } if (from != null) { from.RemoveItem(item, num2); } ((Character)player).Message((MessageType)2, Forage.Sentence(source, num2, name), 0, (Sprite)null, true); Log.Debug($"manger: stocked {num2} {name} from {source}, now {Amount()}"); } private bool Empty(Player player) { ItemDrop val = Food(); int num = Portion.Emptied(Bowl.StackOf(val)); if (num <= 0) { ((Character)player).Message((MessageType)2, "The trough is empty", 0, (Sprite)null, true); return false; } string name = val.m_itemData.m_shared.m_name; ItemData val2 = val.m_itemData.Clone(); val2.m_stack = num; if (!((Humanoid)player).GetInventory().AddItem(val2)) { ((Character)player).Message((MessageType)2, "Your inventory is full", 0, (Sprite)null, true); return false; } ZNetView val3 = Networked(val); if ((Object)(object)val3 == (Object)null) { return false; } val3.ClaimOwnership(); val3.Destroy(); Remember(null); ((Character)player).Message((MessageType)2, $"Took {num} {name}", 0, (Sprite)null, true); return true; } private static ZNetView Networked(ItemDrop item) { if (!((Object)(object)item == (Object)null)) { return ((Component)item).GetComponent<ZNetView>(); } return null; } internal static string PrefabNameOf(ItemData item) { if ((Object)(object)item?.m_dropPrefab != (Object)null) { return ((Object)item.m_dropPrefab).name; } if (item?.m_shared != null) { return item.m_shared.m_name; } return string.Empty; } private static string Complaint(Filling verdict) { return verdict switch { Filling.NotFood => "No animal here eats that", Filling.Mixed => "The trough already holds something else", Filling.Full => "The trough is full", Filling.Warded => "You are not permitted to build here", _ => "The trough refuses that", }; } public string GetHoverName() { return Wording.Localised(Wording.Name); } public string GetHoverText() { if (!Ready) { return string.Empty; } int num = Amount(); return Wording.Localised((num <= 0) ? Wording.Empty() : Wording.Stocked(FoodName(), num)); } public float GetHoverOffset() { return 0f; } } internal static class Wording { internal const string Use = "$KEY_Use"; internal const string Alt = "$KEY_AltPlace"; internal static string Name => "Trough"; internal static string Empty() { return Name + " ( empty )\n[<color=yellow><b>$KEY_Use</b></color>] Stock with feed"; } internal static string Stocked(string food, int amount) { return $"{Name} ( {food} x{amount} )\n" + "[<color=yellow><b>$KEY_Use</b></color>] Add more\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] Take it all back"; } internal static string Localised(string raw) { if (string.IsNullOrEmpty(raw)) { return string.Empty; } Localization instance = Localization.instance; if (instance != null) { return instance.Localize(raw); } return raw; } internal static bool HasToken(string text) { if (!string.IsNullOrEmpty(text)) { return text.Contains("$"); } return false; } } } namespace Manger.Content { internal static class PrefabShelf { private static GameObject _shelf; internal static GameObject Root { get { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown if ((Object)(object)_shelf != (Object)null) { return _shelf; } _shelf = new GameObject("MangerPrefabs"); _shelf.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_shelf); return _shelf; } } internal static void Drop() { if (!((Object)(object)_shelf == (Object)null)) { Object.Destroy((Object)(object)_shelf); _shelf = null; } } } internal enum Stage { Prefab, Menu, Diet } internal static class TroughPiece { [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class Install { [HarmonyPrefix] private static void Prefix(ZNetScene __instance) { Ensure(__instance); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class Items { [HarmonyPostfix] private static void Postfix() { Ensure(ZNetScene.instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class ItemsCopied { [HarmonyPostfix] private static void Postfix() { Ensure(ZNetScene.instance); } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class Spawned { [HarmonyPostfix] private static void Postfix() { Ensure(ZNetScene.instance); } } private static readonly string[] Donors = new string[3] { "piece_cookingstation", "piece_cookingstation_iron", "piece_workbench_ext1" }; private const string HammerMarker = "piece_workbench"; private static GameObject _trough; internal static bool PrefabReady { get; private set; } internal static bool InMenu { get; private set; } internal static bool DietRead { get; private set; } internal static string Trouble { get; private set; } = string.Empty; internal static string UsedDonor { get; private set; } = string.Empty; internal static void ResetForTests() { PrefabReady = false; InMenu = false; DietRead = false; Trouble = string.Empty; UsedDonor = string.Empty; _trough = null; } internal static bool Needs(bool enabled, bool done, bool prerequisiteReady) { return enabled && !done && prerequisiteReady; } internal static void Ensure(ZNetScene scene) { if (MangerConfig.Enabled == null || !MangerConfig.Enabled.Value) { return; } try { if (Needs(enabled: true, PrefabReady, (Object)(object)scene != (Object)null)) { BuildPrefab(scene); } if (Needs(enabled: true, DietRead, (Object)(object)scene != (Object)null)) { ReadDiets(scene); } if (Needs(enabled: true, InMenu, PrefabReady)) { TrySeat(); } } catch (Exception ex) { Trouble = ex.Message; Log.Error("Manger stumbled while registering its trough: " + ex); } } private static void BuildPrefab(ZNetScene scene) { GameObject val = Donate(scene); if ((Object)(object)val == (Object)null) { Trouble = "none of " + string.Join(", ", Donors) + " exist to clone"; Log.Error("Manger found nothing to clone. No trough this session."); return; } GameObject val2 = Object.Instantiate<GameObject>(val, PrefabShelf.Root.transform, false); ((Object)val2).name = "manger_trough"; Strip(val2); val2.AddComponent<Trough>(); Piece component = val2.GetComponent<Piece>(); if ((Object)(object)component != (Object)null) { component.m_name = "Trough"; component.m_description = "Holds animal feed where tames can reach it."; component.m_groundPiece = true; component.m_allowedInDungeons = false; } if (scene.m_prefabs != null && !scene.m_prefabs.Contains(val2)) { scene.m_prefabs.Add(val2); } _trough = val2; PrefabReady = true; Log.Info("Manger: trough prefab built from " + UsedDonor + "."); } internal static bool TrySeat() { if ((Object)(object)_trough == (Object)null) { return false; } PieceTable val = HammerTable(); if ((Object)(object)val == (Object)null) { Trouble = "the hammer's piece table is not available yet"; Log.Debug("manger: no hammer table yet, will try again"); return false; } if (!val.m_pieces.Contains(_trough)) { val.m_pieces.Add(_trough); } InMenu = true; Trouble = string.Empty; Log.Info("Manger: trough added to the hammer."); return true; } internal static void ForTests_PrefabReady(GameObject stand) { _trough = stand; PrefabReady = (Object)(object)stand != (Object)null; } private static void ReadDiets(ZNetScene scene) { int num = LearnMenu(scene.m_prefabs); if (num <= 0) { Log.Debug("manger: no tameable creatures read yet, will try again"); return; } DietRead = true; Log.Info($"Manger: read the diets of {num} tameable creature(s) - " + $"{Fodder.Count} thing(s) count as feed."); } private static GameObject Donate(ZNetScene scene) { if (scene.m_prefabs == null) { return null; } string[] donors = Donors; foreach (string text in donors) { foreach (GameObject prefab in scene.m_prefabs) { if ((Object)(object)prefab != (Object)null && ((Object)prefab).name == text) { UsedDonor = text; return prefab; } } } return null; } private static PieceTable HammerTable() { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance != (Object)null) { GameObject itemPrefab = instance.GetItemPrefab("Hammer"); PieceTable val = (((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent<ItemDrop>())?.m_itemData?.m_shared?.m_buildPieces; if ((Object)(object)val != (Object)null) { return val; } } PieceTable[] array = Resources.FindObjectsOfTypeAll<PieceTable>(); foreach (PieceTable val2 in array) { if (val2?.m_pieces == null) { continue; } foreach (GameObject piece in val2.m_pieces) { if ((Object)(object)piece != (Object)null && ((Object)piece).name == "piece_workbench") { return val2; } } } return null; } private static void Strip(GameObject trough) { CookingStation[] componentsInChildren = trough.GetComponentsInChildren<CookingStation>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } CraftingStation[] componentsInChildren2 = trough.GetComponentsInChildren<CraftingStation>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } Container[] componentsInChildren3 = trough.GetComponentsInChildren<Container>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren3[i]); } } internal static int LearnMenu(IEnumerable<GameObject> prefabs) { if (prefabs == null) { return 0; } int num = 0; foreach (GameObject prefab in prefabs) { if ((Object)(object)prefab == (Object)null) { continue; } MonsterAI component = prefab.GetComponent<MonsterAI>(); if (component?.m_consumeItems == null || component.m_consumeItems.Count == 0 || (Object)(object)prefab.GetComponent<Tameable>() == (Object)null) { continue; } List<string> list = new List<string>(); foreach (ItemDrop consumeItem in component.m_consumeItems) { if ((Object)(object)consumeItem != (Object)null) { list.Add(((Object)consumeItem).name); } } Fodder.Learn(list); num++; } return num; } } } namespace Manger.Config { internal static class MangerConfig { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> Capacity; internal static ConfigEntry<bool> TamesWild; internal static ConfigEntry<int> BreedingCap; internal static ConfigEntry<float> Reach; internal static ConfigEntry<bool> Verbose; internal static void Bind(ConfigFile cfg) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown Enabled = cfg.Bind<bool>("General", "Enabled", true, "Master switch. Off means the trough is not added to the build menu."); Capacity = cfg.Bind<int>("Trough", "Capacity", 50, new ConfigDescription("How many items one trough holds. The food sits on it as a real world item, so this is a stack size rather than an inventory.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 999), Array.Empty<object>())); TamesWild = cfg.Bind<bool>("Trough", "TamesWild", true, "A stocked trough tames wild animals that wander in and eat from it. This is the game's own behaviour - feeding a wild tameable is exactly how taming works - so turning it OFF is the part that costs extra code. On means a baited pen tames unattended. Note that wolves are tameable too."); BreedingCap = cfg.Bind<int>("Trough", "BreedingCap", 0, new ConfigDescription("Stop feeding once this many tames are already near the trough. A permanently stocked pen breeds without supervision, and Valheim handles large herds badly - this is the lever for that. ZERO MEANS NO CAP, which is the default: it is your pen and your framerate.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 200), Array.Empty<object>())); Reach = cfg.Bind<float>("Trough", "Reach", 8f, new ConfigDescription("How far the trough will reach into nearby chests when you press Use with nothing suitable in your bag. Your own inventory is always tried first. Set to 0 to only ever use what you are carrying.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 32f), Array.Empty<object>())); Verbose = cfg.Bind<bool>("Advanced", "Verbose", false, "Log every decision. Useful for a bug report, noisy otherwise."); } } } namespace Manger.Commands { internal static class MangerCommand { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__0_0; internal void <Register>b__0_0(ConsoleEventArgs args) { args.Context.AddString(Report()); } } internal static void Register() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown object obj = <>c.<>9__0_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { args.Context.AddString(Report()); }; <>c.<>9__0_0 = val; obj = (object)val; } new ConsoleCommand("manger", "what Manger registered and what animals eat", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } internal static string Report() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Manger 1.0.2 - " + (MangerConfig.Enabled.Value ? "on" : "OFF")); stringBuilder.AppendLine(" prefab: " + (TroughPiece.PrefabReady ? ("built" + (string.IsNullOrEmpty(TroughPiece.UsedDonor) ? "" : (" from " + TroughPiece.UsedDonor))) : "NOT BUILT")); stringBuilder.AppendLine(" build menu: " + (TroughPiece.InMenu ? "in the hammer" : "NOT IN IT")); stringBuilder.AppendLine(" diets: " + (TroughPiece.DietRead ? "read" : "NOT READ")); if (!string.IsNullOrEmpty(TroughPiece.Trouble)) { stringBuilder.AppendLine(" last trouble: " + TroughPiece.Trouble); } stringBuilder.AppendLine($" capacity {MangerConfig.Capacity.Value}, " + "tames wild: " + (MangerConfig.TamesWild.Value ? "yes" : "no") + ", breeding cap: " + ((MangerConfig.BreedingCap.Value <= 0) ? "none" : MangerConfig.BreedingCap.Value.ToString())); if (!Fodder.Ready) { stringBuilder.AppendLine(" feed list: EMPTY - no tameable creature has been read yet, so the trough will refuse everything. This is a load-order problem rather than a disagreement about carrots."); return stringBuilder.ToString(); } stringBuilder.AppendLine($" this install's animals eat {Fodder.Count} thing(s):"); StringBuilder stringBuilder2 = new StringBuilder(" "); foreach (string item in Fodder.All) { if (stringBuilder2.Length + item.Length > 74) { stringBuilder.AppendLine(stringBuilder2.ToString()); stringBuilder2 = new StringBuilder(" "); } stringBuilder2.Append(' ').Append(item); } if (stringBuilder2.Length > 3) { stringBuilder.AppendLine(stringBuilder2.ToString()); } return stringBuilder.ToString(); } } }