public static void Init()
        {
            try {
                Modder = new MonoModder()
                {
                    InputPath      = Assembly.GetExecutingAssembly().Location,
                    CleanupEnabled = false,
                    DependencyDirs =
                    {
                        ModRelinker.ManagedDirectory
                    }
                };

                Modder.ReaderParameters.ReadSymbols = false;

                // DON'T. The assembly is already patched with the .mm.dlls in there!
                // Otherwise this code here wouldn't even run...
                // Modder.ReadMod(ModRelinker.ManagedDirectory);

                Modder.Read();
                Modder.MapDependencies();

                // Do black magic.
                HarmonyInstance.DEBUG = true;
                MMHarmony             = new MMHarmonyInstance(Modder, Assembly.GetExecutingAssembly());
            } catch (Exception e) {
                ModLogger.Log("rtpatcher", $"Failed initializing: {e}");
                return;
            }
        }
示例#2
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);
        }
示例#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
    public void RunMonoMod()
    {
        Environment.SetEnvironmentVariable("MONOMOD_DEPENDENCY_MISSING_THROW", "0");

        if (this.verbosity > 0)
        {
            Environment.SetEnvironmentVariable("MONOMOD_LOG_VERBOSE", "1");
        }

        using (MonoModder mm = new MonoModder()
        {
            InputPath = this.assemblyPath,
            OutputPath = AssemblyTmpPath,
        })
        {
            // read assembly
            mm.Read();

            // read Seshat.dll
            mm.ReadMod(this.seshatPath);
            mm.MapDependencies();

            // autopatch
            mm.AutoPatch();

            // write assembly
            mm.Write();
        }
    }
示例#5
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);
            }
        }
示例#6
0
        /// <summary>
        /// Perform the actual patching of Assembly-CSharp.dll in the Risk of Rain 2 managed folder
        /// </summary>
        /// <param name="modPath">The path to the Assembly-CSharp.HexiDave.mm.dll file</param>
        private static void PatchWithMod(string modPath)
        {
            // Ensure that we have an Assembly-CSharp.dll.original file to work from
            FileUtilities.EnsureBackup();

            // Get a temporary file to write the new assembly to
            var outputPath = Path.GetTempFileName();

            // Setup MonoModder to patch the original Assembly-CSharp.dll
            using (var monoModder = new MonoModder
            {
                InputPath = FileUtilities.BackupAssemblyPath,
                OutputPath = outputPath
            })
            {
                // Read the assembly
                monoModder.Read();

                // Read the patch
                monoModder.ReadMod(modPath);

                // Ensure all the assembly references are still set
                monoModder.MapDependencies();

                // Re-write assembly with patch functions
                monoModder.AutoPatch();

                // Spit the file out
                monoModder.Write();
            }

            // Clear the assembly in RoR2's managed folder
            File.Delete(FileUtilities.AssemblyPath);

            // Move the patched assembly into place
            File.Move(outputPath, FileUtilities.AssemblyPath);

            // Make sure any dependencies are moved
            // TODO: Maybe remove this, but still tinkering
            var filesToInclude = new[]
            {
                "Mono.Cecil.dll"
            };

            foreach (var fileName in filesToInclude)
            {
                var moveToPath = $@"{FileUtilities.ManagedPath}\{fileName}";

                if (!File.Exists(moveToPath))
                {
                    File.Move(fileName, moveToPath);
                }
            }
        }
示例#7
0
        /// <summary>
        /// Patches an assembly located in Managed.
        /// </summary>
        /// <param name="pathToPatch"></param>
        /// <param name="assemblyName"></param>
        public void PatchAssembly(string pathToPatch, string assemblyName, string[] dependencies)
        {
            string assemblyPath = FindAssemblyByName(assemblyName);

            if (assemblyPath == string.Empty)
            {
                return;
            }

            string outputPath = Path.Combine(Directory.GetParent(assemblyPath).FullName, Path.GetFileNameWithoutExtension(assemblyPath) + "-NEW.dll");

            Console.WriteLine(assemblyPath);
            Console.WriteLine(outputPath);

            using (MonoModder mm = new MonoModder()
            {
                InputPath = assemblyPath,
                OutputPath = outputPath
            }) {
                mm.LogVerboseEnabled = true;
                mm.Read();
                //Force everything to be public
                mm.PublicEverything = true;

                //Read in the patch
                mm.ReadMod(pathToPatch);

                mm.MapDependencies();
                mm.DependencyDirs.Add(Directory.GetParent(Assembly.GetExecutingAssembly().FullName).FullName);

                mm.AutoPatch();

                mm.Write();
            }

            File.Delete(assemblyPath);
            File.Copy(outputPath, assemblyPath);
            File.Delete(outputPath);

            string managedPath = Directory.GetParent(assemblyPath).FullName;

            foreach (string s in dependencies)
            {
                string dependencyDestination = Path.Combine(managedPath, Path.GetFileName(s));

                if (File.Exists(dependencyDestination))
                {
                    File.Delete(dependencyDestination);
                }
                File.Copy(s, dependencyDestination);
            }
        }
示例#8
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);
        }
示例#9
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);
                    }
                }
            }
        }
        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 LoadPatch(Stream stream)
 {
     try {
         ModLogger.Log("rtpatcher", "Loading new patch");
         // Reload main assembly.
         Modder.Module = null;
         Modder.Read();
         // Add new mod to mods list.
         Modder.ReadMod(stream);
         ModRelinker.AssemblyRelinkMap[Modder.Mods[Modder.Mods.Count - 1].Assembly.Name.Name] = ModRelinker.AssemblyRelinkedCache["Assembly-CSharp"];
         Modder.MapDependencies();
         // Auto-patch and then feed Harmony.
         ModLogger.Log("rtpatcher", $"Applying new patch {Modder.Mods[Modder.Mods.Count - 1].Assembly.Name.Name}");
         Modder.AutoPatch();
         MMHarmony.PatchAll();
     } catch (Exception e) {
         ModLogger.Log("rtpatcher", $"Failed patching: {e}");
         return;
     }
 }
示例#12
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);
            }
        }
示例#13
0
        private void _Relink(string input, string output)
        {
            using (var modder = new MonoModder()
            {
                InputPath = input,
                OutputPath = output
            }) {
                modder.CleanupEnabled = false;

                modder.RelinkModuleMap = AssemblyRelinkMap;

                modder.ReaderParameters.ReadSymbols          = false;
                modder.WriterParameters.WriteSymbols         = false;
                modder.WriterParameters.SymbolWriterProvider = null;

                modder.Read();
                modder.MapDependencies();
                modder.AutoPatch();
                modder.Write();
            }
        }
