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); } }
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)); } }
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); }
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); }
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)); } }
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)); } }
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); } }
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); } }
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(); } }
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(); }
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)); } }
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(); }
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(); } }