示例#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
        private static void PostProcess(MonoModder modder)
        {
            // GameControl.ReceiveEvent
            {
                MethodDefinition md = GetMethod(nameof(GameControl), nameof(GameControl.ReceiveEvent));

                var cursor = new ILCursor(new ILContext(md));

                cursor.GotoNext
                (
                    MoveType.After,
                    x => x.MatchLdcI4(4),
                    x => x.MatchStfld <GameControl>("inputPlayerNumber")
                );

                // Move the cursor out of the else if, one instruction into the sequence after
                // This way we're after the ldarg.1 (e) in `e.Key`, so the branches of our if
                // has it point at our code first.
                cursor.Index += 1;

                // Instance for stfld.
                cursor.Emit(OpCodes.Ldarg_0);

                // InputEvent for delegate
                cursor.Emit(OpCodes.Ldarg_1);

                cursor.Emit(OpCodes.Call, GetMethod("GameControl", "GetPlayerNumber"));

                cursor.Emit <GameControl>(OpCodes.Stfld, "inputPlayerNumber");
            }
        }
示例#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 static void RelinkModule(string from, string toName)
        {
            MonoModder self = Modder;

            from   = from.Inject(MonoModExt.SharedData);
            toName = toName.Inject(MonoModExt.SharedData);

            bool             retrying = false;
            ModuleDefinition to       = null;

RETRY:
            if (toName + ".dll" == self.Module.Name)
            {
                to = self.Module;
            }
            else if (self.DependencyCache.TryGetValue(toName, out to))
            {
            }
            else if (!retrying)
            {
                self.MapDependency(self.Module, toName);
                retrying = true;
                goto RETRY;
            }

            if (to != null)
            {
                self.Log($"[MonoModRules] RelinkModule: {from} -> {toName}");
                self.RelinkModuleMap[from] = to;
            }
        }
示例#5
0
        private static void PostProcessType(MonoModder modder, TypeDefinition type)
        {
            foreach (FieldDefinition fdef in type.Fields)
            {
                PostProcessField(modder, fdef);
            }

            foreach (MethodDefinition mDef in type.Methods)
            {
                PostProcessMethod(modder, mDef);
            }

            foreach (TypeDefinition nested in type.NestedTypes)
            {
                PostProcessType(modder, nested);
            }

            foreach (PropertyDefinition pDef in type.Properties)
            {
                PostProcessProperty(modder, pDef);
            }

            if (type.IsNested)
            {
                type.IsNestedPublic = true;
            }
            else
            {
                type.IsPublic = true;
            }
        }
        public DebugILGenerator(MonoModder modder)
        {
            Modder = modder;

            OutputPath        = Path.GetFullPath(modder.OutputPath);
            modder.OutputPath = Path.Combine(OutputPath, Path.GetFileName(modder.InputPath));
        }
示例#7
0
 public static void PostProcessor(MonoModder modder)
 {
     foreach (TypeDefinition type in modder.Module.Types)
     {
         PostProcessType(modder, type);
     }
 }
示例#8
0
        public static void RelinkType(string from, string to)
        {
            MonoModder self = Modder;

            self.Log($"[MonoModRules] RelinkType: {from} -> {to}");
            self.RelinkMap[from] = to;
        }
示例#9
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();
        }
    }
示例#10
0
        public static void RelinkMember(string from, string toType, string toMember)
        {
            MonoModder self = Modder;

            self.Log($"[MonoModRules] RelinkMember: {from} -> {toType}::{toMember}");
            self.RelinkMap[from] = new RelinkMapEntry(toType, toMember);
        }
        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;
            }
        }
示例#12
0
            private static void _FixBGswitch(MonoModder modder)
            {
                // The broken code is inside of Celeste.BGModeToggle::Setup
                TypeDefinition t_BGModeToggle = modder.Module.GetType("Celeste.BGModeToggle");

                if (t_BGModeToggle == null)
                {
                    return;
                }

                ILContext il = new ILContext(t_BGModeToggle.FindMethod("Setup"));
                ILCursor  c  = new ILCursor(il);

                // newobj Grid::.ctor(System.Single,System.Single,System.Boolean[,]) -> newobj Grid::.ctor(System.Single,System.Single,System.Boolean[0...,0...])
                c.Index = 0;
                while (c.TryGotoNext(i => i.MatchNewobj <Grid>()))
                {
                    MethodReference ctor = c.Next.Operand as MethodReference;
                    if (ctor == null)
                    {
                        continue;
                    }

                    ArrayType param = (ArrayType)ctor.Parameters[2].ParameterType;
                    param.Dimensions.Clear();
                    param.Dimensions.Add(new ArrayDimension(0, null));
                    param.Dimensions.Add(new ArrayDimension(0, null));
                }
            }