示例#14
0
        public void Patch()
        {
            // Load the assembly to check if it needs to be patched first
            string assemblyPath       = Path.Combine(_assemblyDirectory, AssemblyName);
            string assemblyBackupPath = assemblyPath.Replace(AssemblyName, AssemblyBackupName);

            if (!IsPatchingNeeded(assemblyPath))
            {
                Console.WriteLine("Game is already patched, no further action required.");
                return;
            }

            // Copy the required assemblies to the game directory
            foreach (var assemblyName in PatchAssemblies)
            {
                File.Copy(assemblyName, Path.Combine(_assemblyDirectory, assemblyName), true);
            }
            File.Copy(assemblyPath, assemblyBackupPath, true);

            // Run MonoMod
            Console.WriteLine("Patching game...");
            using (MonoModder mm = new MonoModder()
            {
                InputPath = assemblyBackupPath,
                OutputPath = assemblyPath + ".tmp"
            })
            {
                Environment.SetEnvironmentVariable("MONOMOD_DEPENDENCY_MISSING_THROW", "0");
                mm.Read();
                mm.ReadMod(Path.Combine(_assemblyDirectory, AssemblyPatchName));
                mm.MapDependencies();
                mm.AutoPatch();
                mm.Write();
            }

            // Copy the resultant assembly
            File.Delete(assemblyPath);
            File.Move(assemblyPath + ".tmp", assemblyPath);
        }
        /// <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.");
            }
        }
示例#16
0
        public static void Main(string[] args)
        {
            // Backup the assembly before setup
            FileUtilities.EnsureBackup();

            // Rebuild the GamePath.targets file with correct game path
            ReplaceGamePathTarget();

            // Directory for storing 'public'-ified assembly
            var libsDir = $@"{EnvHelper.SolutionDir}\libs";

            // Ensure the path exists for output
            Directory.CreateDirectory(libsDir);

            // Output path for the assembly
            var publicAssemblyPath = $@"{libsDir}\{FileUtilities.AssemblyFileName}";

            // Remove the old one, if it exists
            if (File.Exists(publicAssemblyPath))
            {
                File.Delete(publicAssemblyPath);
            }

            // Create the all-public assembly for import
            using (var monoMod = new MonoModder
            {
                InputPath = FileUtilities.BackupAssemblyPath,
                OutputPath = publicAssemblyPath
            })
            {
                monoMod.Read();
                monoMod.PublicEverything = true;
                monoMod.MapDependencies();
                monoMod.AutoPatch();
                monoMod.Write();
            }
        }
示例#17
0
        public static Assembly GetRelinkedAssembly(this GameModMetadata meta, Stream stream, MissingDependencyResolver depResolver = null)
        {
            string name               = Path.GetFileName(meta.DLL);
            string cachedName         = meta.Name + "." + name.Substring(0, name.Length - 3) + "dll";
            string cachedPath         = Path.Combine(ModLoader.ModsCacheDirectory, cachedName);
            string cachedChecksumPath = Path.Combine(ModLoader.ModsCacheDirectory, cachedName + ".sum");

            string[] checksums = new string[2];
            using (MD5 md5 = MD5.Create()) {
                if (GameChecksum == null)
                {
                    using (FileStream fs = File.OpenRead(Assembly.GetAssembly(typeof(ModRelinker)).Location))
                        GameChecksum = md5.ComputeHash(fs).ToHexadecimalString();
                }
                checksums[0] = GameChecksum;

                string modPath = meta.Archive;
                if (modPath.Length == 0)
                {
                    modPath = meta.DLL;
                }
                using (FileStream fs = File.OpenRead(modPath))
                    checksums[1] = md5.ComputeHash(fs).ToHexadecimalString();
            }

            if (File.Exists(cachedPath) && File.Exists(cachedChecksumPath) &&
                checksums.ChecksumsEqual(File.ReadAllLines(cachedChecksumPath)))
            {
                return(Assembly.LoadFrom(cachedPath));
            }

            if (depResolver == null)
            {
                depResolver = _GenerateModDependencyResolver(meta);
            }

            using (MonoModder modder = new MonoModder()
            {
                Input = stream,
                OutputPath = cachedPath,
                CleanupEnabled = false,
                RelinkModuleMap = AssemblyRelinkMap,
                DependencyDirs =
                {
                    ManagedDirectory
                },
                MissingDependencyResolver = depResolver,
                RelinkMap = ModRuntimePatcher.Detourer.RelinkMap
            })
                try {
                    modder.ReaderParameters.ReadSymbols          = false;
                    modder.WriterParameters.WriteSymbols         = false;
                    modder.WriterParameters.SymbolWriterProvider = null;

                    modder.Read();
                    modder.MapDependencies();
                    modder.AutoPatch();
                    modder.Write();
                } catch (Exception e) {
                    ModLogger.Log("relinker", $"Failed relinking {meta}: {e}");
                    return(null);
                }

            return(Assembly.LoadFrom(cachedPath));
        }
示例#18
0
        static void Main(string[] args)
        {
            Console.WriteLine("MonoMod.RuntimeDetour.HookGen " + typeof(Program).Assembly.GetName().Version);
            Console.WriteLine("using MonoMod " + typeof(MonoModder).Assembly.GetName().Version);
            Console.WriteLine("using MonoMod.RuntimeDetour " + typeof(Detour).Assembly.GetName().Version);

            if (args.Length == 0)
            {
                Console.WriteLine("No valid arguments (assembly path) passed.");
                if (System.Diagnostics.Debugger.IsAttached) // Keep window open when running in IDE
                {
                    Console.ReadKey();
                }
                return;
            }

            string pathIn;
            string pathOut;

            int pathInI = 0;

            for (int i = 0; i < args.Length; i++)
            {
                if (args[i] == "--namespace" && i + 2 < args.Length)
                {
                    i++;
                    Environment.SetEnvironmentVariable("MONOMOD_HOOKGEN_NAMESPACE", args[i]);
                }
                else if (args[i] == "--orig")
                {
                    Environment.SetEnvironmentVariable("MONOMOD_HOOKGEN_ORIG", "1");
                }
                else if (args[i] == "--private")
                {
                    Environment.SetEnvironmentVariable("MONOMOD_HOOKGEN_PRIVATE", "1");
                }
                else
                {
                    pathInI = i;
                    break;
                }
            }

            if (pathInI >= args.Length)
            {
                Console.WriteLine("No assembly path passed.");
                if (System.Diagnostics.Debugger.IsAttached) // Keep window open when running in IDE
                {
                    Console.ReadKey();
                }
                return;
            }

            pathIn  = args[pathInI];
            pathOut = args.Length != 1 && pathInI != args.Length - 1 ? args[args.Length - 1] : null;

            pathOut = pathOut ?? Path.Combine(Path.GetDirectoryName(pathIn), "MMHOOK_" + Path.ChangeExtension(Path.GetFileName(pathIn), "dll"));

            using (MonoModder mm = new MonoModder()
            {
                InputPath = pathIn,
                OutputPath = pathOut
            }) {
                mm.Read();

                mm.MapDependencies();

                if (File.Exists(pathOut))
                {
                    mm.Log($"[HookGen] Clearing {pathOut}");
                    File.Delete(pathOut);
                }

                mm.Log("[HookGen] Starting HookGenerator");
                HookGenerator gen = new HookGenerator(mm, Path.GetFileName(pathOut));
                using (ModuleDefinition mOut = gen.OutputModule) {
                    gen.Generate();
                    mOut.Write(pathOut);
                }

                mm.Log("[HookGen] Done.");
            }

            if (System.Diagnostics.Debugger.IsAttached) // Keep window open when running in IDE
            {
                Console.ReadKey();
            }
        }
