Exemplo n.º 1
0
        public static void Entry(bool verbosity)
        {
            Logger.Initialize(verbosity);
            Logger.Log($"Starting ModLoaderLibrary Version {MLVersion.ToString()}");
            Logger.Log("Beginning Patches...", Logger.LogType.Debug);
            try
            {
                var harmony = HarmonyInstance.Create("com.catcherben.modloader");
                harmony.PatchAll(Assembly.GetExecutingAssembly());
                Logger.Log("Finished MLL Patching.", Logger.LogType.Debug);
            }
            catch (Exception e)
            {
                Logger.Log($"Exception when patching: {e.Message}", Logger.LogType.Error);
                while (e.InnerException != null)
                {
                    Logger.Log($"Internal Exception Message: {e.InnerException.Message}", Logger.LogType.Error);
                    e = e.InnerException;
                }
            }

            // All mod-loading code now occurs in a harmony patch, now that ACEO supports modding files, etc.
            Logger.Log("ModLoaderLibrary initialization finished.");
        }
Exemplo n.º 2
0
 private static void PrintHelp()
 {
     Console.WriteLine($"ModLoader {MLVersion.ToString()}");
     Console.WriteLine("Command line arguments:\r\n");
     Console.WriteLine("-h, --help");
     Console.WriteLine("Prints this help menu.\r\n");
     Console.WriteLine("-v, --verbose");
     Console.WriteLine("Enables verbose debug output to log and console.\r\n");
     Console.WriteLine("-ss, --start");
     Console.WriteLine("Start the game through Steam. Note: As of Alpha 26.1, you cannot start the game any other way.\r\n");
     Console.WriteLine("-p, --patch");
     Console.WriteLine("Patches the game with ModLoaderLibrary\r\n");
     Console.WriteLine("-e, --enums");
     Console.WriteLine("Injects enums found in mods\r\n");
     Console.WriteLine("-b, --backupname");
     Console.WriteLine("Specifies custom name to backup assembly file to\r\n");
     Console.WriteLine("-sp, --steampath");
     Console.WriteLine("Specifies path to Steam.\r\n\r\n\r\n");
     Console.WriteLine("To start ACEO normally from ModLoader, run \"ModLoader [-s or -ss]\"");
     Console.WriteLine("To start ACEO with full modding support, run \"ModLoader -p -e [-s or -ss]\"");
     Console.WriteLine("If you are a mod developer, please refer to the project's Git readme at https://github.com/bdgmb2/aceo-modloader");
     Console.WriteLine("\r\nPress any key to exit...");
     Console.ReadKey();
 }
