コード例 #1
0
ファイル: BaseChainloader.cs プロジェクト: hanabi1224/BepInEx
        protected virtual void InitializeLoggers()
        {
            if (ConsoleManager.ConfigConsoleEnabled.Value && !ConsoleManager.ConsoleActive)
            {
                ConsoleManager.CreateConsole();
            }

            if (ConsoleManager.ConsoleActive)
            {
                if (!Logger.Listeners.Any(x => x is ConsoleLogListener))
                {
                    Logger.Listeners.Add(new ConsoleLogListener());
                }

                ConsoleManager.SetConsoleTitle(ConsoleTitle);
            }

            if (ConfigDiskLogging.Value)
            {
                Logger.Listeners.Add(new DiskLogListener("LogOutput.log", ConfigDiskLoggingDisplayedLevel.Value, ConfigDiskAppend.Value, ConfigDiskLoggingInstantFlushing.Value, ConfigDiskLoggingFileLimit.Value));
            }

            if (!TraceLogSource.IsListening)
            {
                Logger.Sources.Add(TraceLogSource.CreateSource());
            }

            if (!Logger.Sources.Any(x => x is HarmonyLogSource))
            {
                Logger.Sources.Add(new HarmonyLogSource());
            }
        }
コード例 #2
0
        /// <summary>
        /// Initializes BepInEx to be able to start the chainloader.
        /// </summary>
        public static void Initialize(string gameExePath, bool startConsole = true)
        {
            if (_initialized)
            {
                return;
            }

            ThreadingHelper.Initialize();

            // Set vitals
            if (gameExePath != null)
            {
                // Checking for null allows a more advanced initialization workflow, where the Paths class has been initialized before calling Chainloader.Initialize
                // This is used by Preloader to use environment variables, for example
                Paths.SetExecutablePath(gameExePath);
            }

            // Start logging
            if (ConsoleWindow.ConfigConsoleEnabled.Value && startConsole)
            {
                ConsoleWindow.Attach();
                Logger.Listeners.Add(new ConsoleLogListener());
            }

            // Fix for standard output getting overwritten by UnityLogger
            if (ConsoleWindow.StandardOut != null)
            {
                Console.SetOut(ConsoleWindow.StandardOut);

                var encoding = ConsoleWindow.ConfigConsoleShiftJis.Value ? 932 : (uint)Encoding.UTF8.CodePage;
                ConsoleEncoding.ConsoleCodePage = encoding;
                Console.OutputEncoding          = ConsoleEncoding.GetEncoding(encoding);
            }

            Logger.Listeners.Add(new UnityLogListener());

            if (ConfigDiskLogging.Value)
            {
                Logger.Listeners.Add(new DiskLogListener("LogOutput.log", ConfigDiskConsoleDisplayedLevel.Value, ConfigDiskAppend.Value, ConfigDiskWriteUnityLog.Value));
            }

            if (!TraceLogSource.IsListening)
            {
                Logger.Sources.Add(TraceLogSource.CreateSource());
            }

            if (ConfigUnityLogging.Value)
            {
                Logger.Sources.Add(new UnityLogSource());
            }


            Logger.LogMessage("Chainloader ready");

            _initialized = true;
        }
コード例 #3
0
    /// <summary>
    ///     Creates a new trace log source.
    /// </summary>
    /// <returns>New log source (or already existing one).</returns>
    public static ILogSource CreateSource()
    {
        if (traceListener == null)
        {
            traceListener = new TraceLogSource();
            Trace.Listeners.Add(traceListener);
            IsListening = true;
        }

        return(traceListener.LogSource);
    }
コード例 #4
0
        /// <summary>
        /// Initializes BepInEx to be able to start the chainloader.
        /// </summary>
        public static void Initialize(string gameExePath, bool startConsole = true, ICollection <LogEventArgs> preloaderLogEvents = null)
        {
            if (_initialized)
            {
                return;
            }

            ThreadingHelper.Initialize();

            // Set vitals
            if (gameExePath != null)
            {
                // Checking for null allows a more advanced initialization workflow, where the Paths class has been initialized before calling Chainloader.Initialize
                // This is used by Preloader to use environment variables, for example
                Paths.SetExecutablePath(gameExePath);
            }

            // Start logging
            if (ConsoleManager.ConfigConsoleEnabled.Value && startConsole)
            {
                ConsoleManager.CreateConsole();
                Logger.Listeners.Add(new ConsoleLogListener());
            }

            Logger.InitializeInternalLoggers();

            if (ConfigDiskLogging.Value)
            {
                Logger.Listeners.Add(new DiskLogListener("LogOutput.log", ConfigDiskConsoleDisplayedLevel.Value, ConfigDiskAppend.Value, ConfigDiskWriteUnityLog.Value));
            }

            if (!TraceLogSource.IsListening)
            {
                Logger.Sources.Add(TraceLogSource.CreateSource());
            }

            ReplayPreloaderLogs(preloaderLogEvents);

            // Add Unity log source only after replaying to prevent duplication in console
            if (ConfigUnityLogging.Value)
            {
                Logger.Sources.Add(new UnityLogSource());
            }
            Logger.Listeners.Add(new UnityLogListener());

            if (Utility.CurrentOs == Platform.Linux)
            {
                Logger.LogInfo($"Detected Unity version: v{Application.unityVersion}");
            }

            Logger.LogMessage("Chainloader ready");

            _initialized = true;
        }