示例#19
0
        /// <summary>
        /// Relink a .dll to point towards the game's assembly at runtime, then load it.
        /// </summary>
        /// <param name="meta">The mod metadata, used for caching, among other things.</param>
        /// <param name="stream">The stream to read the .dll from.</param>
        /// <param name="depResolver">An optional dependency resolver.</param>
        /// <param name="checksumsExtra">Any optional checksums. If you're running this at runtime, pass at least Relinker.GetChecksum(Metadata)</param>
        /// <param name="prePatch">An optional step executed before patching, but after MonoMod has loaded the input assembly.</param>
        /// <returns>The loaded, relinked assembly.</returns>
        public static Assembly GetRelinkedAssembly(ModMetadata meta, Stream stream,
                                                   MissingDependencyResolver depResolver = null, string[] checksumsExtra = null, Action <MonoModder> prePatch = null)
        {
            string cachedPath         = GetCachedPath(meta);
            string cachedChecksumPath = cachedPath.Substring(0, cachedPath.Length - 4) + ".sum";

            string[] checksums = new string[2 + (checksumsExtra?.Length ?? 0)];
            if (GameChecksum == null)
            {
                GameChecksum = GetChecksum(Assembly.GetAssembly(typeof(Utils.Relinker)).Location);
            }
            checksums[0] = GameChecksum;

            checksums[1] = GetChecksum(meta);

            if (checksumsExtra != null)
            {
                for (int i = 0; i < checksumsExtra.Length; i++)
                {
                    checksums[i + 2] = checksumsExtra[i];
                }
            }

            if (File.Exists(cachedPath) && File.Exists(cachedChecksumPath) &&
                ChecksumsEqual(checksums, File.ReadAllLines(cachedChecksumPath)))
            {
                Logger.Log(LogLevel.Verbose, "relinker", $"Loading cached assembly for {meta}");
                try {
                    return(Assembly.LoadFrom(cachedPath));
                } catch (Exception e) {
                    Logger.Log(LogLevel.Warn, "relinker", $"Failed loading {meta}");
                    e.LogDetailed();
                    return(null);
                }
            }

            if (depResolver == null)
            {
                depResolver = GenerateModDependencyResolver(meta);
            }

            try {
                MonoModder modder = Modder;

                modder.Input      = stream;
                modder.OutputPath = cachedPath;
                modder.MissingDependencyResolver = depResolver;

                string symbolPath;
                modder.ReaderParameters.SymbolStream = meta.OpenStream(out symbolPath, meta.DLL.Substring(0, meta.DLL.Length - 4) + ".pdb", meta.DLL + ".mdb");
                modder.ReaderParameters.ReadSymbols  = modder.ReaderParameters.SymbolStream != null;
                if (modder.ReaderParameters.SymbolReaderProvider != null &&
                    modder.ReaderParameters.SymbolReaderProvider is RelinkerSymbolReaderProvider)
                {
                    ((RelinkerSymbolReaderProvider)modder.ReaderParameters.SymbolReaderProvider).Format =
                        string.IsNullOrEmpty(symbolPath) ? DebugSymbolFormat.Auto :
                        symbolPath.EndsWith(".mdb") ? DebugSymbolFormat.MDB :
                        symbolPath.EndsWith(".pdb") ? DebugSymbolFormat.PDB :
                        DebugSymbolFormat.Auto;
                }

                modder.Read();

                modder.ReaderParameters.ReadSymbols = false;

                if (modder.ReaderParameters.SymbolReaderProvider != null &&
                    modder.ReaderParameters.SymbolReaderProvider is RelinkerSymbolReaderProvider)
                {
                    ((RelinkerSymbolReaderProvider)modder.ReaderParameters.SymbolReaderProvider).Format = DebugSymbolFormat.Auto;
                }

                modder.MapDependencies();

                if (RuntimeRuleContainer != null)
                {
                    modder.ParseRules(RuntimeRuleContainer);
                    RuntimeRuleContainer = null;
                }

                prePatch?.Invoke(modder);

                modder.AutoPatch();

                modder.Write();
            } catch (Exception e) {
                Logger.Log(LogLevel.Warn, "relinker", $"Failed relinking {meta}");
                e.LogDetailed();
                return(null);
            } finally {
                Modder.ClearCaches(moduleSpecific: true);
                Modder.Module.Dispose();
                Modder.Module = null;
                Modder.ReaderParameters.SymbolStream?.Dispose();
            }

            if (File.Exists(cachedChecksumPath))
            {
                File.Delete(cachedChecksumPath);
            }
            File.WriteAllLines(cachedChecksumPath, checksums);

            Logger.Log(LogLevel.Verbose, "relinker", $"Loading assembly for {meta}");
            try {
                return(Assembly.LoadFrom(cachedPath));
            } catch (Exception e) {
                Logger.Log(LogLevel.Warn, "relinker", $"Failed loading {meta}");
                e.LogDetailed();
                return(null);
            }
        }
