public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { List <CodeInstruction> codes = TranspilerUtil.ToCodeList(instructions); MethodInfo calcStopPosAndDir = typeof(NetLane).GetMethod(nameof(NetLane.CalculateStopPositionAndDirection)); CodeInstruction searchInstr = new CodeInstruction(OpCodes.Call, calcStopPosAndDir); int index = codes.FindIndex(instr => TranspilerUtil.IsSameInstruction(instr, searchInstr)); if (index > -1) { int targetIndex = index + 1; int replace1stIndex = targetIndex + 3; if (codes[replace1stIndex].opcode.Equals(OpCodes.Ldarg_2)) { codes.RemoveRange(replace1stIndex + 1, 6); codes.Insert(replace1stIndex + 1, new CodeInstruction(OpCodes.Ldloc_3)); } else { throw new Exception("Could not find Ldarg.2 instruction or instructions has been patched"); } codes.InsertRange(targetIndex, GetInstructions()); } else { throw new Exception("Could not find CalculateStopPositionAndDirection call or instructions has been patched"); } return(codes); }
public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { List <CodeInstruction> codes = TranspilerUtil.ToCodeList(instructions); int minus1OpIndex = TranspilerUtil.SearchInstruction(codes, new CodeInstruction(OpCodes.Ldc_I4_M1), 0); //check index and previous instruction if (minus1OpIndex != -1 && codes[minus1OpIndex + 1].opcode.Equals(OpCodes.Bne_Un)) { int ldArg0Index = TranspilerUtil.SearchInstruction(codes, new CodeInstruction(OpCodes.Ldarg_0), minus1OpIndex); //check index and previous instruction if (ldArg0Index != -1 && codes[ldArg0Index - 1].opcode.Equals(OpCodes.Stfld)) { int targetIndex = minus1OpIndex + 2;//move index to first item to remove // replace all instruction between targetIndex and Ldarg_0 codes.RemoveRange(targetIndex, ldArg0Index - targetIndex); var newInstructions = new[] { new CodeInstruction(OpCodes.Ldarg_1), // load node id new CodeInstruction(OpCodes.Call, typeof(ClickNodeButtonPatch).GetMethod(nameof(ClickNodeButtonPatch.ToggleTrafficLight))), }; codes.InsertRange(targetIndex, newInstructions); } else { throw new Exception("Could not found Ldarg_0 Instruction or instruction was already patched!"); } } else { throw new Exception("Could not found Ldc_I4_M1 Instruction or previous instruction was already patched!"); } return(codes); }
// code from: https://github.com/Strdate/SmartIntersections/blob/master/SmartIntersections/Patch/LoadPathsPatch.cs public static IEnumerable <CodeInstruction> Transpiler(ILGenerator il, IEnumerable <CodeInstruction> instructions) { var fTempNodeBuffer = AccessTools.DeclaredField(typeof(NetManager), nameof(NetManager.m_tempNodeBuffer)) ?? throw new Exception("cound not find NetManager.m_tempNodeBuffer"); var mClear = AccessTools.DeclaredMethod(fTempNodeBuffer.FieldType, nameof(FastList <ushort> .Clear)) ?? throw new Exception("cound not find m_tempNodeBuffer.Clear"); var mAfterIntersectionBuilt = AccessTools.DeclaredMethod( typeof(LoadPathsPatch), nameof(AfterIntersectionBuilt)) ?? throw new Exception("cound not find AfterIntersectionBuilt()"); List <CodeInstruction> codes = TranspilerUtil.ToCodeList(instructions); bool comp(int i) => codes[i].opcode == OpCodes.Ldfld && codes[i].operand == fTempNodeBuffer && codes[i + 1].opcode == OpCodes.Callvirt && codes[i + 1].operand == mClear; int index = TranspilerUtil.SearchGeneric(codes, comp, index: 0, counter: 2); index -= 1; // index to insert instructions. var newInstructions = new[] { new CodeInstruction(OpCodes.Ldarg_0), // load argument info new CodeInstruction(OpCodes.Call, mAfterIntersectionBuilt), }; TranspilerUtil.InsertInstructions(codes, newInstructions, index); return(codes); }
public static IEnumerable <CodeInstruction> Transpiler(ILGenerator il, IEnumerable <CodeInstruction> instructions) { var fTempSegmentBuffer = AccessTools.DeclaredField(typeof(NetManager), nameof(NetManager.m_tempSegmentBuffer)) ?? throw new Exception("Could not find NetManager.m_tempSegmentBuffer"); var mSize = AccessTools.DeclaredField(fTempSegmentBuffer.FieldType, nameof(FastList <ushort> .m_size)) ?? throw new Exception("Could not find m_tempSegmentBuffer.m_size"); var mAfterIntersectionBuilt = AccessTools.DeclaredMethod( typeof(LoadPathsPatch), nameof(AfterIntersectionBuilt)) ?? throw new Exception("Could not find AfterIntersectionBuilt()"); List <CodeInstruction> codes = TranspilerUtil.ToCodeList(instructions); bool predicate(int i) => codes[i].opcode == OpCodes.Blt && codes[i - 1].opcode == OpCodes.Ldfld && codes[i - 1].operand == mSize && codes[i - 2].opcode == OpCodes.Ldfld && codes[i - 2].operand == fTempSegmentBuffer; int index = TranspilerUtil.SearchGeneric(codes, predicate, index: 0, counter: 1); index += 1; // index to insert instructions. (end of the loop) var newInstructions = new[] { new CodeInstruction(OpCodes.Ldarg_0), // load argument info new CodeInstruction(OpCodes.Call, mAfterIntersectionBuilt), }; TranspilerUtil.InsertInstructions(codes, newInstructions, index); return(codes); }
public static IEnumerable <CodeInstruction> Transpiler(IEnumerable <CodeInstruction> instructions) { List <CodeInstruction> codes = TranspilerUtil.ToCodeList(instructions); int minus1OpIndex = TranspilerUtil.SearchInstruction(codes, new CodeInstruction(OpCodes.Ldc_I4_M1), 0); //check index and previous instruction if (minus1OpIndex != -1 && codes[minus1OpIndex + 1].opcode.Equals(OpCodes.Bne_Un)) { int ldArg0Index = TranspilerUtil.SearchInstruction(codes, new CodeInstruction(OpCodes.Ldarg_0), minus1OpIndex); //check index and previous instruction if (ldArg0Index != -1 && codes[ldArg0Index - 1].opcode.Equals(OpCodes.Stfld)) { int targetIndex = minus1OpIndex + 2;//move index to first item to remove // replace all instruction between targetIndex and Ldarg_0 codes.RemoveRange(targetIndex, ldArg0Index - targetIndex); codes.InsertRange(targetIndex, GetReplacementInstructions()); } else { throw new Exception("Could not found Ldarg_0 Instruction or instruction was already patched!"); } } else { throw new Exception("Could not found Ldc_I4_M1 Instruction or previous instruction was already patched!"); } return(codes); }
public static IEnumerable <CodeInstruction> Transpiler(ILGenerator il, IEnumerable <CodeInstruction> instructions) { List <CodeInstruction> codes = TranspilerUtil.ToCodeList(instructions); int searchInstruction = TranspilerUtil.SearchInstruction(codes, new CodeInstruction(OpCodes.Call, CheckSegmentProblemsMethod()), 0, 1, 3); if (searchInstruction != -1 && codes[searchInstruction + 1].opcode.Equals(OpCodes.Ldc_I4_1) && codes[searchInstruction + 2].opcode.Equals(OpCodes.Ret)) { int startTarget = searchInstruction + 3; //first instruction to remove, contains labels to copy int createPathCallIndex = TranspilerUtil.SearchInstruction(codes, new CodeInstruction(OpCodes.Callvirt, CreatePathMethod()), startTarget); if (createPathCallIndex != -1 && codes[createPathCallIndex + 1].opcode.Equals(OpCodes.Brfalse)) { List <Label> labels = codes[startTarget].labels; codes.RemoveRange(startTarget, createPathCallIndex + 1 - startTarget); codes.InsertRange(startTarget, GetInjectInstructions(labels)); } else { throw new Exception("Could not find CreatePath call or instructions has been patched"); } } else { throw new Exception("Could not find 3rd. CheckSegmentProblems call or instructions has been patched"); } return(codes); }
/// <summary> /// Inserts MayDespawn call into the instruction chain /// </summary> /// <param name="instructions"></param> /// <returns></returns> public static IEnumerable <CodeInstruction> ReplaceSimulationStepIsCongestedCheck(IEnumerable <CodeInstruction> instructions) { List <CodeInstruction> codes = TranspilerUtil.ToCodeList(instructions); bool found = false; foreach (CodeInstruction instruction in codes) { if (!found && (instruction.opcode.Equals(OpCodes.Brfalse_S) || instruction.opcode.Equals(OpCodes.Brfalse))) { found = true; yield return(instruction); // return found instruction yield return(new CodeInstruction(OpCodes.Ldsfld, _vehicleBehaviourManagerInstanceField)); // loadInstFiled yield return(new CodeInstruction(OpCodes.Ldarg_1)); // vehicleID yield return(new CodeInstruction(OpCodes.Ldarg_2)); // loadVehicleData yield return(new CodeInstruction(OpCodes.Callvirt, _mayDespawnMethod)); // callMayDespawn yield return(instruction.Clone()); //brfalse_s || brfalse - clone including label! } else { yield return(instruction); } } /* * ----------------------------------------------------------------------------------- * SimulationStep(ushort vehicleId, ref Vehicle vehicleData, Vector3 physicsLodRefPos) * ----------------------------------------------------------------------------------- * * IL_0000: ldarg.2 // vehicleData * IL_0001: ldfld valuetype ['Assembly-CSharp']Vehicle/Flags ['Assembly-CSharp']Vehicle::m_flags * IL_0006: ldc.i4 67108864 // 0x04000000 * IL_000b: and * IL_000c: brfalse.s IL_0027 * * // NON-STOCK CODE START * IL_000e: ldsfld class TrafficManager.Manager.Impl.VehicleBehaviorManager TrafficManager.Manager.Impl.VehicleBehaviorManager::Instance * IL_0013: ldarg.1 // vehicleID * IL_0013: ldarg.2 // vehicleData * IL_0014: callvirt instance bool TrafficManager.Manager.Impl.VehicleBehaviorManager::MayDespawn(valuetype ['Assembly-CSharp']Vehicle&) * IL_0019: brfalse.s IL_0027 * // NON-STOCK CODE STOP * * ... */ }
/// <summary> /// Revrites instructions adding necessary TMPE calls /// </summary> /// <param name="il"> Il Generator</param> /// <param name="instructions">List of instructions</param> /// <returns></returns> /// <exception cref="Exception"></exception> public static IEnumerable <CodeInstruction> TranspileTramTrainSimulationStep(ILGenerator il, IEnumerable <CodeInstruction> instructions) { List <CodeInstruction> codes = TranspilerUtil.ToCodeList(instructions); MethodBase trySpawnCall = TranspilerUtil.DeclaredMethod <TrySpawnDelegate>(typeof(VehicleAI), "TrySpawn"); CodeInstruction searchInstruction = new CodeInstruction(OpCodes.Callvirt, trySpawnCall); int index = codes.FindIndex(instruction => TranspilerUtil.IsSameInstruction(instruction, searchInstruction)); if (index > -1) { int target1 = index + 2; Label label = il.DefineLabel(); List <Label> oldLabels = codes[target1].labels.ToList(); codes[target1].labels.Clear(); // clear labels -> they are moved to new instruction codes[target1].labels.Add(label); //add label to next instruction (if() false jump) List <CodeInstruction> newInstructions = GetUpdatePositionInstructions(label); newInstructions[0].labels.AddRange(oldLabels); // add old labels to redirect here codes.InsertRange(target1, newInstructions); // insert new instructions CodeInstruction searchInstruction2 = new CodeInstruction(OpCodes.Ldfld, typeof(Vehicle).GetField(nameof(Vehicle.m_blockCounter))); int index2 = codes.FindIndex(instruction => TranspilerUtil.IsSameInstruction(instruction, searchInstruction2)); if (index2 > -1 && codes[index2 + 1].opcode.Equals(OpCodes.Ldc_I4) && codes[index2 + 2].opcode.Equals(OpCodes.Bne_Un)) { int target2 = index2 + 2; Label retLabel = (Label)codes[target2].operand; codes.InsertRange(target2 + 1, GetModifiedBlockCounterInstructions(retLabel)); } else { throw new Exception("Could not find m_blockCounter field usage or instructions has been patched"); } } else { throw new Exception("Could not find TrySpawn call or instructions has been patched"); } return(codes); }