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 ShieldBalance v1.0.0
ShieldBalance.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Utils; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.0.0.0")] namespace BubShieldBalance; [BepInPlugin("bub.shieldbalance", "Shield Balance", "1.0.0")] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private enum Kind { Buckler, Round, Tower } private class Ctx { public Ctx Prev; public bool Applies; public Kind Kind; public float BlockTimer; public bool Staggered; public bool StaminaScaled; } public const string Guid = "bub.shieldbalance"; public const string Version = "1.0.0"; private static ManualLogSource Log; private static ConfigEntry<bool> GuardBreakStillBlocks; private static ConfigEntry<float> BucklerMinParryBonus; private static ConfigEntry<float> StaggerBuckler; private static ConfigEntry<float> StaggerRound; private static ConfigEntry<float> StaggerTower; private static ConfigEntry<float> StaminaBuckler; private static ConfigEntry<float> StaminaRound; private static ConfigEntry<float> StaminaTower; private static Func<Character, float, Vector3, HitData, bool> AddStaggerDamage; private static FieldInfo BlockTimer; private static Func<Humanoid, ItemData> GetCurrentBlocker; private static Ctx Current; private static HitData lastBlockedHit; private static Kind lastBlockedKind; private void Awake() { //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; GuardBreakStillBlocks = Bind("1 - Guard break", "Guard break still blocks", value: true, "When a blocked hit fills your stagger bar, the shield still reduces it and only the excess reaches your health (vanilla: the whole hit goes through)."); BucklerMinParryBonus = Bind("2 - Shield types", "Buckler min parry bonus", 2f, "Shields with a parry bonus at or above this are bucklers; with no parry bonus (1.0 or less) they are tower shields; the rest are round shields.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1.01f, 10f)); StaggerBuckler = Bind("3 - Stagger taken while blocking", "Buckler", 1f, "Multiplier on the stagger you take when blocking with a buckler.", (AcceptableValueBase)(object)Range(0f, 3f)); StaggerRound = Bind("3 - Stagger taken while blocking", "Round shield", 0.85f, "Multiplier on the stagger you take when blocking with a round shield.", (AcceptableValueBase)(object)Range(0f, 3f)); StaggerTower = Bind("3 - Stagger taken while blocking", "Tower shield", 0.7f, "Multiplier on the stagger you take when blocking with a tower shield.", (AcceptableValueBase)(object)Range(0f, 3f)); StaminaBuckler = Bind("4 - Block stamina cost", "Buckler", 1f, "Multiplier on the stamina cost of a normal block (not parry) with a buckler.", (AcceptableValueBase)(object)Range(0f, 3f)); StaminaRound = Bind("4 - Block stamina cost", "Round shield", 0.85f, "Multiplier on the stamina cost of a normal block (not parry) with a round shield.", (AcceptableValueBase)(object)Range(0f, 3f)); StaminaTower = Bind("4 - Block stamina cost", "Tower shield", 0.7f, "Multiplier on the stamina cost of a normal block with a tower shield.", (AcceptableValueBase)(object)Range(0f, 3f)); MethodInfo methodInfo = AccessTools.Method(typeof(Character), "AddStaggerDamage", new Type[3] { typeof(float), typeof(Vector3), typeof(HitData) }, (Type[])null); AddStaggerDamage = AccessTools.MethodDelegate<Func<Character, float, Vector3, HitData, bool>>(methodInfo, (object)null, true); BlockTimer = AccessTools.Field(typeof(Humanoid), "m_blockTimer"); GetCurrentBlocker = AccessTools.MethodDelegate<Func<Humanoid, ItemData>>(AccessTools.Method(typeof(Humanoid), "GetCurrentBlocker", (Type[])null, (Type[])null), (object)null, true); Harmony val = new Harmony("bub.shieldbalance"); MethodInfo methodInfo2 = AccessTools.Method(typeof(Humanoid), "BlockAttack", (Type[])null, (Type[])null); val.Patch((MethodBase)methodInfo2, Hm("BlockPrefix"), Hm("BlockPostfix"), Hm("BlockTranspiler"), Hm("BlockFinalizer"), (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.Method(typeof(SEMan), "ModifyBlockStaminaUsage", (Type[])null, (Type[])null), (HarmonyMethod)null, Hm("StaminaPostfix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.Method(typeof(Character), "AddStaggerDamage", (Type[])null, (Type[])null), Hm("DamageStaggerPrefix"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private ConfigEntry<T> Bind<T>(string section, string key, T value, string description, AcceptableValueBase range = null) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown ConfigurationManagerAttributes val = new ConfigurationManagerAttributes(); val.IsAdminOnly = true; return ((BaseUnityPlugin)this).Config.Bind<T>(section, key, value, new ConfigDescription(description, range, new object[1] { val })); } private static AcceptableValueRange<float> Range(float min, float max) { return new AcceptableValueRange<float>(min, max); } private static HarmonyMethod Hm(string name) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return new HarmonyMethod(typeof(Plugin).GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic)); } private static Kind Classify(ItemData item) { float timedBlockBonus = item.m_shared.m_timedBlockBonus; if (timedBlockBonus <= 1f) { return Kind.Tower; } if (timedBlockBonus >= BucklerMinParryBonus.Value) { return Kind.Buckler; } return Kind.Round; } private static float Pick(Kind kind, ConfigEntry<float> buckler, ConfigEntry<float> round, ConfigEntry<float> tower) { return kind switch { Kind.Round => round.Value, Kind.Buckler => buckler.Value, _ => tower.Value, }; } private static void BlockPrefix(Humanoid __instance, HitData hit, out Ctx __state) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Invalid comparison between Unknown and I4 Ctx ctx = new Ctx(); ctx.Prev = Current; ItemData val = GetCurrentBlocker(__instance); ctx.Applies = __instance is Player && val != null && (int)val.m_shared.m_itemType == 5; if (ctx.Applies) { ctx.Kind = Classify(val); ctx.BlockTimer = (float)BlockTimer.GetValue(__instance); } Current = ctx; __state = ctx; } private static Exception BlockFinalizer(Exception __exception, Ctx __state) { if (__state != null) { Current = __state.Prev; } return __exception; } private static IEnumerable<CodeInstruction> BlockTranspiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); MethodInfo original = AccessTools.Method(typeof(Character), "AddStaggerDamage", (Type[])null, (Type[])null); int num = list.FindIndex((CodeInstruction ci) => CodeInstructionExtensions.Calls(ci, original)); if (num < 0 || num + 1 >= list.Count || !CodeInstructionExtensions.IsStloc(list[num + 1], (LocalBuilder)null)) { Log.LogError((object)"Humanoid.BlockAttack mudou (AddStaggerDamage não encontrado); patch não aplicado."); return list; } list[num].opcode = OpCodes.Call; list[num].operand = AccessTools.Method(typeof(Plugin), "StaggerHook", (Type[])null, (Type[])null); object operand = list[num + 1].operand; for (int num2 = num + 2; num2 + 1 < list.Count; num2++) { if (CodeInstructionExtensions.IsLdloc(list[num2], (LocalBuilder)null) && SameLocal(list[num2], operand) && (list[num2 + 1].opcode == OpCodes.Brtrue || list[num2 + 1].opcode == OpCodes.Brtrue_S)) { list[num2].opcode = OpCodes.Call; list[num2].operand = AccessTools.Method(typeof(Plugin), "SkipBlockReduction", (Type[])null, (Type[])null); return list; } } Log.LogError((object)"Humanoid.BlockAttack mudou (teste de stagger não encontrado); quebra de guarda fica como no vanilla."); return list; } private static bool SameLocal(CodeInstruction ldloc, object stlocOperand) { LocalBuilder localBuilder = ldloc.operand as LocalBuilder; LocalBuilder localBuilder2 = stlocOperand as LocalBuilder; if (localBuilder != null && localBuilder2 != null) { return localBuilder.LocalIndex == localBuilder2.LocalIndex; } return object.Equals(ldloc.operand, stlocOperand); } private static bool StaggerHook(Character self, float damage, Vector3 dir, HitData hit) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) Ctx current = Current; if (current != null && current.Applies) { damage *= Pick(current.Kind, StaggerBuckler, StaggerRound, StaggerTower); } bool flag = AddStaggerDamage(self, damage, dir, hit); if (current != null) { current.Staggered = flag; } return flag; } private static bool SkipBlockReduction() { Ctx current = Current; if (current == null || !current.Staggered) { return false; } if (current.Applies) { return !GuardBreakStillBlocks.Value; } return true; } private static void BlockPostfix(HitData hit, bool __result, Ctx __state) { if (__state != null && __state.Applies && __result) { lastBlockedHit = hit; lastBlockedKind = __state.Kind; } } private static void DamageStaggerPrefix(ref float __0, HitData __2) { if (__2 != null && __2 == lastBlockedHit) { __0 *= Pick(lastBlockedKind, StaggerBuckler, StaggerRound, StaggerTower); } } private static void StaminaPostfix(ref float __1) { Ctx current = Current; if (current != null && current.Applies && !current.StaminaScaled) { current.StaminaScaled = true; if ((current.Kind == Kind.Tower || !(current.BlockTimer >= 0f) || !(current.BlockTimer < 0.25f)) && __1 > 0f) { __1 *= Pick(current.Kind, StaminaBuckler, StaminaRound, StaminaTower); } } } }