コード例 #5
0
ファイル: NetCorePreloader.cs プロジェクト: BepInEx/BepInEx
        public static void Start()
        {
            var preloaderListener = new PreloaderConsoleListener();

            Logger.Listeners.Add(preloaderListener);

            var entrypointAssemblyPath = Path.ChangeExtension(Process.GetCurrentProcess().MainModule.FileName, "dll");

            Paths.SetExecutablePath(entrypointAssemblyPath);

            TypeLoader.SearchDirectories.Add(Path.GetDirectoryName(entrypointAssemblyPath));

            Logger.Sources.Add(TraceLogSource.CreateSource());

            ChainloaderLogHelper.PrintLogInfo(Log);

            Log.Log(LogLevel.Info, $"CLR runtime version: {Environment.Version}");


            AssemblyBuildInfo executableInfo;

            using (var entrypointAssembly = AssemblyDefinition.ReadAssembly(entrypointAssemblyPath))
                executableInfo = AssemblyBuildInfo.DetermineInfo(entrypointAssembly);

            Log.LogInfo($"Game executable build architecture: {executableInfo}");

            Log.Log(LogLevel.Message, "Preloader started");

            using (var assemblyPatcher = new AssemblyPatcher())
            {
                assemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);

                Log.Log(LogLevel.Info,
                        $"{assemblyPatcher.PatcherContext.PatchDefinitions.Count} patcher definition(s) loaded");

                assemblyPatcher.LoadAssemblyDirectories(new[] { Paths.GameRootPath }, new[] { "dll", "exe" });

                Log.Log(LogLevel.Info, $"{assemblyPatcher.PatcherContext.AvailableAssemblies.Count} assemblies discovered");

                assemblyPatcher.PatchAndLoad();
            }

            Log.LogMessage("Preloader finished");

            Logger.Listeners.Remove(preloaderListener);

            var chainloader = new NetChainloader();

            chainloader.Initialize();
            chainloader.Execute();
        }
コード例 #6
0
ファイル: Chainloader.cs プロジェクト: arocarlisle/BepInEx
        /// <summary>
        /// Initializes BepInEx to be able to start the chainloader.
        /// </summary>
        public static void Initialize(string containerExePath, bool startConsole = true)
        {
            if (_initialized)
            {
                return;
            }

            //Set vitals
            Paths.SetExecutablePath(containerExePath);

            Paths.SetPluginPath(ConfigPluginsDirectory.Value);

            //Start logging

            if (startConsole)
            {
                ConsoleWindow.Attach();

                ConsoleEncoding.ConsoleCodePage = (uint)Encoding.UTF8.CodePage;
                Console.OutputEncoding          = Encoding.UTF8;
                Logger.Listeners.Add(new ConsoleLogListener());
            }

            //Fix for standard output getting overwritten by UnityLogger
            if (ConsoleWindow.StandardOut != null)
            {
                Console.SetOut(ConsoleWindow.StandardOut);
            }


            Logger.Listeners.Add(new UnityLogListener());
            Logger.Listeners.Add(new DiskLogListener());

            if (!TraceLogSource.IsListening)
            {
                Logger.Sources.Add(TraceLogSource.CreateSource());
            }

            if (ConfigUnityLogging.Value)
            {
                Logger.Sources.Add(new UnityLogSource());
            }


            Logger.LogMessage("Chainloader ready");

            _initialized = true;
        }