示例#20
0
            public void Install(Installer installer, bool leave_mmdlls = false)
            {
                var managed = installer.ManagedDir;

                if (HasPluginsDir)
                {
                    _InstallPlugins(installer.PluginsDir);
                }
                if (RequiresPatchedExe)
                {
                    installer.PatchExe();
                }

                using (StreamWriter patches_info_writer = new StreamWriter(File.OpenWrite(installer.PatchesInfoFile))) {
                    patches_info_writer.WriteLine($"{Name} {VersionName}");
                }

                _Install("assembly", Assemblies, managed);
                _Install("MonoMod patch DLL", PatchDLLs, managed);
                _Install("file", OtherFiles, managed, subdir: true);
                _Install("directory", Dirs, managed, subdir: true);

                foreach (var patch_target in Metadata?.OrderedTargets ?? installer.Downloader.GungeonMetadata.ViablePatchTargets)
                {
                    var patch_target_dll = Path.Combine(managed, $"{patch_target}.dll");
                    var patch_target_tmp = Path.Combine(managed, $"{patch_target}{TMP_PATCH_SUFFIX}");

                    var modder = new MonoModder {
                        InputPath  = patch_target_dll,
                        OutputPath = patch_target_tmp
                    };

                    if (Metadata != null && Metadata.RelinkMap != null)
                    {
                        Dictionary <string, string> rmap;
                        if (Metadata.RelinkMap.TryGetValue(patch_target, out rmap))
                        {
                            _Logger.Info($"Reading component relink map for target {patch_target}");
                            foreach (var pair in rmap)
                            {
                                ModuleDefinition module;
                                if (!modder.DependencyCache.TryGetValue(pair.Value, out module))
                                {
                                    var path = Path.Combine(managed, pair.Value);
                                    _Logger.Debug($"Dependency not in cache: {pair.Value} ({path})");
                                    module = modder.DependencyCache[pair.Value] = ModuleDefinition.ReadModule(path);
                                }

                                _Logger.Debug($"Mapping {pair.Key} => {pair.Value}");
                                modder.RelinkModuleMap[pair.Key] = module;
                            }
                        }
                    }

                    modder.Read();

                    var found_mods = false;

                    foreach (var dll in PatchDLLs)
                    {
                        if (File.Exists(Path.Combine(managed, dll)) && dll.StartsWith($"{patch_target}.", StringComparison.InvariantCulture))
                        {
                            found_mods = true;
                            _Logger.Debug($"Using patch DLL: {dll}");

                            modder.ReadMod(Path.Combine(managed, dll));
                        }
                    }

                    if (!found_mods)
                    {
                        _Logger.Info($"Not patching {patch_target} because this component has no patches for it");
                        continue;
                    }

                    _Logger.Info($"Patching target: {patch_target}");

                    modder.MapDependencies();
                    modder.AutoPatch();
                    modder.Write();
                    modder.Dispose();

                    _Logger.Debug($"Replacing original ({patch_target_tmp} => {patch_target_dll})");
                    if (File.Exists(patch_target_dll))
                    {
                        File.Delete(patch_target_dll);
                    }
                    File.Move(patch_target_tmp, patch_target_dll);
                }

                if (!leave_mmdlls)
                {
                    foreach (var dll in PatchDLLs)
                    {
                        if (!File.Exists(Path.Combine(managed, dll)))
                        {
                            continue;
                        }

                        _Logger.Debug($"Cleaning up patch DLL {dll}");
                        File.Delete(Path.Combine(managed, dll));
                    }
                }

                _Logger.Debug($"Cleaning up patched DLL MDB/PDBs");
                foreach (var ent in Directory.GetFileSystemEntries(managed))
                {
                    if (ent.EndsWith($"{TMP_PATCH_SUFFIX}.mdb", StringComparison.InvariantCulture))
                    {
                        File.Delete(ent);
                    }
                }
            }
示例#21
0
        public static bool Mod(this InstallerWindow ins, string file)
        {
            string     inPath  = Path.Combine(ins.MainModDir, file);
            string     outPath = Path.Combine(ins.MainModDir, file + ".tmp.dll");
            MonoModder monomod = new MonoModder()
            {
                InputPath  = inPath,
                OutputPath = outPath
            };

            monomod.SetupETGModder();
            using (FileStream fileStream = File.Open(LogPath, FileMode.Append)) {
                using (StreamWriter streamWriter = new StreamWriter(fileStream)) {
                    monomod.Logger  = (string s) => ins.OnActivity();
                    monomod.Logger += (string s) => streamWriter.WriteLine(s);
                    // Unity wants .mdbs
                    // monomod.WriterParameters.SymbolWriterProvider = new Mono.Cecil.Mdb.MdbWriterProvider();
                    string db    = Path.ChangeExtension(inPath, "pdb");
                    string dbTmp = Path.ChangeExtension(outPath, "pdb");
                    if (!File.Exists(db))
                    {
                        db    = inPath + ".mdb";
                        dbTmp = outPath + ".mdb";
                    }
#if !DEBUG
RETRY:
                    try {
#endif
                    monomod.Read();                                        // Read main module first
                    monomod.ReadMod(Directory.GetParent(inPath).FullName); // ... then mods
                    monomod.MapDependencies();                             // ... then all dependencies
                    monomod.AutoPatch();                                   // Patch,
                    monomod.Write();                                       // and write.
                    monomod.Dispose();                                     // Finally, dispose, because file access happens now.

                    File.Delete(inPath);
                    File.Move(outPath, inPath);
                    if (File.Exists(db))
                    {
                        File.Delete(db);
                    }
                    if (File.Exists(dbTmp))
                    {
                        File.Move(dbTmp, db);
                    }
                    return(true);

#if !DEBUG
                } catch (ArgumentException e) {
                    monomod.Dispose();
                    if (File.Exists(db))
                    {
                        File.Delete(db);
                        if (File.Exists(dbTmp))
                        {
                            File.Delete(dbTmp);
                        }
                        goto RETRY;
                    }
                    ins.LogLine(e.ToString());
                    throw;
                    return(false);
                } catch (Exception e) {
                    monomod.Dispose();
                    ins.LogLine(e.ToString());
                    throw;
                    return(false);
                }
#endif
                }
            }
        }
示例#22
0
        /// <summary>
        /// Relink a .dll to point towards Celeste.exe and FNA / XNA properly at runtime, then load it.
        /// </summary>
        /// <param name="meta">The mod metadata, used for caching, among other things.</param>
        /// <param name="stream">The stream to read the .dll from.</param>
        /// <param name="depResolver">An optional dependency resolver.</param>
        /// <param name="checksumsExtra">Any optional checksums. If you're running this at runtime, pass at least Everest.Relinker.GetChecksum(Metadata)</param>
        /// <param name="prePatch">An optional step executed before patching, but after MonoMod has loaded the input assembly.</param>
        /// <returns>The loaded, relinked assembly.</returns>
        public static Assembly GetRelinkedAssembly(Stream stream, string modName)
        {
            string cachedPath = GetCachedPath(modName);

            MissingDependencyResolver depResolver = GenerateModDependencyResolver();

            try
            {
                MonoModder modder = Modder;

                modder.Input      = stream;
                modder.OutputPath = cachedPath;
                modder.MissingDependencyResolver = depResolver;

                modder.ReaderParameters.ReadSymbols = false;
                if (modder.ReaderParameters.SymbolReaderProvider is RelinkerSymbolReaderProvider)
                {
                    ((RelinkerSymbolReaderProvider)modder.ReaderParameters.SymbolReaderProvider).Format = DebugSymbolFormat.Auto;
                }

                modder.Read();

                modder.ReaderParameters.ReadSymbols = false;

                if (modder.ReaderParameters.SymbolReaderProvider != null &&
                    modder.ReaderParameters.SymbolReaderProvider is RelinkerSymbolReaderProvider)
                {
                    ((RelinkerSymbolReaderProvider)modder.ReaderParameters.SymbolReaderProvider).Format = DebugSymbolFormat.Auto;
                }

                modder.MapDependencies();

                modder.AutoPatch();

                modder.Write();
            }
            catch (Exception e)
            {
                Logger.LogError($"[API] Failed relinking\n{e}");
                e.LogDetailed();
                return(null);
            }
            finally
            {
                Modder.ClearCaches(moduleSpecific: true);
                Modder.Module.Dispose();
                Modder.Module = null;
                Modder.ReaderParameters.SymbolStream?.Dispose();
            }

            Logger.LogDebug($"[API] Loading assembly for {modName}");
            try
            {
                return(Assembly.LoadFrom(cachedPath));
            }
            catch (Exception e)
            {
                Logger.LogError($"[API] Failed loading\n{e}");
                e.LogDetailed();
                return(null);
            }
        }
