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 AnimalFeedingTrough v1.0.4
AnimalFeedingTrough.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BepInEx; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using UnityEngine; [assembly: Guid("55912d84-4458-440a-b4d5-ee0eb383d22e")] [assembly: AssemblyFileVersion("1.0.4.0")] [assembly: CompilationRelaxations(8)] [assembly: ComVisible(false)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyTitle("Animal Feeding Trough")] [assembly: AssemblyDescription("Adds a functional animal feeding trough to Valheim.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("xNeliox")] [assembly: AssemblyProduct("Animal Feeding Trough")] [assembly: AssemblyCopyright("Copyright © 2026 xNeliox")] [assembly: AssemblyTrademark("")] [assembly: AssemblyVersion("1.0.4.0")] namespace AnimalFeedingTrough; [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [BepInPlugin("xneliox.animalfeedingtrough", "Animal Feeding Trough", "1.0.4")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class AnimalFeedingTroughPlugin : BaseUnityPlugin { public const string PluginGuid = "xneliox.animalfeedingtrough"; public const string PluginName = "Animal Feeding Trough"; public const string PluginVersion = "1.0.4"; internal const string PrefabName = "xneliox_FeedingTrough"; private void Awake() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) TroughTranslations.Register(); new Harmony("xneliox.animalfeedingtrough").PatchAll(typeof(AnimalFeedingTroughPlugin).Assembly); PrefabManager.OnVanillaPrefabsAvailable += RegisterTrough; } private void OnDestroy() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) new Harmony("xneliox.animalfeedingtrough").UnpatchSelf(); PrefabManager.OnVanillaPrefabsAvailable -= RegisterTrough; } private void RegisterTrough() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) PrefabManager.OnVanillaPrefabsAvailable -= RegisterTrough; try { PieceConfig val = new PieceConfig(); val.Name = "$xneliox_trough_name"; val.Description = "$xneliox_trough_description"; val.PieceTable = "_HammerPieceTable"; val.Category = "Furniture"; val.CraftingStation = "piece_workbench"; val.Icon = TroughModelV3.CreateIcon(); val.Requirements = (RequirementConfig[])(object)new RequirementConfig[2] { new RequirementConfig("Wood", 20, 0, true), new RequirementConfig("BronzeNails", 4, 0, true) }; PieceConfig val2 = val; CustomPiece val3 = new CustomPiece("xneliox_FeedingTrough", "piece_chest_wood", val2); GameObject piecePrefab = val3.PiecePrefab; ((Object)piecePrefab).name = "xneliox_FeedingTrough"; Renderer componentInChildren = piecePrefab.GetComponentInChildren<Renderer>(true); Material val4 = (Object.op_Implicit((Object)(object)componentInChildren) ? componentInChildren.sharedMaterial : null); if (!Object.op_Implicit((Object)(object)val4)) { throw new InvalidOperationException("No Valheim piece material was available."); } Renderer[] componentsInChildren = piecePrefab.GetComponentsInChildren<Renderer>(true); foreach (Renderer val5 in componentsInChildren) { val5.enabled = false; } Collider[] componentsInChildren2 = piecePrefab.GetComponentsInChildren<Collider>(true); foreach (Collider val6 in componentsInChildren2) { val6.enabled = false; } AssetBundleTroughModel.Instantiate(piecePrefab.transform); BoxCollider val7 = piecePrefab.GetComponent<BoxCollider>(); if (!Object.op_Implicit((Object)(object)val7)) { val7 = piecePrefab.AddComponent<BoxCollider>(); } val7.center = new Vector3(0f, 0.5f, 0f); val7.size = new Vector3(5.24f, 1f, 1.34f); ((Collider)val7).enabled = true; Container component = piecePrefab.GetComponent<Container>(); component.m_name = "$xneliox_trough_name"; component.m_width = 6; component.m_height = 1; component.m_privacy = (PrivacySetting)2; Piece component2 = piecePrefab.GetComponent<Piece>(); component2.m_name = "$xneliox_trough_name"; component2.m_description = "$xneliox_trough_description"; if (!Object.op_Implicit((Object)(object)piecePrefab.GetComponent<TroughFeeder>())) { piecePrefab.AddComponent<TroughFeeder>(); } PieceManager.Instance.AddPiece(val3); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Registered the networked animal feeding trough."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not register feeding trough: " + ex)); } } } [HarmonyPatch(typeof(ZNetScene), "CreateObject")] internal static class TroughPrefabHashMigration { private const int PreviousPrefabHash = 160077371; private static void Prefix(ZDO zdo) { if (zdo != null && zdo.GetPrefab() == 160077371) { zdo.SetPrefab(StringExtensionMethods.GetStableHashCode("xneliox_FeedingTrough")); } } } [HarmonyPatch(typeof(ZNetScene), "GetPrefab", new Type[] { typeof(int) })] internal static class TroughPrefabHashLookup { private const int PreviousPrefabHash = 160077371; private static void Prefix(ref int hash) { if (hash == 160077371) { hash = StringExtensionMethods.GetStableHashCode("xneliox_FeedingTrough"); } } } internal static class AssetBundleTroughModel { private const string BundleResource = "animalfeedingtrough_v4"; private const string PrefabAsset = "Assets/AnimalFeedingTrough/FeedingTroughV4.prefab"; private static AssetBundle _bundle; private static GameObject _prefab; internal static void Instantiate(Transform parent) { //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: 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_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)_bundle)) { Assembly assembly = typeof(AnimalFeedingTroughPlugin).Assembly; using Stream stream = assembly.GetManifestResourceStream("animalfeedingtrough_v4"); if (stream == null) { throw new InvalidOperationException("The embedded feeding trough AssetBundle resource is missing."); } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); _bundle = AssetBundle.LoadFromMemory(memoryStream.ToArray()); } if (!Object.op_Implicit((Object)(object)_bundle)) { throw new InvalidOperationException("The embedded feeding trough AssetBundle could not be loaded."); } if (!Object.op_Implicit((Object)(object)_prefab)) { _prefab = _bundle.LoadAsset<GameObject>("Assets/AnimalFeedingTrough/FeedingTroughV4.prefab"); } if (!Object.op_Implicit((Object)(object)_prefab)) { throw new InvalidOperationException("The feeding trough prefab is missing from the AssetBundle."); } GameObject val = Object.Instantiate<GameObject>(_prefab, parent, false); ((Object)val).name = "AnimalFeedingTroughModelV3"; Transform[] componentsInChildren = val.GetComponentsInChildren<Transform>(true); foreach (Transform val2 in componentsInChildren) { if (((Object)val2).name.EndsWith(" foot", StringComparison.Ordinal)) { Vector3 localPosition = val2.localPosition; localPosition.y = 0.16f; val2.localPosition = localPosition; Vector3 localScale = val2.localScale; localScale.y = 0.36f; val2.localScale = localScale; } } } } public sealed class TroughFeeder : MonoBehaviour { private const float AttractionRange = 16f; private const string ServingMarker = "xneliox_trough_serving"; private static readonly MethodInfo CanConsumeMethod = AccessTools.Method(typeof(MonsterAI), "CanConsume", (Type[])null, (Type[])null); private static readonly MethodInfo InventoryChangedMethod = AccessTools.Method(typeof(Inventory), "Changed", new Type[2] { typeof(bool), typeof(bool) }, (Type[])null); private static readonly MethodInfo ContainerSaveMethod = AccessTools.Method(typeof(Container), "Save", (Type[])null, (Type[])null); private static readonly FieldInfo ConsumeTargetField = AccessTools.Field(typeof(MonsterAI), "m_consumeTarget"); private static readonly FieldInfo ConsumeSearchTimerField = AccessTools.Field(typeof(MonsterAI), "m_consumeSearchTimer"); private Container _container; private ZNetView _view; private GameObject _visibleFeed; private float _nextSearch; private float _nextVisualRefresh; private ItemDrop _currentServing; private void Awake() { _container = ((Component)this).GetComponent<Container>(); _view = ((Component)this).GetComponent<ZNetView>(); Transform val = ((Component)this).transform.Find("AnimalFeedingTroughModelV3/VisibleFeed"); _visibleFeed = (Object.op_Implicit((Object)(object)val) ? ((Component)val).gameObject : null); } private void Update() { //IL_00d7: 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) RefreshFeedVisual(); if (!Object.op_Implicit((Object)(object)_container) || !Object.op_Implicit((Object)(object)_view) || !_view.IsValid() || Time.time < _nextSearch) { return; } _nextSearch = Time.time + 2f; EnableTroughSearchForOwnedAnimals(); if (!_view.IsOwner()) { return; } if (Object.op_Implicit((Object)(object)_currentServing)) { ZNetView component = ((Component)_currentServing).GetComponent<ZNetView>(); if (_currentServing.m_itemData != null && _currentServing.m_itemData.m_stack > 0 && Object.op_Implicit((Object)(object)component) && component.IsValid()) { return; } _currentServing = null; } List<Character> allCharacters = Character.GetAllCharacters(); foreach (Character item in allCharacters) { if (!Object.op_Implicit((Object)(object)item)) { continue; } float num = Vector3.Distance(((Component)this).transform.position, ((Component)item).transform.position); if (num > 16f) { continue; } Tameable component2 = ((Component)item).GetComponent<Tameable>(); MonsterAI component3 = ((Component)item).GetComponent<MonsterAI>(); if (Object.op_Implicit((Object)(object)component2) && Object.op_Implicit((Object)(object)component3) && CanUseTrough(item, component2)) { ItemData val = FindFood(component3); if (val != null) { SpawnServing(val, item); break; } } } } private void EnableTroughSearchForOwnedAnimals() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) List<Character> allCharacters = Character.GetAllCharacters(); foreach (Character item in allCharacters) { if (!Object.op_Implicit((Object)(object)item)) { continue; } float num = Vector3.Distance(((Component)this).transform.position, ((Component)item).transform.position); if (num > 16f) { continue; } Tameable component = ((Component)item).GetComponent<Tameable>(); MonsterAI component2 = ((Component)item).GetComponent<MonsterAI>(); ZNetView component3 = ((Component)item).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component2) && Object.op_Implicit((Object)(object)component3) && component3.IsValid() && CanUseTrough(item, component) && component3.IsOwner()) { ItemData val = FindFood(component2); if (val != null && component2.m_consumeSearchRange < 16f) { component2.m_consumeSearchRange = 16f; } } } } private static bool CanUseTrough(Character character, Tameable tameable) { if (!Object.op_Implicit((Object)(object)character) || !Object.op_Implicit((Object)(object)tameable) || !tameable.IsHungry()) { return false; } return true; } private void SpawnServing(ItemData food, Character animal) { //IL_0034: 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_003e: 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) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_00f1: Unknown result type (might be due to invalid IL or missing references) if (food == null || (Object)(object)animal == (Object)null || (Object)(object)_container == (Object)null || _container.GetInventory() == null) { return; } Vector3 val = ((Component)this).transform.InverseTransformPoint(((Component)animal).transform.position); float[] array = new float[4] { -1.65f, -0.55f, 0.55f, 1.65f }; float num = array[0]; float num2 = Mathf.Abs(val.x - num); float[] array2 = array; foreach (float num3 in array2) { float num4 = Mathf.Abs(val.x - num3); if (num4 < num2) { num2 = num4; num = num3; } } float num5 = ((!(val.z < 0f)) ? 1f : (-1f)); Vector3 val2 = ((Component)this).transform.TransformPoint(new Vector3(num, 0.12f, num5 * 0.95f)); ItemData val3 = food.Clone(); val3.m_stack = 1; ItemDrop val4 = ItemDrop.DropItem(val3, 1, val2, Quaternion.identity); if (!Object.op_Implicit((Object)(object)val4)) { Debug.LogWarning((object)"[Animal Feeding Trough] Could not create a food serving."); return; } _currentServing = val4; MonsterAI component = ((Component)animal).GetComponent<MonsterAI>(); ZNetView component2 = ((Component)animal).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component2) && component2.IsValid() && component2.IsOwner()) { component.m_consumeSearchRange = Mathf.Max(component.m_consumeSearchRange, 16f); if (ConsumeTargetField != null) { ConsumeTargetField.SetValue(component, val4); } if (ConsumeSearchTimerField != null) { ConsumeSearchTimerField.SetValue(component, 0f); } } ZNetView component3 = ((Component)val4).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component3) && component3.IsValid() && component3.IsOwner()) { component3.GetZDO().Set("xneliox_trough_serving", true); } Renderer[] componentsInChildren = ((Component)val4).GetComponentsInChildren<Renderer>(true); foreach (Renderer val5 in componentsInChildren) { val5.enabled = false; } ParticleSystem[] componentsInChildren2 = ((Component)val4).GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem val6 in componentsInChildren2) { val6.Stop(true, (ParticleSystemStopBehavior)0); Renderer component4 = ((Component)val6).GetComponent<Renderer>(); if (Object.op_Implicit((Object)(object)component4)) { component4.enabled = false; } } Light[] componentsInChildren3 = ((Component)val4).GetComponentsInChildren<Light>(true); foreach (Light val7 in componentsInChildren3) { ((Behaviour)val7).enabled = false; } Inventory inventory = _container.GetInventory(); inventory.RemoveItem(food, 1); if (InventoryChangedMethod != null) { InventoryChangedMethod.Invoke(inventory, new object[2] { false, false }); } if (ContainerSaveMethod != null) { ContainerSaveMethod.Invoke(_container, null); } } private void RefreshFeedVisual() { if (!Object.op_Implicit((Object)(object)_visibleFeed) || Time.time < _nextVisualRefresh) { return; } _nextVisualRefresh = Time.time + 0.35f; bool active = false; if (Object.op_Implicit((Object)(object)_container) && _container.GetInventory() != null) { foreach (ItemData allItem in _container.GetInventory().GetAllItems()) { if (allItem != null && allItem.m_stack > 0 && TroughFoodRules.IsFood(allItem)) { active = true; break; } } } if (Object.op_Implicit((Object)(object)_currentServing) && _currentServing.m_itemData != null && _currentServing.m_itemData.m_stack > 0) { active = true; } _visibleFeed.SetActive(active); } private ItemData FindFood(MonsterAI ai) { if ((Object)(object)ai == (Object)null || (Object)(object)_container == (Object)null) { return null; } Inventory inventory = _container.GetInventory(); if (inventory == null) { return null; } foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem != null && allItem.m_stack > 0 && !(CanConsumeMethod == null)) { object obj = CanConsumeMethod.Invoke(ai, new object[1] { allItem }); if (obj is bool && (bool)obj) { return allItem; } } } return null; } } internal static class TroughModelV3 { internal const string RootName = "AnimalFeedingTroughModelV3"; internal const string FeedName = "VisibleFeed"; private const string WoodResource = "AnimalFeedingTroughV3.Wood"; private const string MetalResource = "AnimalFeedingTroughV3.Metal"; private const string FeedResource = "AnimalFeedingTroughV3.Feed"; private const string IconResource = "AnimalFeedingTroughV3.Icon"; private static Material _wood; private static Material _darkWood; private static Material _iron; private static Material _feed; internal static void Build(Transform parent, Shader fallbackShader) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //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) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0152: 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_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_0201: 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_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03c4: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_0413: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_0462: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Unknown result type (might be due to invalid IL or missing references) //IL_04b1: Unknown result type (might be due to invalid IL or missing references) //IL_04d9: Unknown result type (might be due to invalid IL or missing references) //IL_0500: Unknown result type (might be due to invalid IL or missing references) //IL_0519: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("AnimalFeedingTroughModelV3"); Transform transform = val.transform; transform.SetParent(parent, false); transform.localPosition = Vector3.zero; transform.localRotation = Quaternion.identity; transform.localScale = Vector3.one; Shader val2 = Shader.Find("Standard") ?? fallbackShader; if (!Object.op_Implicit((Object)(object)val2)) { throw new InvalidOperationException("No supported shader is available for the feeding trough."); } _wood = CreateMaterial("AFT V3 - aged oak", val2, "AnimalFeedingTroughV3.Wood", Color.white, 0f, 0.22f, new Vector2(2.15f, 0.135f), new Vector2(0f, 0.335f)); _darkWood = CreateMaterial("AFT V3 - carved oak", val2, "AnimalFeedingTroughV3.Wood", new Color(0.47f, 0.39f, 0.31f, 1f), 0f, 0.16f, new Vector2(2.15f, 0.135f), new Vector2(0f, 0.335f)); _iron = CreateMaterial("AFT V3 - forged iron", val2, "AnimalFeedingTroughV3.Metal", new Color(0.58f, 0.6f, 0.61f, 1f), 0.72f, 0.28f, Vector2.one, Vector2.zero); _feed = CreateMaterial("AFT V3 - straw vegetables and berries", val2, "AnimalFeedingTroughV3.Feed", Color.white, 0f, 0.12f, Vector2.one, Vector2.zero); CreateBeam(transform, "Front solid oak wall", new Vector3(0f, 0.625f, -0.505f), 4.92f, 0.55f, 0.23f, 0.045f, Quaternion.identity, _wood, 3.6f); CreateBeam(transform, "Rear solid oak wall", new Vector3(0f, 0.625f, 0.505f), 4.92f, 0.55f, 0.23f, 0.045f, Quaternion.identity, _wood, 3.6f); CreateBeam(transform, "Solid basin floor", new Vector3(0f, 0.385f, 0f), 4.72f, 0.16f, 0.79f, 0.035f, Quaternion.identity, _darkWood, 3.5f); Quaternion rotation = Quaternion.Euler(0f, 90f, 0f); CreateBeam(transform, "Closed left end", new Vector3(-2.48f, 0.62f, 0f), 1.18f, 0.58f, 0.3f, 0.05f, rotation, _wood, 0.9f); CreateBeam(transform, "Closed right end", new Vector3(2.48f, 0.62f, 0f), 1.18f, 0.58f, 0.3f, 0.05f, rotation, _wood, 0.9f); CreateBeam(transform, "Left wooden locking peg", new Vector3(-2.665f, 0.61f, 0f), 0.13f, 0.17f, 0.17f, 0.025f, Quaternion.identity, _darkWood, 0.25f); CreateBeam(transform, "Right wooden locking peg", new Vector3(2.665f, 0.61f, 0f), 0.13f, 0.17f, 0.17f, 0.025f, Quaternion.identity, _darkWood, 0.25f); float[] array = new float[3] { -2.02f, 0f, 2.02f }; foreach (float num in array) { CreateBeam(transform, "Cross support", new Vector3(num, 0.255f, 0f), 1.17f, 0.15f, 0.23f, 0.025f, rotation, _darkWood, 0.9f); CreateBeam(transform, "Front foot", new Vector3(num, 0.13f, -0.4f), 0.43f, 0.28f, 0.31f, 0.035f, Quaternion.Euler(-7f, 0f, 0f), _wood, 0.7f); CreateBeam(transform, "Rear foot", new Vector3(num, 0.13f, 0.4f), 0.43f, 0.28f, 0.31f, 0.035f, Quaternion.Euler(7f, 0f, 0f), _wood, 0.7f); CreateBeam(transform, "Front flush iron band", new Vector3(num, 0.625f, -0.626f), 0.54f, 0.105f, 0.028f, 0.012f, Quaternion.Euler(0f, 0f, 90f), _iron, 0.55f); CreateBeam(transform, "Rear flush iron band", new Vector3(num, 0.625f, 0.626f), 0.54f, 0.105f, 0.028f, 0.012f, Quaternion.Euler(0f, 0f, 90f), _iron, 0.55f); CreateBeam(transform, "Top flush iron band", new Vector3(num, 0.905f, 0f), 1.15f, 0.055f, 0.105f, 0.012f, rotation, _iron, 0.9f); } AddCarvedRunes(transform, -0.626f, reverse: false); AddCarvedRunes(transform, 0.626f, reverse: true); GameObject val3 = CreateFeedSurface(transform); val3.SetActive(false); } private static void AddCarvedRunes(Transform root, float z, bool reverse) { //IL_003b: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) float[] array = new float[6] { -1.54f, -1.12f, -0.7f, 0.7f, 1.12f, 1.54f }; foreach (float num in array) { float num2 = (reverse ? (-1f) : 1f); CreateBeam(root, "Shallow carved rune", new Vector3(num, 0.61f, z), 0.26f, 0.042f, 0.016f, 0.006f, Quaternion.Euler(0f, 0f, 38f * num2), _darkWood, 0.25f); CreateBeam(root, "Shallow carved rune", new Vector3(num, 0.61f, z), 0.26f, 0.042f, 0.016f, 0.006f, Quaternion.Euler(0f, 0f, -38f * num2), _darkWood, 0.25f); } } private static GameObject CreateFeedSurface(Transform root) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Expected O, but got Unknown GameObject val = new GameObject("VisibleFeed"); val.transform.SetParent(root, false); int num = 49; List<Vector3> list = new List<Vector3>(539); List<Vector3> list2 = new List<Vector3>(539); List<Vector2> list3 = new List<Vector2>(539); List<int> list4 = new List<int>(2880); for (int i = 0; i <= 10; i++) { float num2 = (float)i / 10f; for (int j = 0; j <= 48; j++) { float num3 = (float)j / 48f; float num4 = Mathf.Sin(num3 * (float)Math.PI) * Mathf.Sin(num2 * (float)Math.PI); float num5 = 0.012f * num4 * (Mathf.Sin((float)j * 1.31f + (float)i * 0.73f) + Mathf.Sin((float)j * 0.43f - (float)i * 1.19f)); list.Add(new Vector3((num3 - 0.5f) * 4.53f, 0.76f + 0.1f * num4 + num5, (num2 - 0.5f) * 0.69f)); list2.Add(Vector3.up); list3.Add(new Vector2(num3 * 6.55f, num2)); } } for (int k = 0; k < 10; k++) { for (int l = 0; l < 48; l++) { int num6 = k * num + l; int num7 = num6 + num; list4.Add(num6); list4.Add(num7); list4.Add(num6 + 1); list4.Add(num6 + 1); list4.Add(num7); list4.Add(num7 + 1); } } Mesh val2 = new Mesh(); ((Object)val2).name = "AFT V3 continuous feed surface"; Mesh val3 = val2; val3.SetVertices(list); val3.SetNormals(list2); val3.SetUVs(0, list3); val3.SetTriangles(list4, 0); val3.RecalculateNormals(); val3.RecalculateBounds(); val.AddComponent<MeshFilter>().sharedMesh = val3; ((Renderer)val.AddComponent<MeshRenderer>()).sharedMaterial = _feed; return val; } private static GameObject CreateBeam(Transform parent, string name, Vector3 position, float length, float height, float depth, float bevel, Quaternion rotation, Material material, float uvLength) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_001a: 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) GameObject val = new GameObject(name); val.transform.SetParent(parent, false); val.transform.localPosition = position; val.transform.localRotation = rotation; val.AddComponent<MeshFilter>().sharedMesh = BuildBevelledBeamMesh(name + " mesh", length, height, depth, bevel, uvLength); ((Renderer)val.AddComponent<MeshRenderer>()).sharedMaterial = material; return val; } private static Mesh BuildBevelledBeamMesh(string name, float length, float height, float depth, float bevel, float uvLength) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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_0147: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: 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_020f: 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_028a: Expected O, but got Unknown float num = length * 0.5f; float num2 = height * 0.5f; float num3 = depth * 0.5f; bevel = Mathf.Min(bevel, Mathf.Min(num2, num3) * 0.7f); Vector2[] array = (Vector2[])(object)new Vector2[8] { new Vector2(0f - num2 + bevel, 0f - num3), new Vector2(num2 - bevel, 0f - num3), new Vector2(num2, 0f - num3 + bevel), new Vector2(num2, num3 - bevel), new Vector2(num2 - bevel, num3), new Vector2(0f - num2 + bevel, num3), new Vector2(0f - num2, num3 - bevel), new Vector2(0f - num2, 0f - num3 + bevel) }; List<Vector3> list = new List<Vector3>(); List<Vector2> list2 = new List<Vector2>(); List<int> list3 = new List<int>(); for (int i = 0; i < array.Length; i++) { int num4 = (i + 1) % array.Length; int count = list.Count; list.Add(new Vector3(0f - num, array[i].x, array[i].y)); list.Add(new Vector3(num, array[i].x, array[i].y)); list.Add(new Vector3(num, array[num4].x, array[num4].y)); list.Add(new Vector3(0f - num, array[num4].x, array[num4].y)); list2.Add(new Vector2(0f, 0f)); list2.Add(new Vector2(uvLength, 0f)); list2.Add(new Vector2(uvLength, 1f)); list2.Add(new Vector2(0f, 1f)); list3.AddRange(new int[6] { count, count + 1, count + 2, count, count + 2, count + 3 }); } AddCap(list, list2, list3, array, 0f - num, positive: false); AddCap(list, list2, list3, array, num, positive: true); Mesh val = new Mesh(); ((Object)val).name = name; Mesh val2 = val; val2.SetVertices(list); val2.SetUVs(0, list2); val2.SetTriangles(list3, 0); val2.RecalculateNormals(); val2.RecalculateBounds(); return val2; } private static void AddCap(List<Vector3> vertices, List<Vector2> uv, List<int> triangles, Vector2[] profile, float x, bool positive) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) int count = vertices.Count; vertices.Add(new Vector3(x, 0f, 0f)); uv.Add(new Vector2(0.5f, 0.5f)); for (int i = 0; i < profile.Length; i++) { vertices.Add(new Vector3(x, profile[i].x, profile[i].y)); uv.Add(new Vector2(0.5f + profile[i].y, 0.5f + profile[i].x)); } for (int j = 0; j < profile.Length; j++) { int num = count + 1 + j; int num2 = count + 1 + (j + 1) % profile.Length; if (positive) { triangles.AddRange(new int[3] { count, num, num2 }); } else { triangles.AddRange(new int[3] { count, num2, num }); } } } private static Material CreateMaterial(string name, Shader shader, string resource, Color tint, float metallic, float smoothness, Vector2 scale, Vector2 offset) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) Texture2D val = LoadTexture(resource, name + " albedo"); ((Texture)val).wrapMode = (TextureWrapMode)0; ((Texture)val).filterMode = (FilterMode)2; ((Texture)val).anisoLevel = 4; Material val2 = new Material(shader); ((Object)val2).name = name; val2.color = tint; val2.enableInstancing = true; Material val3 = val2; string[] array = new string[8] { "_BumpMap", "_MetallicGlossMap", "_SpecGlossMap", "_EmissionMap", "_OcclusionMap", "_DetailAlbedoMap", "_DetailNormalMap", "_ParallaxMap" }; foreach (string text in array) { if (val3.HasProperty(text)) { val3.SetTexture(text, (Texture)null); } } val3.DisableKeyword("_NORMALMAP"); val3.DisableKeyword("_METALLICGLOSSMAP"); val3.DisableKeyword("_SPECGLOSSMAP"); val3.DisableKeyword("_EMISSION"); val3.DisableKeyword("_DETAIL_MULX2"); val3.DisableKeyword("_PARALLAXMAP"); val3.mainTexture = (Texture)(object)val; val3.mainTextureScale = scale; val3.mainTextureOffset = offset; if (val3.HasProperty("_MainTex")) { val3.SetTexture("_MainTex", (Texture)(object)val); } if (val3.HasProperty("_BaseMap")) { val3.SetTexture("_BaseMap", (Texture)(object)val); } if (val3.HasProperty("_Color")) { val3.SetColor("_Color", tint); } if (val3.HasProperty("_BaseColor")) { val3.SetColor("_BaseColor", tint); } if (val3.HasProperty("_Metallic")) { val3.SetFloat("_Metallic", metallic); } if (val3.HasProperty("_Glossiness")) { val3.SetFloat("_Glossiness", smoothness); } if (val3.HasProperty("_Smoothness")) { val3.SetFloat("_Smoothness", smoothness); } return val3; } private static Texture2D LoadTexture(string resourceName, string textureName) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true); ((Object)val).name = textureName; Texture2D val2 = val; using Stream stream = typeof(TroughModelV3).Assembly.GetManifestResourceStream(resourceName); if (stream == null) { throw new InvalidOperationException("New embedded texture is missing: " + resourceName); } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule", throwOnError: true); MethodInfo method = type.GetMethod("LoadImage", new Type[3] { typeof(Texture2D), typeof(byte[]), typeof(bool) }); if (method == null || !(bool)method.Invoke(null, new object[3] { val2, memoryStream.ToArray(), false })) { throw new InvalidOperationException("New embedded texture could not be decoded: " + resourceName); } return val2; } internal static Sprite CreateIcon() { //IL_0030: 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) Texture2D val = LoadTexture("AnimalFeedingTroughV3.Icon", "AFT V3 build icon"); ((Texture)val).wrapMode = (TextureWrapMode)1; return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), (float)((Texture)val).width); } } internal static class TroughFoodRules { internal static readonly ConditionalWeakTable<Inventory, Container> Troughs = new ConditionalWeakTable<Inventory, Container>(); private static readonly HashSet<string> Foods = new HashSet<string>(StringComparer.Ordinal); private static float _nextRefresh; private static float _nextMessage; [ThreadStatic] internal static int Loading; internal static bool IsFood(ItemData item) { if (item == null || item.m_shared == null) { return false; } if (Time.time >= _nextRefresh || Foods.Count == 0) { _nextRefresh = Time.time + 10f; Foods.Clear(); if (Object.op_Implicit((Object)(object)ZNetScene.instance)) { foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab.GetComponent<Tameable>())) { continue; } MonsterAI component = prefab.GetComponent<MonsterAI>(); if (!Object.op_Implicit((Object)(object)component) || component.m_consumeItems == null) { continue; } foreach (ItemDrop consumeItem in component.m_consumeItems) { if (Object.op_Implicit((Object)(object)consumeItem) && consumeItem.m_itemData != null && consumeItem.m_itemData.m_shared != null) { Foods.Add(consumeItem.m_itemData.m_shared.m_name); } } } } } return Foods.Contains(item.m_shared.m_name); } internal static bool Accept(Inventory inventory, ItemData item, bool notify) { if (Loading > 0 || !Troughs.TryGetValue(inventory, out var value) || !Object.op_Implicit((Object)(object)value) || IsFood(item)) { return true; } if (notify && Object.op_Implicit((Object)(object)Player.m_localPlayer) && Time.time >= _nextMessage) { _nextMessage = Time.time + 1.5f; ((Character)Player.m_localPlayer).Message((MessageType)2, LocalizationManager.Instance.TryTranslate("$xneliox_trough_food_only"), 0, (Sprite)null, false); } return false; } } [HarmonyPatch(typeof(Container), "GetInventory")] internal static class RegisterTroughInventory { private static void Postfix(Container __instance, Inventory __result) { if (__result != null && Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<TroughFeeder>()) && !TroughFoodRules.Troughs.TryGetValue(__result, out var _)) { TroughFoodRules.Troughs.Add(__result, __instance); } } } [HarmonyPatch] internal static class FilterTroughInsertion { private static IEnumerable<MethodBase> TargetMethods() { try { MethodInfo[] methods = typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo method in methods) { ParameterInfo[] args = method.GetParameters(); if ((method.Name == "AddItem" || method.Name == "CanAddItem") && method.ReturnType == typeof(bool) && args.Length > 0 && args[0].ParameterType == typeof(ItemData)) { yield return method; } } } finally { } } private static bool Prefix(Inventory __instance, ItemData __0, MethodBase __originalMethod, ref bool __result) { if (TroughFoodRules.Accept(__instance, __0, __originalMethod.Name == "AddItem")) { return true; } __result = false; return false; } } [HarmonyPatch] internal static class PreserveSavedTroughContents { private static IEnumerable<MethodBase> TargetMethods() { try { MethodInfo[] methods = typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo method in methods) { if (method.Name == "Load") { yield return method; } } } finally { } } private static void Prefix() { TroughFoodRules.Loading++; } private static Exception Finalizer(Exception __exception) { TroughFoodRules.Loading--; return __exception; } } internal static class TroughServingProtection { internal const string Marker = "xneliox_trough_serving"; private static readonly FieldInfo Instances = AccessTools.Field(typeof(ItemDrop), "s_instances"); private static readonly MethodInfo CloneShared = AccessTools.Method(typeof(object), "MemberwiseClone", (Type[])null, (Type[])null); private static readonly ConditionalWeakTable<ItemDrop, object> Protected = new ConditionalWeakTable<ItemDrop, object>(); internal static void ApplyLocalProtection(ItemDrop item) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)item)) { return; } item.m_autoPickup = false; if (!Protected.TryGetValue(item, out var _) && item.m_itemData != null && item.m_itemData.m_shared != null) { item.m_itemData.m_shared = (SharedData)CloneShared.Invoke(item.m_itemData.m_shared, null); item.m_itemData.m_shared.m_autoStack = false; Renderer[] componentsInChildren = ((Component)item).GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { val.enabled = false; } ParticleSystem[] componentsInChildren2 = ((Component)item).GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem val2 in componentsInChildren2) { val2.Stop(true, (ParticleSystemStopBehavior)0); } Light[] componentsInChildren3 = ((Component)item).GetComponentsInChildren<Light>(true); foreach (Light val3 in componentsInChildren3) { ((Behaviour)val3).enabled = false; } Rigidbody component = ((Component)item).GetComponent<Rigidbody>(); if (Object.op_Implicit((Object)(object)component)) { component.linearVelocity = Vector3.zero; component.angularVelocity = Vector3.zero; component.useGravity = false; component.constraints = (RigidbodyConstraints)126; } Protected.Add(item, new object()); } } internal static bool IsServing(ItemDrop item) { if (!Object.op_Implicit((Object)(object)item)) { return false; } if (((Object)((Component)item).gameObject).name.StartsWith("TroughServing_")) { return true; } ZNetView component = ((Component)item).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && component.IsValid()) { return component.GetZDO().GetBool("xneliox_trough_serving", false); } return false; } internal static void DisableAttraction() { if (!(Instances.GetValue(null) is List<ItemDrop> list)) { return; } foreach (ItemDrop item in list) { if (IsServing(item)) { ApplyLocalProtection(item); } } } internal static IEnumerable<ItemDrop> GetServings() { if (!(Instances.GetValue(null) is List<ItemDrop> items)) { yield break; } foreach (ItemDrop item in items) { if (IsServing(item)) { yield return item; } } } } [HarmonyPatch(typeof(ItemDrop), "SlowUpdate")] internal static class RestoreServingProtection { private static void Prefix(ItemDrop __instance) { if (TroughServingProtection.IsServing(__instance)) { TroughServingProtection.ApplyLocalProtection(__instance); } } } [HarmonyPatch(typeof(ItemDrop), "AutoStackItems")] internal static class PreventServingStackMerge { private static bool Prefix(ItemDrop __instance) { TroughServingProtection.DisableAttraction(); return !TroughServingProtection.IsServing(__instance); } } [HarmonyPatch(typeof(Player), "AutoPickup")] internal static class NoTroughServingAttraction { private static void Prefix() { TroughServingProtection.DisableAttraction(); } } [HarmonyPatch(typeof(Humanoid), "Pickup", new Type[] { typeof(GameObject), typeof(bool), typeof(bool) })] internal static class NoPlayerServingPickup { private static bool Prefix(Humanoid __instance, GameObject __0, ref bool __result) { if (!((Character)__instance).IsPlayer() || !Object.op_Implicit((Object)(object)__0) || !TroughServingProtection.IsServing(__0.GetComponent<ItemDrop>())) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(ItemDrop), "Pickup", new Type[] { typeof(Humanoid) })] internal static class NoManualServingPickup { private static bool Prefix(ItemDrop __instance, Humanoid __0) { if (Object.op_Implicit((Object)(object)__0) && ((Character)__0).IsPlayer()) { return !TroughServingProtection.IsServing(__instance); } return true; } } [HarmonyPatch(typeof(WearNTear), "Damage", new Type[] { typeof(HitData) })] internal static class PreventTameableAnimalTroughDamage { private static bool Prefix(WearNTear __instance, HitData hit) { if (!Object.op_Implicit((Object)(object)__instance) || hit == null || !Object.op_Implicit((Object)(object)((Component)__instance).GetComponentInParent<TroughFeeder>())) { return true; } Character attacker = hit.GetAttacker(); if (Object.op_Implicit((Object)(object)attacker)) { return !Object.op_Implicit((Object)(object)((Component)attacker).GetComponent<Tameable>()); } return true; } } internal static class TroughTranslations { internal static void Register() { CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); string text = "English"; localization.AddTranslation(ref text, new Dictionary<string, string> { { "xneliox_trough_name", "Feeding Trough" }, { "xneliox_trough_description", "A long trough for feeding tamed and tameable animals. Only suitable animal food can be stored here." }, { "xneliox_trough_food_only", "Only food eaten by tameable animals can be placed in this trough." } }); string text2 = "German"; localization.AddTranslation(ref text2, new Dictionary<string, string> { { "xneliox_trough_name", "Futtertrog" }, { "xneliox_trough_description", "Ein langer Futtertrog für gezähmte und zähmbare Tiere. Hier kann nur geeignetes Tierfutter gelagert werden." }, { "xneliox_trough_food_only", "In diesen Trog kann nur Futter gelegt werden, das von zähmbaren Tieren gefressen wird." } }); string text3 = "Russian"; localization.AddTranslation(ref text3, new Dictionary<string, string> { { "xneliox_trough_name", "Кормушка" }, { "xneliox_trough_description", "Длинная кормушка для приручённых и приручаемых животных. Сюда можно класть только подходящий для них корм." }, { "xneliox_trough_food_only", "В эту кормушку можно класть только корм, который едят приручаемые животные." } }); string text4 = "Ukrainian"; localization.AddTranslation(ref text4, new Dictionary<string, string> { { "xneliox_trough_name", "Годівниця" }, { "xneliox_trough_description", "Довга годівниця для приручених тварин і тварин, яких можна приручити. Сюди можна класти лише придатний для них корм." }, { "xneliox_trough_food_only", "У цю годівницю можна класти лише корм, який їдять тварини, яких можна приручити." } }); string text5 = "Japanese"; localization.AddTranslation(ref text5, new Dictionary<string, string> { { "xneliox_trough_name", "飼い葉桶" }, { "xneliox_trough_description", "飼いならした動物や、これから飼いならす動物に餌を与えるための長い飼い葉桶。飼いならせる動物が食べる餌だけを入れられます。" }, { "xneliox_trough_food_only", "この桶には、飼いならせる動物が食べる餌だけを入れられます。" } }); } }