コード例 #7
0
ファイル: NetPreloader.cs プロジェクト: hanabi1224/BepInEx
        public static void Start(string[] args)
        {
            if (ConfigEntrypointExecutable.Value == null)
            {
                Log.LogFatal($"Entry executable was not set. Please set this in your config before launching the application");
                Program.ReadExit();
                return;
            }

            string executablePath = Path.GetFullPath(ConfigEntrypointExecutable.Value);

            if (!File.Exists(executablePath))
            {
                Log.LogFatal($"Unable to locate executable: {ConfigEntrypointExecutable.Value}");
                Program.ReadExit();
                return;
            }

            Paths.SetExecutablePath(executablePath);
            Program.ResolveDirectories.Add(Paths.GameRootPath);
            TypeLoader.SearchDirectories.Add(Paths.GameRootPath);

            Logger.Sources.Add(TraceLogSource.CreateSource());

            ChainloaderLogHelper.PrintLogInfo(Log);

            Log.LogInfo($"CLR runtime version: {Environment.Version}");

            Log.LogMessage("Preloader started");

            Assembly entrypointAssembly;

            using (var assemblyPatcher = new AssemblyPatcher())
            {
                assemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);

                Log.LogInfo($"{assemblyPatcher.PatcherPlugins.Count} patcher plugin(s) loaded");

                assemblyPatcher.LoadAssemblyDirectory(Paths.GameRootPath, "dll", "exe");

                Log.LogInfo($"{assemblyPatcher.AssembliesToPatch.Count} assemblies discovered");

                assemblyPatcher.PatchAndLoad();


                var assemblyName = AssemblyName.GetAssemblyName(executablePath);

                entrypointAssembly = assemblyPatcher.LoadedAssemblies.Values.FirstOrDefault(x => x.FullName == assemblyName.FullName);

                if (entrypointAssembly != null)
                {
                    Log.LogDebug("Found patched entrypoint assembly! Using it");
                }
                else
                {
                    Log.LogDebug("Using entrypoint assembly from disk");
                    entrypointAssembly = Assembly.LoadFrom(executablePath);
                }
            }

            Log.LogMessage("Preloader finished");

            var chainloader = new NetChainloader();

            chainloader.Initialize();
            chainloader.Execute();


            AssemblyFix.Execute(entrypointAssembly);

            entrypointAssembly.EntryPoint.Invoke(null, new [] { args });
        }
コード例 #8
0
        public static void Run()
        {
            try
            {
                AllocateConsole();

                bool bridgeInitialized = Utility.TryDo(() =>
                {
                    if (ConfigShimHarmony.Value)
                    {
                        HarmonyDetourBridge.Init();
                    }
                }, out var harmonyBridgeException);

                Exception runtimePatchException = null;
                if (bridgeInitialized)
                {
                    Utility.TryDo(() =>
                    {
                        if (ConfigApplyRuntimePatches.Value)
                        {
                            UnityPatches.Apply();
                        }
                    }, out runtimePatchException);
                }

                Logger.Sources.Add(TraceLogSource.CreateSource());

                HarmonyFixes.Apply();

                PreloaderLog = new PreloaderConsoleListener(ConfigPreloaderCOutLogging.Value);
                Logger.Listeners.Add(PreloaderLog);

                string consoleTile = $"BepInEx {typeof(Paths).Assembly.GetName().Version} - {Process.GetCurrentProcess().ProcessName}";
                ConsoleWindow.Title = consoleTile;
                Logger.LogMessage(consoleTile);

                //See BuildInfoAttribute for more information about this section.
                object[] attributes = typeof(BuildInfoAttribute).Assembly.GetCustomAttributes(typeof(BuildInfoAttribute), false);

                if (attributes.Length > 0)
                {
                    var attribute = (BuildInfoAttribute)attributes[0];
                    Logger.LogMessage(attribute.Info);
                }

                Logger.LogInfo($"Running under Unity v{FileVersionInfo.GetVersionInfo(Paths.ExecutablePath).FileVersion}");
                Logger.LogInfo($"CLR runtime version: {Environment.Version}");
                Logger.LogInfo($"Supports SRE: {Utility.CLRSupportsDynamicAssemblies}");

                if (harmonyBridgeException != null)
                {
                    Logger.LogWarning($"Failed to enable fix for Harmony for .NET Standard API. Error message: {harmonyBridgeException.Message}");
                }

                if (runtimePatchException != null)
                {
                    Logger.LogWarning($"Failed to apply runtime patches for Mono. See more info in the output log. Error message: {runtimePatchException.Message}");
                }

                Logger.LogMessage("Preloader started");

                AssemblyPatcher.AddPatcher(new PatcherPlugin
                {
                    TargetDLLs = () => new[] { ConfigEntrypointAssembly.Value },
                    Patcher    = PatchEntrypoint,
                    TypeName   = "BepInEx.Chainloader"
                });

                AssemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);

                Logger.LogInfo($"{AssemblyPatcher.PatcherPlugins.Count} patcher plugin(s) loaded");

                AssemblyPatcher.PatchAndLoad(Paths.ManagedPath);
                AssemblyPatcher.DisposePatchers();


                Logger.LogMessage("Preloader finished");

                Logger.Listeners.Remove(PreloaderLog);
                Logger.Listeners.Add(new ConsoleLogListener());

                PreloaderLog.Dispose();
            }
            catch (Exception ex)
            {
                try
                {
                    Logger.LogFatal("Could not run preloader!");
                    Logger.LogFatal(ex);

                    PreloaderLog?.Dispose();

                    if (!ConsoleWindow.IsAttached)
                    {
                        //if we've already attached the console, then the log will already be written to the console
                        AllocateConsole();
                        Console.Write(PreloaderLog);
                    }

                    PreloaderLog = null;
                }
                finally
                {
                    File.WriteAllText(
                        Path.Combine(Paths.GameRootPath, $"preloader_{DateTime.Now:yyyyMMdd_HHmmss_fff}.log"),
                        PreloaderLog + "\r\n" + ex);

                    PreloaderLog?.Dispose();
                    PreloaderLog = null;
                }
            }
        }
