Browse Source

Fix stdout not being written to Unity log when console is enabled

ghorsington 4 years ago
parent
commit
a404365498

+ 0 - 1
BepInEx.Preloader/Preloader.cs

@@ -223,7 +223,6 @@ namespace BepInEx.Preloader
 			try
 			{
 				ConsoleManager.CreateConsole();
-				ConsoleManager.SetConsoleEncoding();
 			}
 			catch (Exception ex)
 			{

+ 11 - 0
BepInEx.Preloader/RuntimeFixes/ConsoleSetOutFix.cs

@@ -7,6 +7,15 @@ using HarmonyLib;
 
 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.
+	 */
 	internal static class ConsoleSetOutFix
 	{
 		private static AggregatedTextWriter aggregatedTextWriter;
@@ -22,6 +31,8 @@ namespace BepInEx.Preloader.RuntimeFixes
 		[HarmonyPrefix]
 		private static bool OnSetOut(TextWriter newOut)
 		{
+			if (newOut == TextWriter.Null)
+				return false;
 			aggregatedTextWriter.Add(newOut);
 			return false;
 		}

+ 0 - 7
BepInEx/Bootstrap/Chainloader.cs

@@ -74,13 +74,6 @@ namespace BepInEx.Bootstrap
 				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());
 

+ 7 - 22
BepInEx/Console/ConsoleManager.cs

@@ -63,8 +63,13 @@ namespace BepInEx
 				return;
 
 			DriverCheck();
-
-			Driver.CreateConsole();
+			
+			// Apparently some versions of Mono throw a "Encoding name 'xxx' not supported"
+			// if you use Encoding.GetEncoding
+			// That's why we use of codepages directly and handle then in console drivers separately
+			var codepage = ConfigConsoleShiftJis.Value ? SHIFT_JIS_CP: (uint)Encoding.UTF8.CodePage;
+			
+			Driver.CreateConsole(codepage);
 			SetConsoleStreams();
 		}
 
@@ -79,26 +84,6 @@ namespace BepInEx
 			SetConsoleStreams();
 		}
 
-		public static void SetConsoleEncoding()
-		{
-			// Apparently some versions of Mono throw a "Encoding name 'xxx' not supported"
-			// if you use Encoding.GetEncoding
-			// That's why we use of codepages directly and handle then in console drivers separately
-			var codepage = ConfigConsoleShiftJis.Value ? SHIFT_JIS_CP: (uint)Encoding.UTF8.CodePage;
-
-			SetConsoleEncoding(codepage);
-		}
-
-		public static void SetConsoleEncoding(uint codepage)
-		{
-			if (!ConsoleActive)
-				throw new InvalidOperationException("Console is not currently active");
-
-			DriverCheck();
-
-			Driver.SetConsoleEncoding(codepage);
-		}
-
 		public static void SetConsoleTitle(string title)
 		{
 			DriverCheck();

+ 4 - 5
BepInEx/Console/IConsoleDriver.cs

@@ -13,15 +13,14 @@ namespace BepInEx
 		bool ConsoleIsExternal { get; }
 
 		void Initialize(bool alreadyActive);
-
-		void CreateConsole();
+		
+		// Apparently Windows code-pages work in Mono.
+		// https://stackoverflow.com/a/33456543
+		void CreateConsole(uint codepage);
 		void DetachConsole();
 
 		void SetConsoleColor(ConsoleColor color);
 		
-		// Apparently Windows code-pages work in Mono.
-		// https://stackoverflow.com/a/33456543
-		void SetConsoleEncoding(uint codepage);
 		void SetConsoleTitle(string title);
 	}
 }

+ 1 - 6
BepInEx/Console/Unix/LinuxConsoleDriver.cs

@@ -58,7 +58,7 @@ namespace BepInEx.Unix
 			ConsoleOut = StandardOut;
 		}
 
-		public void CreateConsole()
+		public void CreateConsole(uint codepage)
 		{
 			Logger.LogWarning("An external console currently cannot be spawned on a Unix platform.");
 		}
@@ -84,11 +84,6 @@ namespace BepInEx.Unix
 			}
 		}
 
-		public void SetConsoleEncoding(uint codepage)
-		{
-			// We shouldn't be changing this on Unix
-		}
-
 		public void SetConsoleTitle(string title)
 		{
 			if (StdoutRedirected)

+ 7 - 10
BepInEx/Console/Windows/WindowsConsoleDriver.cs

@@ -21,12 +21,17 @@ namespace BepInEx
 			StandardOut = Console.Out;
 		}
 
-		public void CreateConsole()
+		public void CreateConsole(uint codepage)
 		{
 			// On some Unity mono builds the SafeFileHandle overload for FileStream is missing
 			// so we use the older but always included one instead
 #pragma warning disable 618
 			ConsoleWindow.Attach();
+
+			// Make sure of ConsoleEncoding helper class because on some Monos
+			// Encoding.GetEncoding throws NotImplementedException on most codepages
+			// NOTE: We don't set Console.OutputEncoding because it resets any existing Console.Out writers
+			ConsoleEncoding.ConsoleCodePage = codepage;
 			
 			// If stdout exists, write to it, otherwise make it the same as console out
 			// Not sure if this is needed? Does the original Console.Out still work?
@@ -38,7 +43,7 @@ namespace BepInEx
 			};
 
 			var consoleOutStream = new FileStream(ConsoleWindow.ConsoleOutHandle, FileAccess.Write);
-			// Can't use Console.OutputEncoding because it can be null on older Monos
+			// Can't use Console.OutputEncoding because it can be null (i.e. not preference by user)
 			ConsoleOut = new StreamWriter(consoleOutStream, ConsoleEncoding.OutputEncoding)
 			{
 				AutoFlush = true
@@ -63,14 +68,6 @@ namespace BepInEx
 			Kon.ForegroundColor = color;
 		}
 
-		public void SetConsoleEncoding(uint codepage)
-		{
-			// Make sure of ConsoleEncoding helper class because on some Monos
-			// Encoding.GetEncoding throws NotImplementedException on most codepages
-			ConsoleEncoding.ConsoleCodePage = codepage;
-			Console.OutputEncoding = ConsoleEncoding.GetEncoding(codepage);
-		}
-
 		public void SetConsoleTitle(string title)
 		{
 			ConsoleWindow.Title = title;