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 FreyjasFeeder v1.0.0
FreyjasFeeder.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; [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("FreyjasFeeder")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+901b84ab23f2f10926b13865f9b40bb283490874")] [assembly: AssemblyProduct("FreyjasFeeder")] [assembly: AssemblyTitle("FreyjasFeeder")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace FreyjasFeeder { public static class FeederSettings { public static ConfigEntry<bool> Enabled { get; private set; } public static ConfigEntry<float> FeedRange { get; private set; } public static ConfigEntry<float> FeedInterval { get; private set; } public static ConfigEntry<int> MaxFeedsPerCycle { get; private set; } public static ConfigEntry<bool> FeedTamed { get; private set; } public static ConfigEntry<bool> HealInjuredPets { get; private set; } public static ConfigEntry<float> HealAmount { get; private set; } public static ConfigEntry<float> HealCooldown { get; private set; } public static ConfigEntry<bool> PreventOvercrowding { get; private set; } public static ConfigEntry<int> MaxCreaturesLimit { get; private set; } public static ConfigEntry<bool> FeedUntamed { get; private set; } public static ConfigEntry<bool> FeedUntamedWhenAlerted { get; private set; } public static ConfigEntry<bool> PreventNightDespawn { get; private set; } public static ConfigEntry<float> TamingSpeedMultiplier { get; private set; } public static ConfigEntry<int> ContainerWidth { get; private set; } public static ConfigEntry<int> ContainerHeight { get; private set; } public static ConfigEntry<bool> PullFromNearbyChests { get; private set; } public static ConfigEntry<bool> EnableAnyChestFeeding { get; private set; } public static ConfigEntry<int> WoodCost { get; private set; } public static ConfigEntry<int> FineWoodCost { get; private set; } public static ConfigEntry<int> BronzeCost { get; private set; } public static ConfigEntry<int> DandelionCost { get; private set; } public static ConfigEntry<string> ModelFile { get; private set; } public static ConfigEntry<float> ModelScale { get; private set; } public static ConfigEntry<float> ModelRotationY { get; private set; } public static ConfigEntry<float> ModelOffsetX { get; private set; } public static ConfigEntry<float> ModelOffsetY { get; private set; } public static ConfigEntry<float> ModelOffsetZ { get; private set; } public static void Bind(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Expected O, but got Unknown //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Expected O, but got Unknown //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Expected O, but got Unknown //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Expected O, but got Unknown //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Expected O, but got Unknown //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Expected O, but got Unknown //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Expected O, but got Unknown //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Expected O, but got Unknown //IL_03bb: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Expected O, but got Unknown //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_03fd: Expected O, but got Unknown Enabled = config.Bind<bool>("1 - General", "Enabled", true, "Master toggle for Freyja's Feeder mod."); FeedRange = config.Bind<float>("1 - General", "FeedRange", 15f, new ConfigDescription("Radius in meters around the feeder to detect hungry animals.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 50f), Array.Empty<object>())); FeedInterval = config.Bind<float>("1 - General", "FeedInterval", 5f, new ConfigDescription("How often (in seconds) the feeder scans for hungry animals.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>())); MaxFeedsPerCycle = config.Bind<int>("1 - General", "MaxFeedsPerCycle", 4, new ConfigDescription("Maximum number of animals fed in a single scan cycle.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>())); FeedTamed = config.Bind<bool>("2 - Tamed Pets", "FeedTamed", true, "Automatically feed nearby tamed pets when hungry, keeping them happy and ready for breeding."); HealInjuredPets = config.Bind<bool>("2 - Tamed Pets", "HealInjuredPets", true, "Feed injured tamed pets to restore their health, even if they are not yet fully hungry."); HealAmount = config.Bind<float>("2 - Tamed Pets", "HealAmount", 25f, new ConfigDescription("Health points restored to an injured pet upon eating.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 200f), Array.Empty<object>())); HealCooldown = config.Bind<float>("2 - Tamed Pets", "HealCooldown", 20f, new ConfigDescription("Minimum seconds between healing feeds for the same pet to prevent rapid food waste.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 300f), Array.Empty<object>())); PreventOvercrowding = config.Bind<bool>("2 - Tamed Pets", "PreventOvercrowding", false, "If true, stops feeding tamed animals when the nearby population of that species reaches MaxCreaturesLimit."); MaxCreaturesLimit = config.Bind<int>("2 - Tamed Pets", "MaxCreaturesLimit", 10, new ConfigDescription("Population limit for PreventOvercrowding check.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 50), Array.Empty<object>())); FeedUntamed = config.Bind<bool>("3 - Taming Untamed", "FeedUntamed", true, "Automatically feed untamed wild beasts (boars, wolves, lox, asksvin) to tame them."); FeedUntamedWhenAlerted = config.Bind<bool>("3 - Taming Untamed", "FeedUntamedWhenAlerted", false, "If true, feeds untamed beasts even while alerted/frightened. If false, respects vanilla behavior where animals must calm down first."); PreventNightDespawn = config.Bind<bool>("3 - Taming Untamed", "PreventNightDespawn", true, "Prevent night-spawned creatures (e.g. 2-star wolves) from despawning during the day once they have eaten from the feeder."); TamingSpeedMultiplier = config.Bind<float>("3 - Taming Untamed", "TamingSpeedMultiplier", 1f, new ConfigDescription("Multiplier for taming progression speed while within range of Freyja's Feeder (1.0 = vanilla).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>())); ContainerWidth = config.Bind<int>("4 - Storage", "ContainerWidth", 6, new ConfigDescription("Number of inventory slot columns for Freyja's Feeder (default 6).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 8), Array.Empty<object>())); ContainerHeight = config.Bind<int>("4 - Storage", "ContainerHeight", 4, new ConfigDescription("Number of inventory slot rows for Freyja's Feeder (default 4 = 24 slots).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 4), Array.Empty<object>())); PullFromNearbyChests = config.Bind<bool>("4 - Storage", "PullFromNearbyChests", false, "If true, Freyja's Feeder will also search nearby standard chests (within FeedRange) for matching food if its own inventory runs out."); EnableAnyChestFeeding = config.Bind<bool>("4 - Storage", "EnableAnyChestFeeding", false, "If true, any standard chest in the world will also feed nearby hungry animals within FeedRange."); WoodCost = config.Bind<int>("5 - Crafting", "WoodCost", 10, new ConfigDescription("Wood cost to build Freyja's Feeder.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); FineWoodCost = config.Bind<int>("5 - Crafting", "FineWoodCost", 5, new ConfigDescription("Fine Wood cost to build Freyja's Feeder.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); BronzeCost = config.Bind<int>("5 - Crafting", "BronzeCost", 2, new ConfigDescription("Bronze cost to build Freyja's Feeder.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), Array.Empty<object>())); DandelionCost = config.Bind<int>("5 - Crafting", "DandelionCost", 2, new ConfigDescription("Dandelion offering cost to build Freyja's Feeder.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 50), Array.Empty<object>())); ModelFile = config.Bind<string>("6 - Visuals", "ModelFile", "FreyjasFeeder.obj", "Filename of custom 3D model for Freyja's Feeder. Set to 'none' to use vanilla chest visuals."); ModelScale = config.Bind<float>("6 - Visuals", "ModelScale", 1f, new ConfigDescription("Uniform scale of custom 3D model.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>())); ModelRotationY = config.Bind<float>("6 - Visuals", "ModelRotationY", 0f, new ConfigDescription("Y rotation offset in degrees.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-180f, 180f), Array.Empty<object>())); ModelOffsetX = config.Bind<float>("6 - Visuals", "ModelOffsetX", 0f, "X position offset in meters."); ModelOffsetY = config.Bind<float>("6 - Visuals", "ModelOffsetY", 0f, "Y position offset in meters."); ModelOffsetZ = config.Bind<float>("6 - Visuals", "ModelOffsetZ", 0f, "Z position offset in meters."); } } [HarmonyPatch(typeof(Container), "Awake")] internal static class ContainerAwakePatch { private static void Postfix(Container __instance) { if ((Object)(object)__instance != (Object)null) { ContainerTracker.Register(__instance); } } } [HarmonyPatch(typeof(Container), "OnDestroyed")] internal static class ContainerOnDestroyedPatch { private static void Prefix(Container __instance) { if ((Object)(object)__instance != (Object)null) { ContainerTracker.Unregister(__instance); } } } [HarmonyPatch(typeof(Container), "GetHoverText")] internal static class ContainerHoverTextPatch { private static void Postfix(Container __instance, ref string __result) { if ((Object)(object)__instance == (Object)null || !FeederSettings.Enabled.Value) { return; } FeederController component = ((Component)__instance).GetComponent<FeederController>(); if (!((Object)(object)component == (Object)null)) { string statusSummary = component.GetStatusSummary(); if (!string.IsNullOrEmpty(statusSummary)) { __result = __result + "\n" + statusSummary; } } } } internal static class ContainerTracker { private static readonly HashSet<Container> s_containers = new HashSet<Container>(); public static IEnumerable<Container> Containers => s_containers; public static void Register(Container container) { if ((Object)(object)container != (Object)null && !s_containers.Contains(container)) { s_containers.Add(container); } } public static void Unregister(Container container) { if ((Object)(object)container != (Object)null) { s_containers.Remove(container); } } public static void Clear() { s_containers.Clear(); } } public sealed class FeederController : MonoBehaviour { public static readonly List<FeederController> AllFeeders = new List<FeederController>(); private static readonly List<Character> s_charBuffer = new List<Character>(); private static readonly Dictionary<int, float> s_healCooldowns = new Dictionary<int, float>(); private static MethodInfo s_tameMethod; private static float s_globalChestScanTimer; private Container m_container; private ZNetView m_nview; private float m_timer; public Container Container { get { if ((Object)(object)m_container == (Object)null) { m_container = ((Component)this).GetComponent<Container>(); } return m_container; } } private void Awake() { m_container = ((Component)this).GetComponent<Container>(); m_nview = ((Component)this).GetComponent<ZNetView>(); FeederModel.EnsureVisuals(((Component)this).gameObject); m_timer = Random.Range(0.5f, 2f); } private void OnEnable() { if (!AllFeeders.Contains(this)) { AllFeeders.Add(this); } } private void OnDisable() { AllFeeders.Remove(this); } private void OnDestroy() { AllFeeders.Remove(this); } private void Update() { if (!FeederSettings.Enabled.Value) { return; } m_timer -= Time.deltaTime; if (!(m_timer > 0f)) { m_timer = FeederSettings.FeedInterval.Value; if ((Object)(object)m_nview != (Object)null && m_nview.IsValid() && m_nview.IsOwner()) { PerformFeedScan(); } } } internal static void UpdateGlobalChests() { if (!FeederSettings.Enabled.Value || !FeederSettings.EnableAnyChestFeeding.Value) { return; } s_globalChestScanTimer -= Time.deltaTime; if (s_globalChestScanTimer > 0f) { return; } s_globalChestScanTimer = FeederSettings.FeedInterval.Value; foreach (Container container in ContainerTracker.Containers) { if (!((Object)(object)container == (Object)null) && !((Object)(object)((Component)container).GetComponent<FeederController>() != (Object)null)) { ZNetView component = ((Component)container).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner()) { ScanAndFeedFromContainer(container); } } } } private void PerformFeedScan() { //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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_container == (Object)null) { return; } Inventory inventory = m_container.GetInventory(); if (inventory == null) { return; } Vector3 position = ((Component)this).transform.position; float value = FeederSettings.FeedRange.Value; s_charBuffer.Clear(); Character.GetCharactersInRange(position, value, s_charBuffer); if (s_charBuffer.Count == 0) { return; } int num = FeederSettings.MaxFeedsPerCycle.Value; for (int i = 0; i < s_charBuffer.Count; i++) { if (num <= 0) { break; } Character val = s_charBuffer[i]; if ((Object)(object)val == (Object)null || val.IsDead()) { continue; } Tameable component = ((Component)val).GetComponent<Tameable>(); if ((Object)(object)component == (Object)null) { continue; } MonsterAI component2 = ((Component)val).GetComponent<MonsterAI>(); if ((Object)(object)component2 == (Object)null || component2.m_consumeItems == null || component2.m_consumeItems.Count == 0) { continue; } if (component.IsTamed()) { if (FeederSettings.FeedTamed.Value) { bool num2 = component.IsHungry(); bool flag = val.GetHealth() < val.GetMaxHealth() && FeederSettings.HealInjuredPets.Value && CanHealCreature(val); if ((num2 || flag) && (!FeederSettings.PreventOvercrowding.Value || !IsOvercrowded(val, position, value)) && TryFeedCreature(val, component, component2, inventory, isTamed: true, flag)) { num--; } } } else if (FeederSettings.FeedUntamed.Value && component.IsHungry() && (!((BaseAI)component2).IsAlerted() || FeederSettings.FeedUntamedWhenAlerted.Value) && TryFeedCreature(val, component, component2, inventory, isTamed: false, isHealing: false)) { num--; } } } private static void ScanAndFeedFromContainer(Container container) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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) Inventory inventory = container.GetInventory(); if (inventory == null) { return; } Vector3 position = ((Component)container).transform.position; float value = FeederSettings.FeedRange.Value; s_charBuffer.Clear(); Character.GetCharactersInRange(position, value, s_charBuffer); if (s_charBuffer.Count == 0) { return; } int num = FeederSettings.MaxFeedsPerCycle.Value; for (int i = 0; i < s_charBuffer.Count; i++) { if (num <= 0) { break; } Character val = s_charBuffer[i]; if ((Object)(object)val == (Object)null || val.IsDead()) { continue; } Tameable component = ((Component)val).GetComponent<Tameable>(); if ((Object)(object)component == (Object)null) { continue; } MonsterAI component2 = ((Component)val).GetComponent<MonsterAI>(); if ((Object)(object)component2 == (Object)null || component2.m_consumeItems == null || component2.m_consumeItems.Count == 0) { continue; } if (component.IsTamed()) { if (FeederSettings.FeedTamed.Value) { bool num2 = component.IsHungry(); bool flag = val.GetHealth() < val.GetMaxHealth() && FeederSettings.HealInjuredPets.Value && CanHealCreature(val); if ((num2 || flag) && (!FeederSettings.PreventOvercrowding.Value || !IsOvercrowded(val, position, value)) && ExecuteFeed(val, component, component2, inventory, isTamed: true, flag)) { num--; } } } else if (FeederSettings.FeedUntamed.Value && component.IsHungry() && (!((BaseAI)component2).IsAlerted() || FeederSettings.FeedUntamedWhenAlerted.Value) && ExecuteFeed(val, component, component2, inventory, isTamed: false, isHealing: false)) { num--; } } } private bool TryFeedCreature(Character ch, Tameable tameable, MonsterAI ai, Inventory feederInv, bool isTamed, bool isHealing) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) ItemData val = FindMatchingFood(ai, feederInv); Inventory foundInv = feederInv; if (val == null && FeederSettings.PullFromNearbyChests.Value) { val = FindMatchingFoodInNearbyChests(ai, ((Component)this).transform.position, FeederSettings.FeedRange.Value, out foundInv); } if (val == null || foundInv == null) { return false; } return ApplyFeed(ch, tameable, ai, foundInv, val, isTamed, isHealing); } private static bool ExecuteFeed(Character ch, Tameable tameable, MonsterAI ai, Inventory inv, bool isTamed, bool isHealing) { ItemData val = FindMatchingFood(ai, inv); if (val == null) { return false; } return ApplyFeed(ch, tameable, ai, inv, val, isTamed, isHealing); } private static bool ApplyFeed(Character ch, Tameable tameable, MonsterAI ai, Inventory sourceInv, ItemData foodItem, bool isTamed, bool isHealing) { //IL_0060: 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_0073: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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_00be: Unknown result type (might be due to invalid IL or missing references) sourceInv.RemoveOneItem(foodItem); ZNetView component = ((Component)ch).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { if (!component.IsOwner()) { component.ClaimOwnership(); } component.GetZDO().Set(ZDOVars.s_tameLastFeeding, ZNet.instance.GetTime().Ticks); } if (tameable.m_sootheEffect != null) { tameable.m_sootheEffect.Create(ch.GetCenterPoint(), Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } Humanoid val = (Humanoid)(object)((ch is Humanoid) ? ch : null); if ((Object)(object)val != (Object)null && val.m_consumeItemEffects != null) { val.m_consumeItemEffects.Create(((Component)ch).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } ZSyncAnimation zAnim = ch.GetZAnim(); if ((Object)(object)zAnim != (Object)null) { zAnim.SetTrigger("consume"); } if (isTamed) { if (isHealing) { float maxHealth = ch.GetMaxHealth(); float health = ch.GetHealth(); float num = Mathf.Min(FeederSettings.HealAmount.Value, maxHealth - health); if (num > 0f) { ch.Heal(num, true); s_healCooldowns[((Object)ch).GetInstanceID()] = Time.time; } } } else { if (FeederSettings.PreventNightDespawn.Value) { ai.SetDespawnInDay(false); ai.SetEventCreature(false); } float value = FeederSettings.TamingSpeedMultiplier.Value; if (value > 1f && (Object)(object)component != (Object)null && component.IsValid()) { float num2 = 3f * (value - 1f); float num3 = component.GetZDO().GetFloat(ZDOVars.s_tameTimeLeft, tameable.m_tamingTime); num3 = Mathf.Max(0f, num3 - num2); component.GetZDO().Set(ZDOVars.s_tameTimeLeft, num3); if (num3 <= 0f) { if (s_tameMethod == null) { s_tameMethod = typeof(Tameable).GetMethod("Tame", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } s_tameMethod?.Invoke(tameable, null); } } } FreyjasFeederPlugin.Log.LogInfo((object)("Freyja's Feeder: fed " + ch.m_name + " (Tamed=" + isTamed + ", Heal=" + isHealing + ") with " + foodItem.m_shared.m_name)); return true; } private static ItemData FindMatchingFood(MonsterAI ai, Inventory inv) { if ((Object)(object)ai == (Object)null || inv == null) { return null; } List<ItemData> allItems = inv.GetAllItems(); for (int i = 0; i < allItems.Count; i++) { ItemData val = allItems[i]; if (val != null && val.m_shared != null && IsFoodForAI(ai, val)) { return val; } } return null; } private static ItemData FindMatchingFoodInNearbyChests(MonsterAI ai, Vector3 center, float range, out Inventory foundInv) { //IL_0038: 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_0043: Unknown result type (might be due to invalid IL or missing references) foundInv = null; float num = range * range; foreach (Container container in ContainerTracker.Containers) { if ((Object)(object)container == (Object)null || (Object)(object)((Component)container).GetComponent<FeederController>() != (Object)null) { continue; } Vector3 val = ((Component)container).transform.position - center; if (((Vector3)(ref val)).sqrMagnitude > num) { continue; } Inventory inventory = container.GetInventory(); if (inventory != null) { ItemData val2 = FindMatchingFood(ai, inventory); if (val2 != null) { foundInv = inventory; return val2; } } } return null; } public static bool IsFoodForAI(MonsterAI ai, ItemData item) { if ((Object)(object)ai == (Object)null || item == null || item.m_shared == null) { return false; } if (ai.m_consumeItems != null) { for (int i = 0; i < ai.m_consumeItems.Count; i++) { ItemDrop val = ai.m_consumeItems[i]; if ((Object)(object)val != (Object)null && val.m_itemData != null && val.m_itemData.m_shared != null && string.Equals(val.m_itemData.m_shared.m_name, item.m_shared.m_name, StringComparison.OrdinalIgnoreCase)) { return true; } } } return false; } private static bool CanHealCreature(Character ch) { if ((Object)(object)ch == (Object)null) { return false; } int instanceID = ((Object)ch).GetInstanceID(); if (s_healCooldowns.TryGetValue(instanceID, out var value) && Time.time - value < FeederSettings.HealCooldown.Value) { return false; } return true; } private static bool IsOvercrowded(Character ch, Vector3 center, float range) { string value = ((Object)((Component)ch).gameObject).name.Replace("(Clone)", "").Trim(); int num = 0; for (int i = 0; i < s_charBuffer.Count; i++) { Character val = s_charBuffer[i]; if (!((Object)(object)val == (Object)null) && !val.IsDead() && ((Object)((Component)val).gameObject).name.StartsWith(value, StringComparison.OrdinalIgnoreCase)) { num++; } } return num >= FeederSettings.MaxCreaturesLimit.Value; } public string GetStatusSummary() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) int num = 0; if ((Object)(object)m_container != (Object)null) { Inventory inventory = m_container.GetInventory(); if (inventory != null) { List<ItemData> allItems = inventory.GetAllItems(); for (int i = 0; i < allItems.Count; i++) { num += allItems[i].m_stack; } } } Vector3 position = ((Component)this).transform.position; float value = FeederSettings.FeedRange.Value; s_charBuffer.Clear(); Character.GetCharactersInRange(position, value, s_charBuffer); int num2 = 0; int num3 = 0; int num4 = 0; for (int j = 0; j < s_charBuffer.Count; j++) { Character val = s_charBuffer[j]; if ((Object)(object)val == (Object)null || val.IsDead()) { continue; } Tameable component = ((Component)val).GetComponent<Tameable>(); if ((Object)(object)component == (Object)null) { continue; } if (component.IsTamed()) { num2++; if (component.IsHungry() || (FeederSettings.HealInjuredPets.Value && val.GetHealth() < val.GetMaxHealth())) { num4++; } } else { num3++; if (component.IsHungry()) { num4++; } } } return $"<color=#fde047>Freyja's Grace:</color> <color=#a3e635>Feeding Active ({value:0}m radius)</color>\n" + $"<color=#e2e8f0>Food in trough: {num} items</color> | " + $"<color=#94a3b8>Nearby: {num2} pets, {num3} wild ({num4} hungry)</color>"; } } internal static class FeederModel { internal static GameObject ModelRootTemplate; private static bool s_shaderRefreshed; internal static string FindModelPath() { string text = FeederSettings.ModelFile?.Value; if (string.Equals(text, "none", StringComparison.OrdinalIgnoreCase)) { return null; } if (string.IsNullOrEmpty(text)) { text = "FreyjasFeeder.obj"; } string[] array = new string[5] { FreyjasFeederPlugin.PluginDirectory ?? "", Path.Combine(FreyjasFeederPlugin.PluginDirectory ?? "", "models"), Path.Combine(Paths.PluginPath ?? "", "FreyjasFeeder"), Path.Combine(Paths.PluginPath ?? "", "FreyjasFeeder", "models"), "C:\\Users\\dhugh\\Documents\\MyMods\\FreyjasFeeder" }; string[] array2 = new string[4] { text, Path.GetFileNameWithoutExtension(text) + ".obj", "FreyjasFeeder.obj", "freyjasfeeder.obj" }; foreach (string text2 in array) { if (string.IsNullOrEmpty(text2) || !Directory.Exists(text2)) { continue; } for (int j = 0; j < array2.Length; j++) { string text3 = Path.Combine(text2, array2[j]); if (File.Exists(text3)) { return text3; } } } return null; } internal static Shader FindModelShader(GameObject prefab) { Shader val = Shader.Find("Custom/Creature"); if ((Object)(object)val != (Object)null) { return val; } if ((Object)(object)ZNetScene.instance != (Object)null && ZNetScene.instance.m_prefabs != null) { string[] array = new string[5] { "Greydwarf", "Boar", "Deer", "Wolf", "Lox" }; for (int i = 0; i < array.Length; i++) { GameObject prefab2 = ZNetScene.instance.GetPrefab(array[i]); if (!((Object)(object)prefab2 != (Object)null)) { continue; } Renderer componentInChildren = prefab2.GetComponentInChildren<Renderer>(true); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.sharedMaterial != (Object)null && (Object)(object)componentInChildren.sharedMaterial.shader != (Object)null) { string name = ((Object)componentInChildren.sharedMaterial.shader).name; if (name.Contains("Creature") || !name.Contains("Piece")) { FreyjasFeederPlugin.Log.LogInfo((object)("Freyja's Feeder: borrowed shader '" + name + "' from " + array[i])); return componentInChildren.sharedMaterial.shader; } } } } val = Shader.Find("Standard"); if ((Object)(object)val != (Object)null) { return val; } val = Shader.Find("Unlit/Texture"); if ((Object)(object)val != (Object)null) { return val; } Renderer val2 = (((Object)(object)prefab != (Object)null) ? prefab.GetComponentInChildren<Renderer>(true) : null); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sharedMaterial != (Object)null && (Object)(object)val2.sharedMaterial.shader != (Object)null) { return val2.sharedMaterial.shader; } return Shader.Find("Hidden/InternalErrorShader"); } internal static Sprite LoadPieceIcon() { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) string[] array = new string[4] { FreyjasFeederPlugin.PluginDirectory ?? "", Path.Combine(FreyjasFeederPlugin.PluginDirectory ?? "", "models"), Path.Combine(Paths.PluginPath ?? "", "FreyjasFeeder"), "C:\\Users\\dhugh\\Documents\\MyMods\\FreyjasFeeder" }; string[] array2 = new string[6] { "FreyjasFeeder_icon.jpg", "FreyjasFeeder_icon.png", "freyjasfeeder_icon.jpg", "freyjasfeeder_icon.png", "FreyjasFeeder.jpg", "FreyjasFeeder.png" }; foreach (string text in array) { if (string.IsNullOrEmpty(text) || !Directory.Exists(text)) { continue; } for (int j = 0; j < array2.Length; j++) { string text2 = Path.Combine(text, array2[j]); if (!File.Exists(text2)) { continue; } try { byte[] array3 = File.ReadAllBytes(text2); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (ImageConversion.LoadImage(val, array3)) { FreyjasFeederPlugin.Log.LogInfo((object)("Freyja's Feeder: loaded piece icon from " + text2)); return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); } } catch (Exception ex) { FreyjasFeederPlugin.Log.LogWarning((object)("Freyja's Feeder: failed to load icon from " + text2 + ": " + ex.Message)); } } } return null; } internal static void ApplyToPrefab(GameObject prefab) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)prefab == (Object)null) { return; } string text = FindModelPath(); if (string.IsNullOrEmpty(text) || !File.Exists(text)) { FreyjasFeederPlugin.Log.LogInfo((object)"Freyja's Feeder: no custom model file found. Retaining base chest visuals."); return; } Shader shader = FindModelShader(prefab); GameObject val = ObjLoader.Load(text, shader); if ((Object)(object)val == (Object)null) { FreyjasFeederPlugin.Log.LogWarning((object)("Freyja's Feeder: failed to load model from " + text + ". Retaining base chest visuals.")); return; } StripOriginalVisualsAndColliders(prefab); prefab.transform.localScale = Vector3.one; ((Object)val).name = "FeederModel"; val.transform.SetParent(prefab.transform, false); ApplyTransform(val.transform); SetLayerRecursive(val, prefab.layer); BoxCollider componentInChildren = val.GetComponentInChildren<BoxCollider>(true); if ((Object)(object)componentInChildren != (Object)null) { ((Collider)componentInChildren).enabled = true; } ClearWearNTearVisuals(prefab); ClearContainerVisuals(prefab); ModelRootTemplate = val; FreyjasFeederPlugin.Log.LogInfo((object)("Freyja's Feeder: applied custom model " + Path.GetFileName(text) + " to prefab.")); } internal static void EnsureVisuals(GameObject instance) { if (!((Object)(object)instance == (Object)null) && !((Object)(object)ModelRootTemplate == (Object)null) && !((Object)(object)instance.transform.Find("FeederModel") != (Object)null)) { StripOriginalVisualsAndColliders(instance); GameObject obj = Object.Instantiate<GameObject>(ModelRootTemplate); ((Object)obj).name = "FeederModel"; obj.transform.SetParent(instance.transform, false); ApplyTransform(obj.transform); SetLayerRecursive(obj, instance.layer); BoxCollider componentInChildren = obj.GetComponentInChildren<BoxCollider>(true); if ((Object)(object)componentInChildren != (Object)null) { ((Collider)componentInChildren).enabled = true; } ClearWearNTearVisuals(instance); ClearContainerVisuals(instance); } } internal static void TryUpgradeShader(GameObject prefab) { if (s_shaderRefreshed || (Object)(object)ModelRootTemplate == (Object)null) { return; } MeshRenderer componentInChildren = ModelRootTemplate.GetComponentInChildren<MeshRenderer>(true); if ((Object)(object)componentInChildren == (Object)null || (Object)(object)((Renderer)componentInChildren).sharedMaterial == (Object)null) { return; } if ((((Object)(object)((Renderer)componentInChildren).sharedMaterial.shader != (Object)null) ? ((Object)((Renderer)componentInChildren).sharedMaterial.shader).name : "").Contains("Creature")) { s_shaderRefreshed = true; return; } Shader val = FindModelShader(prefab); if (!((Object)(object)val != (Object)null) || !((Object)val).name.Contains("Creature")) { return; } ((Renderer)componentInChildren).sharedMaterial.shader = val; s_shaderRefreshed = true; FreyjasFeederPlugin.Log.LogInfo((object)("Freyja's Feeder: upgraded model shader to " + ((Object)val).name)); FeederController[] array = Object.FindObjectsByType<FeederController>((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { Transform val2 = ((Component)array[i]).transform.Find("FeederModel"); if ((Object)(object)val2 != (Object)null) { MeshRenderer componentInChildren2 = ((Component)val2).GetComponentInChildren<MeshRenderer>(true); if ((Object)(object)componentInChildren2 != (Object)null && (Object)(object)((Renderer)componentInChildren2).sharedMaterial != (Object)null) { ((Renderer)componentInChildren2).sharedMaterial.shader = val; } } } } private static void ApplyTransform(Transform t) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp(FeederSettings.ModelScale?.Value ?? 1f, 0.1f, 5f); float num2 = FeederSettings.ModelRotationY?.Value ?? 0f; float num3 = FeederSettings.ModelOffsetX?.Value ?? 0f; float num4 = FeederSettings.ModelOffsetY?.Value ?? 0f; float num5 = FeederSettings.ModelOffsetZ?.Value ?? 0f; t.localPosition = new Vector3(num3, num4, num5); t.localRotation = Quaternion.Euler(0f, num2, 0f); t.localScale = Vector3.one * num; } private static void StripOriginalVisualsAndColliders(GameObject go) { MeshFilter[] componentsInChildren = go.GetComponentsInChildren<MeshFilter>(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (((Object)((Component)componentsInChildren[i]).gameObject).name != "Mesh" && ((Object)((Component)componentsInChildren[i]).gameObject).name != "FeederModel") { componentsInChildren[i].sharedMesh = null; } } Renderer[] componentsInChildren2 = go.GetComponentsInChildren<Renderer>(true); for (int j = 0; j < componentsInChildren2.Length; j++) { if (((Object)((Component)componentsInChildren2[j]).gameObject).name != "Mesh" && ((Object)((Component)componentsInChildren2[j]).gameObject).name != "FeederModel") { componentsInChildren2[j].enabled = false; } } Collider[] componentsInChildren3 = go.GetComponentsInChildren<Collider>(true); for (int k = 0; k < componentsInChildren3.Length; k++) { if (((Object)((Component)componentsInChildren3[k]).gameObject).name != "Mesh" && ((Object)((Component)componentsInChildren3[k]).gameObject).name != "FeederModel") { componentsInChildren3[k].enabled = false; } } } private static void ClearWearNTearVisuals(GameObject go) { WearNTear component = go.GetComponent<WearNTear>(); if ((Object)(object)component != (Object)null) { component.m_new = null; component.m_worn = null; component.m_broken = null; component.m_wet = null; component.m_snow = null; component.m_snowWorn = null; component.m_snowBroken = null; component.m_noRoofWear = true; component.m_noSupportWear = true; } } private static void ClearContainerVisuals(GameObject go) { Container component = go.GetComponent<Container>(); if ((Object)(object)component != (Object)null) { component.m_open = null; component.m_closed = null; } } private static void SetLayerRecursive(GameObject go, int layer) { if (!((Object)(object)go == (Object)null)) { go.layer = layer; for (int i = 0; i < go.transform.childCount; i++) { SetLayerRecursive(((Component)go.transform.GetChild(i)).gameObject, layer); } } } } internal static class FeederPiece { internal const string PrefabName = "DFG_FreyjasFeeder"; private const string BaseChestPrefabName = "piece_chest_wood"; private const string DisplayName = "Freyja's Feeder"; private const string Description = "Sacred trough blessed by Freyja. Automatically feeds nearby tamed pets and untamed beasts from its stores."; private static bool s_prefabRegistered; private static bool s_pieceManagerAdded; private static bool s_pieceTableRegistered; private static bool s_pieceRegistered; private static bool s_registrationWarningLogged; private static float s_registrationTimer; private static readonly Dictionary<string, ItemDrop> s_cachedRequirementItems = new Dictionary<string, ItemDrop>(); private static MethodInfo s_addKnownPieceMethod; private static MethodInfo s_updateAvailablePiecesListMethod; internal static void Initialize() { PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable; } internal static void Shutdown() { PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable; s_cachedRequirementItems.Clear(); s_prefabRegistered = false; s_pieceManagerAdded = false; s_pieceTableRegistered = false; s_pieceRegistered = false; s_registrationWarningLogged = false; s_registrationTimer = 0f; FeederController.AllFeeders.Clear(); ContainerTracker.Clear(); } internal static void Update() { if (FeederSettings.Enabled.Value) { TryRegisterContent(); EnsureLocalPlayerKnownPiece(); FeederController.UpdateGlobalChests(); } } private static void OnVanillaPrefabsAvailable() { s_registrationTimer = 0f; TryRegisterPrefab(); } private static void ConfigureContainer(GameObject prefab) { Container val = prefab.GetComponent<Container>(); if ((Object)(object)val == (Object)null) { val = prefab.AddComponent<Container>(); } val.m_name = "Freyja's Feeder"; val.m_width = FeederSettings.ContainerWidth.Value; val.m_height = FeederSettings.ContainerHeight.Value; val.m_checkGuardStone = true; val.m_autoDestroyEmpty = false; val.m_defaultItems = null; } private static void TryRegisterPrefab() { if (!FeederSettings.Enabled.Value || s_prefabRegistered) { return; } try { GameObject prefab = PrefabManager.Instance.GetPrefab("piece_chest_wood"); if ((Object)(object)prefab == (Object)null && (Object)(object)ZNetScene.instance != (Object)null) { prefab = ZNetScene.instance.GetPrefab("piece_chest_wood"); } if ((Object)(object)prefab == (Object)null) { if (!s_registrationWarningLogged) { FreyjasFeederPlugin.Log.LogWarning((object)"Freyja's Feeder: could not find piece_chest_wood."); s_registrationWarningLogged = true; } return; } GameObject val = PrefabManager.Instance.CreateClonedPrefab("DFG_FreyjasFeeder", prefab); if ((Object)(object)val == (Object)null) { FreyjasFeederPlugin.Log.LogError((object)"Freyja's Feeder: failed to clone piece_chest_wood."); return; } ConfigureContainer(val); val.AddComponent<FeederController>(); FeederModel.ApplyToPrefab(val); PrefabManager.Instance.AddPrefab(val); s_prefabRegistered = true; s_registrationWarningLogged = false; FreyjasFeederPlugin.Log.LogInfo((object)"Freyja's Feeder: registered prefab DFG_FreyjasFeeder."); } catch (Exception ex) { FreyjasFeederPlugin.Log.LogError((object)("Freyja's Feeder: prefab registration failed: " + ex)); } } private static void TryRegisterContent() { //IL_009e: 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00c6: 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_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Expected I4, but got Unknown if (!FeederSettings.Enabled.Value || s_pieceRegistered) { return; } s_registrationTimer -= Time.deltaTime; if (s_registrationTimer > 0f) { return; } s_registrationTimer = 1f; TryRegisterPrefab(); ZNetScene instance = ZNetScene.instance; if (!s_prefabRegistered || (Object)(object)instance == (Object)null || instance.m_prefabs == null || instance.m_prefabs.Count == 0 || (Object)(object)ObjectDB.instance == (Object)null) { return; } GameObject prefab = PrefabManager.Instance.GetPrefab("DFG_FreyjasFeeder"); if ((Object)(object)prefab == (Object)null) { return; } try { PieceCategory val = PieceManager.Instance.AddPieceCategory("DFG"); if (!s_pieceManagerAdded) { PieceConfig val2 = new PieceConfig { Name = "Freyja's Feeder", Description = "Sacred trough blessed by Freyja. Automatically feeds nearby tamed pets and untamed beasts from its stores.", PieceTable = "Hammer", Category = "DFG", Enabled = true }; PieceManager.Instance.AddPiece(new CustomPiece(prefab, false, val2)); s_pieceManagerAdded = true; } if (!s_pieceTableRegistered) { PieceManager.Instance.RegisterPieceInPieceTable(prefab, "Hammer", "DFG"); s_pieceTableRegistered = true; } FinalizePiece(prefab, val); FeederModel.TryUpgradeShader(prefab); s_pieceRegistered = true; FreyjasFeederPlugin.Log.LogInfo((object)("Freyja's Feeder: added to live Hammer PieceTable in category 'DFG' (id=" + (int)val + ").")); RefreshPieceCategories(); EnsureLocalPlayerKnownPiece(); } catch (Exception ex) { FreyjasFeederPlugin.Log.LogError((object)("Freyja's Feeder: piece registration failed: " + ex)); } } private static void FinalizePiece(GameObject prefab, PieceCategory categoryId) { //IL_0028: 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_0037: Unknown result type (might be due to invalid IL or missing references) Piece component = prefab.GetComponent<Piece>(); if (!((Object)(object)component == (Object)null)) { component.m_name = "Freyja's Feeder"; component.m_description = "Sacred trough blessed by Freyja. Automatically feeds nearby tamed pets and untamed beasts from its stores."; component.m_category = categoryId; component.m_craftingStation = null; component.m_usage = (UsageTagFlags)0; component.m_groundPiece = true; component.m_clipGround = true; component.m_canBeRemoved = true; component.m_resources = BuildRequirements(); Sprite val = FeederModel.LoadPieceIcon(); if ((Object)(object)val != (Object)null) { component.m_icon = val; } } } private static Requirement[] BuildRequirements() { List<Requirement> list = new List<Requirement>(); AddRequirement(list, "Wood", FeederSettings.WoodCost.Value); AddRequirement(list, "FineWood", FeederSettings.FineWoodCost.Value); AddRequirement(list, "Bronze", FeederSettings.BronzeCost.Value); AddRequirement(list, "Dandelion", FeederSettings.DandelionCost.Value); return list.ToArray(); } private static void AddRequirement(List<Requirement> requirements, string itemName, int amount) { //IL_0046: 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_0052: 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_0065: Expected O, but got Unknown if (amount > 0) { ItemDrop val = ResolveRequirementItem(itemName); if ((Object)(object)val == (Object)null || val.m_itemData == null || val.m_itemData.m_shared == null) { FreyjasFeederPlugin.Log.LogWarning((object)("Freyja's Feeder: build requirement " + itemName + " could not be resolved.")); return; } requirements.Add(new Requirement { m_resItem = val, m_amount = amount, m_recover = true }); } } private static ItemDrop ResolveRequirementItem(string prefabName) { if (s_cachedRequirementItems.TryGetValue(prefabName, out var value) && (Object)(object)value != (Object)null && value.m_itemData != null && value.m_itemData.m_shared != null) { return value; } Piece[] array = Resources.FindObjectsOfTypeAll<Piece>(); foreach (Piece val in array) { if ((Object)(object)val == (Object)null || val.m_resources == null) { continue; } for (int j = 0; j < val.m_resources.Length; j++) { Requirement val2 = val.m_resources[j]; if (val2 != null && !((Object)(object)val2.m_resItem == (Object)null) && !(((Object)val2.m_resItem).name != prefabName) && val2.m_resItem.m_itemData != null && val2.m_resItem.m_itemData.m_shared != null) { s_cachedRequirementItems[prefabName] = val2.m_resItem; return val2.m_resItem; } } } if ((Object)(object)ObjectDB.instance != (Object)null) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName); ItemDrop val3 = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val3 != (Object)null && val3.m_itemData != null && val3.m_itemData.m_shared != null) { s_cachedRequirementItems[prefabName] = val3; return val3; } } return null; } private static void EnsureLocalPlayerKnownPiece() { if (!s_pieceRegistered || (Object)(object)Player.m_localPlayer == (Object)null || Player.m_localPlayer.IsRecipeKnown("Freyja's Feeder")) { return; } GameObject prefab = PrefabManager.Instance.GetPrefab("DFG_FreyjasFeeder"); Piece val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Piece>() : null); if (!((Object)(object)val != (Object)null)) { return; } if (s_addKnownPieceMethod == null) { s_addKnownPieceMethod = typeof(Player).GetMethod("AddKnownPiece", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (s_updateAvailablePiecesListMethod == null) { s_updateAvailablePiecesListMethod = typeof(Player).GetMethod("UpdateAvailablePiecesList", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } try { s_addKnownPieceMethod?.Invoke(Player.m_localPlayer, new object[1] { val }); s_updateAvailablePiecesListMethod?.Invoke(Player.m_localPlayer, null); RefreshPieceCategories(); FreyjasFeederPlugin.Log.LogInfo((object)"Freyja's Feeder: unlocked in Hammer menu for local player."); } catch (Exception ex) { FreyjasFeederPlugin.Log.LogWarning((object)("Freyja's Feeder: error adding known piece to player: " + ex.Message)); } } private static void RefreshPieceCategories() { try { MethodInfo method = typeof(PieceManager).GetMethod("RefreshCategories", BindingFlags.Instance | BindingFlags.NonPublic); if (method != null) { method.Invoke(PieceManager.Instance, null); } } catch (Exception ex) { FreyjasFeederPlugin.Log.LogWarning((object)("Freyja's Feeder: could not refresh categories: " + ex.Message)); } } } internal static class ObjLoader { public static GameObject Load(string objPath, Shader shader) { //IL_04e7: Unknown result type (might be due to invalid IL or missing references) //IL_04ee: Expected O, but got Unknown //IL_0151: 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_0573: Unknown result type (might be due to invalid IL or missing references) //IL_0578: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_05bf: Unknown result type (might be due to invalid IL or missing references) //IL_05c4: Unknown result type (might be due to invalid IL or missing references) //IL_060c: Unknown result type (might be due to invalid IL or missing references) //IL_0613: Expected O, but got Unknown //IL_061a: Unknown result type (might be due to invalid IL or missing references) //IL_061f: Unknown result type (might be due to invalid IL or missing references) //IL_0632: Unknown result type (might be due to invalid IL or missing references) //IL_063f: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_06b5: Unknown result type (might be due to invalid IL or missing references) //IL_06bc: Expected O, but got Unknown //IL_06ca: 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_036a: Unknown result type (might be due to invalid IL or missing references) //IL_06e9: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_03e6: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Unknown result type (might be due to invalid IL or missing references) //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_0446: Unknown result type (might be due to invalid IL or missing references) //IL_044b: Unknown result type (might be due to invalid IL or missing references) //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_045a: Unknown result type (might be due to invalid IL or missing references) //IL_045f: Unknown result type (might be due to invalid IL or missing references) //IL_0461: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_0468: Unknown result type (might be due to invalid IL or missing references) //IL_046a: Unknown result type (might be due to invalid IL or missing references) //IL_046c: Unknown result type (might be due to invalid IL or missing references) //IL_0471: Unknown result type (might be due to invalid IL or missing references) //IL_0476: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03a7: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Unknown result type (might be due to invalid IL or missing references) //IL_03be: Unknown result type (might be due to invalid IL or missing references) //IL_0795: Unknown result type (might be due to invalid IL or missing references) //IL_07a1: Unknown result type (might be due to invalid IL or missing references) //IL_080f: Unknown result type (might be due to invalid IL or missing references) //IL_0814: Unknown result type (might be due to invalid IL or missing references) //IL_0818: Unknown result type (might be due to invalid IL or missing references) //IL_0824: Unknown result type (might be due to invalid IL or missing references) //IL_0829: Unknown result type (might be due to invalid IL or missing references) //IL_082d: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(objPath) || !File.Exists(objPath)) { FreyjasFeederPlugin.Log.LogWarning((object)("Freyja's Feeder: OBJ file not found: " + objPath)); return null; } FreyjasFeederPlugin.Log.LogInfo((object)("Freyja's Feeder: loading OBJ model: " + objPath)); string directoryName = Path.GetDirectoryName(objPath); string[] array; try { array = File.ReadAllLines(objPath); } catch (Exception ex) { FreyjasFeederPlugin.Log.LogError((object)("Freyja's Feeder: could not read OBJ file: " + ex.Message)); return null; } List<Vector3> list = new List<Vector3>(); List<Vector2> list2 = new List<Vector2>(); List<Vector3> list3 = new List<Vector3>(); List<Vector3> list4 = new List<Vector3>(); List<Vector2> list5 = new List<Vector2>(); List<Vector3> list6 = new List<Vector3>(); List<int> list7 = new List<int>(); Dictionary<string, int> dictionary = new Dictionary<string, int>(); string mtlLib = null; for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length < 2 || text[0] == '#') { continue; } if (text.StartsWith("v ") || text.StartsWith("v\t")) { string[] array2 = text.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); if (array2.Length >= 4) { float num = float.Parse(array2[1], CultureInfo.InvariantCulture); float num2 = float.Parse(array2[2], CultureInfo.InvariantCulture); float num3 = float.Parse(array2[3], CultureInfo.InvariantCulture); list.Add(new Vector3(0f - num, num2, num3)); } } else if (text.StartsWith("vt ") || text.StartsWith("vt\t")) { string[] array3 = text.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); if (array3.Length >= 3) { float num4 = float.Parse(array3[1], CultureInfo.InvariantCulture); float num5 = float.Parse(array3[2], CultureInfo.InvariantCulture); list2.Add(new Vector2(num4, num5)); } } else if (text.StartsWith("vn ") || text.StartsWith("vn\t")) { string[] array4 = text.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); if (array4.Length >= 4) { float num6 = float.Parse(array4[1], CultureInfo.InvariantCulture); float num7 = float.Parse(array4[2], CultureInfo.InvariantCulture); float num8 = float.Parse(array4[3], CultureInfo.InvariantCulture); list3.Add(new Vector3(0f - num6, num7, num8)); } } else if (text.StartsWith("mtllib ", StringComparison.OrdinalIgnoreCase)) { mtlLib = text.Substring(7).Trim(); } else { if (!text.StartsWith("f ") && !text.StartsWith("f\t")) { continue; } string[] array5 = text.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); if (array5.Length < 4) { continue; } int[] array6 = new int[array5.Length - 1]; for (int j = 1; j < array5.Length; j++) { string text2 = array5[j]; if (!dictionary.TryGetValue(text2, out var value)) { string[] array7 = text2.Split('/'); int num9 = int.Parse(array7[0]); if (num9 < 0) { num9 = list.Count + num9 + 1; } Vector3 item = list[num9 - 1]; Vector2 item2 = Vector2.zero; if (array7.Length > 1 && !string.IsNullOrEmpty(array7[1])) { int num10 = int.Parse(array7[1]); if (num10 < 0) { num10 = list2.Count + num10 + 1; } item2 = list2[num10 - 1]; } Vector3 item3 = Vector3.up; if (array7.Length > 2 && !string.IsNullOrEmpty(array7[2])) { int num11 = int.Parse(array7[2]); if (num11 < 0) { num11 = list3.Count + num11 + 1; } item3 = list3[num11 - 1]; item3 = ((!(((Vector3)(ref item3)).sqrMagnitude > 0.0001f)) ? Vector3.up : ((Vector3)(ref item3)).normalized); } value = list4.Count; list4.Add(item); list5.Add(item2); list6.Add(item3); dictionary[text2] = value; } array6[j - 1] = value; } for (int k = 1; k < array6.Length - 1; k++) { int num12 = array6[0]; int num13 = array6[k]; int num14 = array6[k + 1]; if (num12 != num13 && num12 != num14 && num13 != num14) { Vector3 val = list4[num12]; Vector3 val2 = list4[num13]; Vector3 val3 = list4[num14]; Vector3 val4 = Vector3.Cross(val2 - val, val3 - val); if (!(((Vector3)(ref val4)).sqrMagnitude < 1E-10f)) { list7.Add(num12); list7.Add(num13); list7.Add(num14); } } } } } if (list4.Count == 0 || list7.Count == 0) { FreyjasFeederPlugin.Log.LogWarning((object)"Freyja's Feeder: OBJ file contained no valid geometry."); return null; } Mesh val5 = new Mesh(); ((Object)val5).name = Path.GetFileNameWithoutExtension(objPath); val5.indexFormat = (IndexFormat)1; val5.SetVertices(list4); val5.SetTriangles(list7, 0); if (list5.Count == list4.Count) { val5.SetUVs(0, list5); } if (list3.Count > 0 && list6.Count == list4.Count) { val5.SetNormals(list6); } else { val5.RecalculateNormals(); } Color[] array8 = (Color[])(object)new Color[list4.Count]; for (int l = 0; l < array8.Length; l++) { array8[l] = Color.white; } val5.colors = array8; Vector4[] array9 = (Vector4[])(object)new Vector4[list4.Count]; for (int m = 0; m < array9.Length; m++) { array9[m] = new Vector4(1f, 0f, 0f, 1f); } val5.tangents = array9; val5.RecalculateBounds(); string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(objPath); Texture2D val6 = ResolveDiffuseTexture(directoryName, mtlLib, fileNameWithoutExtension); Texture2D val7 = ResolveNormalTexture(directoryName, mtlLib, fileNameWithoutExtension); GameObject val8 = new GameObject("FeederModel"); GameObject val9 = new GameObject(((Object)val5).name); val9.transform.SetParent(val8.transform, false); val9.AddComponent<MeshFilter>().sharedMesh = val5; MeshRenderer obj = val9.AddComponent<MeshRenderer>(); Shader val10 = shader; if ((Object)(object)val10 == (Object)null || ((Object)val10).name == "Hidden/InternalErrorShader") { val10 = Shader.Find("Custom/Creature"); } if ((Object)(object)val10 == (Object)null) { val10 = Shader.Find("Standard"); } if ((Object)(object)val10 == (Object)null) { val10 = Shader.Find("Unlit/Texture"); } Material val11 = new Material(((Object)(object)val10 != (Object)null) ? val10 : Shader.Find("Hidden/InternalErrorShader")); ((Object)val11).name = "FreyjasFeederMaterial"; val11.color = Color.white; if (val11.HasProperty("_Color")) { val11.SetColor("_Color", Color.white); } if (val11.HasProperty("_Glossiness")) { val11.SetFloat("_Glossiness", 0.35f); } if (val11.HasProperty("_Metallic")) { val11.SetFloat("_Metallic", 0.15f); } if (val11.HasProperty("_Mode")) { val11.SetFloat("_Mode", 0f); } val11.DisableKeyword("_ALPHATEST_ON"); val11.DisableKeyword("_ALPHABLEND_ON"); val11.DisableKeyword("_ALPHAPREMULTIPLY_ON"); val11.renderQueue = 2000; if ((Object)(object)val6 != (Object)null) { val11.mainTexture = (Texture)(object)val6; val11.mainTextureScale = Vector2.one; val11.mainTextureOffset = Vector2.zero; } if ((Object)(object)val7 != (Object)null && val11.HasProperty("_BumpMap")) { val11.SetTexture("_BumpMap", (Texture)(object)val7); val11.EnableKeyword("_NORMALMAP"); } if (val11.HasProperty("_Cull")) { val11.SetInt("_Cull", 0); } val11.doubleSidedGI = true; ((Renderer)obj).sharedMaterial = val11; BoxCollider obj2 = val9.AddComponent<BoxCollider>(); Bounds bounds = val5.bounds; obj2.size = ((Bounds)(ref bounds)).size; bounds = val5.bounds; obj2.center = ((Bounds)(ref bounds)).center; FreyjasFeederPlugin.Log.LogInfo((object)("Freyja's Feeder: OBJ loaded successfully - " + list4.Count + " vertices, " + list7.Count / 3 + " triangles.")); return val8; } private static Texture2D ResolveDiffuseTexture(string dir, string mtlLib, string baseName) { string[] array; if (!string.IsNullOrEmpty(mtlLib)) { string path = Path.Combine(dir, mtlLib); if (File.Exists(path)) { try { array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.StartsWith("map_Kd ", StringComparison.OrdinalIgnoreCase)) { string path2 = text.Substring(7).Trim(); string path3 = Path.Combine(dir, path2); if (File.Exists(path3)) { return LoadTextureFromFile(path3); } } } } catch { } } } array = new string[8] { baseName + "_basecolor.jpg", baseName + "_basecolor.png", baseName + ".jpg", baseName + ".png", baseName + "_diffuse.jpg", baseName + "_diffuse.png", "basecolor.jpg", "basecolor.png" }; foreach (string path4 in array) { string path5 = Path.Combine(dir, path4); if (File.Exists(path5)) { return LoadTextureFromFile(path5); } } return null; } private static Texture2D ResolveNormalTexture(string dir, string mtlLib, string baseName) { string[] array; if (!string.IsNullOrEmpty(mtlLib)) { string path = Path.Combine(dir, mtlLib); if (File.Exists(path)) { try { array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (!text.StartsWith("norm ", StringComparison.OrdinalIgnoreCase) && !text.StartsWith("bump ", StringComparison.OrdinalIgnoreCase) && !text.StartsWith("map_Bump ", StringComparison.OrdinalIgnoreCase)) { continue; } int num = text.IndexOf(' '); if (num > 0) { string path2 = text.Substring(num + 1).Trim(); string path3 = Path.Combine(dir, path2); if (File.Exists(path3)) { return LoadTextureFromFile(path3, isNormal: true); } } } } catch { } } } array = new string[4] { baseName + "_normal.png", baseName + "_normal.jpg", "normal.png", "normal.jpg" }; foreach (string path4 in array) { string path5 = Path.Combine(dir, path4); if (File.Exists(path5)) { return LoadTextureFromFile(path5, isNormal: true); } } return null; } public static Texture2D LoadTextureFromFile(string path, bool isNormal = false) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown try { byte[] array = File.ReadAllBytes(path); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false, isNormal); if (ImageConversion.LoadImage(val, array)) { ((Object)val).name = Path.GetFileNameWithoutExtension(path); ((Texture)val).wrapMode = (TextureWrapMode)0; ((Texture)val).filterMode = (FilterMode)1; FreyjasFeederPlugin.Log.LogInfo((object)("Freyja's Feeder: loaded texture: " + Path.GetFileName(path) + " (" + ((Texture)val).width + "x" + ((Texture)val).height + ")")); return val; } Object.Destroy((Object)(object)val); } catch (Exception ex) { FreyjasFeederPlugin.Log.LogWarning((object)("Freyja's Feeder: failed to load texture " + path + ": " + ex.Message)); } return null; } } [BepInPlugin("com.dfg.freyjasfeeder", "Freyja's Feeder", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class FreyjasFeederPlugin : BaseUnityPlugin { public const string PluginGUID = "com.dfg.freyjasfeeder"; public const string PluginName = "Freyja's Feeder"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; internal static string PluginDirectory; private Harmony m_harmony; internal static FreyjasFeederPlugin Instance { get; private set; } private void Awake() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; PluginDirectory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); FeederSettings.Bind(((BaseUnityPlugin)this).Config); try { m_harmony = new Harmony("com.dfg.freyjasfeeder"); m_harmony.PatchAll(); Log.LogInfo((object)"Freyja's Feeder: Harmony patches applied."); } catch (Exception ex) { Log.LogError((object)("Freyja's Feeder: failed to apply Harmony patches: " + ex)); } FeederPiece.Initialize(); Log.LogInfo((object)"Freyja's Feeder v1.0.0 initialized."); } private void Update() { FeederPiece.Update(); } private void OnDestroy() { FeederPiece.Shutdown(); try { Harmony harmony = m_harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } } } }