private static void PatchDistributedUpdate(PatchContext ctx, MethodBase callerMethod) { var foundAnyIterate = false; var msil = PatchUtilities.ReadInstructions(callerMethod).ToList(); for (var i = 0; i < msil.Count; i++) { var insn = msil[i]; if ((insn.OpCode != OpCodes.Callvirt && insn.OpCode != OpCodes.Call) || !IsDistributedIterate((insn.Operand as MsilOperandInline <MethodBase>)?.Value as MethodInfo)) { continue; } foundAnyIterate = true; // Call to Iterate(). Backtrace up the instruction stack to find the statement creating the delegate. var foundNewDel = false; for (var j = i - 1; j >= 1; j--) { var insn2 = msil[j]; if (insn2.OpCode != OpCodes.Newobj) { continue; } var ctorType = (insn2.Operand as MsilOperandInline <MethodBase>)?.Value?.DeclaringType; if (ctorType == null || !ctorType.IsGenericType || ctorType.GetGenericTypeDefinition() != typeof(Action <>)) { continue; } foundNewDel = true; // Find the instruction loading the function pointer this delegate is created with var ldftn = msil[j - 1]; if (ldftn.OpCode != OpCodes.Ldftn || !(ldftn.Operand is MsilOperandInline <MethodBase> targetMethod)) { Log.Error( $"Unable to find ldftn instruction for call to Iterate in {callerMethod.DeclaringType}#{callerMethod}"); } else { Log.Debug( $"Patching {targetMethod.Value.DeclaringType}#{targetMethod.Value} for {callerMethod.DeclaringType}#{callerMethod}"); PatchDistUpdateDel(ctx, targetMethod.Value); } break; } if (!foundNewDel) { Log.Error( $"Unable to find new Action() call for Iterate in {callerMethod.DeclaringType}#{callerMethod}"); } } if (!foundAnyIterate) { Log.Error($"Unable to find any calls to {_distributedUpdaterIterate} in {callerMethod.DeclaringType}#{callerMethod}"); } }
static MethodBase FindAction(MethodBase caller) { var msil = PatchUtilities.ReadInstructions(caller).ToList(); for (var i = 0; i < msil.Count; i++) { Log.Trace($"insn: {i} {msil[i]}"); var newobj = msil[i]; if (newobj.OpCode != OpCodes.Newobj) { continue; } Log.Trace("newobj found"); var newobjType = (newobj.Operand as MsilOperandInline <MethodBase>)?.Value?.DeclaringType; if (newobjType == null) { continue; } if (newobjType != typeof(GenericLoop.VoidAction)) { continue; } var ldftn = msil[i - 1]; Log.Trace($"ldftn found: {ldftn}"); if (ldftn.OpCode != OpCodes.Ldftn) { continue; } if (!(ldftn.Operand is MsilOperandInline <MethodBase> action)) { continue; } return(action.Value); } throw new Exception("Failed to patch: action not found in FixedLoop.Run()"); }
//Code taken from PrisonLabor private static IEnumerable <CodeInstruction> ScrollTranspiler(ILGenerator gen, IEnumerable <CodeInstruction> instr) { #region fragment>>GUI.BeginGroup(position); OpCode[] opCodes1 = { OpCodes.Call, OpCodes.Stloc_S, OpCodes.Ldloc_S, OpCodes.Call, }; string[] operands1 = { "UnityEngine.Rect ContractedBy(UnityEngine.Rect, Single)", "UnityEngine.Rect (7)", "UnityEngine.Rect (7)", "Void BeginGroup(UnityEngine.Rect)", }; int step1 = 0; #endregion #region fragment>>GUI.EndGroup(); OpCode[] opCodes2 = { OpCodes.Ldloc_S, OpCodes.Callvirt, OpCodes.Endfinally, OpCodes.Call, }; string[] operands2 = { "System.Collections.Generic.IEnumerator`1[RimWorld.PrisonerInteractionModeDef] (22)", "Void Dispose()", "", "Void EndGroup()", }; int step2 = 0; #endregion #region fragment>>Rect position = rect6.ContractedBy(10f); OpCode[] opCodes3 = { OpCodes.Ldc_R4, OpCodes.Call, OpCodes.Stloc_S, OpCodes.Ldloc_S, }; String[] operands3 = { "10", "UnityEngine.Rect ContractedBy(UnityEngine.Rect, Single)", "UnityEngine.Rect (7)", "UnityEngine.Rect (7)", }; int step3 = 0; var rect = PatchUtilities.FindOperandAfter(opCodes3, operands3, instr); #endregion foreach (var ci in instr) { // end scroll if (PatchUtilities.IsFragment(opCodes2, operands2, ci, ref step2, "AddScrollToPrisonerTab2")) { var instruction = new CodeInstruction(OpCodes.Call, typeof(ITabPatches).GetMethod(nameof(StopScrolling))); instruction.labels.AddRange(ci.labels); ci.labels.Clear(); yield return(instruction); } /* // resize * if (HPatcher.IsFragment(opCodes3, operands3, ci, ref step3, "AddScrollToPrisonerTab3")) * { * }*/ yield return(ci); // begin scroll if (PatchUtilities.IsFragment(opCodes1, operands1, ci, ref step1, "AddScrollToPrisonerTab1")) { yield return(new CodeInstruction(OpCodes.Ldloc_S, rect)); yield return(new CodeInstruction(OpCodes.Call, typeof(ITabPatches).GetMethod(nameof(StartScrolling)))); yield return(new CodeInstruction(OpCodes.Stloc_S, rect)); } } }