Browse Source

Simplify ConsoleSetOut fix; redirect console messages to logging system
Rebase of f2b7b99

Bepis 4 years ago
parent
commit
7f880390a0

+ 18 - 38
BepInEx.Preloader.Core/RuntimeFixes/ConsoleSetOutFix.cs

@@ -1,29 +1,20 @@
 using System;
-using System.Collections.Generic;
 using System.IO;
-using System.Linq;
 using System.Text;
+using BepInEx.Logging;
 using HarmonyLib;
 
-namespace BepInEx.Preloader.Core.RuntimeFixes
+namespace BepInEx.Preloader.RuntimeFixes
 {
-	/*
-	 * By default, setting Console.Out removes the previous listener
-	 * This can be a problem in Unity because it installs its own TextWriter while BepInEx needs to install it
-	 * one too for the console. This runtime fix collects all Console.Out setters and aggregates them into a single
-	 * text writer.
-	 *
-	 * This allows to both fix the old problem with log overwriting and problem with writing stdout when console is
-	 * enabled.
-	 */
-	public static class ConsoleSetOutFix
+	internal static class ConsoleSetOutFix
 	{
-		private static AggregatedTextWriter aggregatedTextWriter;
+		private static LoggedTextWriter loggedTextWriter;
+		internal static ManualLogSource ConsoleLogSource = Logger.CreateLogSource("Console");
 
 		public static void Apply()
 		{
-			aggregatedTextWriter = new AggregatedTextWriter(Console.Out);
-			Console.SetOut(aggregatedTextWriter);
+			loggedTextWriter = new LoggedTextWriter { Parent = Console.Out };
+			Console.SetOut(loggedTextWriter);
 			HarmonyLib.Harmony.CreateAndPatchAll(typeof(ConsoleSetOutFix));
 		}
 
@@ -31,40 +22,29 @@ namespace BepInEx.Preloader.Core.RuntimeFixes
 		[HarmonyPrefix]
 		private static bool OnSetOut(TextWriter newOut)
 		{
-			if (newOut == TextWriter.Null)
-				return false;
-
-			aggregatedTextWriter.Add(newOut);
+			loggedTextWriter.Parent = newOut;
 			return false;
 		}
 	}
 
-	internal class AggregatedTextWriter : TextWriter
+	internal class LoggedTextWriter : TextWriter
 	{
 		public override Encoding Encoding { get; } = Encoding.UTF8;
 
-		private List<TextWriter> writers = new List<TextWriter>();
+		public TextWriter Parent { get; set; }
+
+		public override void Flush() => Parent.Flush();
 
-		public AggregatedTextWriter(params TextWriter[] initialWriters)
+		public override void Write(string value)
 		{
-			writers.AddRange(initialWriters.Where(w => w != null));
+			ConsoleSetOutFix.ConsoleLogSource.LogInfo(value);
+			Parent.Write(value);
 		}
 
-		public void Add(TextWriter tw)
+		public override void WriteLine(string value)
 		{
-			if (writers.Any(t => t == tw))
-				return;
-			writers.Add(tw);
+			ConsoleSetOutFix.ConsoleLogSource.LogInfo(value);
+			Parent.WriteLine(value);
 		}
-
-		public override void Flush() => writers.ForEach(w => w.Flush());
-
-		public override void Write(object value) => writers.ForEach(w => w.Write(value));
-		public override void Write(string value) => writers.ForEach(w => w.Write(value));
-		public override void Write(char value) => writers.ForEach(w => w.Write(value));
-
-		public override void WriteLine(object value) => writers.ForEach(w => w.WriteLine(value));
-		public override void WriteLine(string value) => writers.ForEach(w => w.WriteLine(value));
-		public override void WriteLine(char value) => writers.ForEach(w => w.WriteLine(value));
 	}
 }

+ 1 - 11
BepInEx.Unity/Bootstrap/UnityChainloader.cs

@@ -52,9 +52,7 @@ namespace BepInEx.Unity.Bootstrap
 		{
 			base.InitializeLoggers();
 
-			// Write to Unity logs directly only if console is not present (or user explicitly wants to)
-			if (ConfigWriteToUnityLog.Value || !ConsoleManager.ConsoleActive)
-				Logger.Listeners.Add(new UnityLogListener());
+			Logger.Listeners.Add(new UnityLogListener());
 
 			if (Utility.CurrentPlatform != Platform.Windows)
 			{
@@ -85,14 +83,6 @@ namespace BepInEx.Unity.Bootstrap
 			true,
 			"Enables showing unity log messages in the BepInEx logging system.");
 
-		private static readonly ConfigEntry<bool> ConfigWriteToUnityLog = ConfigFile.CoreConfig.Bind(
-			"Logging", "WriteToUnityLog",
-			false,
-			new StringBuilder()
-				.AppendLine("Enables writing log messages to Unity's log system")
-				.AppendLine("NOTE: By default, Unity already writes BepInEx console output to Unity logs")
-				.Append("Use this setting only if no BepInEx log messages are present in Unity's output_log").ToString());
-
 		private static readonly ConfigEntry<bool> ConfigDiskWriteUnityLog = ConfigFile.CoreConfig.Bind(
 			"Logging.Disk", "WriteUnityLog",
 			false,

+ 11 - 1
BepInEx.Unity/Logging/UnityLogListener.cs

@@ -2,6 +2,8 @@
 using System;
 using System.Reflection;
 using System.Runtime.CompilerServices;
+using System.Text;
+using BepInEx.Configuration;
 
 namespace BepInEx.Unity.Logging
 {
@@ -38,10 +40,18 @@ namespace BepInEx.Unity.Logging
 			if (eventArgs.Source is UnityLogSource)
 				return;
 
-			WriteStringToUnityLog?.Invoke(eventArgs.ToStringLine());
+			// Special case: don't write console twice since Unity can already do that
+			if (LogConsoleToUnity.Value || eventArgs.Source.SourceName != "Console")
+				WriteStringToUnityLog?.Invoke(eventArgs.ToStringLine());
 		}
 
 		public void Dispose() { }
+
+		private ConfigEntry<bool> LogConsoleToUnity = ConfigFile.CoreConfig.Bind("Logging",
+			"LogConsoleToUnityLog", false,
+			new StringBuilder()
+				.AppendLine("If enabled, writes Standard Output messages to Unity log")
+				.AppendLine("NOTE: By default, Unity does so automatically. Only use this option if no console messages are visible in Unity log").ToString());
 	}
 }