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}");
            }
        }
Exemple #2
0
        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()");
        }
Exemple #3
0
        //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));
                }
            }
        }