//Insert FilterForUrgentHediffs when counting needed medicine public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { MethodInfo SortByTendPriorityInfo = AccessTools.Method( typeof(TendUtility), nameof(TendUtility.SortByTendPriority)); MethodInfo filterMethodInfo = AccessTools.Method( typeof(GetMedicineCountToFullyHeal_Patch), nameof(FilterInjuriesForMedCount)); FieldInfo filterMethodParameter = AccessTools.Field(typeof(Medicine), "tendableHediffsInTendPriorityOrder"); List <CodeInstruction> instructionList = instructions.ToList(); for (int i = 0; i < instructionList.Count; i++) { CodeInstruction instruction = instructionList[i]; if (instruction.LoadsField(filterMethodParameter)) { i++; CodeInstruction nextInstruction = instructionList[i]; if (nextInstruction.Calls(SortByTendPriorityInfo)) { //insert before the sort call yield return(new CodeInstruction(OpCodes.Ldsfld, filterMethodParameter)); yield return(new CodeInstruction(OpCodes.Call, filterMethodInfo)); } yield return(instruction); yield return(nextInstruction); } else { yield return(instruction); } } }
public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { FieldInfo buildingInfo = AccessTools.Field(typeof(ThingDef), nameof(ThingDef.building)); List <CodeInstruction> instList = instructions.ToList(); for (int i = 0; i < instList.Count(); i++) { CodeInstruction inst = instList[i]; if (inst.LoadsField(buildingInfo)) { //IL_0015: ldarg.0 // this //IL_0016: ldfld class RimWorld.BuildingProperties Verse.ThingDef::building //replace the this.building code with the end return true: instList[i - 1].opcode = OpCodes.Ldc_I4_1; //preserve label here instList[i] = new CodeInstruction(OpCodes.Ret); //chop off rest of the code that checks rock and smooth ezpz, we can corner touch rocks now! return(instList.Take(i + 1)); } } Verse.Log.Warning("Replace Stuff failed to patch CanInteractThroughCorners"); return(instructions); }
public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { // public static void BeginGroup(Rect position); MethodInfo BeginGroupInfo = AccessTools.Method(typeof(GUI), nameof(GUI.BeginGroup), new Type[] { typeof(Rect) }); //class Verse.ThingFilter RimWorld.StorageSettings::'filter' FieldInfo filterInfo = AccessTools.Field(typeof(StorageSettings), "filter"); int count = 0; bool firstTopAreaHeight = true; List <CodeInstruction> instList = instructions.ToList(); for (int i = 0; i < instList.Count; i++) { CodeInstruction inst = instList[i]; //replace // settings.filter //with // RankComp.GetFilter(settings.filter, FillTab.curRank) //but there's another .filter that is Parent filter so check for .settings //IL_01f0: ldfld class RimWorld.StorageSettings RimWorld.ITab_Storage/'<>c__DisplayClass12_0'::settings //IL_01f5: ldfld class Verse.ThingFilter RimWorld.StorageSettings::'filter' //What why the ITab_Storage.\u003C\u003Ec__DisplayClass12_0 really //Soo I guess just skip it for the first call to filter in the method if (inst.LoadsField(filterInfo) && count++ > 0) { //instead of settings.filter, do RankComp.GetFilter(settings, curRank) yield return(new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(FillTab), "curRank"))); yield return(new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(RankComp), "GetFilter"))); } else { yield return(inst); } if (firstTopAreaHeight && inst.Calls(GetTopAreaHeight)) { firstTopAreaHeight = false; yield return(new CodeInstruction(OpCodes.Ldc_R4, TopAreaHeight.rankHeight)); yield return(new CodeInstruction(OpCodes.Sub)); } if (inst.Calls(BeginGroupInfo)) { yield return(new CodeInstruction(OpCodes.Ldarg_0)); //ITab_Storage this yield return(new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(FillTab), nameof(DrawRanking)))); } } }
//AllowsPlacing(BuildableDef checkingDef, IntVec3 loc, Rot4 rot, Map map, Thing thingToIgnore = null) public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { FieldInfo entityDefInfo = AccessTools.Field(typeof(ThingDef), "entityDefToBuild"); //need to find loop continue label object continueLabel = null; //just easier to find the 3-line code to get thingList[i] bool foundLdLoc = false; List <CodeInstruction> currentThing = new List <CodeInstruction>(); List <CodeInstruction> iList = instructions.ToList(); for (int k = 0; k < iList.Count(); k++) { CodeInstruction i = iList[k]; if (!foundLdLoc && i.opcode == OpCodes.Ldloc_0) { foundLdLoc = true; currentThing.AddRange(iList.GetRange(k, 3)); } if (i.LoadsField(entityDefInfo)) { continueLabel = iList[k + 1].operand; break; } } foundLdLoc = false; foreach (CodeInstruction i in instructions) { if (!foundLdLoc && i.opcode == OpCodes.Ldloc_0) { foundLdLoc = true; yield return(new CodeInstruction(OpCodes.Nop) { labels = i.labels }); //start of loop label i.labels = new List <Label>(); foreach (CodeInstruction ci in currentThing) { yield return(new CodeInstruction(ci.opcode, ci.operand)); //thingList[i] } yield return(new CodeInstruction(OpCodes.Ldarg_S, 5)); //thingToIgnore yield return(new CodeInstruction(OpCodes.Beq, continueLabel)); //continue } yield return(i); } }
public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { var codes = new List <CodeInstruction>(instructions); for (int i = 0; i < codes.Count; ++i) { CodeInstruction inst = codes[i]; if (inst.LoadsField(f_ToolTier)) { codes[i - 1] = new CodeInstruction(OpCodes.Call, m_GetToolTier); codes[i].opcode = OpCodes.Nop; break; } else if (inst.LoadsField(f_MiningSpeed)) { codes[i - 1] = new CodeInstruction(OpCodes.Ldarg_3); codes[i] = new CodeInstruction(OpCodes.Call, m_GetMiningSpeed); } } return(codes.AsEnumerable()); }
public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator generator) { FieldInfo allowOpportunisticPrefix_Field = AccessTools.Field(typeof(JobDef), "allowOpportunisticPrefix"); List <CodeInstruction> instuctionList = instructions.ToList(); for (int i = 0; i < instuctionList.Count; i++) { CodeInstruction instruction = instuctionList[i]; if (instruction.LoadsField(allowOpportunisticPrefix_Field)) { while (!instuctionList[i].IsLdarg(1)) { i--; } // i -= 2; Label brLabel = generator.DefineLabel(); Label oldLabel = instuctionList[i].labels.First(); LocalBuilder localVar = generator.DeclareLocal(typeof(Job)); instuctionList[i].labels[0] = brLabel; List <CodeInstruction> insertedInstructions = new List <CodeInstruction>() { new CodeInstruction(OpCodes.Ldarg_0, null) { labels = new List <Label>() { oldLabel } }, new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(Pawn_JobTracker), "pawn")), new CodeInstruction(OpCodes.Ldarg_1, null), new CodeInstruction(OpCodes.Ldloca_S, localVar), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Patch_Pawn_JobTracker_TryOpportunisticJob), "CheckOportunisticToolJob")), new CodeInstruction(OpCodes.Brfalse_S, brLabel), new CodeInstruction(OpCodes.Ldloc_S, localVar), new CodeInstruction(OpCodes.Ret, null) }; instuctionList.InsertRange(i, insertedInstructions); break; } } return(instuctionList); }
private static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions, ILGenerator ilg) { List <CodeInstruction> instructionList = instructions.ToList(); for (int i = 0; i < instructionList.Count; i++) { CodeInstruction instruction = instructionList[i]; if (instruction.opcode == OpCodes.Ldfld && instruction.LoadsField(AccessTools.Field(typeof(Pawn), nameof(Pawn.mindState)))) { yield return(new CodeInstruction(opcode: OpCodes.Pop)); yield return(new CodeInstruction(opcode: OpCodes.Dup)); yield return(new CodeInstruction(opcode: OpCodes.Ldarg_0)); yield return(new CodeInstruction(opcode: OpCodes.Call, operand: AccessTools.Method(typeof(GenerateQualityCreatedByPawn_Patch), nameof(GenerateQualityCreatedByPawn_Patch.Notify_Progress)))); yield return(new CodeInstruction(opcode: OpCodes.Ldarg_0)); } yield return(instruction); } }
/// <summary> /// Add FloatMenuOption(s) for Pawns towards Vehicles /// </summary> /// <param name="instructions"></param> /// <param name="ilg"></param> public static IEnumerable <CodeInstruction> AddHumanLikeOrdersLoadVehiclesTranspiler(IEnumerable <CodeInstruction> instructions, ILGenerator ilg) { List <CodeInstruction> instructionList = instructions.ToList(); for (int i = 0; i < instructionList.Count; i++) { CodeInstruction instruction = instructionList[i]; if (instruction.LoadsField(AccessTools.Field(typeof(JobDefOf), nameof(JobDefOf.GiveToPackAnimal)))) { yield return(instruction); //Ldsfld : JobDefOf::GiveToPackAnimal instruction = instructionList[++i]; Label jobLabel = ilg.DefineLabel(); yield return(new CodeInstruction(opcode: OpCodes.Ldsfld, operand: AccessTools.Field(typeof(FloatMenuMakerMap), nameof(FloatMenuMakerMap.makingFor)))); yield return(new CodeInstruction(opcode: OpCodes.Call, operand: AccessTools.Method(typeof(Ext_Vehicles), nameof(Ext_Vehicles.HasVehicleInCaravan)))); yield return(new CodeInstruction(opcode: OpCodes.Brfalse, jobLabel)); yield return(new CodeInstruction(opcode: OpCodes.Pop)); yield return(new CodeInstruction(opcode: OpCodes.Ldsfld, AccessTools.Field(typeof(JobDefOf_Vehicles), nameof(JobDefOf_Vehicles.CarryItemToVehicle)))); int j = i; while (j < instructionList.Count) { j++; if (instructionList[j].opcode == OpCodes.Stfld) { instructionList[j].labels.Add(jobLabel); break; } } } if (instruction.Calls(AccessTools.Property(typeof(Lord), nameof(Lord.LordJob)).GetGetMethod())) { yield return(instruction); instruction = instructionList[++i]; Label label = ilg.DefineLabel(); Label label2 = ilg.DefineLabel(); yield return(new CodeInstruction(opcode: OpCodes.Dup)); yield return(new CodeInstruction(opcode: OpCodes.Isinst, operand: typeof(LordJob_FormAndSendVehicles))); yield return(new CodeInstruction(opcode: OpCodes.Brtrue, label)); yield return(instruction); //CASTCLASS : LordJob_FormAndSendCaravan instruction = instructionList[++i]; yield return(instruction); //STLOC_S : 50 instruction = instructionList[++i]; yield return(instruction); //LDLOC_S : 49 instruction = instructionList[++i]; yield return(instruction); //LDLOC_S : 50 instruction = instructionList[++i]; yield return(instruction); //CALL : CapacityLeft instruction = instructionList[++i]; yield return(new CodeInstruction(opcode: OpCodes.Br, label2)); yield return(new CodeInstruction(opcode: OpCodes.Pop) { labels = new List <Label> { label } }); yield return(new CodeInstruction(opcode: OpCodes.Ldloc_S, operand: 49)); yield return(new CodeInstruction(opcode: OpCodes.Ldarg_1)); yield return(new CodeInstruction(opcode: OpCodes.Call, operand: AccessTools.Method(typeof(LordUtility), "GetLord", new Type[] { typeof(Pawn) }))); yield return(new CodeInstruction(opcode: OpCodes.Callvirt, operand: AccessTools.Property(typeof(Lord), nameof(Lord.LordJob)).GetGetMethod())); yield return(new CodeInstruction(opcode: OpCodes.Castclass, operand: typeof(LordJob_FormAndSendVehicles))); yield return(new CodeInstruction(opcode: OpCodes.Call, operand: AccessTools.Method(typeof(CaravanHelper), nameof(CaravanHelper.CapacityLeft)))); instruction.labels.Add(label2); yield return(instruction); //STFLD : capacityLeft instruction = instructionList[++i]; } yield return(instruction); } }
public static IEnumerable <CodeInstruction> SetControlsTranspiler(IEnumerable <CodeInstruction> instructions) { bool foundCancelCrouch = false; bool foundAutoRunCondition = false; bool foundMoveDirCondition = false; bool foundCancelAutorunCondition = false; bool foundMoveDirAssignment = false; CodeInstruction branchEndAutoRun = null; List <CodeInstruction> codes = new List <CodeInstruction>(instructions); //DumpIL(codes); for (int i = 0; i < codes.Count(); i++) { CodeInstruction code = codes[i]; if (!foundCancelCrouch && codes[i + 0].opcode == OpCodes.Ldarg_0 && codes[i + 1].opcode == OpCodes.Ldc_I4_0 && codes[i + 2].Calls(AccessTools.Method(typeof(Character), nameof(Character.SetCrouch)))) { //Debug.Log("foundit0 " + i); // Nop out the call to "this.SetCrouch(false)" codes[i + 0].opcode = OpCodes.Nop; codes[i + 0].operand = null; codes[i + 1].opcode = OpCodes.Nop; codes[i + 1].operand = null; codes[i + 2].opcode = OpCodes.Nop; codes[i + 2].operand = null; foundCancelCrouch = true; } // We're looking for a ldfld of m_autoRun followed by a brfalse: "if(this.m_autoRun)" if (!foundAutoRunCondition && code.opcode == OpCodes.Ldfld && code.LoadsField(AccessTools.DeclaredField(typeof(Player), nameof(Player.m_autoRun))) && codes[i + 1].opcode == OpCodes.Brfalse) { //Debug.Log("foundit1 " + i); foundAutoRunCondition = true; } // Nop out the "jump || crouch || movedir != Vector3.zero" conditions if (foundAutoRunCondition && codes[i - 5].opcode == OpCodes.Ldarg_S && codes[i - 4].opcode == OpCodes.Or && codes[i - 3].opcode == OpCodes.Ldarg_S && codes[i - 2].opcode == OpCodes.Or && codes[i - 1].Branches(out Label? asdfasdfasdsa) && codes[i + 0].opcode == OpCodes.Ldarg_1 && codes[i + 1].opcode == OpCodes.Call) { //Debug.Log("foundit3 " + i); codes[i - 5].opcode = OpCodes.Nop; codes[i - 5].operand = null; codes[i - 4].opcode = OpCodes.Nop; codes[i - 4].operand = null; codes[i - 3].opcode = OpCodes.Nop; codes[i - 3].operand = null; codes[i - 2].opcode = OpCodes.Nop; codes[i - 2].operand = null; // Leave codes[i - 1] alone since it's the branching instruction for the very first condition codes[i + 0].opcode = OpCodes.Nop; codes[i + 0].operand = null; codes[i + 1].opcode = OpCodes.Nop; codes[i + 1].operand = null; codes[i + 2].opcode = OpCodes.Nop; codes[i + 2].operand = null; codes[i + 3].opcode = OpCodes.Nop; codes[i + 3].operand = null; // Add in our own autorun canceling conditions: if either forwards or backwards are pressed. branchEndAutoRun = codes[i - 1]; codes.InsertRange(i, new List <CodeInstruction>() { new CodeInstruction(OpCodes.Ldstr, "Forward"), CodeInstruction.Call(typeof(ZInput), nameof(ZInput.GetButton)), branchEndAutoRun.Clone(), new CodeInstruction(OpCodes.Ldstr, "Backward"), CodeInstruction.Call(typeof(ZInput), nameof(ZInput.GetButton)), branchEndAutoRun.Clone() }); foundCancelAutorunCondition = true; } // Convert "else if (autoRun || blockHold)" into "else" if (foundCancelAutorunCondition && codes[i + 0].opcode == OpCodes.Ldarg_S && //&& codes[i + 0].operand as string == "10" codes[i + 1].opcode == OpCodes.Ldarg_S && //&& codes[i + 1].operand as string == "6" codes[i + 2].opcode == OpCodes.Or && codes[i + 3].Branches(out Label? asdfasdfsad)) { //Debug.Log("foundit4 " + i); codes[i + 0].opcode = OpCodes.Nop; codes[i + 0].operand = null; codes[i + 1].opcode = OpCodes.Nop; codes[i + 1].operand = null; codes[i + 2].opcode = OpCodes.Nop; codes[i + 2].operand = null; codes[i + 3].opcode = OpCodes.Nop; codes[i + 3].operand = null; foundMoveDirCondition = true; } // Lastly, add "movedir.x * Vector3.Cross(Vector3.up, this.m_lookDir)" to the player's movedir so that they can strafe while autorunning if (foundMoveDirCondition && codes[i - 3].opcode == OpCodes.Ldarg_0 && codes[i - 2].opcode == OpCodes.Ldarg_0 && codes[i - 1].LoadsField(AccessTools.Field(typeof(Character), nameof(Character.m_lookDir))) && codes[i - 0].StoresField(AccessTools.Field(typeof(Character), nameof(Character.m_moveDir)))) { //Debug.Log("foundit5 " + i); codes.InsertRange(i, new List <CodeInstruction>() { new CodeInstruction(OpCodes.Ldarg_1), CodeInstruction.LoadField(typeof(Vector3), nameof(Vector3.x)), new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(Vector3), nameof(Vector3.up))), new CodeInstruction(OpCodes.Ldarg_0), CodeInstruction.LoadField(typeof(Player), nameof(Player.m_lookDir)), CodeInstruction.Call(typeof(Vector3), nameof(Vector3.Cross)), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Vector3), "op_Multiply", new Type[] { typeof(float), typeof(Vector3) })), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Vector3), "op_Addition", new Type[] { typeof(Vector3), typeof(Vector3) })) }); foundMoveDirAssignment = true; break; // we done } } //DumpIL(codes); //Debug.Log(string.Format("{0} {1} {2} {3} {4}", foundAutoRunCondition, branchEndAutoRun != null, foundCancelAutorunCondition, foundMoveDirCondition, foundMoveDirAssignment)); if (!foundAutoRunCondition || branchEndAutoRun == null || !foundCancelAutorunCondition || !foundMoveDirCondition || !foundMoveDirAssignment) { throw new Exception("BetterAutoRun injection point NOT found!! Game has most likely updated and broken this mod!"); } if (!foundCancelCrouch) { Main.log.LogWarning("One of the BetterAutoRun injection points were not found, game has most likely updated and broken this mod."); Main.log.LogWarning("Autorun while crouching will not work but everything else should be fine."); } return(codes.AsEnumerable()); }