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 RaskatAilments v1.1.0
BepInEx/plugins/RaskatAilments.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Logging; using HarmonyLib; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace Raskat.Ailments; [BepInPlugin("raskat.ailments", "RASKAT Ailments", "1.1.0")] [BepInDependency("treextr.pathofvalheiman", "0.0.0")] public sealed class RaskatAilments : BaseUnityPlugin { internal static ManualLogSource Log; internal static float ReferenceDamage; internal static float PerHitCap; internal static float HoldSeconds; internal static float DecayPerSecond; internal static float FireProcDamageMultiplier; internal static float PoisonProcDamageMultiplier; private const BindingFlags AllStatic = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private Harmony harmony; private void Awake() { //IL_0436: Unknown result type (might be due to invalid IL or missing references) //IL_0440: Expected O, but got Unknown //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_0470: Expected O, but got Unknown //IL_049e: Unknown result type (might be due to invalid IL or missing references) //IL_04aa: Expected O, but got Unknown //IL_04d8: Unknown result type (might be due to invalid IL or missing references) //IL_04e4: Expected O, but got Unknown //IL_0511: Unknown result type (might be due to invalid IL or missing references) //IL_051e: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; bool value = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable RASKAT ailment buildup patch. Requires an original PathOfValheiman.dll.").Value; ReferenceDamage = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "ReferenceDamage", 60f, "Buildup = PerHitCap * elementalDamage / (elementalDamage + ReferenceDamage), before the tree bonus.").Value; PerHitCap = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "PerHitCap", 0.4f, "Maximum buildup from a very large hit, before the tree bonus.").Value; HoldSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "HoldSeconds", 6.5f, "Time since the last hit before an ailment gauge starts to decay.").Value; DecayPerSecond = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "DecayPerSecond", 0.175f, "Gauge fraction lost per second after the hold period.").Value; FireProcDamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "FireProcDamageMultiplier", 0.6f, "Multiply the accumulated fire damage passed to Path of Valheiman when Ignite triggers; direct hits unchanged.").Value; PoisonProcDamageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Balance", "PoisonProcDamageMultiplier", 0.6f, "Multiply the accumulated poison damage passed to Path of Valheiman when Poison triggers; direct hits unchanged.").Value; if (!value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Disabled by configuration."); return; } if (!(ReferenceDamage > 0f) || !(ReferenceDamage <= 10000f) || !(PerHitCap > 0f) || !(PerHitCap <= 1f) || !(HoldSeconds >= 0f) || !(HoldSeconds <= 120f) || !(DecayPerSecond > 0f) || !(DecayPerSecond <= 1f) || !(FireProcDamageMultiplier >= 0f) || !(FireProcDamageMultiplier <= 1f) || !(PoisonProcDamageMultiplier >= 0f) || !(PoisonProcDamageMultiplier <= 1f)) { ((BaseUnityPlugin)this).Logger.LogError((object)"Invalid balance settings; no methods patched."); return; } try { Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "PathOfValheiman"); if (assembly == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"PathOfValheiman.dll is not loaded; patch disabled."); return; } Type type = assembly.GetType("PassiveTree.Ailments"); Type type2 = assembly.GetType("PassiveTree.AilmentGauges"); if (type == null || type2 == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Ailment types changed; patch disabled."); return; } MethodInfo method = GetMethod(type, "Grip", typeof(float), 3); MethodInfo method2 = GetMethod(type2, "Melt", typeof(void), 2); MethodInfo method3 = GetMethod(type2, "Shown", typeof(float), 2); MethodInfo method4 = GetMethod(type2, "Feed", typeof(float), 4); if (method == null || method2 == null || method3 == null || method4 == null || method.GetParameters()[0].ParameterType != typeof(float) || method.GetParameters()[2].ParameterType != typeof(float) || !method4.GetParameters()[1].ParameterType.IsEnum || method4.GetParameters()[2].ParameterType != typeof(float) || method4.GetParameters()[3].ParameterType != typeof(float)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Ailment method signatures changed; patch disabled."); return; } if (!Patches.CheckGrip(ILReader.Read(method)) || !Patches.CheckDecay(ILReader.Read(method2), 2) || !Patches.CheckDecay(ILReader.Read(method3), 1) || !Patches.CheckFeed(method4)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Ailment formula changed (or the main DLL is already modified); patch disabled."); return; } harmony = new Harmony("raskat.ailments"); Type typeFromHandle = typeof(Patches); harmony.Patch((MethodBase)method, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle.GetMethod("Grip", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null); if (!Patches.GripApplied) { throw new InvalidOperationException("Grip transpiler refused the method"); } harmony.Patch((MethodBase)method2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle.GetMethod("Melt", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null); if (!Patches.MeltApplied) { throw new InvalidOperationException("Melt transpiler refused the method"); } harmony.Patch((MethodBase)method3, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle.GetMethod("Shown", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null); if (!Patches.ShownApplied) { throw new InvalidOperationException("Shown transpiler refused the method"); } harmony.Patch((MethodBase)method4, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle.GetMethod("FeedPostfix", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Concat("Active: PathOfValheiman ", assembly.GetName().Version, "; reference=", ReferenceDamage, ", cap=", PerHitCap, ", hold=", HoldSeconds, "s, decay=", DecayPerSecond, "/s, fire proc=", FireProcDamageMultiplier, ", poison proc=", PoisonProcDamageMultiplier, ".")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Ailment patch failed: " + ex)); if (harmony == null) { return; } try { MethodInfo method5 = typeof(Harmony).GetMethod("UnpatchSelf", Type.EmptyTypes); if (method5 != null) { method5.Invoke(harmony, null); return; } typeof(Harmony).GetMethod("UnpatchAll", new Type[1] { typeof(string) }).Invoke(harmony, new object[1] { "raskat.ailments" }); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogError((object)("Could not remove partial patch: " + ex2)); } } } private static MethodInfo GetMethod(Type type, string name, Type result, int parameterCount) { MethodInfo[] array = (from m in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where m.Name == name && m.ReturnType == result && m.GetParameters().Length == parameterCount select m).ToArray(); return (array.Length != 1) ? null : array[0]; } } internal static class Patches { internal static bool GripApplied; internal static bool MeltApplied; internal static bool ShownApplied; private static bool Float(CodeInstruction c, float value) { return c.opcode == OpCodes.Ldc_R4 && c.operand is float && (float)c.operand == value; } private static bool Call(CodeInstruction c) { return c.opcode == OpCodes.Call || c.opcode == OpCodes.Callvirt; } private static int GripIndex(IList<CodeInstruction> c) { int num = -1; for (int i = 0; i + 17 < c.Count; i++) { if (Float(c[i], 1f) && c[i + 1].opcode == OpCodes.Ldarg_1 && Call(c[i + 2]) && Call(c[i + 3]) && c[i + 4].opcode == OpCodes.Stloc_0 && c[i + 5].opcode == OpCodes.Ldarg_0 && c[i + 6].opcode == OpCodes.Ldloc_0 && c[i + 7].opcode == OpCodes.Div && Float(c[i + 8], 0.625f) && c[i + 9].opcode == OpCodes.Div && Float(c[i + 10], 1f) && Float(c[i + 11], 0f) && c[i + 12].opcode == OpCodes.Ldarg_2 && Call(c[i + 13]) && c[i + 14].opcode == OpCodes.Add && c[i + 15].opcode == OpCodes.Mul && Call(c[i + 16]) && c[i + 17].opcode == OpCodes.Ret) { if (num != -1) { return -1; } num = i; } } return num; } internal static bool CheckGrip(IList<CodeInstruction> c) { return GripIndex(c) >= 0; } internal static bool CheckDecay(IList<CodeInstruction> c, int expectedHolds) { int num = 0; int num2 = 0; for (int i = 0; i + 1 < c.Count; i++) { if (Float(c[i], 3f) && c[i + 1].opcode == OpCodes.Sub) { num++; } if (Float(c[i], 0.25f) && c[i + 1].opcode == OpCodes.Mul) { num2++; } } return num == expectedHolds && num2 == 1; } internal static bool CheckFeed(MethodInfo feed) { List<CodeInstruction> list = ILReader.Read(feed); if (list.Count((CodeInstruction c) => c.opcode == OpCodes.Ret) != 3 || !list.Any((CodeInstruction c) => Float(c, 1f)) || list.Count((CodeInstruction c) => c.opcode == OpCodes.Stelem_R4) < 3) { return false; } for (int num = 0; num + 2 < list.Count; num++) { if (!(list[num].opcode != OpCodes.Ldfld) && !(list[num + 1].opcode != OpCodes.Ldloc_2) && !(list[num + 2].opcode != OpCodes.Ldelem_R4)) { int? num2 = list[num].operand as int?; if (num2.HasValue && feed.Module.ResolveField(num2.Value).Name == "Stored") { return true; } } } return false; } internal static void FeedPostfix(object[] __args, ref float __result) { if (!(__result <= 0f) && __args != null && __args.Length == 4) { string text = __args[1].ToString(); if (text == "Ignite") { __result *= RaskatAilments.FireProcDamageMultiplier; } else if (text == "Poison") { __result *= RaskatAilments.PoisonProcDamageMultiplier; } } } internal static IEnumerable<CodeInstruction> Grip(IEnumerable<CodeInstruction> instructions) { //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Expected O, but got Unknown //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Expected O, but got Unknown List<CodeInstruction> list = instructions.Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction c) => new CodeInstruction(c))).ToList(); int num = GripIndex(list); if (num < 0 || list.Skip(num + 1).Take(9).Any((CodeInstruction c) => c.labels.Count > 0 || c.blocks.Count > 0)) { RaskatAilments.Log.LogError((object)"Grip IL changed; original method preserved."); return instructions; } list[num].opcode = OpCodes.Ldarg_0; list[num].operand = null; list.RemoveRange(num + 1, 9); list.InsertRange(num + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[6] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldc_R4, (object)RaskatAilments.ReferenceDamage), new CodeInstruction(OpCodes.Add, (object)null), new CodeInstruction(OpCodes.Div, (object)null), new CodeInstruction(OpCodes.Ldc_R4, (object)RaskatAilments.PerHitCap), new CodeInstruction(OpCodes.Mul, (object)null) }); GripApplied = true; return list; } internal static IEnumerable<CodeInstruction> Melt(IEnumerable<CodeInstruction> instructions) { return Decay(instructions, 2, "Melt"); } internal static IEnumerable<CodeInstruction> Shown(IEnumerable<CodeInstruction> instructions) { return Decay(instructions, 1, "Shown"); } private static IEnumerable<CodeInstruction> Decay(IEnumerable<CodeInstruction> instructions, int expectedHolds, string name) { List<CodeInstruction> list = instructions.Select((Func<CodeInstruction, CodeInstruction>)((CodeInstruction c) => new CodeInstruction(c))).ToList(); if (!CheckDecay(list, expectedHolds)) { RaskatAilments.Log.LogError((object)(name + " IL changed; original method preserved.")); return instructions; } for (int num = 0; num + 1 < list.Count; num++) { if (Float(list[num], 3f) && list[num + 1].opcode == OpCodes.Sub) { list[num].operand = RaskatAilments.HoldSeconds; } else if (Float(list[num], 0.25f) && list[num + 1].opcode == OpCodes.Mul) { list[num].operand = RaskatAilments.DecayPerSecond; } } if (name == "Melt") { MeltApplied = true; } else { ShownApplied = true; } return list; } } internal static class ILReader { private static readonly Dictionary<short, OpCode> Ops = BuildOps(); private static Dictionary<short, OpCode> BuildOps() { Dictionary<short, OpCode> dictionary = new Dictionary<short, OpCode>(); FieldInfo[] fields = typeof(OpCodes).GetFields(BindingFlags.Static | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.FieldType == typeof(OpCode)) { OpCode value = (OpCode)fieldInfo.GetValue(null); dictionary[value.Value] = value; } } return dictionary; } internal static List<CodeInstruction> Read(MethodInfo method) { //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Expected O, but got Unknown MethodBody methodBody = method.GetMethodBody(); if (methodBody == null) { throw new InvalidOperationException("Method has no IL: " + method.Name); } byte[] iLAsByteArray = methodBody.GetILAsByteArray(); List<CodeInstruction> list = new List<CodeInstruction>(); int num = 0; while (num < iLAsByteArray.Length) { short key = ((iLAsByteArray[num] != 254) ? iLAsByteArray[num] : ((short)(0xFE00 | iLAsByteArray[num + 1]))); num += ((iLAsByteArray[num] != 254) ? 1 : 2); if (!Ops.TryGetValue(key, out var value)) { throw new InvalidOperationException("Unknown IL opcode"); } object obj = null; switch (value.OperandType) { case OperandType.ShortInlineBrTarget: case OperandType.ShortInlineI: case OperandType.ShortInlineVar: obj = iLAsByteArray[num]; num++; break; case OperandType.InlineVar: obj = BitConverter.ToUInt16(iLAsByteArray, num); num += 2; break; case OperandType.ShortInlineR: obj = BitConverter.ToSingle(iLAsByteArray, num); num += 4; break; case OperandType.InlineR: obj = BitConverter.ToDouble(iLAsByteArray, num); num += 8; break; case OperandType.InlineBrTarget: case OperandType.InlineField: case OperandType.InlineI: case OperandType.InlineMethod: case OperandType.InlineSig: case OperandType.InlineString: case OperandType.InlineTok: case OperandType.InlineType: obj = BitConverter.ToInt32(iLAsByteArray, num); num += 4; break; case OperandType.InlineI8: obj = BitConverter.ToInt64(iLAsByteArray, num); num += 8; break; case OperandType.InlineSwitch: { int num2 = BitConverter.ToInt32(iLAsByteArray, num); if (num2 < 0 || num2 > 100000) { throw new InvalidOperationException("Invalid IL switch"); } num += 4 + 4 * num2; break; } default: throw new InvalidOperationException("Unsupported IL operand"); case OperandType.InlineNone: break; } list.Add(new CodeInstruction(value, obj)); } return list; } }