Exemplo n.º 3
0
        private void Patch()
        {
            try
            {
                Logger.Log("Patching Assembly-CSharp" + LibExtension, Logger.LogType.Debug);

                // This is the ExitPoint class we're patching
                var exitPointIL        = module.Types.Single(x => x.Name == "Utils").Methods.Single(x => x.Name == "QuitGame").Body;
                var exitPointProcessor = exitPointIL.GetILProcessor();

                // Remove all instructions (It's only a call to Application.Quit() and a 'ret')
                exitPointIL.Instructions.Clear();

                // Load the ModLoaderLibrary assembly
                exitPointIL.Instructions.Add(exitPointProcessor.Create(OpCodes.Ldstr, "ModLoader/MLL" + LibExtension));
                exitPointIL.Instructions.Add(exitPointProcessor.Create(OpCodes.Call, module.ImportReference(typeof(Assembly).GetMethod("LoadFile", new[] { typeof(string) }))));
                // Get the ModLoader class in the assembly
                exitPointIL.Instructions.Add(exitPointProcessor.Create(OpCodes.Ldstr, "ModLoaderLibrary.ModLoader"));
                exitPointIL.Instructions.Add(exitPointProcessor.Create(OpCodes.Callvirt, module.ImportReference(typeof(Assembly).GetMethod("GetType", new[] { typeof(string) }))));
                // Get the Exit() function in the ModLoader class
                exitPointIL.Instructions.Add(exitPointProcessor.Create(OpCodes.Ldstr, "Exit"));
                exitPointIL.Instructions.Add(exitPointProcessor.Create(OpCodes.Callvirt, module.ImportReference(typeof(Type).GetMethod("GetMethod", new[] { typeof(string) }))));
                // Call the Exit() function
                exitPointIL.Instructions.Add(exitPointProcessor.Create(OpCodes.Ldnull));
                exitPointIL.Instructions.Add(exitPointProcessor.Create(OpCodes.Ldnull));
                exitPointIL.Instructions.Add(exitPointProcessor.Create(OpCodes.Callvirt, module.ImportReference(typeof(MethodBase).GetMethod("Invoke", new[] { typeof(object), typeof(object[]) }))));
                exitPointIL.Instructions.Add(exitPointProcessor.Create(OpCodes.Pop));

                // Add the 'Application.Quit()' back in
                exitPointIL.Instructions.Add(exitPointProcessor.Create(OpCodes.Call, module.ImportReference(typeof(UnityEngine.Application).GetMethod("Quit"))));
                // Add the 'ret' back in
                exitPointIL.Instructions.Add(exitPointProcessor.Create(OpCodes.Ret));
                // Ok we're done with the exitpoint.

                // This is the entry point method we're patching
                var entryPointIL        = module.Types.Single(x => x.Name == "GameVersionLabelUI").Methods.Single(x => x.Name == "Awake").Body;
                var entryPointProcessor = entryPointIL.GetILProcessor();

                // Remove the 'ret' at the end of the instruction list in the method
                entryPointIL.Instructions.RemoveAt(entryPointIL.Instructions.Count - 1);

                // Add ModLoader Message (since we're at the end of GameVersionLabelUI)
                var gameVerReference = module.Types.Single(x => x.Name == "GameVersionLabelUI");
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Ldarg_0));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Ldfld, module.ImportReference(gameVerReference.Fields.Single(x => x.Name == "versionLabelText"))));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Dup));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Callvirt, module.ImportReference(typeof(UnityEngine.UI.Text).GetMethod("get_text"))));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Ldstr, " - ModLoader " + MLVersion.ToString()));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Call, module.ImportReference(typeof(System.String).GetMethod("Concat", new [] { typeof(string), typeof(string) }))));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Callvirt, module.ImportReference(typeof(UnityEngine.UI.Text).GetMethod("set_text", new [] { typeof(string) }))));

                // Load Harmony
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Ldstr, "ModLoader/0Harmony" + LibExtension));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Call, module.ImportReference(typeof(Assembly).GetMethod("LoadFile", new[] { typeof(string) }))));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Pop));

                // Load the ModLoaderLibrary assembly
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Ldstr, "ModLoader/MLL" + LibExtension));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Call, module.ImportReference(typeof(Assembly).GetMethod("LoadFile", new[] { typeof(string) }))));

                // Get the ModLoader class in the assembly
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Ldstr, "ModLoaderLibrary.ModLoader"));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Callvirt, module.ImportReference(typeof(Assembly).GetMethod("GetType", new[] { typeof(string) }))));
                // Get the Entry() function in the ModLoader class
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Ldstr, "Entry"));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Callvirt, module.ImportReference(typeof(Type).GetMethod("GetMethod", new[] { typeof(string) }))));
                // Call the Entry() function
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Ldnull));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Ldc_I4_1));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Newarr, module.ImportReference(typeof(Object))));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Dup));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Ldc_I4_0));
                if (Logger.logDebug)
                {
                    entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Ldc_I4_1));
                }
                else
                {
                    entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Ldc_I4_0));
                }
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Box, module.ImportReference(typeof(Boolean))));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Stelem_Ref));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Callvirt, module.ImportReference(typeof(MethodBase).GetMethod("Invoke", new[] { typeof(object), typeof(object[]) }))));
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Pop));

                // Add the 'ret' back in
                entryPointIL.Instructions.Add(entryPointProcessor.Create(OpCodes.Ret));

                Logger.Log("Done.", Logger.LogType.Debug);
            }
            catch (Exception ex)
            {
                Logger.Log("Problem when patching assembly: " + ex.Message + ", Reverting.", Logger.LogType.Error);
                module.Dispose();
                RevertAssembly();
                throw;
            }
        }