示例#23
0
            public static Assembly GetRelinkedAssembly(EverestModuleMetadata meta, Stream stream,
                                                       MissingDependencyResolver depResolver = null, string[] checksumsExtra = null, Action <MonoModder> prePatch = null)
            {
                string cachedPath         = GetCachedPath(meta);
                string cachedChecksumPath = cachedPath.Substring(0, cachedPath.Length - 4) + ".sum";

                string[] checksums = new string[2 + (checksumsExtra?.Length ?? 0)];
                if (GameChecksum == null)
                {
                    GameChecksum = GetChecksum(Assembly.GetAssembly(typeof(Relinker)).Location);
                }
                checksums[0] = GameChecksum;

                checksums[1] = GetChecksum(meta);

                if (checksumsExtra != null)
                {
                    for (int i = 0; i < checksumsExtra.Length; i++)
                    {
                        checksums[i + 2] = checksumsExtra[i];
                    }
                }

                if (File.Exists(cachedPath) && File.Exists(cachedChecksumPath) &&
                    ChecksumsEqual(checksums, File.ReadAllLines(cachedChecksumPath)))
                {
                    return(Assembly.LoadFrom(cachedPath));
                }

                if (depResolver == null)
                {
                    depResolver = GenerateModDependencyResolver(meta);
                }

                try {
                    MonoModder modder = Modder;

                    modder.Input      = stream;
                    modder.OutputPath = cachedPath;
                    modder.MissingDependencyResolver = depResolver;

                    modder.Read();
                    modder.MapDependencies();
                    prePatch?.Invoke(modder);
                    modder.AutoPatch();
                    modder.Write();
                } catch (Exception e) {
                    Logger.Log("relinker", $"Failed relinking {meta}: {e}");
                    return(null);
                } finally {
                    Modder.ClearCaches(moduleSpecific: true);
                    Modder.Module.Dispose();
                    Modder.Module = null;
                }

                if (File.Exists(cachedChecksumPath))
                {
                    File.Delete(cachedChecksumPath);
                }
                File.WriteAllLines(cachedChecksumPath, checksums);

                return(Assembly.LoadFrom(cachedPath));
            }
示例#24
0
        public static void Main(string[] args)
        {
            Console.WriteLine("MonoMod " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);

            if (args.Length == 0)
            {
                Console.WriteLine("No valid arguments (assembly path) passed.");
                if (System.Diagnostics.Debugger.IsAttached) // Keep window open when running in IDE
                {
                    Console.ReadKey();
                }
                return;
            }

            string pathIn;
            string pathOut;

            if (args.Length > 1 &&
                args[0] == "--generate-debug-il" ||
                args[0] == "--gen-dbg-il")
            {
                Console.WriteLine("[DbgILGen] Generating debug hierarchy and debug data (pdb / mdb).");

                pathIn  = args[1];
                pathOut = args.Length != 2 ? args[args.Length - 1] : Path.Combine(Path.GetDirectoryName(pathIn), "MMDBGIL_" + Path.GetFileName(pathIn));

                using (MonoModder mm = new MonoModder()
                {
                    InputPath = pathIn,
                    OutputPath = pathOut
                }) {
                    mm.Read(false);

                    mm.Log("[DbgILGen] DebugILGenerator.Generate(mm);");
                    DebugILGenerator.Generate(mm);

                    mm.Write();

                    mm.Log("[DbgILGen] Done.");
                }

                if (System.Diagnostics.Debugger.IsAttached) // Keep window open when running in IDE
                {
                    Console.ReadKey();
                }
                return;
            }

            int pathInI = 0;

            for (int i = 0; i < args.Length; i++)
            {
                if (args[i] == "--dependency-missing-throw=0" || args[i] == "--lean-dependencies")
                {
                    Environment.SetEnvironmentVariable("MONOMOD_DEPENDENCY_MISSING_THROW", "0");
                    pathInI = i + 1;
                }
                else if (args[i] == "--cleanup=0" || args[i] == "--skip-cleanup")
                {
                    Environment.SetEnvironmentVariable("MONOMOD_CLEANUP", "0");
                    pathInI = i + 1;
                }
                else if (args[i] == "--cleanup-all=1" || args[i] == "--cleanup-all")
                {
                    Environment.SetEnvironmentVariable("MONOMOD_CLEANUP_ALL", "1");
                    pathInI = i + 1;
                }
                else if (args[i] == "--verbose=1" || args[i] == "--verbose" || args[i] == "-v")
                {
                    Environment.SetEnvironmentVariable("MONOMOD_VERBOSE", "1");
                    pathInI = i + 1;
                }
            }

            if (pathInI >= args.Length)
            {
                Console.WriteLine("No assembly path passed.");
                if (System.Diagnostics.Debugger.IsAttached) // Keep window open when running in IDE
                {
                    Console.ReadKey();
                }
                return;
            }

            pathIn  = args[pathInI];
            pathOut = args.Length != 1 && pathInI != args.Length - 1 ? args[args.Length - 1] : Path.Combine(Path.GetDirectoryName(pathIn), "MONOMODDED_" + Path.GetFileName(pathIn));

            if (File.Exists(pathOut))
            {
                File.Delete(pathOut);
            }

            try {
                using (MonoModder mm = new MonoModder()
                {
                    InputPath = pathIn,
                    OutputPath = pathOut,
                    Verbose = Environment.GetEnvironmentVariable("MONOMOD_VERBOSE") == "1"
                }) {
                    mm.Read(false);

                    if (args.Length <= 2)
                    {
                        mm.Log("[Main] Scanning for mods in directory.");
                        mm.ReadMod(Directory.GetParent(pathIn).FullName);
                    }
                    else
                    {
                        mm.Log("[Main] Reading mods list from arguments.");
                        for (int i = pathInI + 1; i < args.Length - 2; i++)
                        {
                            mm.ReadMod(args[i]);
                        }
                    }

                    mm.Read(true);

                    mm.Log("[Main] mm.AutoPatch();");
                    mm.AutoPatch();

                    mm.Write();

                    mm.Log("[Main] Done.");
                }
            } catch (Exception e) {
                Console.WriteLine(e);
            }

            if (System.Diagnostics.Debugger.IsAttached) // Keep window open when running in IDE
            {
                Console.ReadKey();
            }
        }
        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", );
        }