コード例 #9
0
        /// <summary>
        /// Initializes BepInEx to be able to start the chainloader.
        /// </summary>
        public static void Initialize(string gameExePath, bool startConsole = true, ICollection <LogEventArgs> preloaderLogEvents = null)
        {
            if (_initialized)
            {
                return;
            }

            ThreadingHelper.Initialize();

            // Set vitals
            if (gameExePath != null)
            {
                // Checking for null allows a more advanced initialization workflow, where the Paths class has been initialized before calling Chainloader.Initialize
                // This is used by Preloader to use environment variables, for example
                Paths.SetExecutablePath(gameExePath);
            }

            // Start logging
            if (ConsoleManager.ConfigConsoleEnabled.Value && startConsole)
            {
                ConsoleManager.CreateConsole();
                Logger.Listeners.Add(new ConsoleLogListener());
            }

            // Fix for standard output getting overwritten by UnityLogger
            if (ConsoleManager.ConsoleActive)
            {
                ConsoleManager.SetConsoleStreams();
                ConsoleManager.SetConsoleEncoding();
            }

            Logger.InitializeInternalLoggers();
            Logger.Listeners.Add(new UnityLogListener());

            if (ConfigDiskLogging.Value)
            {
                Logger.Listeners.Add(new DiskLogListener("LogOutput.log", ConfigDiskConsoleDisplayedLevel.Value, ConfigDiskAppend.Value, ConfigDiskWriteUnityLog.Value));
            }

            if (!TraceLogSource.IsListening)
            {
                Logger.Sources.Add(TraceLogSource.CreateSource());
            }

            if (ConfigUnityLogging.Value)
            {
                Logger.Sources.Add(new UnityLogSource());
            }


            // Temporarily disable the console log listener as we replay the preloader logs
            var logListener = Logger.Listeners.FirstOrDefault(logger => logger is ConsoleLogListener);

            if (logListener != null)
            {
                Logger.Listeners.Remove(logListener);
            }

            // Write preloader log events if there are any, including the original log source name
            if (preloaderLogEvents != null)
            {
                var preloaderLogSource = Logger.CreateLogSource("Preloader");

                foreach (var preloaderLogEvent in preloaderLogEvents)
                {
                    Logger.InternalLogEvent(preloaderLogSource, preloaderLogEvent);
                }

                Logger.Sources.Remove(preloaderLogSource);
            }

            if (logListener != null)
            {
                Logger.Listeners.Add(logListener);
            }

            if (Utility.CurrentOs == Platform.Linux)
            {
                Logger.LogInfo($"Detected Unity version: v{Application.unityVersion}");
            }

            Logger.LogMessage("Chainloader ready");

            _initialized = true;
        }
