Example #1
0
        public static void HookAllGlobalRouteMethods(CecilContext stardewContext)
        {
            var methods = stardewContext.GetMethods().Where(n => n.DeclaringType.Namespace.StartsWith("StardewValley")).ToArray();

            var ilProcessor2 = stardewContext.GetMethodIlProcessor("Farmhand.Test", "TesttttgetNewID");

            ilProcessor2.Body.SimplifyMacros();


            {
                var listenedMethodField = stardewContext.GetFieldDefinition("Farmhand.Events.GlobalRouteManager", "ListenedMethods");
                var ilProcessor         = stardewContext.GetMethodIlProcessor("Farmhand.Events.GlobalRouteManager", ".cctor");
                var loadInt             = ilProcessor.Create(OpCodes.Ldc_I4, methods.Length);
                var setValue            = ilProcessor.Create(OpCodes.Stsfld, listenedMethodField);
                ilProcessor.InsertAfter(ilProcessor.Body.Instructions[ilProcessor.Body.Instructions.Count - 2], loadInt);
                ilProcessor.InsertAfter(loadInt, setValue);
            }

            for (int i = 0; i < methods.Length; ++i)
            {
                //InjectGlobalRoutePreMethod(stardewContext, methods[i].DeclaringType.FullName, methods[i].Name, i);
                InjectGlobalRoutePostMethod(stardewContext, methods[i].DeclaringType.FullName, methods[i].Name, i);
                InjectMappingInformation(stardewContext, methods[i].DeclaringType.FullName, methods[i].Name, i);
            }
        }
Example #2
0
        public static void RedirectConstructorFromBase(CecilContext stardewContext, Type asmType, string type, string method)
        {
            var test = stardewContext.GetTypeDefinition("StardewValley.SaveGame");

            var newConstructor = asmType.GetConstructor(new Type[] { });

            if (asmType.BaseType == null)
            {
                return;
            }
            var oldConstructor = asmType.BaseType.GetConstructor(new Type[] { });

            if (newConstructor == null)
            {
                return;
            }
            var newConstructorReference = stardewContext.GetMethodDefinition(asmType.FullName, newConstructor.Name);

            if (oldConstructor == null)
            {
                return;
            }
            var oldConstructorReference = stardewContext.GetMethodDefinition(asmType.BaseType.FullName, oldConstructor.Name);

            ILProcessor ilProcessor  = stardewContext.GetMethodIlProcessor(type, method);
            var         instructions = ilProcessor.Body.Instructions.Where(n => n.OpCode == OpCodes.Newobj && n.Operand == oldConstructorReference).ToList();

            foreach (var instruction in instructions)
            {
                ilProcessor.Replace(instruction, ilProcessor.Create(OpCodes.Newobj, newConstructorReference));
            }
        }
Example #3
0
        public static void InjectExitMethod <TParam, TThis, TInput, TLocal>(CecilContext stardewContext, string injecteeType, string injecteeMethod,
                                                                            string injectedType, string injectedMethod)
        {
            var methodDefinition = stardewContext.GetMethodDefinition(injectedType, injectedMethod);
            var ilProcessor      = stardewContext.GetMethodIlProcessor(injecteeType, injecteeMethod);

            InjectMethod <TParam, TThis, TInput, TLocal>(ilProcessor, ilProcessor.Body.Instructions.Where(i => i.OpCode == OpCodes.Ret), methodDefinition, true);
        }
Example #4
0
        public static void InjectEntryMethod <TParam, TThis, TInput, TLocal>(CecilContext stardewContext, string injecteeType, string injecteeMethod,
                                                                             string injectedType, string injectedMethod)
        {
            var methodDefinition = stardewContext.GetMethodDefinition(injectedType, injectedMethod);
            var ilProcessor      = stardewContext.GetMethodIlProcessor(injecteeType, injecteeMethod);

            InjectMethod <TParam, TThis, TInput, TLocal>(ilProcessor, ilProcessor.Body.Instructions.First(), methodDefinition, false, methodDefinition.ReturnType != null && methodDefinition.ReturnType.FullName == typeof(bool).FullName);
        }
