public static void HookGen(string inputPath, string outputPath) { using var mm = new MonoModder { InputPath = inputPath, OutputPath = outputPath, ReadingMode = ReadingMode.Deferred, DependencyDirs = { Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) + @"\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5", Path.Combine(libsPath, "Common") }, MissingDependencyThrow = false, }; mm.Read(); mm.MapDependencies(); var gen = new HookGenerator(mm, "TerrariaHooks") { HookPrivate = true, }; gen.Generate(); RemoveModLoaderTypes(gen.OutputModule); gen.OutputModule.Write(outputPath); }
public static int Main(string[] args) { if (args.Length < 1) { return(XConsole.PrintInfo("HookGenerator.CLI - generate API-like osu! methods access assembly\n" + "by exys, 2019\n" + "\n" + "Usage:\n" + "HookGenerator.CLI [clean module]")); } string originalModulePath; if (!File.Exists(originalModulePath = Path.GetFullPath(args[0]))) { return(XConsole.PrintError("Specified module path does not exist!")); } try { _originalModule = ModuleDefMD.Load(originalModulePath); } catch (Exception e) { return(XConsole.PrintError("An error occurred while trying to load module! Details:\n" + e)); } XConsole.PrintInfo($"Loaded module: {_originalModule.Assembly.FullName}."); var assemblyName = $"OsuHooks-{MD5Helper.Compute(originalModulePath).Substring(0, 8)}"; var moduleName = $"{assemblyName}.dll"; var hookModule = new HookGenerator(assemblyName, _originalModule).CreateHookModule(); XConsole.PrintInfo($"Finally writing {moduleName}!"); hookModule.Write(Path.Combine(Path.GetDirectoryName(originalModulePath) ?? throw new Exception("Path to write module to is null unexpectedly"), moduleName)); return(0); }
static void GenHooks(string input, string output) { Console.WriteLine($"Hooking: {input} -> {output}"); using (MonoModder mm = new MonoModder() { InputPath = input, OutputPath = output, ReadingMode = ReadingMode.Deferred, MissingDependencyThrow = false, }) { mm.Read(); mm.MapDependencies(); if (File.Exists(output)) { File.Delete(output); } HookGenerator gen = new HookGenerator(mm, Path.GetFileName(output)) { HookPrivate = true, }; gen.Generate(); gen.OutputModule.Write(output); } }
static HookgenPreloader() { Logging.LogMessage($"BepInEx-Partiality-Wrapper initializing HOOKS..."); if (!File.Exists(AsmCSharpFilePath)) { Logging.LogMessage($"Could not find 'Assembly-CSharp.dll' file, aborting HOOKS generatiion."); return; } if (File.Exists(HooksAsmFilePath)) { // if HOOKS file is older than the Assembly-Csharp file... if (File.GetLastWriteTime(HooksAsmFilePath) < File.GetLastWriteTime(AsmCSharpFilePath)) { Logging.LogMessage($"HOOKS file is outdated, deleting..."); File.Delete(HooksAsmFilePath); } else { Logging.LogMessage($"HOOKS file is up to date!"); return; } } Logging.LogMessage("Generating new HOOKS file..."); try { using (var modder = new MonoModder { InputPath = AsmCSharpFilePath, OutputPath = HooksAsmFilePath, PublicEverything = true, DependencyDirs = new List <string> { Paths.ManagedPath, HookgenPatcherFolder } }) { modder.Read(); modder.MapDependencies(); var generator = new HookGenerator(modder, Path.GetFileName(HooksAsmFilePath)); using (ModuleDefinition module = generator.OutputModule) { generator.HookPrivate = true; generator.Generate(); module.Write(HooksAsmFilePath); } } Logging.LogMessage("Done!"); } catch (Exception ex) { Logging.LogWarning($"Exception running HOOKS generation!"); Logging.LogMessage(ex); } }
/// <summary> /// Call Monomod hookgen. /// </summary> /// <param name="input">Input assembly</param> /// <param name="mmhookFolder">MMHOOK output folder</param> /// <returns></returns> public static bool GenerateMMHook(string input, string mmhookFolder, string md5, string ValheimPath, TaskLoggingHelper Log) { string output = Path.Combine(mmhookFolder, $"{JotunnBuildTask.Mmhook}_{Path.GetFileName(input)}"); Log.LogMessage(MessageImportance.High, $"Generating MMHOOK of {input}."); MonoModder modder = new MonoModder(); modder.InputPath = input; modder.OutputPath = output; modder.ReadingMode = ReadingMode.Deferred; ((BaseAssemblyResolver)modder.AssemblyResolver)?.AddSearchDirectory(Path.Combine(Environment.CurrentDirectory, "bin", "Debug")); ((BaseAssemblyResolver)modder.AssemblyResolver)?.AddSearchDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase.Replace("file:///home", "/home").Replace("file:///", ""))); if (Directory.Exists(Path.Combine(ValheimPath, JotunnBuildTask.ValheimData, JotunnBuildTask.Managed))) { ((BaseAssemblyResolver)modder.AssemblyResolver)?.AddSearchDirectory(Path.Combine(ValheimPath, JotunnBuildTask.ValheimData, JotunnBuildTask.Managed)); } if (Directory.Exists(Path.Combine(ValheimPath, JotunnBuildTask.ValheimServerData, JotunnBuildTask.Managed))) { ((BaseAssemblyResolver)modder.AssemblyResolver)?.AddSearchDirectory(Path.Combine(ValheimPath, JotunnBuildTask.ValheimServerData, JotunnBuildTask.Managed)); } ((BaseAssemblyResolver)modder.AssemblyResolver)?.AddSearchDirectory(Path.Combine(ValheimPath, JotunnBuildTask.UnstrippedCorlib)); modder.Read(); modder.MapDependencies(); if (File.Exists(output)) { Log.LogMessage(MessageImportance.High, $"Clearing {output}"); File.Delete(output); } HookGenerator hookGenerator = new HookGenerator(modder, Path.GetFileName(output)); hookGenerator.HookPrivate = true; using (ModuleDefinition mOut = hookGenerator.OutputModule) { hookGenerator.Generate(); mOut.Types.Add(new TypeDefinition("BepHookGen", "hash" + md5, TypeAttributes.AutoClass)); mOut.Write(output); } Log.LogMessage(MessageImportance.High, $"Finished writing {output}"); return(true); }
public void TestHookGenRun() { string outputPath = Path.Combine(Environment.CurrentDirectory, "testdump", "MonoMod.UnitTest.Hooks.dll"); try { string dir = Path.GetDirectoryName(outputPath); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } if (File.Exists(outputPath)) { File.SetAttributes(outputPath, FileAttributes.Normal); File.Delete(outputPath); } } catch (Exception e) { Console.WriteLine("Couldn't create testdump."); Console.WriteLine(e); } using (MonoModder mm = new MonoModder { InputPath = typeof(HookGenRunTest).Assembly.Location, ReadingMode = ReadingMode.Deferred, MissingDependencyThrow = false, }) { mm.Read(); mm.MapDependencies(); HookGenerator gen = new HookGenerator(mm, "MonoMod.UnitTest.Hooks") { HookPrivate = true, }; using (ModuleDefinition mOut = gen.OutputModule) { gen.Generate(); if (outputPath != null) { mOut.Write(outputPath); } else { using (MemoryStream ms = new MemoryStream()) mOut.Write(ms); } } } }
private void CheckHooks() { string asmPath = Path.Combine(Paths.ManagedPath, "Assembly-CSharp.dll"); string hooksPath = Path.Combine(PluginFolder, "HOOKS-Assembly-CSharp.dll"); if (File.Exists(hooksPath)) { // if HOOKS file is older than the Assembly-Csharp file... if (File.GetLastWriteTime(hooksPath) < File.GetLastWriteTime(asmPath)) { File.Delete(hooksPath); } else { return; } } Logger.Log(LogLevel.Message, "Generating new HOOKS file..."); using (var modder = new MonoModder { InputPath = asmPath, OutputPath = hooksPath, PublicEverything = true, DependencyDirs = new List <string> { Paths.ManagedPath, PluginFolder } }) { modder.Read(); modder.MapDependencies(); var generator = new HookGenerator(modder, Path.GetFileName(hooksPath)); using (ModuleDefinition module = generator.OutputModule) { generator.HookPrivate = true; generator.Generate(); module.Write(hooksPath); } } Assembly.Load(File.ReadAllBytes(hooksPath)); }
public static void HookGen(string inputPath, string outputPath, string refsDir) { using (var mm = new MonoModder { InputPath = inputPath, OutputPath = outputPath, ReadingMode = ReadingMode.Deferred, MissingDependencyThrow = false, }) { mm.Read(); mm.MapDependencies(); mm.DependencyCache["MonoMod.RuntimeDetour"] = ModuleDefinition.ReadModule(Path.Combine(refsDir, "MonoMod.RuntimeDetour.dll")); var gen = new HookGenerator(mm, "TerrariaHooks") { HookPrivate = true, }; gen.Generate(); gen.OutputModule.Write(outputPath); } }
/// <summary>Generates the HOOKS-Assembly-CSharp.dll the same as Partiality</summary> void GenerateHooks() { string pathIn = Path.Combine(Paths.ManagedPath, "Assembly-CSharp.dll"); string pathOut = Path.Combine(Path.GetDirectoryName(Info.Location), "HOOKS-Assembly-CSharp.dll"); if (File.Exists(pathOut)) { // Only Regenerate if Managed is newer than HOOKS if (File.GetLastWriteTime(pathOut) > File.GetLastWriteTime(pathIn)) { return; } File.Delete(pathOut); } using (MonoModder mm = new MonoModder { InputPath = pathIn, OutputPath = pathOut, PublicEverything = true, DependencyDirs = new List <string>() { Paths.ManagedPath, Paths.BepInExAssemblyDirectory }, }) { mm.Read(); mm.MapDependencies(); mm.Log("[HookGen] Starting HookGenerator"); HookGenerator gen = new HookGenerator(mm, Path.GetFileName(pathOut)); using (ModuleDefinition mOut = gen.OutputModule) { gen.HookPrivate = true; gen.Generate(); mOut.Write(pathOut); } mm.Log("[HookGen] Done."); } }
public static void PatchGame() { string executablePath = Assembly.GetEntryAssembly().Location; string executableDirectory = Directory.GetParent(executablePath).FullName; string monoModPath = Path.Combine(executableDirectory, "MonoMod.exe"); string hookGenPath = Path.Combine(executableDirectory, "MonoMod.RuntimeDetour.HookGen.exe"); string runtimeDetourDLL = "MonoMod.RuntimeDetour.dll"; string mmUtilsDLL = "MonoMod.Utils.dll"; string jsonDLL = "YamlDotNet.dll"; string gameDirectory = Directory.GetParent(GameManager.exePath).FullName; string hashesFolder = Path.Combine(gameDirectory, "DustDevilHashes"); string modDependencies = Path.Combine(gameDirectory, "ModDependencies"); string dataDirectory = Path.Combine(gameDirectory, Path.GetFileNameWithoutExtension(GameManager.exePath) + "_Data"); string managedFolder = Path.Combine(dataDirectory, "Managed"); string codeDll = Path.Combine(managedFolder, "Assembly-CSharp.dll"); string hookGenDLL = Path.Combine(managedFolder, "HOOKS-Assembly-CSharp.dll"); string engineDll = Path.Combine(managedFolder, "UnityEngine.dll"); string coreModuleDLL = Path.Combine(managedFolder, "UnityEngine.CoreModule.dll"); string backupFolder = managedFolder + "_backup"; Process currentProcess = Process.GetCurrentProcess(); Process monomodProcess = new Process(); monomodProcess.StartInfo.FileName = monoModPath; //monomodProcess.StartInfo.CreateNoWindow = true; monomodProcess.StartInfo.UseShellExecute = false; monomodProcess.StartInfo.RedirectStandardOutput = true; //Create backup if there isn't one if (!Directory.Exists(backupFolder)) { Directory.CreateDirectory(backupFolder); CopyFilesRecursively(managedFolder, backupFolder); } //Install the default patch for Partiality { string engineDLLName = "UnityEngine.dll"; if (File.Exists(coreModuleDLL)) { engineDLLName = "UnityEngine.CoreModule.dll"; engineDll = coreModuleDLL; } string moddedDLL = Path.Combine(Path.GetDirectoryName(engineDll), "patched" + engineDLLName); string defaultPatchLocation = Path.Combine(executableDirectory, "PartialityPatch.dll"); string partialityModLocation = Path.Combine(Path.GetDirectoryName(engineDll), "Partiality.dll"); bool shouldPatch = false; if (!File.Exists(Path.Combine(hashesFolder, "ENGINEHASH.hash"))) { shouldPatch = true; } else { shouldPatch = !ModMetadata.CompareHashes(defaultPatchLocation, Path.Combine(hashesFolder, "ENGINEHASH.hash")); } //Delete mod if it exists if (File.Exists(partialityModLocation)) { File.Delete(partialityModLocation); } //Copy mod to folder with assembly-chsharp.dll File.Copy(Path.Combine(executableDirectory, "Partiality.dll"), partialityModLocation); if (shouldPatch) { //Restore backup File.Delete(engineDll); File.Copy(Path.Combine(backupFolder, engineDLLName), engineDll); //Set monomod arguments to "[UnityEngine.dll] [PartialityPatch.dll] [patched_UnityEngine.dll]" monomodProcess.StartInfo.Arguments = ('"' + engineDll + '"') + " " + ('"' + defaultPatchLocation + '"') + " " + ('"' + moddedDLL + '"'); monomodProcess.Start(); string mmoutput = monomodProcess.StandardOutput.ReadToEnd(); Console.WriteLine(mmoutput); monomodProcess.WaitForExit(); int exitCode = monomodProcess.ExitCode; Console.WriteLine("MMEC:" + exitCode); Console.WriteLine(mmoutput); //Replace file if (File.Exists(moddedDLL)) { //Move modded .dll over original .dll File.Delete(engineDll); File.Copy(moddedDLL, engineDll); File.Delete(moddedDLL); } byte[] newHash = ChecksumHasher.ComputeHash(File.ReadAllBytes(defaultPatchLocation)); File.WriteAllBytes(Path.Combine(hashesFolder, "ENGINEHASH.hash"), newHash); } } //Install custom patches { string[] files = Directory.GetFiles(modDependencies); //Copy mod dependencies foreach (string dependency in files) { string fileName = Path.GetFileName(dependency); //Delete the dependency if it already exists if (File.Exists(Path.Combine(managedFolder, fileName))) { File.Delete(Path.Combine(managedFolder, fileName)); } //Copy the file File.Copy(dependency, Path.Combine(managedFolder, fileName)); } bool shouldPatch = false; string moddedDLL = Path.Combine(Path.GetDirectoryName(engineDll), "patched_Assembly-CSharp.dll"); string epListLocation = Path.Combine(hashesFolder, "ENABLEDPATCHES.enp"); //Check if we have the same enabled/disabled mods as last time, if we do, then { string totalEnabledPatches = "Partiality+"; foreach (ModMetadata md in GameManager.modMetas) { if ((md.isStandalone || md.isPatch) && md.isEnabled) { totalEnabledPatches += Path.GetFileNameWithoutExtension(md.modPath) + "+"; } } DebugLogger.Log(totalEnabledPatches); if (File.Exists(epListLocation)) { string getList = File.ReadAllText(epListLocation); shouldPatch = getList != totalEnabledPatches; if (shouldPatch) { File.WriteAllText(epListLocation, totalEnabledPatches); } } else { shouldPatch = true; File.WriteAllText(epListLocation, totalEnabledPatches); } } //If all the same mods are enabled, check if any mods are dirty. If they are, we gotta re-patch. if (!shouldPatch) { foreach (ModMetadata md in GameManager.modMetas) { if (md.isDirty) { shouldPatch = true; break; } } } if (shouldPatch) { DebugLogger.Log("Patching Assembly-CSharp"); string backupDll = Path.Combine(backupFolder, "Assembly-CSharp.dll"); foreach (ModMetadata md in GameManager.modMetas) { if (md.isStandalone && md.isEnabled) { backupDll = md.modPath; } } //Restore backup File.Delete(codeDll); File.Copy(backupDll, codeDll); List <string> failedPatches = new List <string>(); foreach (ModMetadata md in GameManager.modMetas) { if (md.isPatch && md.isEnabled) { monomodProcess.StartInfo.Arguments = ('"' + codeDll + '"') + " " + ('"' + md.modPath + '"') + " " + ('"' + moddedDLL + '"'); monomodProcess.Start(); string mmoutput = monomodProcess.StandardOutput.ReadToEnd(); monomodProcess.WaitForExit(); int exitCode = monomodProcess.ExitCode; DebugLogger.Log("MMEC:" + exitCode); DebugLogger.Log(mmoutput); if (exitCode != 0) { failedPatches.Add(Path.GetFileNameWithoutExtension(md.modPath)); } //Replace file if (File.Exists(moddedDLL)) { //Move modded .dll over original .dll File.Delete(codeDll); File.Copy(moddedDLL, codeDll); File.Delete(moddedDLL); } } } if (failedPatches.Count > 0) { Eto.Forms.MessageBox.Show("Some mods failed to apply correctly! Please send your LOG.txt (in the Partiality folder) to someone who can help, probably from the people who made the mod."); } //Set mods to all not be dirty, and save them. foreach (ModMetadata md in GameManager.modMetas) { md.isDirty = false; } try { GameManager.SaveAllMetadata(); } catch (System.Exception e) { DebugLogger.Log(e); } } } //HookGen stuff { //Delete Legacy DLL if (File.Exists(Path.Combine(managedFolder, "HOOKS-Assembly-CSharp.dll"))) { File.Delete(Path.Combine(managedFolder, "HOOKS-Assembly-CSharp.dll")); } if (File.Exists(hookGenDLL)) { File.Delete(hookGenDLL); } //Delete files if they existed, so we can update them. if (File.Exists(Path.Combine(managedFolder, runtimeDetourDLL))) { File.Delete(Path.Combine(managedFolder, runtimeDetourDLL)); } if (File.Exists(Path.Combine(managedFolder, mmUtilsDLL))) { File.Delete(Path.Combine(managedFolder, mmUtilsDLL)); } if (File.Exists(Path.Combine(managedFolder, jsonDLL))) { File.Delete(Path.Combine(managedFolder, jsonDLL)); } //Copy files File.Copy(Path.Combine(executableDirectory, runtimeDetourDLL), Path.Combine(managedFolder, runtimeDetourDLL)); File.Copy(Path.Combine(executableDirectory, mmUtilsDLL), Path.Combine(managedFolder, mmUtilsDLL)); File.Copy(Path.Combine(executableDirectory, jsonDLL), Path.Combine(managedFolder, jsonDLL)); string pathIn = codeDll; string pathOut = hookGenDLL; using (MonoModder mm = new MonoModder { InputPath = pathIn, OutputPath = pathOut }) { mm.Read(); mm.MapDependencies(); if (File.Exists(pathOut)) { mm.Log(string.Format("Clearing {0}", pathOut)); File.Delete(pathOut); } mm.Log("[HookGen] Starting HookGenerator"); HookGenerator gen = new HookGenerator(mm, Path.GetFileName(pathOut)); using (ModuleDefinition mOut = gen.OutputModule) { gen.HookPrivate = true; gen.Generate(); mOut.Write(pathOut); } mm.Log("[HookGen] Done."); } } //File.WriteAllText( gameDirectory + "\\PARTIALITY_OUTPUT.txt", ); }
/// <summary> /// Runs HookGen on an assembly located in Managed /// </summary> /// <param name="assemblyName"></param> public void RunHookGen(string assemblyName) { string assemblyPath = FindAssemblyByName(assemblyName); if (assemblyPath == string.Empty) { return; } string hooksPath = Path.Combine(Directory.GetParent(assemblyPath).FullName, Path.GetFileNameWithoutExtension(assemblyPath) + "-HOOKS.dll"); using (MonoModder mm = new MonoModder() { InputPath = assemblyPath, OutputPath = hooksPath, ReadingMode = ReadingMode.Deferred }) { mm.Read(); mm.MapDependencies(); if (File.Exists(hooksPath)) { File.Delete(hooksPath); } HookGenerator gen = new HookGenerator(mm, Path.GetFileName(hooksPath)); #if !CECIL0_9 using (ModuleDefinition mOut = gen.OutputModule) { #else ModuleDefinition mOut = gen.OutputModule; { #endif gen.Generate(); mOut.Write(hooksPath); } } string managedPath = Directory.GetParent(assemblyPath).FullName; string currentDirectory = Directory.GetParent(Assembly.GetExecutingAssembly().FullName).FullName; string[] filesToCopy = new string[] { "MonoMod.dll", "MonoMod.RuntimeDetour.dll", "MonoMod.Utils.dll", }; foreach (string s in filesToCopy) { string fromPath = Path.Combine(currentDirectory, s); string toPath = Path.Combine(managedPath, s); if (File.Exists(fromPath)) { File.Delete(fromPath); } File.Copy(fromPath, toPath); } }
/** * Code largely based on https://github.com/MonoMod/MonoMod/blob/master/MonoMod.RuntimeDetour.HookGen/Program.cs */ public static void Initialize() { var assemblyNames = AssemblyNamesToHookGenPatch.Value.Split(EntrySeparator); var mmhookFolder = Path.Combine(Paths.PluginPath, "MMHOOK"); foreach (var customAssemblyName in assemblyNames) { var mmhookFileName = "MMHOOK_" + customAssemblyName; string pathIn = Path.Combine(Paths.ManagedPath, customAssemblyName); string pathOut = Path.Combine(mmhookFolder, mmhookFileName); bool shouldCreateDirectory = true; foreach (string mmhookFile in Directory.GetFiles(Paths.PluginPath, mmhookFileName, SearchOption.AllDirectories)) { if (Path.GetFileName(mmhookFile).Equals(mmhookFileName)) { pathOut = mmhookFile; Logger.LogInfo("Previous MMHOOK location found. Using that location to save instead."); shouldCreateDirectory = false; break; } } if (shouldCreateDirectory) { Directory.CreateDirectory(mmhookFolder); } var fileInfo = new FileInfo(pathIn); var size = fileInfo.Length; long hash = 0; if (File.Exists(pathOut)) { try { using (var oldMM = AssemblyDefinition.ReadAssembly(pathOut)) { bool mmSizeHash = oldMM.MainModule.GetType("BepHookGen.size" + size) != null; if (mmSizeHash) { if (skipHashing) { Logger.LogInfo("Already ran for this version, reusing that file."); continue; } hash = fileInfo.makeHash(); bool mmContentHash = oldMM.MainModule.GetType("BepHookGen.content" + hash) != null; if (mmContentHash) { Logger.LogInfo("Already ran for this version, reusing that file."); continue; } } } } catch (BadImageFormatException) { Logger.LogWarning($"Failed to read {Path.GetFileName(pathOut)}, probably corrupted, remaking one."); } } Environment.SetEnvironmentVariable("MONOMOD_HOOKGEN_PRIVATE", "1"); Environment.SetEnvironmentVariable("MONOMOD_DEPENDENCY_MISSING_THROW", "0"); using (MonoModder mm = new MonoModder() { InputPath = pathIn, OutputPath = pathOut, ReadingMode = ReadingMode.Deferred }) { (mm.AssemblyResolver as BaseAssemblyResolver)?.AddSearchDirectory(Paths.BepInExAssemblyDirectory); mm.Read(); mm.MapDependencies(); if (File.Exists(pathOut)) { Logger.LogDebug($"Clearing {pathOut}"); File.Delete(pathOut); } Logger.LogInfo("Starting HookGenerator"); HookGenerator gen = new HookGenerator(mm, Path.GetFileName(pathOut)); using (ModuleDefinition mOut = gen.OutputModule) { gen.Generate(); mOut.Types.Add(new TypeDefinition("BepHookGen", "size" + size, TypeAttributes.Class | TypeAttributes.Public, mOut.TypeSystem.Object)); if (!skipHashing) { mOut.Types.Add(new TypeDefinition("BepHookGen", "content" + (hash == 0 ? fileInfo.makeHash() : hash), TypeAttributes.Class | TypeAttributes.Public, mOut.TypeSystem.Object)); } mOut.Write(pathOut); } Logger.LogInfo("Done."); } } }
public override void Run() { if (!File.Exists(Program.TerrariaPath)) { throw new FileNotFoundException(Program.TerrariaPath); } var outputPath = Path.Combine(Program.ReferencesDir, "TerrariaHooks.Windows.dll"); if (File.Exists(outputPath)) { File.Delete(outputPath); } taskInterface.SetStatus($"Hooking: Terraria.exe -> TerrariaHooks.dll"); using (MonoModder mm = new MonoModder { InputPath = Program.TerrariaPath, OutputPath = outputPath, ReadingMode = ReadingMode.Deferred, MissingDependencyThrow = false, }) { mm.Read(); mm.MapDependencies(); mm.DependencyCache["MonoMod.RuntimeDetour"] = ModuleDefinition.ReadModule(Path.Combine(Program.ReferencesDir, "MonoMod.RuntimeDetour.dll")); HookGenerator gen = new HookGenerator(mm, "TerrariaHooks") { HookPrivate = true, }; gen.Generate(); gen.OutputModule.Write(outputPath); } taskInterface.SetStatus($"XnaToFna: TerrariaHooks.Windows.dll -> TerrariaHooks.Mono.dll"); var monoPath = Path.Combine(Program.ReferencesDir, "TerrariaHooks.Mono.dll"); if (File.Exists(monoPath)) { File.Delete(monoPath); } File.Copy(outputPath, monoPath); using (var xnaToFnaUtil = new XnaToFnaUtil { HookCompatHelpers = false, HookEntryPoint = false, DestroyLocks = false, StubMixedDeps = false, DestroyMixedDeps = false, HookBinaryFormatter = false, HookReflection = false, AddAssemblyReference = false }) { xnaToFnaUtil.ScanPath(Path.Combine(Program.ReferencesDir, "FNA.dll")); xnaToFnaUtil.ScanPath(monoPath); xnaToFnaUtil.RelinkAll(); } File.Delete(Path.ChangeExtension(monoPath, "pdb")); }