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 Tamed Creature Balance v1.0.1
BepInEx/plugins/TamedCreatureBalance/TamedCreatureBalance.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("1.0.1.0")] namespace Fai.TamedCreatureBalance; [BepInPlugin("fai.tamedcreaturebalance", "Tamed Creature Balance", "1.0.1")] [BepInIncompatibility("fai.tamedwolfbalance")] public sealed class Plugin : BaseUnityPlugin { internal struct HealthRecord { internal float Normal; internal float Maximum; internal bool Current; internal bool NeedsRepair; } [HarmonyPatch(typeof(Tameable), "Tame", new Type[] { })] internal static class TamePatch { [HarmonyPriority(0)] internal static void Postfix(Tameable __instance) { Character component = ((Component)__instance).GetComponent<Character>(); if (IsTamedCreature(component)) { Apply(component); } } } internal struct LevelSnapshot { internal float Normal; internal int Level; } [HarmonyPatch(typeof(Character), "SetLevel", new Type[] { typeof(int) })] internal static class LevelPatch { [HarmonyPriority(800)] internal static void Prefix(Character __instance, out LevelSnapshot __state) { __state = default(LevelSnapshot); if (IsTamedCreature(__instance) && __instance.IsOwner() && !__instance.IsDead() && ReadSaved(Data(__instance), out var record)) { __state.Normal = record.Normal; __state.Level = __instance.GetLevel(); } } [HarmonyPriority(0)] internal static void Postfix(Character __instance, LevelSnapshot __state) { if (__state.Level < 1 || !IsTamedCreature(__instance) || !__instance.IsOwner() || __instance.IsDead()) { return; } int level = __instance.GetLevel(); if (level < 1 || level == __state.Level) { return; } ZDO val = Data(__instance); if (val != null) { float num = __state.Normal * ((float)level / (float)__state.Level); if (Plan(__instance.GetMaxHealth(), __instance.GetHealth(), num, out var targetMaximum, out var targetHealth)) { Save(__instance, val, num, targetMaximum, targetHealth); } } } } [HarmonyPatch(typeof(Character), "SetMaxHealth", new Type[] { typeof(float) })] internal static class WriteMaxPatch { [HarmonyPriority(0)] internal static void Prefix(Character __instance, ref float __0) { if (Target(__instance, out var maximum)) { __0 = maximum; } } } [HarmonyPatch(typeof(Character), "GetMaxHealth", new Type[] { })] internal static class ReadMaxPatch { [HarmonyPriority(0)] internal static void Postfix(Character __instance, ref float __result) { if (Target(__instance, out var maximum)) { __result = maximum; } } } [HarmonyPatch(typeof(Attack), "ModifyDamage", new Type[] { typeof(HitData), typeof(float) })] internal static class DamagePatch { private static readonly ConditionalWeakTable<HitData, object> adjusted = new ConditionalWeakTable<HitData, object>(); private static readonly object adjustedMarker = new object(); [HarmonyPriority(0)] internal static void Postfix(Humanoid ___m_character, HitData __0) { if (__0 != null && IsTamedCreature((Character)(object)___m_character) && !adjusted.TryGetValue(__0, out var _)) { adjusted.Add(__0, adjustedMarker); ((DamageTypes)(ref __0.m_damage)).Modify(0.35f); } } } [HarmonyPatch(typeof(BaseAI), "UpdateRegeneration", new Type[] { typeof(float) })] internal static class RegenerationPatch { internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo method = typeof(Character).GetMethod("Heal", new Type[2] { typeof(float), typeof(bool) }); MethodInfo method2 = typeof(Plugin).GetMethod("HealRegeneration", BindingFlags.Static | BindingFlags.NonPublic); int num = 0; foreach (CodeInstruction item in list) { if ((item.opcode == OpCodes.Callvirt || item.opcode == OpCodes.Call) && object.Equals(item.operand, method)) { item.opcode = OpCodes.Call; item.operand = method2; num++; } } if (num != 1) { throw new InvalidOperationException("TCB: unrecognized BaseAI.UpdateRegeneration layout (Heal calls: " + num + ")."); } return list; } } public const string Id = "fai.tamedcreaturebalance"; public const string Version = "1.0.1"; internal const float HealthFactor = 3f; internal const float DamageFactor = 0.35f; internal const float RegenerationFactor = 0.01f; internal const string Marker = "fai_tcb_v100"; internal const string BaseKey = "fai_tcb_basehp_v100"; internal const string MaxKey = "fai_tcb_maxhp_v100"; internal const string SourceMarker = "fai_twb_alltamed_v170"; internal const string SourceBaseKey = "fai_twb_alltamed_basehp_v170"; internal const string SourceMaxKey = "fai_twb_alltamed_maxhp_v170"; internal const string PreviousMarker = "fai_twb_alltamed_v160"; internal const string PreviousBaseKey = "fai_twb_alltamed_basehp_v160"; internal const string PreviousMaxKey = "fai_twb_alltamed_maxhp_v160"; internal const string LegacyMarker = "fai_twb_newtame_v150"; internal const string LegacyMaxKey = "fai_twb_newtame_maxhp_v150"; internal static ManualLogSource Log; private Harmony harmony; private bool ready; private float scanTimer; private void Awake() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ((BaseUnityPlugin)this).Logger.LogInfo((object)("TCB 1.0.1 LOADING: " + typeof(Plugin).Assembly.Location)); harmony = new Harmony("fai.tamedcreaturebalance"); try { harmony.PatchAll(typeof(Plugin).Assembly); ready = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"TCB 1.0.1 READY | all tamed creatures | HP x3 | damage x0.35 | fed regeneration 1% per tick"); } catch (Exception ex) { harmony.UnpatchSelf(); ((BaseUnityPlugin)this).Logger.LogError((object)("TCB 1.0.1 PATCH FAILED; no balance patches active: " + ex)); } } private void Update() { if (!ready) { return; } scanTimer -= Time.unscaledDeltaTime; if (!(scanTimer > 0f)) { scanTimer = 1f; List<Character> allCharacters = Character.GetAllCharacters(); for (int i = 0; i < allCharacters.Count; i++) { Apply(allCharacters[i]); } } } private void OnDestroy() { ready = false; if (harmony != null) { harmony.UnpatchSelf(); } Log = null; } internal static bool Positive(float value) { return value > 0f && !float.IsNaN(value) && !float.IsInfinity(value); } internal static bool IsTamedCreature(Character c) { return (Object)(object)c != (Object)null && !c.IsPlayer() && c.IsTamed(); } internal static ZDO Data(Character c) { if ((Object)(object)c == (Object)null) { return null; } ZNetView val = ((!((Object)(object)c.m_nViewOverride != (Object)null)) ? ((Component)c).GetComponent<ZNetView>() : c.m_nViewOverride); return (!((Object)(object)val != (Object)null) || !val.IsValid()) ? null : val.GetZDO(); } private static bool ReadRecord(ZDO zdo, string marker, string baseKey, string maxKey, float factor, out HealthRecord record) { record = default(HealthRecord); if (!zdo.GetBool(marker, false)) { return false; } float num = ((baseKey != null) ? zdo.GetFloat(baseKey, 0f) : 0f); float num2 = zdo.GetFloat(maxKey, 0f); float num3 = num; if (!Positive(num3) || !Positive(num3 * factor)) { num3 = num2 / factor; } float num4 = num3 * factor; if (!Positive(num3) || !Positive(num4)) { return false; } record = new HealthRecord { Normal = num3, Maximum = num4, NeedsRepair = (num != num3 || num2 != num4) }; return true; } internal static bool ReadSaved(ZDO zdo, out HealthRecord record) { record = default(HealthRecord); if (zdo == null) { return false; } if (ReadRecord(zdo, "fai_tcb_v100", "fai_tcb_basehp_v100", "fai_tcb_maxhp_v100", 3f, out record)) { record.Current = true; return true; } return ReadRecord(zdo, "fai_twb_alltamed_v170", "fai_twb_alltamed_basehp_v170", "fai_twb_alltamed_maxhp_v170", 3f, out record) || ReadRecord(zdo, "fai_twb_alltamed_v160", "fai_twb_alltamed_basehp_v160", "fai_twb_alltamed_maxhp_v160", 5f, out record) || ReadRecord(zdo, "fai_twb_newtame_v150", null, "fai_twb_newtame_maxhp_v150", 3f, out record); } internal static bool Target(Character c, out float maximum) { maximum = 0f; if (!IsTamedCreature(c) || !ReadSaved(Data(c), out var record)) { return false; } maximum = record.Maximum; return true; } internal static bool Plan(float currentMaximum, float currentHealth, float normalMaximum, out float targetMaximum, out float targetHealth) { targetMaximum = (targetHealth = 0f); if (!Positive(currentMaximum) || !Positive(currentHealth) || !Positive(normalMaximum)) { return false; } float num = normalMaximum * 3f; if (!Positive(num)) { return false; } targetMaximum = num; targetHealth = Math.Min(1f, currentHealth / currentMaximum) * num; return Positive(targetHealth); } private static void Save(Character c, ZDO zdo, float normal, float maximum, float health) { zdo.Set("fai_tcb_basehp_v100", normal); zdo.Set("fai_tcb_maxhp_v100", maximum); zdo.Set("fai_tcb_v100", true); c.SetMaxHealth(maximum); c.SetHealth(health); } internal static void Apply(Character c) { //IL_0155: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)c == (Object)null || c.IsPlayer() || !c.IsOwner() || c.IsDead()) { return; } ZDO val = Data(c); if (val == null) { return; } HealthRecord record; bool flag = ReadSaved(val, out record); if (!c.IsTamed()) { if (flag) { Restore(c, val, record.Normal); } } else { if ((flag && record.Current && !record.NeedsRepair) || (!flag && (val.GetBool("fai_tcb_v100", false) || val.GetBool("fai_twb_alltamed_v170", false) || val.GetBool("fai_twb_alltamed_v160", false) || val.GetBool("fai_twb_newtame_v150", false)))) { return; } float maxHealth = c.GetMaxHealth(); float health = c.GetHealth(); float num = ((!flag) ? maxHealth : record.Normal); if (Plan(maxHealth, health, num, out var targetMaximum, out var targetHealth)) { Save(c, val, num, targetMaximum, targetHealth); if (Log != null) { Log.LogInfo((object)string.Concat("TCB ", (!flag) ? "APPLIED" : "UPDATED", " | ZDO=", c.GetZDOID(), " | normalMax=", num.ToString("0.##"), " | HP=", c.GetHealth().ToString("0.##"), "/", targetMaximum.ToString("0.##"), " | damage=x0.35")); } } } } private static void Restore(Character c, ZDO zdo, float normal) { float maxHealth = c.GetMaxHealth(); float health = c.GetHealth(); if (Positive(maxHealth) && Positive(health) && Positive(normal)) { float num = Math.Min(1f, health / maxHealth) * normal; if (Positive(num)) { zdo.Set("fai_tcb_v100", false); zdo.Set("fai_twb_alltamed_v170", false); zdo.Set("fai_twb_alltamed_v160", false); zdo.Set("fai_twb_newtame_v150", false); c.SetMaxHealth(normal); c.SetHealth(num); } } } internal static void HealRegeneration(Character c, float amount, bool showText) { if ((Object)(object)c == (Object)null) { return; } if (IsTamedCreature(c)) { Tameable component = ((Component)c).GetComponent<Tameable>(); if ((Object)(object)component != (Object)null) { if (component.IsHungry() || !c.IsOwner() || c.IsDead() || !Positive(c.GetHealth())) { return; } float maxHealth = c.GetMaxHealth(); if (!Positive(maxHealth)) { return; } amount = maxHealth * 0.01f; } } c.Heal(amount, showText); } }