Example #5
0
        public static void RedirectConstructorFromBase(CecilContext stardewContext, Type asmType, string type, string method, Type[] parameters)
        {
            string parametersString = "";

            for (int i = 0; i < parameters.Length; i++)
            {
                if (parameters[i].FullName.Contains("`"))
                {
                    parametersString += ConvertGenericTypeFullNameToGenericTypeParameterFormat(parameters[i].FullName);
                }
                else
                {
                    parametersString += parameters[i].FullName;
                }

                if (i != parameters.Length - 1)
                {
                    parametersString += ",";
                }
            }

            var newConstructor = asmType.GetConstructor(parameters);

            if (asmType.BaseType == null)
            {
                return;
            }
            var oldConstructor = asmType.BaseType.GetConstructor(parameters);

            if (newConstructor == null)
            {
                return;
            }
            // Build a FullName version of newConstructor.Name
            string newConstructorFullName  = "System.Void " + asmType.FullName + "::.ctor" + "(" + parametersString + ")";
            var    newConstructorReference = stardewContext.GetMethodDefinitionFullName(asmType.FullName, newConstructorFullName);

            if (oldConstructor == null)
            {
                return;
            }
            // Build a FullName version of oldConstructor.Name
            string oldConstructorFullName  = "System.Void " + asmType.BaseType.FullName + "::.ctor" + "(" + parametersString + ")";
            var    oldConstructorReference = stardewContext.GetMethodDefinitionFullName(asmType.BaseType.FullName ?? asmType.BaseType.Namespace + "." + asmType.BaseType.Name, oldConstructorFullName);


            ILProcessor ilProcessor = stardewContext.GetMethodIlProcessor(type, method);

            var instructions = ilProcessor.Body.Instructions.Where(n => n.OpCode == OpCodes.Newobj && n.Operand == oldConstructorReference).ToList();

            foreach (var instruction in instructions)
            {
                ilProcessor.Replace(instruction, ilProcessor.Create(OpCodes.Newobj, newConstructorReference));
            }
        }
Example #6
0
        public static void SetVirtualCallOnMethod(CecilContext cecilContext, string fullName, string name, string type, string method)
        {
            MethodDefinition methodDefinition = cecilContext.GetMethodDefinition(fullName, name);
            ILProcessor      ilProcessor      = cecilContext.GetMethodIlProcessor(type, method);

            var instructions = ilProcessor.Body.Instructions.Where(n => n.OpCode == OpCodes.Call && n.Operand == methodDefinition).ToList();

            foreach (var instruction in instructions)
            {
                ilProcessor.Replace(instruction, ilProcessor.Create(OpCodes.Callvirt, methodDefinition));
            }
        }
Example #7
0
        public static void InjectReturnableExitMethod <TParam, TThis, TInput, TLocal, TUseOutput, TMethodOutputBind>(CecilContext stardewContext, string injecteeType, string injecteeMethod,
                                                                                                                     string injectedType, string injectedMethod)
        {
            var methodDefinition = stardewContext.GetMethodDefinition(injectedType, injectedMethod);

            if (methodDefinition.HasGenericParameters)
            {
                var injecteeMethodDef = stardewContext.GetMethodDefinition(injecteeType, injecteeMethod);

                var inst = new GenericInstanceMethod(methodDefinition);
                for (var i = 0; i < methodDefinition.GenericParameters.Count; ++i)
                {
                    inst.GenericArguments.Add(injecteeMethodDef.DeclaringType.GenericParameters[i]);
                }

                var ilProcessor = stardewContext.GetMethodIlProcessor(injecteeType, injecteeMethod);
                InjectReturnableMethod <TParam, TThis, TInput, TLocal, TUseOutput, TMethodOutputBind>(stardewContext, ilProcessor, ilProcessor.Body.Instructions.Where(i => i.OpCode == OpCodes.Ret), methodDefinition, true);
            }
            else
            {
                var ilProcessor = stardewContext.GetMethodIlProcessor(injecteeType, injecteeMethod);
                InjectReturnableMethod <TParam, TThis, TInput, TLocal, TUseOutput, TMethodOutputBind>(stardewContext, ilProcessor, ilProcessor.Body.Instructions.Where(i => i.OpCode == OpCodes.Ret), methodDefinition, true);
            }
        }
