ConsoleSetOutFix.cs 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using HarmonyLib;
  7. namespace BepInEx.Preloader.Core.RuntimeFixes
  8. {
  9. /*
  10. * By default, setting Console.Out removes the previous listener
  11. * This can be a problem in Unity because it installs its own TextWriter while BepInEx needs to install it
  12. * one too for the console. This runtime fix collects all Console.Out setters and aggregates them into a single
  13. * text writer.
  14. *
  15. * This allows to both fix the old problem with log overwriting and problem with writing stdout when console is
  16. * enabled.
  17. */
  18. public static class ConsoleSetOutFix
  19. {
  20. private static AggregatedTextWriter aggregatedTextWriter;
  21. public static void Apply()
  22. {
  23. aggregatedTextWriter = new AggregatedTextWriter(Console.Out);
  24. Console.SetOut(aggregatedTextWriter);
  25. HarmonyLib.Harmony.CreateAndPatchAll(typeof(ConsoleSetOutFix));
  26. }
  27. [HarmonyPatch(typeof(Console), nameof(Console.SetOut))]
  28. [HarmonyPrefix]
  29. private static bool OnSetOut(TextWriter newOut)
  30. {
  31. if (newOut == TextWriter.Null)
  32. return false;
  33. aggregatedTextWriter.Add(newOut);
  34. return false;
  35. }
  36. }
  37. internal class AggregatedTextWriter : TextWriter
  38. {
  39. public override Encoding Encoding { get; } = Encoding.UTF8;
  40. private List<TextWriter> writers = new List<TextWriter>();
  41. public AggregatedTextWriter(params TextWriter[] initialWriters)
  42. {
  43. writers.AddRange(initialWriters.Where(w => w != null));
  44. }
  45. public void Add(TextWriter tw)
  46. {
  47. if (writers.Any(t => t == tw))
  48. return;
  49. writers.Add(tw);
  50. }
  51. public override void Flush() => writers.ForEach(w => w.Flush());
  52. public override void Write(object value) => writers.ForEach(w => w.Write(value));
  53. public override void Write(string value) => writers.ForEach(w => w.Write(value));
  54. public override void Write(char value) => writers.ForEach(w => w.Write(value));
  55. public override void WriteLine(object value) => writers.ForEach(w => w.WriteLine(value));
  56. public override void WriteLine(string value) => writers.ForEach(w => w.WriteLine(value));
  57. public override void WriteLine(char value) => writers.ForEach(w => w.WriteLine(value));
  58. }
  59. }