示例#26
0
            /// <summary>
            /// Relink a .dll to point towards Celeste.exe and FNA / XNA properly at runtime, then load it.
            /// </summary>
            /// <param name="meta">The mod metadata, used for caching, among other things.</param>
            /// <param name="stream">The stream to read the .dll from.</param>
            /// <param name="depResolver">An optional dependency resolver.</param>
            /// <param name="checksumsExtra">Any optional checksums</param>
            /// <param name="prePatch">An optional step executed before patching, but after MonoMod has loaded the input assembly.</param>
            /// <returns>The loaded, relinked assembly.</returns>
            public static Assembly GetRelinkedAssembly(EverestModuleMetadata meta, string asmname, Stream stream,
                                                       MissingDependencyResolver depResolver = null, string[] checksumsExtra = null, Action <MonoModder> prePatch = null)
            {
                if (!Flags.SupportRelinkingMods)
                {
                    Logger.Log(LogLevel.Warn, "relinker", "Relinker disabled!");
                    return(null);
                }

                string cachedPath         = GetCachedPath(meta, asmname);
                string cachedChecksumPath = cachedPath.Substring(0, cachedPath.Length - 4) + ".sum";

                string[] checksums = new string[2 + (checksumsExtra?.Length ?? 0)];
                if (GameChecksum == null)
                {
                    GameChecksum = Everest.GetChecksum(Assembly.GetAssembly(typeof(Relinker)).Location).ToHexadecimalString();
                }
                checksums[0] = GameChecksum;

                checksums[1] = Everest.GetChecksum(ref stream).ToHexadecimalString();

                if (checksumsExtra != null)
                {
                    for (int i = 0; i < checksumsExtra.Length; i++)
                    {
                        checksums[i + 2] = checksumsExtra[i];
                    }
                }

                if (File.Exists(cachedPath) && File.Exists(cachedChecksumPath) &&
                    ChecksumsEqual(checksums, File.ReadAllLines(cachedChecksumPath)))
                {
                    Logger.Log(LogLevel.Verbose, "relinker", $"Loading cached assembly for {meta} - {asmname}");
                    try {
                        Assembly asm = Assembly.LoadFrom(cachedPath);
                        _RelinkedAssemblies.Add(asm);
                        return(asm);
                    } catch (Exception e) {
                        Logger.Log(LogLevel.Warn, "relinker", $"Failed loading {meta} - {asmname}");
                        e.LogDetailed();
                        return(null);
                    }
                }

                if (depResolver == null)
                {
                    depResolver = GenerateModDependencyResolver(meta);
                }

                bool temporaryASM = false;

                try {
                    MonoModder modder = Modder;

                    modder.Input      = stream;
                    modder.OutputPath = cachedPath;
                    modder.MissingDependencyResolver = depResolver;

                    string symbolPath;
                    modder.ReaderParameters.SymbolStream = OpenStream(meta, out symbolPath, meta.DLL.Substring(0, meta.DLL.Length - 4) + ".pdb", meta.DLL + ".mdb");
                    modder.ReaderParameters.ReadSymbols  = modder.ReaderParameters.SymbolStream != null;
                    if (modder.ReaderParameters.SymbolReaderProvider != null &&
                        modder.ReaderParameters.SymbolReaderProvider is RelinkerSymbolReaderProvider)
                    {
                        ((RelinkerSymbolReaderProvider)modder.ReaderParameters.SymbolReaderProvider).Format =
                            string.IsNullOrEmpty(symbolPath) ? DebugSymbolFormat.Auto :
                            symbolPath.EndsWith(".mdb") ? DebugSymbolFormat.MDB :
                            symbolPath.EndsWith(".pdb") ? DebugSymbolFormat.PDB :
                            DebugSymbolFormat.Auto;
                    }

                    try {
                        modder.ReaderParameters.ReadSymbols = true;
                        modder.Read();
                    } catch {
                        modder.ReaderParameters.SymbolStream?.Dispose();
                        modder.ReaderParameters.SymbolStream = null;
                        modder.ReaderParameters.ReadSymbols  = false;
                        stream.Seek(0, SeekOrigin.Begin);
                        modder.Read();
                    }

                    if (modder.ReaderParameters.SymbolReaderProvider != null &&
                        modder.ReaderParameters.SymbolReaderProvider is RelinkerSymbolReaderProvider)
                    {
                        ((RelinkerSymbolReaderProvider)modder.ReaderParameters.SymbolReaderProvider).Format = DebugSymbolFormat.Auto;
                    }

                    modder.MapDependencies();

                    if (!RuntimeRulesParsed)
                    {
                        RuntimeRulesParsed = true;

                        InitMMSharedData();

                        string rulesPath = Path.Combine(
                            Path.GetDirectoryName(typeof(Celeste).Assembly.Location),
                            Path.GetFileNameWithoutExtension(typeof(Celeste).Assembly.Location) + ".Mod.mm.dll"
                            );
                        if (!File.Exists(rulesPath))
                        {
                            // Fallback if someone renamed Celeste.exe
                            rulesPath = Path.Combine(
                                Path.GetDirectoryName(typeof(Celeste).Assembly.Location),
                                "Celeste.Mod.mm.dll"
                                );
                        }
                        if (File.Exists(rulesPath))
                        {
                            ModuleDefinition rules = ModuleDefinition.ReadModule(rulesPath, new ReaderParameters(ReadingMode.Immediate));
                            modder.ParseRules(rules);
                            rules.Dispose(); // Is this safe?
                        }
                    }

                    prePatch?.Invoke(modder);

                    modder.ParseRules(modder.Module);

                    modder.AutoPatch();

RetryWrite:
                    try {
                        modder.WriterParameters.WriteSymbols = true;
                        modder.Write();
                    } catch {
                        try {
                            modder.WriterParameters.WriteSymbols = false;
                            modder.Write();
                        } catch when(!temporaryASM)
                        {
                            temporaryASM = true;
                            long stamp = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;

                            cachedPath          = Path.Combine(Path.GetTempPath(), $"Everest.Relinked.{Path.GetFileNameWithoutExtension(cachedPath)}.{stamp}.dll");
                            modder.Module.Name += "." + stamp;
                            modder.Module.Assembly.Name.Name += "." + stamp;
                            modder.OutputPath = cachedPath;
                            modder.WriterParameters.WriteSymbols = true;
                            goto RetryWrite;
                        }
                    }
                } catch (Exception e) {
                    Logger.Log(LogLevel.Warn, "relinker", $"Failed relinking {meta} - {asmname}");
                    e.LogDetailed();
                    return(null);
                } finally {
                    Modder.ReaderParameters.SymbolStream?.Dispose();
                    if (SharedModder)
                    {
                        Modder.ClearCaches(moduleSpecific: true);
                        Modder.Module.Dispose();
                        Modder.Module = null;
                    }
                    else
                    {
                        Modder.Dispose();
                        Modder = null;
                    }
                }

                if (File.Exists(cachedChecksumPath))
                {
                    File.Delete(cachedChecksumPath);
                }
                if (!temporaryASM)
                {
                    File.WriteAllLines(cachedChecksumPath, checksums);
                }

                Logger.Log(LogLevel.Verbose, "relinker", $"Loading assembly for {meta} - {asmname}");
                try {
                    Assembly asm = Assembly.LoadFrom(cachedPath);
                    _RelinkedAssemblies.Add(asm);
                    return(asm);
                } catch (Exception e) {
                    Logger.Log(LogLevel.Warn, "relinker", $"Failed loading {meta} - {asmname}");
                    e.LogDetailed();
                    return(null);
                }
            }