Example #8
0
        public static void InjectEntryMethod <TParam, TThis, TInput, TLocal>(CecilContext stardewContext, string injecteeType, string injecteeMethod,
                                                                             string injectedType, string injectedMethod)
        {
            var methodDefinition = stardewContext.GetMethodDefinition(injectedType, injectedMethod);

            if (methodDefinition.HasGenericParameters)
            {
                var injecteeMethodDef = stardewContext.GetMethodDefinition(injecteeType, injecteeMethod);

                var inst = new GenericInstanceMethod(methodDefinition);
                for (var i = 0; i < methodDefinition.GenericParameters.Count; ++i)
                {
                    inst.GenericArguments.Add(injecteeMethodDef.DeclaringType.GenericParameters[i]);
                }

                var ilProcessor = stardewContext.GetMethodIlProcessor(injecteeType, injecteeMethod);
                InjectMethod <TParam, TThis, TInput, TLocal>(stardewContext, ilProcessor, ilProcessor.Body.Instructions.First(), inst, false, methodDefinition.ReturnType != null && methodDefinition.ReturnType.FullName == typeof(bool).FullName);
            }
            else
            {
                var ilProcessor = stardewContext.GetMethodIlProcessor(injecteeType, injecteeMethod);
                InjectMethod <TParam, TThis, TInput, TLocal>(stardewContext, ilProcessor, ilProcessor.Body.Instructions.First(), methodDefinition, false, methodDefinition.ReturnType != null && methodDefinition.ReturnType.FullName == typeof(bool).FullName);
            }
        }
Example #9
0
        public static void RedirectConstructorToMethod(CecilContext stardewContext, Type asmType, string type, string method, string methodType, string methodName, Type[] parameters)
        {
            // Get a single string containing the full names of all parameters, comma separated
            string parametersString = "";

            for (int i = 0; i < parameters.Length; i++)
            {
                parametersString += parameters[i].FullName;
                if (i != parameters.Length - 1)
                {
                    parametersString += ",";
                }
            }

            if (asmType == null)
            {
                return;
            }
            var oldConstructor = asmType.GetConstructor(parameters);

            if (oldConstructor == null)
            {
                return;
            }
            // Build a FullName version of oldConstructor.Name
            string oldConstructorFullName  = "System.Void " + asmType.FullName + "::.ctor" + "(" + parametersString + ")";
            var    oldConstructorReference = stardewContext.GetMethodDefinitionFullName(asmType.FullName ?? asmType.Namespace + "." + asmType.Name, oldConstructorFullName);

            // Build a FullName version of the new method
            string methodFullName = $"{asmType} {methodType}::{methodName}({parametersString})";
            var    newMethod      = stardewContext.GetMethodDefinitionFullName(methodType, methodFullName);

            if (newMethod == null)
            {
                return;
            }

            ILProcessor ilProcessor = stardewContext.GetMethodIlProcessor(type, method);

            var instructions = ilProcessor.Body.Instructions.Where(n => n.OpCode == OpCodes.Newobj && n.Operand == oldConstructorReference).ToList();

            foreach (var instruction in instructions)
            {
                ilProcessor.Body.SimplifyMacros();
                ilProcessor.Replace(instruction, ilProcessor.Call(newMethod));
                ilProcessor.Body.OptimizeMacros();
            }
        }
