From 4cae3c1ed1f5e5a4706d5c2cd6a30aecda25ff10 Mon Sep 17 00:00:00 2001 From: denikson Date: Mon, 18 Jun 2018 18:57:31 +0300 Subject: [PATCH 1/3] Add option to listen to Unity log messages --- BepInEx/Bootstrap/Chainloader.cs | 3 ++ BepInEx/Logging/UnityLogWriter.cs | 48 +++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/BepInEx/Bootstrap/Chainloader.cs b/BepInEx/Bootstrap/Chainloader.cs index 60d615a..3b3cb46 100644 --- a/BepInEx/Bootstrap/Chainloader.cs +++ b/BepInEx/Bootstrap/Chainloader.cs @@ -52,6 +52,9 @@ namespace BepInEx.Bootstrap Logger.SetLogger(unityLogWriter); + if(bool.Parse(Config.GetEntry("log_unity_messages", "false", "Global"))) + UnityLogWriter.ListenUnityLogs(); + string consoleTile = $"BepInEx {Assembly.GetExecutingAssembly().GetName().Version} - {Application.productName}"; ConsoleWindow.Title = consoleTile; diff --git a/BepInEx/Logging/UnityLogWriter.cs b/BepInEx/Logging/UnityLogWriter.cs index 5707470..f1a04c1 100644 --- a/BepInEx/Logging/UnityLogWriter.cs +++ b/BepInEx/Logging/UnityLogWriter.cs @@ -1,6 +1,8 @@ using System; +using System.Reflection; using System.Runtime.CompilerServices; using BepInEx.ConsoleUtil; +using UnityEngine; namespace BepInEx.Logging { @@ -39,6 +41,52 @@ namespace BepInEx.Logging public override void WriteLine(string value) => InternalWrite($"{value}\r\n"); public override void Write(char value) => InternalWrite(value.ToString()); public override void Write(string value) => InternalWrite(value); + + /// + /// Start listening to Unity's log message events and sending the messages to BepInEx logger. + /// + public static void ListenUnityLogs() + { + Type application = typeof(Application); + + MethodInfo registerLogCallback = application.GetMethod("RegisterLogCallback", BindingFlags.Public | BindingFlags.Static); + if (registerLogCallback != null) + { + registerLogCallback.Invoke(null, new object[] {new Application.LogCallback(OnUnityLogMessageReceived)}); + } + else + { + EventInfo logEvent = application.GetEvent("logMessageReceived", BindingFlags.Public | BindingFlags.Static); + logEvent?.AddEventHandler(null, new Application.LogCallback(OnUnityLogMessageReceived)); + } + } + + private static void OnUnityLogMessageReceived(string message, string stackTrace, LogType type) + { + LogLevel logLevel = LogLevel.Message; + + switch (type) + { + case LogType.Error: + case LogType.Assert: + case LogType.Exception: + logLevel = LogLevel.Error; + break; + case LogType.Warning: + logLevel = LogLevel.Warning; + break; + case LogType.Log: + default: + logLevel = LogLevel.Message; + break; + } + + Logger.Log(logLevel, message); + if (type == LogType.Exception) + { + Logger.Log(logLevel, $"Stack trace:\n{stackTrace}"); + } + } } } From 7526289507cf5de81cef7cae43d59ccb022f5152 Mon Sep 17 00:00:00 2001 From: denikson Date: Mon, 18 Jun 2018 19:08:21 +0300 Subject: [PATCH 2/3] Prevent dumping unpatched assemblies --- BepInEx/Bootstrap/AssemblyPatcher.cs | 49 ++++++++++++++-------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/BepInEx/Bootstrap/AssemblyPatcher.cs b/BepInEx/Bootstrap/AssemblyPatcher.cs index 8e25fe9..8b3d615 100644 --- a/BepInEx/Bootstrap/AssemblyPatcher.cs +++ b/BepInEx/Bootstrap/AssemblyPatcher.cs @@ -82,46 +82,47 @@ namespace BepInEx.Bootstrap //sort the assemblies so load the assemblies that are dependant upon first AssemblyDefinition[] sortedAssemblies = Utility.TopologicalSort(assemblies, x => assemblyDependencyDict[x]).ToArray(); - List sortedAssemblyFilenames = sortedAssemblies.Select(x => assemblyFilenames[x]).ToList(); + Dictionary sortedAssemblyFilenames = sortedAssemblies.ToDictionary(ass => assemblyFilenames[ass]); + + HashSet patchedAssemblies = new HashSet(); //call the patchers on the assemblies foreach (var patcherMethod in patcherMethodDictionary) { foreach (string assemblyFilename in patcherMethod.Value) { - int index = sortedAssemblyFilenames.FindIndex(x => x == assemblyFilename); - - if (index < 0) - continue; - - Patch(ref sortedAssemblies[index], patcherMethod.Key); + if (sortedAssemblyFilenames.TryGetValue(assemblyFilename, out var assembly)) + { + Patch(ref assembly, patcherMethod.Key); + patchedAssemblies.Add(assemblyFilenames[assembly]); + } } } - - for (int i = 0; i < sortedAssemblies.Length; i++) + // Finally, load all assemblies into memory + foreach (var assembly in sortedAssemblies) { - string filename = Path.GetFileName(assemblyFilenames[sortedAssemblies[i]]); + string filename = Path.GetFileName(assemblyFilenames[assembly]); - if (DumpingEnabled) - { - using (MemoryStream mem = new MemoryStream()) - { - string dirPath = Path.Combine(Preloader.PluginPath, "DumpedAssemblies"); + if (DumpingEnabled && patchedAssemblies.Contains(filename)) + { + using (MemoryStream mem = new MemoryStream()) + { + string dirPath = Path.Combine(Preloader.PluginPath, "DumpedAssemblies"); - if (!Directory.Exists(dirPath)) - Directory.CreateDirectory(dirPath); + if (!Directory.Exists(dirPath)) + Directory.CreateDirectory(dirPath); - sortedAssemblies[i].Write(mem); - File.WriteAllBytes(Path.Combine(dirPath, filename), mem.ToArray()); - } - } + assembly.Write(mem); + File.WriteAllBytes(Path.Combine(dirPath, filename), mem.ToArray()); + } + } - Load(sortedAssemblies[i]); + Load(assembly); #if CECIL_10 - sortedAssemblies[i].Dispose(); + assembly.Dispose(); #endif - } + } //run all finalizers if (finalizers != null) From 573e6d6792ea64cae1be1878107232aa466b2be8 Mon Sep 17 00:00:00 2001 From: denikson Date: Mon, 18 Jun 2018 19:12:33 +0300 Subject: [PATCH 3/3] Prefer using logMessageReceived to RegisterLogCallback --- BepInEx/Logging/UnityLogWriter.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/BepInEx/Logging/UnityLogWriter.cs b/BepInEx/Logging/UnityLogWriter.cs index f1a04c1..b67e38d 100644 --- a/BepInEx/Logging/UnityLogWriter.cs +++ b/BepInEx/Logging/UnityLogWriter.cs @@ -49,15 +49,15 @@ namespace BepInEx.Logging { Type application = typeof(Application); - MethodInfo registerLogCallback = application.GetMethod("RegisterLogCallback", BindingFlags.Public | BindingFlags.Static); - if (registerLogCallback != null) + EventInfo logEvent = application.GetEvent("logMessageReceived", BindingFlags.Public | BindingFlags.Static); + if (logEvent != null) { - registerLogCallback.Invoke(null, new object[] {new Application.LogCallback(OnUnityLogMessageReceived)}); + logEvent.AddEventHandler(null, new Application.LogCallback(OnUnityLogMessageReceived)); } else { - EventInfo logEvent = application.GetEvent("logMessageReceived", BindingFlags.Public | BindingFlags.Static); - logEvent?.AddEventHandler(null, new Application.LogCallback(OnUnityLogMessageReceived)); + MethodInfo registerLogCallback = application.GetMethod("RegisterLogCallback", BindingFlags.Public | BindingFlags.Static); + registerLogCallback.Invoke(null, new object[] { new Application.LogCallback(OnUnityLogMessageReceived) }); } }