コード例 #10
0
        /// <summary>
        /// Initializes BepInEx to be able to start the chainloader.
        /// </summary>
        public static void Initialize(string gameExePath, bool startConsole = true, ICollection <LogEventArgs> preloaderLogEvents = null)
        {
            if (_initialized)
            {
                return;
            }

            ThreadingHelper.Initialize();

            // Set vitals
            if (gameExePath != null)
            {
                // Checking for null allows a more advanced initialization workflow, where the Paths class has been initialized before calling Chainloader.Initialize
                // This is used by Preloader to use environment variables, for example
                Paths.SetExecutablePath(gameExePath);
            }

            // Start logging
            if (ConsoleWindow.ConfigConsoleEnabled.Value && startConsole)
            {
                ConsoleWindow.Attach();
                Logger.Listeners.Add(new ConsoleLogListener());
            }

            // Fix for standard output getting overwritten by UnityLogger
            if (ConsoleWindow.StandardOut != null)
            {
                Console.SetOut(ConsoleWindow.StandardOut);

                var encoding = ConsoleWindow.ConfigConsoleShiftJis.Value ? 932 : (uint)Encoding.UTF8.CodePage;
                ConsoleEncoding.ConsoleCodePage = encoding;
                Console.OutputEncoding          = ConsoleEncoding.GetEncoding(encoding);
            }

            Logger.Listeners.Add(new UnityLogListener());

            if (ConfigDiskLogging.Value)
            {
                Logger.Listeners.Add(new DiskLogListener("LogOutput.log", ConfigDiskConsoleDisplayedLevel.Value, ConfigDiskAppend.Value, ConfigDiskWriteUnityLog.Value));
            }

            if (!TraceLogSource.IsListening)
            {
                Logger.Sources.Add(TraceLogSource.CreateSource());
            }

            if (ConfigUnityLogging.Value)
            {
                Logger.Sources.Add(new UnityLogSource());
            }


            // Temporarily disable the console log listener as we replay the preloader logs
            var logListener = Logger.Listeners.FirstOrDefault(logger => logger is ConsoleLogListener);

            if (logListener != null)
            {
                Logger.Listeners.Remove(logListener);
            }

            // Write preloader log events if there are any, including the original log source name
            if (preloaderLogEvents != null)
            {
                var preloaderLogSource = Logger.CreateLogSource("Preloader");

                foreach (var preloaderLogEvent in preloaderLogEvents)
                {
                    preloaderLogSource.Log(preloaderLogEvent.Level, $"[{preloaderLogEvent.Source.SourceName,10}] {preloaderLogEvent.Data}");
                }

                Logger.Sources.Remove(preloaderLogSource);
            }

            if (logListener != null)
            {
                Logger.Listeners.Add(logListener);
            }

            Logger.LogMessage("Chainloader ready");

            _initialized = true;
        }
コード例 #11
0
ファイル: Preloader.cs プロジェクト: langresser/BepInEx
        public static void Run()
        {
            try
            {
                AllocateConsole();

                UnityPatches.Apply();

                Logger.Sources.Add(TraceLogSource.CreateSource());

                PreloaderLog = new PreloaderConsoleListener(Utility.SafeParseBool(Config.GetEntry("preloader-logconsole", "false", "BepInEx")));

                Logger.Listeners.Add(PreloaderLog);


                string consoleTile = $"BepInEx {typeof(Paths).Assembly.GetName().Version} - {Process.GetCurrentProcess().ProcessName}";

                ConsoleWindow.Title = consoleTile;
                Logger.LogMessage(consoleTile);

                //See BuildInfoAttribute for more information about this section.
                object[] attributes = typeof(BuildInfoAttribute).Assembly.GetCustomAttributes(typeof(BuildInfoAttribute), false);

                if (attributes.Length > 0)
                {
                    var attribute = (BuildInfoAttribute)attributes[0];

                    Logger.LogMessage(attribute.Info);
                }

#if UNITY_2018
                Logger.LogMessage("Compiled in Unity v2018 mode");
#else
                Logger.LogMessage("Compiled in Legacy Unity mode");
#endif

                Logger.LogInfo($"Running under Unity v{Process.GetCurrentProcess().MainModule.FileVersionInfo.FileVersion}");

                Logger.LogMessage("Preloader started");

                string entrypointAssembly = Config.GetEntry("entrypoint-assembly", "UnityEngine.dll", "Preloader");

                AssemblyPatcher.AddPatcher(new PatcherPlugin
                {
                    TargetDLLs = new[] { entrypointAssembly }, Patcher = PatchEntrypoint
                });
                AssemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath, GetPatcherMethods);

                Logger.LogInfo($"{AssemblyPatcher.PatcherPlugins.Count} patcher plugin(s) loaded");

                AssemblyPatcher.PatchAndLoad(Paths.ManagedPath);

                AssemblyPatcher.DisposePatchers();

                Logger.LogMessage("Preloader finished");

                Logger.Listeners.Remove(PreloaderLog);
                Logger.Listeners.Add(new ConsoleLogListener());

                PreloaderLog.Dispose();
            }
            catch (Exception ex)
            {
                try
                {
                    Logger.LogFatal("Could not run preloader!");
                    Logger.LogFatal(ex);

                    PreloaderLog?.Dispose();

                    if (!ConsoleWindow.IsAttached)
                    {
                        //if we've already attached the console, then the log will already be written to the console
                        AllocateConsole();
                        Console.Write(PreloaderLog);
                    }

                    PreloaderLog = null;
                }
                finally
                {
                    File.WriteAllText(
                        Path.Combine(Paths.GameRootPath, $"preloader_{DateTime.Now:yyyyMMdd_HHmmss_fff}.log"),
                        PreloaderLog + "\r\n" + ex);

                    PreloaderLog?.Dispose();
                    PreloaderLog = null;
                }
            }
        }