Example #10
0
        private static void InjectMappingInformation(CecilContext stardewContext, string className, string methodName, int index)
        {
            var mapMethodDefinition = stardewContext.GetMethodDefinition("Farmhand.Events.GlobalRouteManager", "MapIndex");
            var ilProcessor         = stardewContext.GetMethodIlProcessor("Farmhand.Events.GlobalRouteManager", "InitialiseMappings");

            if (ilProcessor == null || mapMethodDefinition == null)
            {
                return;
            }

            var newInstructions = new List <Instruction>();

            newInstructions.Add(ilProcessor.Create(OpCodes.Ldstr, className));
            newInstructions.Add(ilProcessor.Create(OpCodes.Ldstr, methodName));
            newInstructions.Add(ilProcessor.Create(OpCodes.Ldc_I4, index));
            newInstructions.Add(ilProcessor.Create(OpCodes.Call, mapMethodDefinition));

            ilProcessor.Body.SimplifyMacros();
            if (newInstructions.Any())
            {
                var previousInstruction = newInstructions.First();
                if (ilProcessor.Body.Instructions.Count > 1)
                {
                    ilProcessor.InsertAfter(ilProcessor.Body.Instructions[ilProcessor.Body.Instructions.Count - 2],
                                            previousInstruction);
                }
                else
                {
                    ilProcessor.InsertBefore(ilProcessor.Body.Instructions[0], previousInstruction);
                }

                for (var i = 1; i < newInstructions.Count; ++i)
                {
                    ilProcessor.InsertAfter(previousInstruction, newInstructions[i]);
                    previousInstruction = newInstructions[i];
                }
            }
            ilProcessor.Body.OptimizeMacros();
        }
Example #11
0
        public static void RedirectConstructorFromBase(CecilContext stardewContext, Type asmType, Type[] test, string type, string method, Type[] parameters)
        {
            var types       = test.Select(n => stardewContext.GetTypeReference(n)).ToArray();
            var typeDef     = stardewContext.GetTypeDefinition(asmType.Namespace + "." + asmType.Name);
            var typeDefBase = stardewContext.GetTypeDefinition(asmType.BaseType.Namespace + "." + asmType.BaseType.Name);

            var newConstructorReference = stardewContext.GetConstructorReference(typeDef);
            var oldConstructorReference = stardewContext.GetConstructorReference(typeDefBase);

            var concreteFromConstructor = MakeHostInstanceGeneric(oldConstructorReference, types);
            var concreteToConstructor   = MakeHostInstanceGeneric(newConstructorReference, types);

            ILProcessor ilProcessor = stardewContext.GetMethodIlProcessor(type, method);

            var instructions = ilProcessor.Body.Instructions.Where(n => n.OpCode == OpCodes.Newobj && n.Operand is MethodReference &&
                                                                   ((MethodReference)n.Operand).FullName == concreteFromConstructor.FullName).ToList();

            foreach (var instruction in instructions)
            {
                ilProcessor.Replace(instruction, ilProcessor.Create(OpCodes.Newobj, concreteToConstructor));
            }
        }