示例#13
0
            public static void RelinkType(MonoModder self, string from, string to)
            {
                from = from.Inject(MonoModder.Data);
                to   = to.Inject(MonoModder.Data);

                self.Log($"[MonoModRules] RelinkType: {from} -> {to}");
                self.RelinkMap[from] = to;
            }
示例#14
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);
            }
        }
示例#15
0
            public static void RelinkMember(MonoModder self, string from, string toType, string toMember)
            {
                from     = from.Inject(MonoModder.Data);
                toType   = toType.Inject(MonoModder.Data);
                toMember = toMember.Inject(MonoModder.Data);

                self.Log($"[MonoModRules] RelinkMember: {from} -> {toType}::{toMember}");
                self.RelinkMap[from] = Tuple.Create(toType, toMember);
            }
示例#16
0
        public DebugILGenerator(MonoModder modder)
        {
            Modder = modder;

            OutputPath        = Path.GetFullPath(modder.OutputPath);
            modder.OutputPath = Path.Combine(OutputPath, Path.GetFileName(modder.InputPath));

            Relative = Environment.GetEnvironmentVariable("MONOMOD_DEBUGIL_RELATIVE") == "1";
        }
示例#17
0
        public static void Register(MonoModder self)
        {
            bool firstTime;

            ModderMap[ModderIdGen.GetId(self, out firstTime)] = new WeakReference(self);
            if (!firstTime)
            {
                throw new InvalidOperationException("MonoModder instance already registered in MMILProxyManager");
            }
        }
        public static long GetId(MonoModder self)
        {
            WeakReference weak = new WeakReference(self);

            if (!IDMap.TryGetValue(weak, out long id))
            {
                throw new InvalidOperationException("MonoModder instance wasn't registered in MMILProxyManager");
            }
            return(id);
        }
示例#19
0
        public static void ParseMMILAccessCtorHead(
            MonoModder self, MethodBody body, MethodReference callCtor, ref int instri,
            out TypeReference type_, out IMetadataTokenProvider member_
            )
        {
            TypeReference          type   = null;
            IMetadataTokenProvider member = null;

            if (callCtor.DeclaringType.IsGenericInstance)
            {
                type = self.Relink(((GenericInstanceType)callCtor.DeclaringType).GenericArguments[0], body.Method);
            }

            if (callCtor.Parameters.Count >= 2 && callCtor.Parameters[callCtor.Parameters.Count - 2].Name == "type")
            {
                type = self.FindTypeDeep((string)body.Instructions[instri - 2].Operand);
                body.Instructions.RemoveAt(instri - 2);
                instri--;
            }
            else if (callCtor.Parameters.Count == 1 && callCtor.Parameters[0].Name == "type")
            {
                type = self.FindTypeDeep((string)body.Instructions[instri - 1].Operand);
                body.Instructions.RemoveAt(instri - 1);
                instri--;
            }

            TypeDefinition typeDef = type.Resolve();

            if (callCtor.Parameters.Count >= 1 && callCtor.Parameters[callCtor.Parameters.Count - 1].Name == "name")
            {
                string memberName = (string)body.Instructions[instri - 1].Operand;
                body.Instructions.RemoveAt(instri - 1);
                instri--;
                if (memberName.StartsWith("field:"))
                {
                    member = typeDef.FindField(memberName.Substring(6).Trim());
                }
                else if (memberName.StartsWith("method:"))
                {
                    member = typeDef.FindMethod(memberName.Substring(7).Trim());
                }
                else
                {
                    member = typeDef.FindField(memberName) ?? (IMetadataTokenProvider)typeDef.FindMethod(memberName);
                }

                member.SetPublic(true);
            }

            // Remove the newobj constructor call
            body.Instructions.RemoveAt(instri);

            type_   = type;
            member_ = member;
        }
示例#20
0
        public static long GetId(MonoModder self)
        {
            bool firstTime;
            long id = ModderIdGen.GetId(self, out firstTime);

            if (firstTime)
            {
                throw new InvalidOperationException("MonoModder instance wasn't registered in MMILProxyManager");
            }
            return(id);
        }
