Ver código fonte

Merge pull request #30 from BepInEx/defect-logging

Add logging for Unity messages and fix assembly dumping
Geoffrey Horsington 6 anos atrás
pai
commit
a1d3cfdbbd

+ 25 - 24
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<string> sortedAssemblyFilenames = sortedAssemblies.Select(x => assemblyFilenames[x]).ToList();
+            Dictionary<string, AssemblyDefinition> sortedAssemblyFilenames = sortedAssemblies.ToDictionary(ass => assemblyFilenames[ass]);
+
+            HashSet<string> patchedAssemblies = new HashSet<string>();
 
             //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)

+ 3 - 0
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;
                 

+ 48 - 0
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);
+
+        /// <summary>
+        /// Start listening to Unity's log message events and sending the messages to BepInEx logger.
+        /// </summary>
+        public static void ListenUnityLogs()
+        {
+            Type application = typeof(Application);
+
+            EventInfo logEvent = application.GetEvent("logMessageReceived", BindingFlags.Public | BindingFlags.Static);
+            if (logEvent != null)
+            {
+                logEvent.AddEventHandler(null, new Application.LogCallback(OnUnityLogMessageReceived));
+            }
+            else
+            {
+                MethodInfo registerLogCallback = application.GetMethod("RegisterLogCallback", BindingFlags.Public | BindingFlags.Static);
+                registerLogCallback.Invoke(null, new object[] { 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}");
+            }
+        }
     }
 }