コード例 #12
0
ファイル: Preloader.cs プロジェクト: yuemenglong/BepInEx
        public static void Run()
        {
            try
            {
                ConsoleManager.Initialize(false);
                AllocateConsole();

                Utility.TryDo(() =>
                {
                    if (ConfigApplyRuntimePatches.Value)
                    {
                        UnityPatches.Apply();
                    }
                }, out var runtimePatchException);

                Logger.InitializeInternalLoggers();
                Logger.Sources.Add(TraceLogSource.CreateSource());

                PreloaderLog = new PreloaderConsoleListener(ConfigPreloaderCOutLogging.Value);
                Logger.Listeners.Add(PreloaderLog);

                string consoleTile = $"BepInEx {typeof(Paths).Assembly.GetName().Version} - {Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().ProcessName)}";

                if (ConsoleManager.ConsoleActive)
                {
                    ConsoleManager.SetConsoleTitle(consoleTile);
                }

                Logger.LogMessage(consoleTile);

                //See BuildInfoAttribute for more information about this section.
                object[] attributes = typeof(BuildInfoAttribute).Assembly.GetCustomAttributes(typeof(BuildInfoAttribute), false);

                if (attributes.Length > 0)
                {
                    var attribute = (BuildInfoAttribute)attributes[0];
                    Logger.LogMessage(attribute.Info);
                }

                Logger.LogInfo($"Running under Unity v{GetUnityVersion()}");
                Logger.LogInfo($"CLR runtime version: {Environment.Version}");
                Logger.LogInfo($"Supports SRE: {Utility.CLRSupportsDynamicAssemblies}");

                if (runtimePatchException != null)
                {
                    Logger.LogWarning($"Failed to apply runtime patches for Mono. See more info in the output log. Error message: {runtimePatchException.Message}");
                }

                Logger.LogMessage("Preloader started");

                AssemblyPatcher.AddPatcher(new PatcherPlugin
                {
                    TargetDLLs = () => new[] { ConfigEntrypointAssembly.Value },
                    Patcher    = PatchEntrypoint,
                    TypeName   = "BepInEx.Chainloader"
                });

                AssemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);

                Logger.LogInfo($"{AssemblyPatcher.PatcherPlugins.Count} patcher plugin(s) loaded");

                AssemblyPatcher.PatchAndLoad(Paths.ManagedPath);
                AssemblyPatcher.DisposePatchers();


                Logger.LogMessage("Preloader finished");

                Logger.Listeners.Remove(PreloaderLog);
                Logger.Listeners.Add(new ConsoleLogListener());

                PreloaderLog.Dispose();
            }
            catch (Exception ex)
            {
                try
                {
                    Logger.LogFatal("Could not run preloader!");
                    Logger.LogFatal(ex);

                    if (!ConsoleManager.ConsoleActive)
                    {
                        //if we've already attached the console, then the log will already be written to the console
                        AllocateConsole();
                        Console.Write(PreloaderLog);
                    }
                }
                catch { }

                string log = string.Empty;

                try
                {
                    // We could use platform-dependent newlines, however the developers use Windows so this will be easier to read :)

                    log  = string.Join("\r\n", PreloaderConsoleListener.LogEvents.Select(x => x.ToString()).ToArray());
                    log += "\r\n";

                    PreloaderLog?.Dispose();
                    PreloaderLog = null;
                }
                catch { }

                File.WriteAllText(
                    Path.Combine(Paths.GameRootPath, $"preloader_{DateTime.Now:yyyyMMdd_HHmmss_fff}.log"),
                    log + ex);
            }
        }