示例#27
0
        public static int Main(string[] args)
        {
            Console.WriteLine("MonoMod " + typeof(Program).GetTypeInfo().Assembly.GetName().Version);

            if (args.Length == 0)
            {
                Console.WriteLine("No valid arguments (assembly path) passed.");
                if (System.Diagnostics.Debugger.IsAttached) // Keep window open when running in IDE
                {
                    Console.ReadKey();
                }
                return(0);
            }

            string pathIn;
            string pathOut;

            int pathInI = 0;

            for (int i = 0; i < args.Length; i++)
            {
                if (args[i] == "--dependency-missing-throw=0" || args[i] == "--lean-dependencies")
                {
                    Environment.SetEnvironmentVariable("MONOMOD_DEPENDENCY_MISSING_THROW", "0");
                    pathInI = i + 1;
                }
                else if (args[i] == "--cleanup=0" || args[i] == "--skip-cleanup")
                {
                    Environment.SetEnvironmentVariable("MONOMOD_CLEANUP", "0");
                    pathInI = i + 1;
                }
                else if (args[i] == "--cleanup-all=1" || args[i] == "--cleanup-all")
                {
                    Environment.SetEnvironmentVariable("MONOMOD_CLEANUP_ALL", "1");
                    pathInI = i + 1;
                }
                else if (args[i] == "--verbose=1" || args[i] == "--verbose" || args[i] == "-v")
                {
                    Environment.SetEnvironmentVariable("MONOMOD_LOG_VERBOSE", "1");
                    pathInI = i + 1;
                }
                else if (args[i] == "--cache=0" || args[i] == "--uncached")
                {
                    Environment.SetEnvironmentVariable("MONOMOD_RELINKER_CACHED", "0");
                    pathInI = i + 1;
                }
            }

            if (pathInI >= args.Length)
            {
                Console.WriteLine("No assembly path passed.");
                if (System.Diagnostics.Debugger.IsAttached) // Keep window open when running in IDE
                {
                    Console.ReadKey();
                }
                return(0);
            }

            pathIn  = args[pathInI];
            pathOut = args.Length != 1 && pathInI != args.Length - 1 ? args[args.Length - 1] : null;
            pathOut = pathOut ?? Path.Combine(Path.GetDirectoryName(pathIn), "MONOMODDED_" + Path.GetFileName(pathIn));

            if (File.Exists(pathOut))
            {
                File.Delete(pathOut);
            }

#if !DEBUG
            try {
#endif
            using (MonoModder mm = new MonoModder()
            {
                InputPath = pathIn,
                OutputPath = pathOut
            }) {
                mm.Read();

                if (args.Length <= 2)
                {
                    mm.Log("[Main] Scanning for mods in directory.");
                    mm.ReadMod(Directory.GetParent(pathIn).FullName);
                }
                else
                {
                    mm.Log("[Main] Reading mods list from arguments.");
                    for (int i = pathInI + 1; i < args.Length - 1; i++)
                    {
                        mm.ReadMod(args[i]);
                    }
                }

                mm.MapDependencies();

                mm.Log("[Main] mm.AutoPatch();");
                mm.AutoPatch();

                mm.Write();

                mm.Log("[Main] Done.");
            }
#if !DEBUG
        }

        catch (Exception e) {
            Console.WriteLine(e);
            if (System.Diagnostics.Debugger.IsAttached)     // Keep window open when running in IDE
            {
                Console.ReadKey();
            }
            return(-1);
        }
#endif

            if (System.Diagnostics.Debugger.IsAttached) // Keep window open when running in IDE
            {
                Console.ReadKey();
            }
            return(0);
        }