Exemplo n.º 4
0
        private static void Main(string[] args)
        {
            bool   logVerbose = false;
            string logLocation = "", backupName = "", assmOutput = "", steamPath = "";
            bool   patching = false, enums = false, launchGame = false;

            if (args.Length == 0)
            {
                PrintHelp();
                return;
            }

            // PARSE ARGUMENTS
            // This would be a foreach, but I'm doing lookahead to check some arguments
            for (int i = 0; i < args.Length; i++)
            {
                // For simplicity
                string arg = args[i];

                switch (arg)
                {
                // Turn the verbosity up
                case "-v":
                case "--verbose":
                    logVerbose = true;
                    break;

                // Custom log output location
                case "-l":
                case "--log":
                    if (i + 1 >= args.Length)
                    {
                        Console.WriteLine("[ERROR] Log is missing file argument. Exiting.");
                        return;
                    }
                    else
                    {
                        logLocation = args[i + 1];
                    }

                    break;

                // Patch the assembly
                case "-p":
                case "--patch":
                    patching = true;
                    break;

                // Inject enums
                case "-e":
                case "--enums":
                    if (!patching)
                    {
                        Console.WriteLine("Cannot inject enums without patching library. Please run with \"-p\"");
                        return;
                    }
                    else
                    {
                        enums = true;
                    }

                    break;

                // Custom assembly backup name
                case "-b":
                case "--backupname":
                    if (!patching)
                    {
                        Console.WriteLine(
                            "Cannot specify custom backup name without patching library. Please run with \"-p\"");
                        return;
                    }
                    else if (i + 1 >= args.Length)
                    {
                        Console.WriteLine("[ERROR] Backup file name is missing argument. Exiting.");
                        return;
                    }
                    else
                    {
                        backupName = args[i + 1];
                    }

                    break;

                // Custom patched assembly output name
                case "-o":
                case "--output":
                    if (i + 1 >= args.Length)
                    {
                        Console.WriteLine("[ERROR] Library output is missing file argument. Exiting.");
                        return;
                    }
                    else
                    {
                        assmOutput = args[i + 1];
                    }

                    break;

                // Launch game through Steam
                case "-s":
                case "--start":
                    launchGame = true;
                    break;

                // Specify Steam Path
                case "-sp":
                case "--steampath":
                    if (i + 1 >= args.Length)
                    {
                        Console.WriteLine("[ERROR] Steam Path is missing argument. Exiting.");
                        return;
                    }
                    else
                    {
                        steamPath = args[i + 1];
                    }

                    break;

                // Show help menu
                case "-h":
                case "--help":
                default:
                    PrintHelp();
                    return;
                }
            }

            // INITIATE LOGGER
            if (logLocation != "")
            {
                Logger.Initialize(logVerbose, logLocation);
            }
            else
            {
                Logger.Initialize(logVerbose);
            }

            Logger.Log($"Starting ACEO ModLoader version {MLVersion.ToString()}");

            // INITIATE PATCHER
            Patcher patcher;

            try
            {
                patcher = new Patcher
                {
                    IsPatching       = patching,
                    IsInjectingEnums = enums,
                    IsLaunchingGame  = launchGame
                };
                if (backupName != "")
                {
                    patcher.BackupFilename = backupName;
                }
                if (assmOutput != "")
                {
                    patcher.AssemblyName = assmOutput;
                }
                if (steamPath != "")
                {
                    patcher.SteamDirectory = steamPath;
                }
            }
            catch (Exception ex)
            {
                Logger.Log($"Critical error when starting up: {ex.Message}", Logger.LogType.Error);
                Logger.Log("Press any key to continue.");
                Console.ReadKey();
                return;
            }

            // RUN LOGIC
            try
            {
                patcher.Run();
            }
            catch (Exception)
            {
                Logger.Log("Attempting to restore backup...");
                patcher.RevertAssembly();
                Logger.Log("ModLoader encountered a problem and has stopped. If you think there is a bug in ModLoader, please submit an issue to the ModLoader Github repository.", Logger.LogType.Error);
                Console.WriteLine("Press any key to continue.");
                Console.ReadKey();
            }

            Logger.Log("ModLoader Exiting...");
        }