Browse Source

Fix faulty Mono implementation of trace events

Bepis 6 years ago
parent
commit
4e7b9c42b9
3 changed files with 84 additions and 7 deletions
  1. 1 1
      BepInEx.Common/Utility.cs
  2. 4 5
      BepInEx/Bootstrap/Preloader.cs
  3. 79 1
      BepInEx/Logger/LoggerTraceListener.cs

+ 1 - 1
BepInEx.Common/Utility.cs

@@ -13,7 +13,7 @@ namespace BepInEx.Common
     public static class Utility
     {
         /// <summary>
-        /// The directory that the Koikatsu .exe is being run from.
+        /// The directory that the game .exe is being run from.
         /// </summary>
         public static string ExecutingDirectory => Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
 

+ 4 - 5
BepInEx/Bootstrap/Preloader.cs

@@ -57,6 +57,10 @@ namespace BepInEx.Bootstrap
         {
             try
             {
+                AppDomain.CurrentDomain.AssemblyResolve += LocalResolve;
+                ExecutablePath = args[0];
+
+
                 PreloaderLog = new PreloaderLogWriter();
                 PreloaderLog.Enabled = true;
 
@@ -64,11 +68,6 @@ namespace BepInEx.Bootstrap
                 PreloaderLog.Log(LogLevel.Message, "Preloader started");
 
 
-                ExecutablePath = args[0];
-
-                AppDomain.CurrentDomain.AssemblyResolve += LocalResolve;
-
-
 
                 AddPatcher("UnityEngine.dll", PatchEntrypoint);
 

+ 79 - 1
BepInEx/Logger/LoggerTraceListener.cs

@@ -1,4 +1,8 @@
-using System.Diagnostics;
+using System;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using Harmony;
 
 namespace BepInEx.Logger
 {
@@ -6,6 +10,15 @@ namespace BepInEx.Logger
     {
         public BaseLogger Logger;
 
+        static LoggerTraceListener()
+        {
+            try
+            {
+                TraceFixer.ApplyFix();
+            }
+            catch { } //ignore everything, if it's thrown an exception, we're using an assembly that has already fixed this
+        }
+
         public LoggerTraceListener(BaseLogger logger)
         {
             Logger = logger;
@@ -50,5 +63,70 @@ namespace BepInEx.Logger
 
             Logger.Log(level, $"{source} : {message}");
         }
+
+        private static class TraceFixer
+        {
+            private static Type TraceImplType;
+            
+            private static object ListenersSyncRoot;
+            private static TraceListenerCollection Listeners;
+            private static PropertyInfo prop_AutoFlush;
+
+            private static bool AutoFlush => (bool)prop_AutoFlush.GetValue(null, null);
+
+
+            public static void ApplyFix()
+            {
+                TraceImplType = AppDomain.CurrentDomain.GetAssemblies()
+                    .First(x => x.GetName().Name == "System")
+                    .GetTypes()
+                    .First(x => x.Name == "TraceImpl");
+
+                
+                ListenersSyncRoot = AccessTools.Property(TraceImplType, "ListenersSyncRoot").GetValue(null, null);
+                
+                Listeners = (TraceListenerCollection)AccessTools.Property(TraceImplType, "Listeners").GetValue(null, null);
+                
+                prop_AutoFlush = AccessTools.Property(TraceImplType, "AutoFlush");
+
+
+
+                HarmonyInstance instance = HarmonyInstance.Create("com.bepis.bepinex.tracefix");
+
+                instance.Patch(
+                    typeof(Trace).GetMethod("DoTrace", BindingFlags.Static | BindingFlags.NonPublic),
+                    new HarmonyMethod(typeof(TraceFixer).GetMethod("DoTraceReplacement", BindingFlags.Static | BindingFlags.Public)),
+                    null);
+            }
+
+
+            public static bool DoTraceReplacement(string kind, Assembly report, string message)
+            {
+                string arg = string.Empty;
+                try
+                {
+                    arg = report.GetName().Name;
+                }
+                catch (MethodAccessException) { }
+
+                TraceEventType type = (TraceEventType)Enum.Parse(typeof(TraceEventType), kind);
+
+                lock (ListenersSyncRoot)
+                {
+                    foreach (object obj in Listeners)
+                    {
+                        TraceListener traceListener = (TraceListener)obj;
+                        traceListener.TraceEvent(new TraceEventCache(), arg, type, 0, message);
+
+                        if (AutoFlush)
+                        {
+                            traceListener.Flush();
+                        }
+                    }
+                }
+
+                return false;
+            }
+        }
     }
 }