Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #3
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);
            }
        }
Пример #4
0
        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);
            }
        }
Пример #5
0
        /// <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);
        }
Пример #6
0
        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);
                    }
                }
            }
        }
Пример #7
0
        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));
        }
Пример #8
0
        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", );
        }
Пример #11
0
        /// <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.");
                }
            }
        }
Пример #13
0
        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"));
        }