Example #12
0
        public static void InjectGlobalRouteMethod(CecilContext stardewContext, string injecteeType, string injecteeMethod)
        {
            var fieldDefinition  = stardewContext.GetFieldDefinition("Farmhand.Events.GlobalRouteManager", "IsEnabled");
            var methodDefinition = stardewContext.GetMethodDefinition("Farmhand.Events.GlobalRouteManager", "GlobalRouteInvoke");
            var ilProcessor      = stardewContext.GetMethodIlProcessor(injecteeType, injecteeMethod);

            if (ilProcessor == null || methodDefinition == null || fieldDefinition == null)
            {
                return;
            }

            var method   = ilProcessor.Body.Method;
            var hasThis  = method.HasThis;
            var argIndex = 0;

            VariableDefinition outputVar = null;

            Instruction first = ilProcessor.Body.Instructions.First();
            Instruction last  = ilProcessor.Body.Instructions.Last();
            Instruction prelast;

            if (ilProcessor.Body.Instructions.Count > 1)
            {
                prelast = ilProcessor.Body.Instructions[ilProcessor.Body.Instructions.Count - 2];
            }
            else
            {
                prelast = first;
            }
            var objectType = stardewContext.GetInbuiltTypeReference(typeof(object));
            var voidType   = stardewContext.GetInbuiltTypeReference(typeof(void));

            var newInstructions = new List <Instruction>();

            newInstructions.Add(ilProcessor.Create(OpCodes.Ldsfld, fieldDefinition));
            newInstructions.Add(ilProcessor.Create(OpCodes.Brfalse, first));

            newInstructions.Add(ilProcessor.Create(OpCodes.Ldstr, injecteeType));
            newInstructions.Add(ilProcessor.Create(OpCodes.Ldstr, injecteeMethod));

            /*//if (method.ReturnType != null && method.ReturnType != voidType)
             * {
             *  outputVar = new VariableDefinition("GlobalRouteOutput", objectType);
             *  ilProcessor.Body.Variables.Add(outputVar);
             *  newInstructions.Add(ilProcessor.Create(OpCodes.Ldloca, outputVar));
             * }
             *
             * newInstructions.Add(ilProcessor.Create(OpCodes.Ldc_I4, method.Parameters.Count + (hasThis ? 1 : 0)));
             * newInstructions.Add(ilProcessor.Create(OpCodes.Newarr, objectType));
             *
             * if (hasThis)
             * {
             *  newInstructions.Add(ilProcessor.Create(OpCodes.Dup));
             *  newInstructions.Add(ilProcessor.Create(OpCodes.Ldc_I4, argIndex++));
             *  newInstructions.Add(ilProcessor.Create(OpCodes.Ldarg, ilProcessor.Body.ThisParameter));
             *  newInstructions.Add(ilProcessor.Create(OpCodes.Stelem_Ref));
             * }
             *
             * foreach (var param in method.Parameters)
             * {
             *  newInstructions.Add(ilProcessor.Create(OpCodes.Dup));
             *  newInstructions.Add(ilProcessor.Create(OpCodes.Ldc_I4, argIndex++));
             *  newInstructions.Add(ilProcessor.Create(OpCodes.Ldarg, param));
             *  if (param.ParameterType.IsPrimitive)
             *      newInstructions.Add(ilProcessor.Create(OpCodes.Box, param.ParameterType));
             *  newInstructions.Add(ilProcessor.Create(OpCodes.Stelem_Ref));
             * }*/

            newInstructions.Add(ilProcessor.Create(OpCodes.Call, methodDefinition));
            //newInstructions.Add(ilProcessor.Create(OpCodes.Brfalse, first));

            //if (method.ReturnType != null && method.ReturnType.FullName != voidType.FullName)
            //{
            //    newInstructions.Add(ilProcessor.Create(OpCodes.Ldloc, outputVar));
            //    if (method.ReturnType.IsPrimitive || method.ReturnType.IsGenericParameter)
            //    {
            //        newInstructions.Add(ilProcessor.Create(OpCodes.Unbox_Any, method.ReturnType));
            //    }
            //    else
            //    {
            //        newInstructions.Add(ilProcessor.Create(OpCodes.Castclass, method.ReturnType));
            //    }
            //    newInstructions.Add(ilProcessor.Create(OpCodes.Br, last));
            //}
            //else
            //{
            //    newInstructions.Add(ilProcessor.Create(OpCodes.Br, prelast));
            //}

            ilProcessor.Body.SimplifyMacros();
            if (newInstructions.Any())
            {
                var previousInstruction = newInstructions.First();
                ilProcessor.InsertBefore(first, previousInstruction);
                for (var i = 1; i < newInstructions.Count; ++i)
                {
                    ilProcessor.InsertAfter(previousInstruction, newInstructions[i]);
                    previousInstruction = newInstructions[i];
                }
            }
            ilProcessor.Body.OptimizeMacros();
        }
