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 AbsentBreed v1.0.0
AbsentBreed.dll
Decompiled a year agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = ".NET Framework 4.6")] [assembly: AssemblyCompany("AbsentBreed")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Valheim Plugin")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+41963fcec691b0b4b9bb842977e7b5196bd07614")] [assembly: AssemblyProduct("AbsentBreed")] [assembly: AssemblyTitle("AbsentBreed")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 AbsentBreed { public class BreedCatchupPatch { [HarmonyPatch(typeof(MonsterAI))] public class MonsterAIUpdate_Patch { private static MethodBase TargetMethod() { return typeof(MonsterAI).GetMethod("UpdateConsumeItem", BindingFlags.Instance | BindingFlags.NonPublic); } private static void Prefix(MonsterAI __instance, ref float ___m_consumeSearchInterval, ref float ___m_consumeSearchRange) { BreedCatchupData tameableData = TamedTimingData.GetTameableData(__instance); if (tameableData != null && tameableData.State == CatchupState.CatchingUp) { tameableData.ConsumeSearchInterval = ___m_consumeSearchInterval; tameableData.ConsumeSearchRange = ___m_consumeSearchRange; ___m_consumeSearchInterval = 0f; ___m_consumeSearchRange *= Constants.CONSUMABLE_SEARCH_RADIUS_MULTIPLIER; } } private static void Postfix(MonsterAI __instance, ref float ___m_consumeSearchInterval, ref float ___m_consumeSearchRange, ref ItemDrop ___m_consumeTarget, ref Action<ItemDrop> ___m_onConsumedItem) { BreedCatchupData tameableData = TamedTimingData.GetTameableData(__instance); if (tameableData != null && tameableData.State == CatchupState.CatchingUp && (Object)(object)___m_consumeTarget != (Object)null) { Plugin.Log("MonsterAI insta-consumed food as part of speed-breeding"); ___m_consumeTarget.RemoveOne(); if (___m_onConsumedItem != null) { ___m_onConsumedItem(___m_consumeTarget); } ___m_consumeTarget = null; ___m_consumeSearchInterval = tameableData.ConsumeSearchInterval; ___m_consumeSearchRange = tameableData.ConsumeSearchRange; } } } [HarmonyPatch(typeof(Character))] public class CharacterUpdateWalking_Patch { } [HarmonyPatch(typeof(Tameable))] public class TameableTamingUpdate_Patch { private static MethodBase TargetMethod() { return typeof(Tameable).GetMethod("TamingUpdate", BindingFlags.Instance | BindingFlags.NonPublic); } private static void Postfix(ZNetView ___m_nview, Character ___m_character) { if (___m_character.IsTamed()) { if (___m_nview.IsValid() && ___m_nview.IsOwner()) { TamedTimingData.SetLastCheckedOnTime(___m_nview.GetZDO()); } else { Plugin.Log("Tamed animal, but m_nview was not valid!"); } } } } [HarmonyPatch(typeof(Tameable))] public class TameableAwake_Patch { private static MethodBase TargetMethod() { return typeof(Tameable).GetMethod("Awake", BindingFlags.Instance | BindingFlags.NonPublic); } private static void Postfix(Tameable __instance, Character ___m_character, MonsterAI ___m_monsterAI, ZNetView ___m_nview) { if (!___m_character.IsTamed()) { return; } if (___m_nview.IsValid() && ___m_nview.IsOwner()) { if (Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<Procreation>())) { TamedTimingData.RegisterTameable(__instance, ___m_character, ___m_monsterAI, ___m_nview.GetZDO()); } } else { Plugin.Log("Would have registered a tamed animal, but we are not the owner"); } } } [HarmonyPatch(typeof(Procreation))] public class ProcreationAwake_Patch { private static MethodBase TargetMethod() { return typeof(Procreation).GetMethod("Awake", BindingFlags.Instance | BindingFlags.NonPublic); } private static void Postfix(Procreation __instance, Tameable ___m_tameable, Character ___m_character) { if (___m_character.IsTamed()) { TamedTimingData.RegisterProcreation(__instance, ___m_tameable); } } } [HarmonyPatch(typeof(Procreation))] public class ProcreationProcreate_Patch { private static MethodBase TargetMethod() { return typeof(Procreation).GetMethod("Procreate", BindingFlags.Instance | BindingFlags.NonPublic); } private static void Postfix(Procreation __instance, ref float ___m_totalCheckRange, ref float ___m_partnerCheckRange, ref float ___m_pregnancyDuration, ref Tameable ___m_tameable, ref float ___m_updateInterval) { BreedCatchupData tameableData = TamedTimingData.GetTameableData(___m_tameable); if (tameableData != null && tameableData.State == CatchupState.NormalBehavior && tameableData.RemainingCatchupTicks > 0) { Plugin.Log("Tamed animal " + ((object)(ZDOID)(ref tameableData.ID)).ToString() + " is speed-breeding for " + new TimeSpan(tameableData.RemainingCatchupTicks).TotalSeconds + " secs"); tameableData.State = CatchupState.CatchingUp; tameableData.SetSpeedyProcreateValues(ref ___m_totalCheckRange, ref ___m_partnerCheckRange, ref ___m_pregnancyDuration, ref ___m_tameable, ___m_updateInterval); ((MonoBehaviour)tameableData.ProcreationInstance).CancelInvoke("Procreate"); ((MonoBehaviour)tameableData.ProcreationInstance).InvokeRepeating("Procreate", 1f, 1f); } if (tameableData != null && tameableData.State == CatchupState.CatchingUp) { if (tameableData.RemainingCatchupTicks > 0) { tameableData.ConsumeCatchupTime(tameableData.ProcreateUpdateTicks); return; } Plugin.Log("Tamed animal " + ((object)(ZDOID)(ref tameableData.ID)).ToString() + " finished speed-breeding"); tameableData.State = CatchupState.NormalBehavior; tameableData.ResetProcreateValues(ref ___m_totalCheckRange, ref ___m_partnerCheckRange, ref ___m_pregnancyDuration, ref ___m_tameable); ((MonoBehaviour)__instance).CancelInvoke("Procreate"); ((MonoBehaviour)__instance).InvokeRepeating("Procreate", tameableData.BaseProcreateUpdateSeconds, tameableData.BaseProcreateUpdateSeconds); TamedTimingData.UnregisterTameable(___m_tameable); } } } [HarmonyPatch(typeof(Growup))] public class GrowupGrowUpdate_Patch { private static MethodBase TargetMethod() { return typeof(Growup).GetMethod("Start", BindingFlags.Instance | BindingFlags.NonPublic); } private static void Postfix(Growup __instance) { if (TamedTimingData.TryGetRemainingCatchupTime(out var time)) { float num = __instance.m_growTime - (float)time; float num2 = Mathf.Clamp(num, 0f, __instance.m_growTime); Plugin.Log($"Offspring growtime (base:{__instance.m_growTime}, new:{num}, clamped:{num2})"); __instance.m_growTime = num2; } } } [HarmonyPatch(typeof(EggGrow))] public class EggGrowGrowUpdate_Patch { private static MethodBase TargetMethod() { return typeof(EggGrow).GetMethod("Start", BindingFlags.Instance | BindingFlags.NonPublic); } private static void Postfix(EggGrow __instance) { if (TamedTimingData.TryGetRemainingCatchupTime(out var time)) { float num = __instance.m_growTime - (float)time; float num2 = Mathf.Clamp(num, 0f, __instance.m_growTime); Plugin.Log($"Egg growtime (base:{__instance.m_growTime}, new:{num}, clamped:{num2})"); __instance.m_growTime = num2; } } } } public static class Constants { public static float CONSUMABLE_SEARCH_RADIUS_MULTIPLIER = 3f; public const float SPEEDY_PROCREATE_UPDATE_INTERVAL = 1f; public const float BREED_PARTNER_RANGE_MULTIPLIER = 10f; public const float CROWDED_RANGE_MULTIPLIER = 0.5f; } [BepInPlugin("AbsentBreed", "AbsentBreed", "1.0.0")] public class Plugin : BaseUnityPlugin { private readonly Harmony harmony = new Harmony("untamedprogress.ValheimMod"); public static Plugin Instance; public static Queue<string> _printQueue = new Queue<string>(); private void Awake() { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin AbsentBreed is loaded!"); harmony.PatchAll(); Instance = this; Flush(); } public static void Log(string message) { _printQueue.Enqueue(message); if ((Object)(object)Instance != (Object)null) { Instance.Flush(); } } public void Flush() { while (_printQueue.Count > 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)_printQueue.Dequeue()); } } } public static class TameableExtensions { private static Dictionary<Tameable, ZDOID> _tameableIDMap = new Dictionary<Tameable, ZDOID>(); public static ZDOID GetZDOID(this Tameable tameable) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return tameable.GetZDO().m_uid; } public static ZDO GetZDO(this Tameable tameable) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) FieldInfo[] fields = ((object)tameable).GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { Plugin.Log("field: " + fieldInfo.Name); } FieldInfo fieldInfo2 = fields.FirstOrDefault((FieldInfo f) => string.Equals(f.Name, "m_nview", StringComparison.OrdinalIgnoreCase)); if (fieldInfo2 != null) { Plugin.Log("Field info non-null"); return ((ZNetView)fieldInfo2.GetValue(tameable)).GetZDO(); } throw new InvalidOperationException("Failed to access m_nview using reflection."); } } public enum CatchupState { CatchingUp, NormalBehavior } public struct ProcreateStats { public float ProcreateUpdateBaseInterval; public float FullPenCheckRange; public float BreedPartnerCheckRange; public float PregnancyDuration; public float FedDuration; } public class BreedCatchupData { public Procreation ProcreationInstance; public Tameable TameableInstance; public Character CharacterInstance; public ZDOID ID; public float ConsumeSearchInterval; public float ConsumeSearchRange; public long RemainingCatchupTicks; public ProcreateStats NormalProcreationValues { get; set; } public long ProcreateUpdateTicks => TimeSpan.FromSeconds(NormalProcreationValues.ProcreateUpdateBaseInterval).Ticks; public float BaseProcreateUpdateSeconds => (float)new TimeSpan(ProcreateUpdateTicks).TotalSeconds; public CatchupState State { get; set; } public void ConsumeCatchupTime(long consumedTicks) { RemainingCatchupTicks -= consumedTicks; } public void SetSpeedyProcreateValues(ref float totalCheckRange, ref float partnerCheckRange, ref float pregnancyDuration, ref Tameable tameable, float baseUpdateInterval) { NormalProcreationValues = new ProcreateStats { FullPenCheckRange = totalCheckRange, BreedPartnerCheckRange = partnerCheckRange, PregnancyDuration = pregnancyDuration, FedDuration = tameable.m_fedDuration, ProcreateUpdateBaseInterval = baseUpdateInterval }; float num = baseUpdateInterval / 1f; totalCheckRange *= 0.5f; partnerCheckRange *= 10f; pregnancyDuration /= num; Tameable obj = tameable; obj.m_fedDuration /= num; } public void ResetProcreateValues(ref float totalCheckRange, ref float partnerCheckRange, ref float pregnancyDuration, ref Tameable tameable) { totalCheckRange = NormalProcreationValues.FullPenCheckRange; partnerCheckRange = NormalProcreationValues.BreedPartnerCheckRange; pregnancyDuration = NormalProcreationValues.PregnancyDuration; tameable.m_fedDuration = NormalProcreationValues.FedDuration; } } public class TamedTimingData { public const string TIMESTAMP_KEY = "breedmod_last_check"; private static Dictionary<Tameable, BreedCatchupData> TameableDataMap = new Dictionary<Tameable, BreedCatchupData>(); private static Dictionary<Tameable, Procreation> TameableProcreationMap = new Dictionary<Tameable, Procreation>(); private static Dictionary<Tameable, MonsterAI> TameableMonsterMap = new Dictionary<Tameable, MonsterAI>(); private static Dictionary<MonsterAI, Tameable> MonsterTameableMap = new Dictionary<MonsterAI, Tameable>(); public static BreedCatchupData GetTameableData(Tameable tameable) { if (TameableDataMap.TryGetValue(tameable, out var value)) { return value; } return null; } public static BreedCatchupData GetTameableData(MonsterAI monsterAi) { if (MonsterTameableMap.TryGetValue(monsterAi, out var value)) { return GetTameableData(value); } return null; } public static void RegisterTameable(Tameable tameable, Character character, MonsterAI monsterAI, ZDO zdo) { //IL_0027: 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) long remainingCatchupTicks = ZNet.instance.GetTime().Ticks - GetLastCheckedOnTime(zdo); TameableDataMap[tameable] = new BreedCatchupData { ID = zdo.m_uid, TameableInstance = tameable, RemainingCatchupTicks = remainingCatchupTicks, State = CatchupState.NormalBehavior, CharacterInstance = character }; TameableMonsterMap[tameable] = monsterAI; MonsterTameableMap[monsterAI] = tameable; AfterRegistration(tameable); } public static void RegisterProcreation(Procreation procreation, Tameable tameable) { TameableProcreationMap[tameable] = procreation; AfterRegistration(tameable); } public static void AfterRegistration(Tameable tameable) { if (TameableProcreationMap.TryGetValue(tameable, out var value) && TameableDataMap.TryGetValue(tameable, out var value2)) { Plugin.Log("After successful tameable registration; invoking procreation once"); value2.ProcreationInstance = value; ((MonoBehaviour)value2.ProcreationInstance).Invoke("Procreate", 1f); } } public static void UnregisterTameable(Tameable tameable) { MonsterTameableMap.Remove(TameableMonsterMap[tameable]); TameableDataMap.Remove(tameable); TameableMonsterMap.Remove(tameable); } private static long GetLastCheckedOnTime(ZDO zdo) { long ticks = ZNet.instance.GetTime().Ticks; return zdo.GetLong("breedmod_last_check", ticks); } public static void SetLastCheckedOnTime(ZDO zdo) { long ticks = ZNet.instance.GetTime().Ticks; zdo.Set("breedmod_last_check", ticks); } public static bool TryGetRemainingCatchupTime(out double time) { if (TameableDataMap?.Values == null || !TameableDataMap.Values.Any()) { time = 0.0; return false; } BreedCatchupData breedCatchupData = TameableDataMap.Values.OrderByDescending((BreedCatchupData d) => d?.RemainingCatchupTicks ?? 0).FirstOrDefault(); if (breedCatchupData == null) { time = 0.0; return false; } time = new TimeSpan(breedCatchupData.RemainingCatchupTicks).TotalSeconds; return true; } } public static class PluginInfo { public const string PLUGIN_GUID = "AbsentBreed"; public const string PLUGIN_NAME = "AbsentBreed"; public const string PLUGIN_VERSION = "1.0.0"; } }