コード例 #13
0
        public static void Run()
        {
            try
            {
                InitializeHarmony();

                ConsoleManager.Initialize(false);
                AllocateConsole();

                Utility.TryDo(() =>
                {
                    if (ConfigApplyRuntimePatches.Value)
                    {
                        UnityPatches.Apply();
                    }
                }, out var runtimePatchException);

                Logger.Sources.Add(new HarmonyLogSource());
                Logger.Sources.Add(TraceLogSource.CreateSource());

                Logger.Listeners.Add(new ConsoleLogListener());
                PreloaderLog = new PreloaderConsoleListener();
                Logger.Listeners.Add(PreloaderLog);

                ChainloaderLogHelper.PrintLogInfo(Log);

                Log.LogInfo($"Running under Unity v{GetUnityVersion()}");
                Log.LogInfo($"CLR runtime version: {Environment.Version}");
                Log.LogInfo($"Supports SRE: {Utility.CLRSupportsDynamicAssemblies}");

                Log.LogDebug($"Game executable path: {Paths.ExecutablePath}");
                Log.LogDebug($"Unity Managed directory: {Paths.ManagedPath}");
                Log.LogDebug($"BepInEx root path: {Paths.BepInExRootPath}");

                if (runtimePatchException != null)
                {
                    Log.LogWarning($"Failed to apply runtime patches for Mono. See more info in the output log. Error message: {runtimePatchException.Message}");
                }

                Log.LogMessage("Preloader started");

                TypeLoader.SearchDirectories.UnionWith(Paths.DllSearchPaths);

                using (var assemblyPatcher = new AssemblyPatcher())
                {
                    assemblyPatcher.PatcherPlugins.Add(new PatcherPlugin
                    {
                        TargetDLLs = () => new[] { ConfigEntrypointAssembly.Value },
                        Patcher    = PatchEntrypoint,
                        TypeName   = "BepInEx.Chainloader"
                    });

                    assemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);

                    Log.LogInfo($"{assemblyPatcher.PatcherPlugins.Count} patcher plugin{(assemblyPatcher.PatcherPlugins.Count == 1 ? "" : "s")} loaded");

                    assemblyPatcher.LoadAssemblyDirectories(Paths.DllSearchPaths);

                    Log.LogInfo($"{assemblyPatcher.PatcherPlugins.Count} assemblies discovered");

                    assemblyPatcher.PatchAndLoad();
                }


                Log.LogMessage("Preloader finished");

                Logger.Listeners.Remove(PreloaderLog);

                PreloaderLog.Dispose();
            }
            catch (Exception ex)
            {
                try
                {
                    Log.LogFatal("Could not run preloader!");
                    Log.LogFatal(ex);

                    if (!ConsoleManager.ConsoleActive)
                    {
                        //if we've already attached the console, then the log will already be written to the console
                        AllocateConsole();
                        Console.Write(PreloaderLog);
                    }
                }
                catch { }

                var log = string.Empty;

                try
                {
                    // We could use platform-dependent newlines, however the developers use Windows so this will be easier to read :)

                    log  = string.Join("\r\n", PreloaderConsoleListener.LogEvents.Select(x => x.ToString()).ToArray());
                    log += "\r\n";

                    PreloaderLog?.Dispose();
                    PreloaderLog = null;
                }
                catch { }

                File.WriteAllText(
                    Path.Combine(Paths.GameRootPath, $"preloader_{DateTime.Now:yyyyMMdd_HHmmss_fff}.log"),
                    log + ex);
            }
        }