Example #13
0
        public static void InjectGlobalRoutePostMethod(CecilContext stardewContext, string injecteeType, string injecteeMethod, int index)
        {
            var ilProcessor = stardewContext.GetMethodIlProcessor(injecteeType, injecteeMethod);

            if (ilProcessor == null)
            {
                return;
            }

            var objectType   = stardewContext.GetTypeReference(typeof(object));
            var voidType     = stardewContext.GetTypeReference(typeof(void));
            var boolType     = stardewContext.GetTypeReference(typeof(bool));
            var method       = ilProcessor.Body.Method;
            var hasThis      = method.HasThis;
            var returnsValue = method.ReturnType != null && method.ReturnType.FullName != voidType.FullName;

            VariableDefinition outputVar = null;

            var isEnabledField     = stardewContext.GetFieldDefinition("Farmhand.Events.GlobalRouteManager", "IsEnabled");
            var methodIsListenedTo = stardewContext.GetMethodDefinition("Farmhand.Events.GlobalRouteManager", "IsBeingPostListenedTo");
            MethodDefinition methodDefinition;

            methodDefinition = stardewContext.GetMethodDefinition("Farmhand.Events.GlobalRouteManager", "GlobalRoutePostInvoke",
                                                                  n => n.Parameters.Count == (returnsValue ? 5 : 4));

            if (methodDefinition == null || isEnabledField == null)
            {
                return;
            }

            var retInstructions = ilProcessor.Body.Instructions.Where(n => n.OpCode == OpCodes.Ret).ToArray();

            foreach (var ret in retInstructions)
            {
                var newInstructions = new List <Instruction>();

                newInstructions.Add(ilProcessor.PushFieldToStack(isEnabledField));
                newInstructions.Add(ilProcessor.BranchIfFalse(ret));

                newInstructions.Add(ilProcessor.PushInt32ToStack(index));
                newInstructions.Add(ilProcessor.Call(methodIsListenedTo));
                newInstructions.Add(ilProcessor.BranchIfFalse(ret));

                if (returnsValue)
                {
                    outputVar = new VariableDefinition("GlobalRouteOutput", objectType);
                    ilProcessor.Body.Variables.Add(outputVar);
                    if (method.ReturnType.IsPrimitive || method.ReturnType.IsGenericParameter)
                    {
                        newInstructions.Add(ilProcessor.Create(OpCodes.Box, method.ReturnType));
                    }
                    newInstructions.Add(ilProcessor.Create(OpCodes.Stloc, outputVar));
                }

                newInstructions.Add(ilProcessor.PushInt32ToStack(index));
                newInstructions.Add(ilProcessor.PushStringToStack(injecteeType));
                newInstructions.Add(ilProcessor.PushStringToStack(injecteeMethod));

                if (returnsValue)
                {
                    newInstructions.Add(ilProcessor.Create(OpCodes.Ldloca, outputVar));
                }

                int argIndex = 0;
                newInstructions.AddRange(ilProcessor.CreateArray(objectType, method.Parameters.Count + (hasThis ? 1 : 0)));

                if (method.HasThis)
                {
                    newInstructions.AddRange(ilProcessor.InsertParameterIntoArray(ilProcessor.Body.ThisParameter, argIndex++));
                }

                foreach (var param in method.Parameters)
                {
                    newInstructions.AddRange(ilProcessor.InsertParameterIntoArray(param, argIndex++));
                }

                newInstructions.Add(ilProcessor.Call(methodDefinition));

                if (returnsValue)
                {
                    newInstructions.Add(ilProcessor.Create(OpCodes.Ldloc, outputVar));
                    if (method.ReturnType.IsPrimitive || method.ReturnType.IsGenericParameter)
                    {
                        newInstructions.Add(ilProcessor.Create(OpCodes.Unbox_Any, method.ReturnType));
                    }
                    else
                    {
                        newInstructions.Add(ilProcessor.Create(OpCodes.Castclass, method.ReturnType));
                    }
                }

                ilProcessor.Body.SimplifyMacros();
                if (newInstructions.Any())
                {
                    var previousInstruction = newInstructions.First();
                    ilProcessor.InsertBefore(ret, previousInstruction);
                    for (var i = 1; i < newInstructions.Count; ++i)
                    {
                        ilProcessor.InsertAfter(previousInstruction, newInstructions[i]);
                        previousInstruction = newInstructions[i];
                    }
                }
                ilProcessor.Body.OptimizeMacros();
            }
        }