示例#28
0
            /// <summary>
            /// Relink a .dll to point towards Celeste.exe and FNA / XNA properly at runtime, then load it.
            /// </summary>
            /// <param name="meta">The mod metadata, used for caching, among other things.</param>
            /// <param name="stream">The stream to read the .dll from.</param>
            /// <param name="depResolver">An optional dependency resolver.</param>
            /// <param name="checksumsExtra">Any optional checksums. If you're running this at runtime, pass at least Everest.Relinker.GetChecksum(Metadata)</param>
            /// <param name="prePatch">An optional step executed before patching, but after MonoMod has loaded the input assembly.</param>
            /// <returns>The loaded, relinked assembly.</returns>
            public static Assembly GetRelinkedAssembly(EverestModuleMetadata meta, Stream stream,
                                                       MissingDependencyResolver depResolver = null, string[] checksumsExtra = null, Action <MonoModder> prePatch = null)
            {
                if (!Flags.SupportRelinkingMods)
                {
                    Logger.Log(LogLevel.Warn, "relinker", "Relinker disabled!");
                    return(null);
                }

                string cachedPath         = GetCachedPath(meta);
                string cachedChecksumPath = cachedPath.Substring(0, cachedPath.Length - 4) + ".sum";

                string[] checksums = new string[2 + (checksumsExtra?.Length ?? 0)];
                if (GameChecksum == null)
                {
                    GameChecksum = Everest.GetChecksum(Assembly.GetAssembly(typeof(Relinker)).Location).ToHexadecimalString();
                }
                checksums[0] = GameChecksum;

                checksums[1] = Everest.GetChecksum(meta).ToHexadecimalString();

                if (checksumsExtra != null)
                {
                    for (int i = 0; i < checksumsExtra.Length; i++)
                    {
                        checksums[i + 2] = checksumsExtra[i];
                    }
                }

                if (File.Exists(cachedPath) && File.Exists(cachedChecksumPath) &&
                    ChecksumsEqual(checksums, File.ReadAllLines(cachedChecksumPath)))
                {
                    Logger.Log(LogLevel.Verbose, "relinker", $"Loading cached assembly for {meta}");
                    try {
                        return(Assembly.LoadFrom(cachedPath));
                    } catch (Exception e) {
                        Logger.Log(LogLevel.Warn, "relinker", $"Failed loading {meta}");
                        e.LogDetailed();
                        return(null);
                    }
                }

                if (depResolver == null)
                {
                    depResolver = GenerateModDependencyResolver(meta);
                }

                try {
                    MonoModder modder = Modder;

                    modder.Input      = stream;
                    modder.OutputPath = cachedPath;
                    modder.MissingDependencyResolver = depResolver;

                    string symbolPath;
                    modder.ReaderParameters.SymbolStream = OpenStream(meta, out symbolPath, meta.DLL.Substring(0, meta.DLL.Length - 4) + ".pdb", meta.DLL + ".mdb");
                    modder.ReaderParameters.ReadSymbols  = modder.ReaderParameters.SymbolStream != null;
                    if (modder.ReaderParameters.SymbolReaderProvider != null &&
                        modder.ReaderParameters.SymbolReaderProvider is RelinkerSymbolReaderProvider)
                    {
                        ((RelinkerSymbolReaderProvider)modder.ReaderParameters.SymbolReaderProvider).Format =
                            string.IsNullOrEmpty(symbolPath) ? DebugSymbolFormat.Auto :
                            symbolPath.EndsWith(".mdb") ? DebugSymbolFormat.MDB :
                            symbolPath.EndsWith(".pdb") ? DebugSymbolFormat.PDB :
                            DebugSymbolFormat.Auto;
                    }

                    modder.Read();

                    modder.ReaderParameters.ReadSymbols = false;

                    if (modder.ReaderParameters.SymbolReaderProvider != null &&
                        modder.ReaderParameters.SymbolReaderProvider is RelinkerSymbolReaderProvider)
                    {
                        ((RelinkerSymbolReaderProvider)modder.ReaderParameters.SymbolReaderProvider).Format = DebugSymbolFormat.Auto;
                    }

                    modder.MapDependencies();

                    if (!RuntimeRulesParsed)
                    {
                        RuntimeRulesParsed = true;

                        InitMMSharedData();

                        string rulesPath = Path.Combine(
                            Path.GetDirectoryName(typeof(Celeste).Assembly.Location),
                            Path.GetFileNameWithoutExtension(typeof(Celeste).Assembly.Location) + ".Mod.mm.dll"
                            );
                        if (!File.Exists(rulesPath))
                        {
                            // Fallback if someone renamed Celeste.exe
                            rulesPath = Path.Combine(
                                Path.GetDirectoryName(typeof(Celeste).Assembly.Location),
                                "Celeste.Mod.mm.dll"
                                );
                        }
                        if (File.Exists(rulesPath))
                        {
                            ModuleDefinition rules = ModuleDefinition.ReadModule(rulesPath, new ReaderParameters(ReadingMode.Immediate));
                            modder.ParseRules(rules);
                            rules.Dispose(); // Is this safe?
                        }

                        // Fix old mods built against HookIL instead of ILContext.
                        _Modder.RelinkMap["MonoMod.RuntimeDetour.HookGen.ILManipulator"]  = "MonoMod.Cil.ILContext/Manipulator";
                        _Modder.RelinkMap["MonoMod.RuntimeDetour.HookGen.HookIL"]         = "MonoMod.Cil.ILContext";
                        _Modder.RelinkMap["MonoMod.RuntimeDetour.HookGen.HookILCursor"]   = "MonoMod.Cil.ILCursor";
                        _Modder.RelinkMap["MonoMod.RuntimeDetour.HookGen.HookILLabel"]    = "MonoMod.Cil.ILLabel";
                        _Modder.RelinkMap["MonoMod.RuntimeDetour.HookGen.HookExtensions"] = "MonoMod.Cil.ILPatternMatchingExt";

                        _Shim("MonoMod.Utils.ReflectionHelper", typeof(MonoModUpdateShim._ReflectionHelper));
                        _Shim("MonoMod.Cil.ILCursor", typeof(MonoModUpdateShim._ILCursor));

                        // If no entry for MonoMod.Utils exists already, add one.
                        modder.MapDependency(_Modder.Module, "MonoMod.Utils");
                    }

                    prePatch?.Invoke(modder);

                    modder.AutoPatch();

                    modder.Write();
                } catch (Exception e) {
                    Logger.Log(LogLevel.Warn, "relinker", $"Failed relinking {meta}");
                    e.LogDetailed();
                    return(null);
                } finally {
                    Modder.ClearCaches(moduleSpecific: true);
                    Modder.Module.Dispose();
                    Modder.Module = null;
                    Modder.ReaderParameters.SymbolStream?.Dispose();
                }

                if (File.Exists(cachedChecksumPath))
                {
                    File.Delete(cachedChecksumPath);
                }
                File.WriteAllLines(cachedChecksumPath, checksums);

                Logger.Log(LogLevel.Verbose, "relinker", $"Loading assembly for {meta}");
                try {
                    return(Assembly.LoadFrom(cachedPath));
                } catch (Exception e) {
                    Logger.Log(LogLevel.Warn, "relinker", $"Failed loading {meta}");
                    e.LogDetailed();
                    return(null);
                }
            }
示例#29
0
        public static void Main(string[] args)
        {
#if CECIL0_9
            throw new NotSupportedException();
#else
            Console.WriteLine("MonoMod.DebugIL " + typeof(Program).Assembly.GetName().Version);

            if (args.Length == 0)
            {
                Console.WriteLine("No valid arguments (assembly path) passed.");
                if (System.Diagnostics.Debugger.IsAttached) // Keep window open when running in IDE
                {
                    Console.ReadKey();
                }
                return;
            }

            string pathIn;
            string pathOut;

            int pathInI = 0;

            for (int i = 0; i < args.Length; i++)
            {
                if (args[i] == "--relative")
                {
                    Environment.SetEnvironmentVariable("MONOMOD_DEBUGIL_RELATIVE", "1");
                    pathInI = i + 1;
                }
                else if (args[i] == "--skip-maxstack")
                {
                    Environment.SetEnvironmentVariable("MONOMOD_DEBUGIL_SKIP_MAXSTACK", "1");
                    pathInI = i + 1;
                }
            }

            if (pathInI >= args.Length)
            {
                Console.WriteLine("No assembly path passed.");
                if (System.Diagnostics.Debugger.IsAttached) // Keep window open when running in IDE
                {
                    Console.ReadKey();
                }
                return;
            }

            pathIn  = args[pathInI];
            pathOut = args.Length != 1 && pathInI != args.Length - 1 ? args[args.Length - 1] : null;

            pathOut = pathOut ?? Path.Combine(Path.GetDirectoryName(pathIn), "MMDBGIL_" + Path.GetFileName(pathIn));

            using (MonoModder mm = new MonoModder()
            {
                InputPath = pathIn,
                OutputPath = pathOut
            }) {
                mm.Read();

                mm.Log("[DbgILGen] DebugILGenerator.Generate(mm);");
                DebugILGenerator.Generate(mm);

                mm.Write();

                mm.Log("[DbgILGen] Done.");
            }

            if (System.Diagnostics.Debugger.IsAttached) // Keep window open when running in IDE
            {
                Console.ReadKey();
            }
#endif
        }
示例#30
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);
            }
        }