コード例 #14
0
ファイル: NetPreloader.cs プロジェクト: BepInEx/BepInEx
    public static void Start(string[] args)
    {
        var preloaderListener = new PreloaderConsoleListener();

        Logger.Listeners.Add(preloaderListener);

        if (string.IsNullOrEmpty(ConfigEntrypointExecutable.Value))
        {
            Log.Log(LogLevel.Fatal,
                    $"Entry executable was not set. Please set this in your config before launching the application");
            Program.ReadExit();
            return;
        }

        var executablePath = Path.GetFullPath(ConfigEntrypointExecutable.Value);

        if (!File.Exists(executablePath))
        {
            Log.Log(LogLevel.Fatal, $"Unable to locate executable: {ConfigEntrypointExecutable.Value}");
            Program.ReadExit();
            return;
        }


        Paths.SetExecutablePath(executablePath);
        Program.ResolveDirectories.Add(Paths.GameRootPath);

        foreach (var searchDir in Program.ResolveDirectories)
        {
            TypeLoader.SearchDirectories.Add(searchDir);
        }

        if (PlatformHelper.Is(Platform.Windows))
        {
            AddDllDirectory(Paths.GameRootPath);
            SetDllDirectory(Paths.GameRootPath);
        }


        Logger.Sources.Add(TraceLogSource.CreateSource());

        ChainloaderLogHelper.PrintLogInfo(Log);

        Log.Log(LogLevel.Info, $"CLR runtime version: {Environment.Version}");


        AssemblyBuildInfo executableInfo, launcherInfo;

        using (var executableAssembly = AssemblyDefinition.ReadAssembly(executablePath))
            executableInfo = AssemblyBuildInfo.DetermineInfo(executableAssembly);

        using (var launcherAssembly = AssemblyDefinition.ReadAssembly(typeof(NetPreloader).Assembly.Location))
            launcherInfo = AssemblyBuildInfo.DetermineInfo(launcherAssembly);

        // we don't particularly care about AnyCPU here since the fallback bitness is almost never the case
        if (executableInfo.Is64Bit != launcherInfo.Is64Bit)
        {
            Log.LogError($"Game executable is {(executableInfo.Is64Bit ? "64" : "32")}-bit while BepInEx has been compiled as {(launcherInfo.Is64Bit ? "64" : "32")}-bit. Expect crashes");
        }

        if (executableInfo.NetFrameworkVersion != launcherInfo.NetFrameworkVersion || executableInfo.AssemblyFrameworkType != launcherInfo.AssemblyFrameworkType)
        {
            Log.LogWarning($"Game executable has been compiled as {executableInfo}, while BepInEx has been compiled as {launcherInfo}. There may be issues within the game caused by this");
        }

        Log.LogInfo($"Game executable build architecture: {executableInfo}");
        Log.LogInfo($"BepInEx launcher build architecture: {launcherInfo}");

        Log.Log(LogLevel.Message, "Preloader started");

        Assembly entrypointAssembly;

        using (var assemblyPatcher = new AssemblyPatcher())
        {
            assemblyPatcher.AddPatchersFromDirectory(Paths.PatcherPluginPath);

            Log.Log(LogLevel.Info,
                    $"{assemblyPatcher.PatcherContext.PatchDefinitions.Count} patcher definition(s) loaded");

            assemblyPatcher.LoadAssemblyDirectories(new[] { Paths.GameRootPath }, new[] { "dll", "exe" });

            Log.Log(LogLevel.Info, $"{assemblyPatcher.PatcherContext.AvailableAssemblies.Count} assemblies discovered");

            assemblyPatcher.PatchAndLoad();


            var assemblyName = AssemblyName.GetAssemblyName(executablePath);

            entrypointAssembly =
                assemblyPatcher.PatcherContext.LoadedAssemblies.Values.FirstOrDefault(x => x.FullName ==
                                                                                      assemblyName.FullName);

            foreach (var loadedAssembly in assemblyPatcher.PatcherContext.LoadedAssemblies)
            {
                // TODO: Need full paths for loaded assemblies
                var assemblyPath = Path.Combine(Paths.GameRootPath, loadedAssembly.Key);

                Log.LogDebug($"Registering '{assemblyPath}' as a loaded assembly");
                AssemblyFixes.AssemblyLocations[loadedAssembly.Value.FullName] = assemblyPath;
            }

            if (entrypointAssembly != null)
            {
                Log.LogDebug("Found patched entrypoint assembly! Using it");
            }
            else
            {
                Log.LogDebug("Using entrypoint assembly from disk");
                entrypointAssembly = Assembly.LoadFrom(executablePath);
            }
        }

        Log.LogMessage("Preloader finished");

        Logger.Listeners.Remove(preloaderListener);

        var chainloader = new NetChainloader();

        chainloader.Initialize();
        chainloader.Execute();


        AssemblyFixes.Execute(entrypointAssembly);

        try
        {
            var argList = new List <object>();

            var paramTypes = entrypointAssembly.EntryPoint.GetParameters();

            if (paramTypes.Length == 1 && paramTypes[0].ParameterType == typeof(string[]))
            {
                argList.Add(args);
            }
            else if (paramTypes.Length == 1 && paramTypes[0].ParameterType == typeof(string))
            {
                argList.Add(string.Join(" ", args));
            }
            else if (paramTypes.Length != 0)
            {
                // Only other entrypoint signatures I can think of that .NET supports is Task / Task<int>
                //   async entrypoints. That's a can of worms for another time though

                Log.LogFatal($"Could not figure out how to handle entrypoint method with this signature: {entrypointAssembly.EntryPoint.FullDescription()}");
                return;
            }

            entrypointAssembly.EntryPoint.Invoke(null, argList.ToArray());
        }
        catch (Exception ex)
        {
            Log.LogFatal($"Unhandled exception: {ex}");
        }
    }