protected void HookApiVirtualAlterations <T>(CecilContext cecilContext) { try { var types = FarmhandAssemblies.SelectMany(a => a.GetTypesWithCustomAttribute(typeof(T).FullName)).ToArray(); foreach (var asmType in types) { try { if (asmType.BaseType != null) { CecilHelper.SetVirtualOnBaseMethods(cecilContext, asmType.BaseType.FullName ?? asmType.BaseType.Namespace + "." + asmType.BaseType.Name); } } catch (Exception ex) { Console.WriteLine($"Error setting protections for {asmType.FullName}: \n\t{ex.Message}"); } } } catch (System.Reflection.ReflectionTypeLoadException ex) { Console.WriteLine($"Error setting method/field protections: \n\t{ex.Message}\n\t\t{ex.LoaderExceptions[0].Message}"); } catch (Exception ex) { Console.WriteLine($"Error setting method/field protections: \n\t{ex.Message}"); } }
public override void PatchStardew(string path = null) { InjectFarmhandCoreClasses(PatcherConstants.PassTwoPackageResult, PatcherConstants.PassOneFarmhandExe, PatcherConstants.FarmhandUiDll, PatcherConstants.FarmhandGameDll, PatcherConstants.FarmhandCharacterDll); var cecilContext = new CecilContext(PatcherConstants.PassTwoPackageResult, true); FarmhandAssemblies.Add(Assembly.LoadFrom(PatcherConstants.FarmhandUiDll)); FarmhandAssemblies.Add(Assembly.LoadFrom(PatcherConstants.FarmhandGameDll)); FarmhandAssemblies.Add(Assembly.LoadFrom(PatcherConstants.FarmhandCharacterDll)); HookApiEvents(cecilContext); HookOutputableApiEvents(cecilContext); HookApiFieldProtectionAlterations <HookAlterBaseFieldProtectionAttribute>(cecilContext); HookApiTypeProtectionAlterations <HookAlterProtectionAttribute>(cecilContext); HookApiVirtualAlterations <HookForceVirtualBaseAttribute>(cecilContext); HookMakeBaseVirtualCallAlterations <HookMakeBaseVirtualCallAttribute>(cecilContext); HookConstructionRedirectors <HookRedirectConstructorFromBaseAttribute>(cecilContext); HookConstructionToMethodRedirectors(cecilContext); HookGlobalRouting(cecilContext); Console.WriteLine("Second Pass Installation Completed"); path = path ?? PatcherConstants.FarmhandExe; cecilContext.WriteAssembly(path, true); }
protected void HookMakeBaseVirtualCallAlterations <T>(CecilContext cecilContext) { try { var methods = FarmhandAssemblies.SelectMany(a => a.GetMethodsWithCustomAttribute(typeof(T).FullName)).ToArray(); foreach (var asmMethod in methods) { try { SetVirtualCallOnMethod(cecilContext, asmMethod); } catch (Exception ex) { if (asmMethod.DeclaringType != null) { Console.WriteLine($"Error setting protections for {asmMethod.DeclaringType.FullName}.{asmMethod.Name}: \n\t{ex.Message}"); } } } } catch (System.Reflection.ReflectionTypeLoadException ex) { Console.WriteLine($"Error setting method/field protections: \n\t{ex.Message}\n\t\t{ex.LoaderExceptions[0].Message}"); } catch (Exception ex) { Console.WriteLine($"Error setting method/field protections: \n\t{ex.Message}"); } }
protected void HookConstructionRedirectors <T>(CecilContext cecilContext) { try { var test = FarmhandAssemblies.SelectMany(a => a.GetTypes()); var types = FarmhandAssemblies.SelectMany(a => a.GetTypesWithCustomAttribute(typeof(T).FullName)).ToArray(); foreach (var asmType in types) { try { RedirectConstructorInMethod(cecilContext, asmType); } catch (Exception ex) { Console.WriteLine($"Error setting protections for {asmType.FullName}: \n\t{ex.Message}"); } } } catch (System.Reflection.ReflectionTypeLoadException ex) { Console.WriteLine($"Error setting method/field protections: \n\t{ex.Message}\n\t\t{ex.LoaderExceptions[0].Message}"); } catch (Exception ex) { Console.WriteLine($"Error setting method/field protections: \n\t{ex.Message}"); } }
protected void HookApiTypeProtectionAlterations <T>(CecilContext cecilContext) { try { var types = FarmhandAssemblies.SelectMany(a => a.GetTypesWithCustomAttribute(typeof(T).FullName)).ToArray(); foreach (var asmType in types) { try { AlterTypeProtections(cecilContext, asmType); } catch (Exception ex) { Console.WriteLine($"Error setting protections for {asmType.FullName}: \n\t{ex.Message}"); } } } catch (System.Reflection.ReflectionTypeLoadException ex) { Console.WriteLine($"Error setting type protections: \n\t{ex.Message}\n\t\t{ex.LoaderExceptions[0].Message}"); } catch (Exception ex) { Console.WriteLine($"Error setting type protections: \n\t{ex.Message}"); } }
protected override void HookConstructionToMethodRedirectors(CecilContext cecilContext) { var methods = FarmhandAssemblies.SelectMany(a => a.GetTypes()) .SelectMany(t => t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) .Where(m => m.GetCustomAttributes(typeof(HookRedirectConstructorToMethodAttribute), false).Any()) .ToArray(); foreach (var method in methods) { // Check if this method has any properties that would immediately disqualify it from using this hook if (method.ReturnType == typeof(void)) { Logging.Log.Warning($"{method.Name} in {method.DeclaringType.FullName} cannot be used in a hook because it does not return a value!"); continue; } if (!method.IsStatic) { Logging.Log.Warning($"{method.Name} in {method.DeclaringType.FullName} cannot be used in a hook because it is not static!"); continue; } // Get the type that the method returns var typeName = method.ReturnType.FullName; // Get the name of the method var methodName = method.Name; // Get the type name of the method var methodDeclaringType = method.DeclaringType.FullName; // Get an array of parameters that the method returns var methodParameterInfo = method.GetParameters(); Type[] methodParamters = new Type[methodParameterInfo.Length]; for (int i = 0; i < methodParamters.Length; i++) { methodParamters[i] = methodParameterInfo[i].ParameterType; } // Get all the hooks for this method var hookAttributes = method.GetCustomAttributes(typeof(HookRedirectConstructorToMethodAttribute), false).Cast <HookRedirectConstructorToMethodAttribute>(); foreach (var hook in hookAttributes) { // Get the type name that contains the method we're hooking in var hookTypeName = hook.Type; // Get the name of the method we're hooking in var hookMethodName = hook.Method; try { CecilHelper.RedirectConstructorToMethod(cecilContext, method.ReturnType, hookTypeName, hookMethodName, methodDeclaringType, methodName, methodParamters); } catch (Exception ex) { Console.WriteLine($"Failed to Inject {typeName}.{methodName} into {hookTypeName}.{hookMethodName}\n\t{ex.Message}"); throw ex; } } } }
private void HookOutputableApiEvents(CecilContext cecilContext) { try { var methods = FarmhandAssemblies.SelectMany(a => a.GetTypes()) .SelectMany(t => t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) .Where(m => m.GetCustomAttributes(typeof(HookReturnableAttribute), false).Any()) .ToArray(); foreach (var method in methods) { if (method.DeclaringType == null) { continue; } var typeName = method.DeclaringType.FullName; var methodName = method.Name; var hookAttributes = method.GetCustomAttributes(typeof(HookReturnableAttribute), false).Cast <HookReturnableAttribute>(); foreach (var hook in hookAttributes) { var hookTypeName = hook.Type; var hookMethodName = hook.Method; try { switch (hook.HookType) { case HookType.Entry: CecilHelper.InjectReturnableEntryMethod <ParameterBindAttribute, ThisBindAttribute, InputBindAttribute, LocalBindAttribute, UseOutputBindAttribute, MethodOutputBindAttribute> (cecilContext, hookTypeName, hookMethodName, typeName, methodName); break; case HookType.Exit: CecilHelper.InjectReturnableExitMethod <ParameterBindAttribute, ThisBindAttribute, InputBindAttribute, LocalBindAttribute, UseOutputBindAttribute, MethodOutputBindAttribute> (cecilContext, hookTypeName, hookMethodName, typeName, methodName); break; default: throw new Exception("Unknown HookType"); } } catch (Exception ex) { Console.WriteLine($"Failed to Inject {typeName}.{methodName} into {hookTypeName}.{hookMethodName}\n\t{ex.Message}"); } } } } catch (Exception ex) { Console.WriteLine(ex.Message); } }
/// <summary> /// /// </summary> /// <param name="path">Stardew EXE Path</param> public override void PatchStardew(string path = null) { path = path ?? PatcherConstants.StardewExe; InjectFarmhandCoreClasses(PatcherConstants.PassOnePackageResult, path, PatcherConstants.FarmhandDll, PatcherConstants.JsonLibrary); var cecilContext = new CecilContext(PatcherConstants.PassOnePackageResult, true); FarmhandAssemblies.Add(Assembly.LoadFrom(PatcherConstants.FarmhandDll)); HookApiEvents(cecilContext); HookOutputableApiEvents(cecilContext); HookApiFieldProtectionAlterations <HookAlterBaseFieldProtectionAttribute>(cecilContext); HookApiTypeProtectionAlterations <HookAlterProtectionAttribute>(cecilContext); HookApiVirtualAlterations <HookForceVirtualBaseAttribute>(cecilContext); HookMakeBaseVirtualCallAlterations <HookMakeBaseVirtualCallAttribute>(cecilContext); HookConstructionRedirectors <HookRedirectConstructorFromBaseAttribute>(cecilContext); HookConstructionToMethodRedirectors(cecilContext); Console.WriteLine("First Pass Installation Completed"); cecilContext.WriteAssembly(PatcherConstants.PassOneFarmhandExe, true); }