示例#1
0
        public static void PatchBlazingDoTDamage()
        {
            if (!BalanceMod.BlazingDoTFixEnabled.Value)
            {
                return;
            }
            IL.RoR2.GlobalEventManager.OnHitEnemy += (il) =>
            {
                // DevUtilsMonoMod.GenerateToLogInstructionFilterCodeFromIndex(il.Body.Instructions.ToList(), 184, 23);
                var igniteCodeBlock = new List <InstructionFilter>
                {
                    new InstructionFilter(OpCodes.Ldc_I4_S, "System.SByte", "27"),
                    new InstructionFilter(OpCodes.Callvirt, "Mono.Cecil.MethodReference", "System.Boolean RoR2.CharacterBody::HasBuff(RoR2.BuffIndex)"),
                    new InstructionFilter(OpCodes.Brtrue_S, "MonoMod.Cil.ILLabel", "MonoMod.Cil.ILLabel"),
                    new InstructionFilter(OpCodes.Ldc_I4_0, "null"),
                    new InstructionFilter(OpCodes.Br_S, "MonoMod.Cil.ILLabel", "MonoMod.Cil.ILLabel"),
                    new InstructionFilter(OpCodes.Ldc_I4_1, "null"),
                    new InstructionFilter(OpCodes.Ldc_I4_0, "null"),
                    new InstructionFilter(OpCodes.Bgt_S, "MonoMod.Cil.ILLabel", "MonoMod.Cil.ILLabel"),
                    new InstructionFilter(OpCodes.Ldarg_1, "null"),
                    new InstructionFilter(OpCodes.Ldfld, "Mono.Cecil.FieldReference", "RoR2.DamageType RoR2.DamageInfo::damageType"),
                    new InstructionFilter(OpCodes.Ldc_I4, "System.Int32", "128"),
                    new InstructionFilter(OpCodes.And, "null"),
                    new InstructionFilter(OpCodes.Brfalse_S, "MonoMod.Cil.ILLabel", "MonoMod.Cil.ILLabel"),
                    new InstructionFilter(OpCodes.Ldarg_2, "null"),
                    new InstructionFilter(OpCodes.Ldarg_1, "null"),
                    new InstructionFilter(OpCodes.Ldfld, "Mono.Cecil.FieldReference", "UnityEngine.GameObject RoR2.DamageInfo::attacker"),
                    new InstructionFilter(OpCodes.Ldc_I4_1, "null"),
                    new InstructionFilter(OpCodes.Ldc_R4, "System.Single", "4"),
                    new InstructionFilter(OpCodes.Ldarg_1, "null"),
                    new InstructionFilter(OpCodes.Ldfld, "Mono.Cecil.FieldReference", "System.Single RoR2.DamageInfo::procCoefficient"),
                    new InstructionFilter(OpCodes.Mul, "null"),
                    new InstructionFilter(OpCodes.Ldc_R4, "System.Single", "1"),
                    new InstructionFilter(OpCodes.Call, "Mono.Cecil.MethodReference", "System.Void RoR2.DotController::InflictDot(UnityEngine.GameObject,UnityEngine.GameObject,RoR2.DotController/DotIndex,System.Single,System.Single)"),
                };
                var matchingLocations = DevUtilsMonoMod.FindCodeBlockIndexes(il.Body.Instructions.ToList(), igniteCodeBlock); // 184

                if (matchingLocations.Count != 1)
                {
                    if (matchingLocations.Count == 0)
                    {
                        BalanceMod.Logger.LogError($"BlazingDoTFix not loaded - found no matches.");
                    }
                    if (matchingLocations.Count > 1)
                    {
                        BalanceMod.Logger.LogError($"BlazingDoTFix not loaded - found multiple matches. Line numbers follow:");
                        BalanceMod.Logger.LogError(string.Join(", ", matchingLocations));
                    }
                }
                else
                {
                    //This is the location of the DotController::InflictDot call
                    //We will change this to the patched InflictDotModBurnDamageFix
                    var burnDmgFixStartIdx  = matchingLocations[0];
                    var burnDmgFixInsertIdx = burnDmgFixStartIdx + igniteCodeBlock.Count - 1;

                    //This method takes an additional parameter of the damage dealt by the hit
                    il.Body.Instructions.Insert(burnDmgFixInsertIdx, Instruction.Create(OpCodes.Ldarg_1));
                    il.Body.Instructions.Insert(burnDmgFixInsertIdx + 1, Instruction.Create(OpCodes.Ldfld,
                                                                                            il.Method.Module.ImportReference(typeof(DamageInfo).GetField("damage"))));

                    //Now overwrite the call
                    il.Body.Instructions[burnDmgFixInsertIdx + 2] = Instruction.Create(OpCodes.Call,
                                                                                       il.Method.Module.ImportReference(typeof(DotController).GetMethod("InflictDotModBurnDamageFix")));
                    BalanceMod.Logger.Log(LogLevel.Info, $"Patched: BlazingDoTFix loaded @ line {burnDmgFixStartIdx}.");
                }
            };
        }