示例#21
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);
                }
            }
        }
示例#22
0
        public static void RelinkMember(string from, string toType, string toMember)
        {
            MonoModder self = Modder;

            from     = from.Inject(MonoModExt.SharedData);
            toType   = toType.Inject(MonoModExt.SharedData);
            toMember = toMember.Inject(MonoModExt.SharedData);

            self.Log($"[MonoModRules] RelinkMember: {from} -> {toType}::{toMember}");
            self.RelinkMap[from] = new RelinkMapEntry(toType, toMember);
        }
示例#23
0
 private static void PostProcessProperty(MonoModder modder, PropertyDefinition pDef)
 {
     if (pDef.GetMethod != null)
     {
         pDef.GetMethod.IsPublic = true;
     }
     if (pDef.SetMethod != null)
     {
         pDef.SetMethod.IsPublic = true;
     }
 }
示例#24
0
            private static void ApplyModHackfixes(MonoModder modder)
            {
                if (_Relinking == null && !(
                        // Some mods require additional special care.
                        _Relinking.Name == "AdventureHelper" // Don't check the version for this mod as the hackfix is harmless.
                        ))
                {
                    return; // No hackfixes necessary.
                }
                void CrawlMethod(MethodDefinition method)
                {
                    string methodID = method.GetID();

                    if (_ModHackfixNoAtlasFallback.Contains(methodID))
                    {
                        using (ILContext ctx = new ILContext(method)) {
                            ctx.Invoke(ctx => {
                                ILCursor c = new ILCursor(ctx);

                                c.Emit(OpCodes.Ldsfld, typeof(GFX).GetField("Game"));
                                c.Emit(OpCodes.Ldnull);
                                c.Emit(OpCodes.Callvirt, typeof(patch_Atlas).GetMethod("PushFallback"));

                                while (c.TryGotoNext(MoveType.AfterLabel, i => i.MatchRet()))
                                {
                                    c.Emit(OpCodes.Ldsfld, typeof(GFX).GetField("Game"));
                                    c.Emit(OpCodes.Callvirt, typeof(patch_Atlas).GetMethod("PopFallback"));
                                    c.Emit(OpCodes.Pop);
                                    c.Index++;
                                }
                            });
                        }
                    }
                }

                void CrawlType(TypeDefinition type)
                {
                    foreach (MethodDefinition method in type.Methods)
                    {
                        CrawlMethod(method);
                    }

                    foreach (TypeDefinition nested in type.NestedTypes)
                    {
                        CrawlType(nested);
                    }
                }

                foreach (TypeDefinition type in modder.Module.Types)
                {
                    CrawlType(type);
                }
            }
示例#25
0
 public static void PostProcessor(MonoModder modder)
 {
     // Patch previously registered AreaCompleteCtors and LevelExitRoutines _in that order._
     foreach (MethodDefinition method in AreaCompleteCtors)
     {
         PatchAreaCompleteCtor(method);
     }
     foreach (MethodDefinition method in LevelExitRoutines)
     {
         PatchLevelExitRoutine(method);
     }
 }
示例#26
0
        private static void PostProcessType(MonoModder modder, TypeDefinition type)
        {
            foreach (MethodDefinition method in type.Methods)
            {
                PostProcessMethod(modder, method);
            }

            foreach (TypeDefinition nested in type.NestedTypes)
            {
                PostProcessType(modder, nested);
            }
        }
        public static void Register(MonoModder self)
        {
            WeakReference weak = new WeakReference(self);

            if (IDMap.ContainsKey(weak))
            {
                throw new InvalidOperationException("MonoModder instance already registered in MMILProxyManager");
            }
            long id = IDMap[weak] = PrevID++;

            ModderMap[id] = weak;
        }
示例#28
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);
            }
        }
示例#29
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);
        }
示例#30
0
            public static void Patch(MonoModder self, string id, bool patch)
            {
                id = id.Inject(MonoModder.Data);

                self.Log($"[MonoModRules] Patch: {id}: {patch}");
                if (patch && self.SkipList.Contains(id))
                {
                    self.SkipList.Remove(id);
                }
                else if (!patch && !self.SkipList.Contains(id))
                {
                    self.SkipList.Add(id);
                }
            }