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 ReliableBlockRebuilt v1.1.0
plugins/ReliableBlockRebuilt/ReliableBlock.Rebuilt.dll
Decompiled a month agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("Korppis;anneryeo")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Local-player Reliable Block update with strict compatibility guards.")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0+4250ba3708815e401280d7e3feed5b71c9c0d5fc")] [assembly: AssemblyProduct("ReliableBlock.Rebuilt")] [assembly: AssemblyTitle("ReliableBlock.Rebuilt")] [assembly: AssemblyVersion("1.1.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 ReliableBlock { [BepInPlugin("org.bepinex.plugins.reliableblock.rebuilt", "Reliable Block Rebuilt", "1.1.0")] [BepInProcess("valheim.exe")] [BepInIncompatibility("org.bepinex.plugins.reliableblock")] public sealed class ReliableBlockPlugin : BaseUnityPlugin { public const string PluginId = "org.bepinex.plugins.reliableblock.rebuilt"; private Harmony harmony; private ConfigEntry<bool> modEnabled; private MethodInfo target; private bool conflictReported; internal static ReliableBlockPlugin Instance; private void Awake() { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Expected O, but got Unknown Instance = this; modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable local-player damage mitigation on staggered blocks. False uses the original block check. Restart after changing mods."); try { target = AccessTools.DeclaredMethod(typeof(Humanoid), "BlockAttack", new Type[2] { typeof(HitData), typeof(Character) }, (Type[])null); if (target == null || !Compatibility.IsSupported(target.GetMethodBody()?.GetILAsByteArray())) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Disabled: unrecognized BlockAttack code. Inspected against Valheim 1.0.16. No patch applied."); } else if (!HasOtherPatches()) { harmony = new Harmony("org.bepinex.plugins.reliableblock.rebuilt"); harmony.Patch((MethodBase)target, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ReliableBlockPlugin), "Transpiler", (Type[])null) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Disabled: patch installation failed. " + ex)); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } private bool HasOtherPatches() { Patches patchInfo = Harmony.GetPatchInfo((MethodBase)target); string[] array = ((patchInfo != null) ? patchInfo.Owners.Where((string owner) => owner != "org.bepinex.plugins.reliableblock.rebuilt").ToArray() : null); if (array == null || array.Length == 0) { return false; } if (!conflictReported) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Disabled: other BlockAttack patches detected: " + string.Join(", ", array) + ". Remove the conflict and restart.")); conflictReported = true; } return true; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = instructions.ToList(); try { if (Instance.HasOtherPatches()) { return list; } if (!BlockPatch.TryRewrite(list, out var output, out var reason)) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)("Disabled: " + reason + ". Incoming method instructions left unchanged.")); return list; } ((BaseUnityPlugin)Instance).Logger.LogInfo((object)"Verified BlockAttack patch installed for Valheim 1.0.16; local player only. Live gameplay/crossplay validation is still required."); return output; } catch (Exception ex) { ((BaseUnityPlugin)Instance).Logger.LogError((object)("Disabled: patch validation failed; incoming instructions left unchanged. " + ex)); return list; } } internal static bool ShouldRejectForStagger(bool staggered, Humanoid defender) { if (!staggered) { return false; } try { ReliableBlockPlugin instance = Instance; return (Object)(object)instance == (Object)null || !instance.modEnabled.Value || !(defender is Player) || (object)defender != Player.m_localPlayer || !((Character)defender).IsOwner() || ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated()) || instance.HasOtherPatches(); } catch { return true; } } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } if (Instance == this) { Instance = null; } } } internal static class BlockPatch { internal static bool TryRewrite(IReadOnlyList<CodeInstruction> input, out List<CodeInstruction> output, out string reason) { //IL_052e: Unknown result type (might be due to invalid IL or missing references) //IL_0534: Expected O, but got Unknown //IL_053d: Unknown result type (might be due to invalid IL or missing references) //IL_0543: Expected O, but got Unknown output = input.ToList(); reason = "expected unique stagger/stamina/mitigation sequence was not found"; int[] array = (from i in Enumerable.Range(0, input.Count) where Calls(input[i], typeof(Character), "AddStaggerDamage") select i).ToArray(); int[] array2 = (from i in Enumerable.Range(0, input.Count) where Calls(input[i], typeof(HitData), "BlockDamage") select i).ToArray(); if (array.Length != 1 || array2.Length != 1) { return false; } int num = array[0]; if (num + 21 >= input.Count || array2[0] != num + 21) { return false; } if (Local(input[num + 1], load: false) < 0 || input[num + 2].opcode != OpCodes.Ldarg_0 || input[num + 3].opcode != OpCodes.Ldc_R4 || !object.Equals(input[num + 3].operand, 0f) || !Calls(input[num + 4], typeof(Character), "HaveStamina") || input[num + 5].opcode != OpCodes.Dup || !Branch(input[num + 6], whenTrue: false) || Local(input[num + 7], load: true) != Local(input[num + 1], load: false) || input[num + 8].opcode != OpCodes.Ldc_I4_0 || input[num + 9].opcode != OpCodes.Ceq || (!(input[num + 10].opcode == OpCodes.Br) && !(input[num + 10].opcode == OpCodes.Br_S)) || input[num + 11].opcode != OpCodes.Ldc_I4_0 || Local(input[num + 12], load: false) < 0 || Local(input[num + 12], load: false) == Local(input[num + 1], load: false) || !Branch(input[num + 13], whenTrue: false) || Local(input[num + 14], load: true) != Local(input[num + 1], load: false) || !Branch(input[num + 15], whenTrue: true) || Destination(input[num + 13], input) != Destination(input[num + 15], input) || !Targets(input[num + 6], input[num + 11]) || !Targets(input[num + 10], input[num + 12]) || input[num + 16].opcode != OpCodes.Ldarg_1 || input[num + 17].opcode != OpCodes.Ldc_I4_0 || input[num + 18].opcode != OpCodes.Stfld || !(input[num + 18].operand is FieldInfo fieldInfo) || fieldInfo.DeclaringType != typeof(HitData) || fieldInfo.Name != "m_statusEffectHash" || input[num + 19].opcode != OpCodes.Ldarg_1 || Local(input[num + 20], load: true) < 0) { return false; } if (!TargetsAfter(input[num + 15], input, num + 21)) { return false; } if (input.Skip(num).Take(22).Any((CodeInstruction i) => i.blocks.Count != 0) || input[num + 15].labels.Count != 0) { return false; } MethodInfo method = typeof(ReliableBlockPlugin).GetMethod("ShouldRejectForStagger", BindingFlags.Static | BindingFlags.NonPublic); if (method == null) { return false; } output.InsertRange(num + 15, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)method) }); reason = "verified"; return true; } private static bool Calls(CodeInstruction code, Type owner, string name) { if ((code.opcode == OpCodes.Call || code.opcode == OpCodes.Callvirt) && code.operand is MethodInfo methodInfo && methodInfo.DeclaringType == owner) { return methodInfo.Name == name; } return false; } private static bool Branch(CodeInstruction code, bool whenTrue) { if (!whenTrue) { if (!(code.opcode == OpCodes.Brfalse)) { return code.opcode == OpCodes.Brfalse_S; } return true; } if (!(code.opcode == OpCodes.Brtrue)) { return code.opcode == OpCodes.Brtrue_S; } return true; } private static bool Targets(CodeInstruction branch, CodeInstruction destination) { if (branch.operand is Label item) { return destination.labels.Contains(item); } return false; } private static bool TargetsAfter(CodeInstruction branch, IReadOnlyList<CodeInstruction> codes, int after) { return Destination(branch, codes) > after; } private static int Destination(CodeInstruction branch, IReadOnlyList<CodeInstruction> codes) { object operand = branch.operand; if (operand is Label) { Label label = (Label)operand; int[] array = (from i in Enumerable.Range(0, codes.Count) where codes[i].labels.Contains(label) select i).ToArray(); if (array.Length != 1) { return -1; } return array[0]; } return -1; } private static int Local(CodeInstruction code, bool load) { OpCode opcode = code.opcode; if (opcode == (load ? OpCodes.Ldloc_0 : OpCodes.Stloc_0)) { return 0; } if (opcode == (load ? OpCodes.Ldloc_1 : OpCodes.Stloc_1)) { return 1; } if (opcode == (load ? OpCodes.Ldloc_2 : OpCodes.Stloc_2)) { return 2; } if (opcode == (load ? OpCodes.Ldloc_3 : OpCodes.Stloc_3)) { return 3; } if (opcode != (load ? OpCodes.Ldloc : OpCodes.Stloc) && opcode != (load ? OpCodes.Ldloc_S : OpCodes.Stloc_S)) { return -1; } if (!(code.operand is LocalBuilder localBuilder)) { object operand = code.operand; if (operand is int) { return (int)operand; } operand = code.operand; if (operand is byte) { return (byte)operand; } operand = code.operand; if (operand is short) { return (short)operand; } return -1; } return localBuilder.LocalIndex; } } internal static class Compatibility { internal const string SupportedBlockAttackSha256 = "11166b4c192cb90da4d05a27153b89972408bea4a4c4cf92d178e0db698ca80c"; internal static bool IsSupported(byte[] bytes) { if (bytes == null || bytes.Length == 0) { return false; } using SHA256 sHA = SHA256.Create(); return BitConverter.ToString(sHA.ComputeHash(bytes)).Replace("-", "").ToLowerInvariant() == "11166b4c192cb90da4d05a27153b89972408bea4a4c4cf92d178e0db698ca80c"; } } }