示例#2
0
        public static void PatchWakeOfVultures()
        {
            if (!BalanceMod.WakeOfVulturesFixEnabled.Value)
            {
                return;
            }
            IL.RoR2.CharacterBody.RecalculateStats += (il) =>
            {
                // DevUtilsMonoMod.GenerateToLogInstructionFilterCodeFromIndex(il.Body.Instructions.ToList(), 256, 15);
                // DevUtilsMonoMod.GenerateToLogInstructionFilterCodeFromIndex(il.Body.Instructions.ToList(), 358, 9);
                var IfBlueAffix_HalveMaxHealth_CodeBlock = new List <InstructionFilter>
                {
                    new InstructionFilter(OpCodes.Ldarg_0, "null"),
                    new InstructionFilter(OpCodes.Ldc_I4_S, "System.SByte", "28"),
                    new InstructionFilter(OpCodes.Callvirt, "Mono.Cecil.MethodReference", "System.Boolean RoR2.CharacterBody::HasBuff(RoR2.BuffIndex)"),
                    new InstructionFilter(OpCodes.Brfalse_S, "MonoMod.Cil.ILLabel", "MonoMod.Cil.ILLabel"),
                    new InstructionFilter(OpCodes.Ldloc_S, "Mono.Cecil.Cil.VariableDefinition", "V_27"),
                    new InstructionFilter(OpCodes.Ldc_R4, "System.Single", "0.5"),
                    new InstructionFilter(OpCodes.Mul, "null"),
                    new InstructionFilter(OpCodes.Stloc_S, "Mono.Cecil.Cil.VariableDefinition", "V_27"),
                    new InstructionFilter(OpCodes.Ldloc_S, "Mono.Cecil.Cil.VariableDefinition", "V_27"),
                    new InstructionFilter(OpCodes.Ldloc_S, "Mono.Cecil.Cil.VariableDefinition", "V_23"),
                    new InstructionFilter(OpCodes.Div, "null"),
                    new InstructionFilter(OpCodes.Stloc_S, "Mono.Cecil.Cil.VariableDefinition", "V_27"),
                    new InstructionFilter(OpCodes.Ldarg_0, "null"),
                    new InstructionFilter(OpCodes.Ldloc_S, "Mono.Cecil.Cil.VariableDefinition", "V_27"),
                    new InstructionFilter(OpCodes.Callvirt, "Mono.Cecil.MethodReference", "System.Void RoR2.CharacterBody::set_maxHealth(System.Single)"),
                };
                var matchingLocations = DevUtilsMonoMod.FindCodeBlockIndexes(il.Body.Instructions.ToList(), IfBlueAffix_HalveMaxHealth_CodeBlock);
                if (matchingLocations.Count != 1)
                {
                    if (matchingLocations.Count == 0)
                    {
                        BalanceMod.Logger.LogError($"WakeofVultures1 not loaded - found no matches.");
                    }
                    if (matchingLocations.Count > 1)
                    {
                        BalanceMod.Logger.LogError($"WakeofVultures1 not loaded - found multiple matches. Line numbers follow:");
                        BalanceMod.Logger.LogError(string.Join(", ", matchingLocations));
                    }
                    return;
                }
                var wakeOfVultures_halfHealthIndex = matchingLocations[0];
                il.Body.Instructions.RemoveAt(wakeOfVultures_halfHealthIndex + 1);                          // remove the unnecessary BuffIndex parameter
                il.Body.Instructions[wakeOfVultures_halfHealthIndex + 1] = Instruction.Create(OpCodes.Call, //call to custom func IsBlueElite() instead
                                                                                              il.Method.Module.ImportReference(typeof(Hooks).GetMethod("IsBlueElite")));

                var IfBlueAffix_GainShield_CodeBlock = new List <InstructionFilter>
                {
                    new InstructionFilter(OpCodes.Ldarg_0, "null"),
                    new InstructionFilter(OpCodes.Ldc_I4_S, "System.SByte", "28"),
                    new InstructionFilter(OpCodes.Callvirt, "Mono.Cecil.MethodReference", "System.Boolean RoR2.CharacterBody::HasBuff(RoR2.BuffIndex)"),
                    new InstructionFilter(OpCodes.Brfalse_S, "MonoMod.Cil.ILLabel", "MonoMod.Cil.ILLabel"),
                    new InstructionFilter(OpCodes.Ldloc_S, "Mono.Cecil.Cil.VariableDefinition", "V_30"),
                    new InstructionFilter(OpCodes.Ldarg_0, "null"),
                    new InstructionFilter(OpCodes.Callvirt, "Mono.Cecil.MethodReference", "System.Single RoR2.CharacterBody::get_maxHealth()"),
                    new InstructionFilter(OpCodes.Add, "null"),
                    new InstructionFilter(OpCodes.Stloc_S, "Mono.Cecil.Cil.VariableDefinition", "V_30"),
                };
                matchingLocations = DevUtilsMonoMod.FindCodeBlockIndexes(il.Body.Instructions.ToList(), IfBlueAffix_GainShield_CodeBlock, wakeOfVultures_halfHealthIndex);
                if (matchingLocations.Count != 1)
                {
                    if (matchingLocations.Count == 0)
                    {
                        BalanceMod.Logger.LogError($"WakeofVultures2 not loaded - found no matches.");
                    }
                    if (matchingLocations.Count > 1)
                    {
                        BalanceMod.Logger.LogError($"WakeofVultures2 not loaded - found multiple matches. Line numbers follow:");
                        BalanceMod.Logger.LogError(string.Join(", ", matchingLocations));
                    }
                    return;
                }

                //The next fix is injected in the middle of the found block. Commented lines indicate existing unmodified instructions
                var wakeOfVultures_gainShieldIndex = matchingLocations[0];
                var idx          = wakeOfVultures_gainShieldIndex + 7;
                var skipMulLabel = il.Body.Instructions[idx];
                // Ldarg_0, "null"
                // Ldc_I4_S, "System.SByte", "28"
                // Callvirt, "Mono.Cecil.MethodReference", "System.Boolean RoR2.CharacterBody::HasBuff(RoR2.BuffIndex)"
                // Brfalse_S
                // Ldloc_S, "Mono.Cecil.Cil.VariableDefinition", "V_30"
                // Ldarg_0
                // Callvirt, "Mono.Cecil.MethodReference", "System.Single RoR2.CharacterBody::get_maxHealth()"

                var c = new ILCursor(il).Goto(idx);
                c.Emit(OpCodes.Ldarg_0);
                c.Emit(OpCodes.Call, il.Import(typeof(CharacterBody).GetMethod("get_inventory")));
                c.Emit(OpCodes.Ldc_I4_S, (System.SByte)ItemIndex.HeadHunter);
                c.Emit(OpCodes.Callvirt, il.Import(typeof(Inventory).GetMethod("GetItemCount")));
                c.Emit(OpCodes.Ldc_I4_0);
                c.Emit(OpCodes.Ble_S, skipMulLabel);
                c.Emit(OpCodes.Ldc_R4, 0.5f);
                c.Emit(OpCodes.Mul);

                // Add (label: skipMulLabel)
                // Stloc_S, "Mono.Cecil.Cil.VariableDefinition", "V_30"),

                BalanceMod.Logger.LogInfo($"Patched: Wake of Vultures @ lines {wakeOfVultures_halfHealthIndex}, {wakeOfVultures_gainShieldIndex}");
            };
        }
示例#3
0
        public static void PatchGestureOfTheDrowned()
        {
            if (!BalanceMod.GestureOfTheDrownedFixEnabled.Value)
            {
                return;
            }
            IL.RoR2.Inventory.SetEquipmentIndex += (il) =>
            {
                // DevUtilsMonoMod.GenerateToLogInstructionFilterCodeFromIndex(il.Body.Instructions.ToList(), 19);
                var setNewEquipmentStateBlock = new List <InstructionFilter>()
                {
                    //new InstructionFilter(OpCodes.Bne_Un_S, "MonoMod.Cil.ILLabel", "MonoMod.Cil.ILLabel"), //this branches to 22
                    //new InstructionFilter(OpCodes.Ldc_I4_1, "null"),
                    //new InstructionFilter(OpCodes.Stloc_1, "null"),
                    new InstructionFilter(OpCodes.Ldloca_S, "Mono.Cecil.Cil.VariableDefinition", "V_2"),
                    new InstructionFilter(OpCodes.Ldarg_1, "null"),
                    new InstructionFilter(OpCodes.Ldloc_0, "null"),
                    new InstructionFilter(OpCodes.Ldfld, "Mono.Cecil.FieldReference", "RoR2.Run/FixedTimeStamp RoR2.EquipmentState::chargeFinishTime"),
                    new InstructionFilter(OpCodes.Ldloc_1, "null"),
                    new InstructionFilter(OpCodes.Call, "Mono.Cecil.MethodReference", "System.Void RoR2.EquipmentState::.ctor(RoR2.EquipmentIndex,RoR2.Run/FixedTimeStamp,System.Byte)"),
                    new InstructionFilter(OpCodes.Ldarg_0, "null"),
                    new InstructionFilter(OpCodes.Ldloc_2, "null"),
                    new InstructionFilter(OpCodes.Ldarg_0, "null"),
                    new InstructionFilter(OpCodes.Callvirt, "Mono.Cecil.MethodReference", "System.Byte RoR2.Inventory::get_activeEquipmentSlot()"),
                    new InstructionFilter(OpCodes.Callvirt, "Mono.Cecil.MethodReference", "System.Void RoR2.Inventory::SetEquipment(RoR2.EquipmentState,System.UInt32)"),
                    new InstructionFilter(OpCodes.Ret, "null"),
                };
                var matchingLocations = DevUtilsMonoMod.FindCodeBlockIndexes(il.Body.Instructions.ToList(), setNewEquipmentStateBlock);

                if (matchingLocations.Count != 1)
                {
                    if (matchingLocations.Count == 0)
                    {
                        BalanceMod.Logger.LogError($"GestureOfTheDrownedFix not loaded - found no matches.");
                    }
                    if (matchingLocations.Count > 1)
                    {
                        BalanceMod.Logger.LogError($"GestureOfTheDrownedFix not loaded - found multiple matches. Line numbers follow:");
                        BalanceMod.Logger.LogError(string.Join(", ", matchingLocations));
                    }
                }
                else
                {
                    var chargeFinishTimeField = AccessTools.Field(typeof(RoR2.EquipmentState), "chargeFinishTime");
                    var equipmentStateCtor    = AccessTools.Constructor(typeof(RoR2.EquipmentState), new Type[]
                    {
                        typeof(EquipmentIndex),
                        typeof(Run.FixedTimeStamp),
                        typeof(byte)
                    });
                    var getActiveEquipmentSlotMethod = AccessTools.Method(typeof(RoR2.Inventory), "get_activeEquipmentSlot");
                    var setEquipmentMethod           = AccessTools.Method(typeof(RoR2.Inventory), "SetEquipment");

                    var gestureStartIdx = matchingLocations[0]; // == 22
                    var c = new ILCursor(il).Goto(gestureStartIdx);
                    /*22*/ c.Emit(OpCodes.Ldloc_0);
                    c.GotoNext();
                    c.IncomingLabels.First().Target = c.Previous;
                    c.RemoveRange(8);
                    /*23*/ c.Emit(OpCodes.Ldfld, chargeFinishTimeField);
                    /*24*/ c.Emit(OpCodes.Stloc_2);
                    /*25*/ c.Emit(OpCodes.Ldloca_S, (byte)2);
                    /*26*/ c.Emit(OpCodes.Call, AccessTools.Method(typeof(RoR2.Run.FixedTimeStamp), "get_isNegativeInfinity"));
                    /*27*///c.Emit(OpCodes.Brfalse_S); //come back later and set this jump label
                    /*28*/ c.Emit(OpCodes.Ldarg_0);
                    /*29*/ c.Emit(OpCodes.Ldarg_1);
                    /*30*/ c.Emit(OpCodes.Ldsfld, AccessTools.Field(typeof(RoR2.Run.FixedTimeStamp), "positiveInfinity"));
                    /*31*/ c.Emit(OpCodes.Ldloc_1);
                    /*32*/ c.Emit(OpCodes.Newobj, equipmentStateCtor);
                    /*33*/ c.Emit(OpCodes.Ldarg_0);
                    /*34*/ c.Emit(OpCodes.Call, getActiveEquipmentSlotMethod);
                    /*35*/ c.Emit(OpCodes.Call, setEquipmentMethod);
                    /*36*/ c.Emit(OpCodes.Ret);
                    /*37*/ c.Emit(OpCodes.Ldarg_0); var brkInst = c.Previous;
                    /*38*/ c.Emit(OpCodes.Ldarg_1);
                    /*39*/ c.Emit(OpCodes.Ldloc_0);
                    /*40*/ c.Emit(OpCodes.Ldfld, chargeFinishTimeField);
                    /*41*/ c.Emit(OpCodes.Ldloc_1);
                    /*42*/ c.Emit(OpCodes.Newobj, equipmentStateCtor);
                    // c.Emit(OpCodes.Ldarg_0);
                    // call Inventory.get_ActiveEquipmentSlot()
                    // call Inventory.SetEquipment()
                    // ret

                    il.Body.Instructions.Insert(27, Instruction.Create(OpCodes.Brfalse_S, brkInst));
                    il.Body.Variables[2].VariableType = il.Import(typeof(RoR2.Run.FixedTimeStamp));
                    BalanceMod.Logger.LogInfo($"Patched: GestureOfTheDrownedFix loaded @ line {gestureStartIdx}.");
                }
            };

            /* Following is debug output used to diagnose where the bug was coming from */
            //bool ranOnce = false;
            //bool ranTwice = false;
            //On.RoR2.Inventory.UpdateEquipment += (orig, self) =>
            //{
            //    if(self.GetEquipmentSlotCount() > 0 && !ranTwice)
            //    {
            //        if(ranOnce)
            //        {
            //            ranTwice = true;
            //        }
            //        ranOnce = true;
            //        var equip = self.GetEquipment(0);
            //        //0 charges, isNegativeInfinity
            //        Debug.Log($"{equip.charges} {equip.chargeFinishTime.isNegativeInfinity} {equip.chargeFinishTime.isPositiveInfinity}");

            //        //when walking over
            //        //first run, 1 isNegativeInfinity
            //        //second run, 0 isPositiveInfinity

            //        //when picking up with E
            //        //first run, 0 isNegativeInfinity
            //        //second run, 0 isNegativeInfinity
            //    }
            //    orig(self);
            //};

            //On.RoR2.Inventory.SetEquipmentIndex += (orig, self, index) =>
            //{
            //    var oldEquip = self.GetEquipment(0u);
            //    //old charges 0
            //    //chargeFinishTime isNegativeInfinity
            //    Debug.Log($"{oldEquip.chargeFinishTime.isInfinity} {oldEquip.chargeFinishTime.isNegativeInfinity} {oldEquip.chargeFinishTime.isPositiveInfinity}");
            //    orig(self, index);
            //    var newEquip = self.GetEquipment(0u);
            //    //new charges 1
            //    //chargeFinishTime isNegativeInfinity
            //    Debug.Log($"{newEquip.chargeFinishTime.isInfinity} {newEquip.chargeFinishTime.isNegativeInfinity} {newEquip.chargeFinishTime.isPositiveInfinity}");
            //};

            //stock was 1, this was called repeatedly
            //On.RoR2.EquipmentSlot.Execute += (orig, self) =>
            //{
            //    Debug.Log($"this.stock: {self.stock}");
            //    orig(self);
            //};

            //On.RoR2.Inventory.FixedUpdate += (orig, self) =>
            //{
            //    if (self.GetEquipmentSlotCount() > 0)
            //    {
            //        EquipmentState[] equipmentStates = ((EquipmentState[])AccessTools.Field(AccessTools.TypeByName("RoR2.Inventory"), "equipmentStateSlots").GetValue(self));
            //        if (equipmentStates.Length > 0)
            //        {
            //            var equipmentState = equipmentStates[0];
            //            Debug.Log($"charges {equipmentState.charges} finish {equipmentState.chargeFinishTime.ToString()} pos {equipmentState.chargeFinishTime.isPositiveInfinity} neg {equipmentState.chargeFinishTime.isNegativeInfinity}");
            //        }
            //    }
            //    orig(self);
            //};
            //when you go from empty slot -> first equipment, charges = 1 and ispositiveinfinity = false
            //On.RoR2.EquipmentSlot.FixedUpdate += (orig, self) =>
            //{
            //    Debug.Log("FixedUpdate");
            //    orig(self);
            //};
        }