UnityLogWriter.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. using System;
  2. using System.Reflection;
  3. using System.Runtime.CompilerServices;
  4. using System.Runtime.InteropServices;
  5. using BepInEx.ConsoleUtil;
  6. using UnityEngine;
  7. namespace BepInEx.Logging
  8. {
  9. /// <summary>
  10. /// Logs entries using Unity specific outputs.
  11. /// </summary>
  12. public class UnityLogWriter : BaseLogger
  13. {
  14. private delegate void WriteStringToUnityLogDelegate(string s);
  15. private static readonly WriteStringToUnityLogDelegate WriteStringToUnityLog;
  16. [DllImport("mono.dll", EntryPoint = "mono_lookup_internal_call")]
  17. private static extern IntPtr MonoLookupInternalCall(IntPtr gconstpointer);
  18. static UnityLogWriter()
  19. {
  20. foreach (MethodInfo methodInfo in typeof(UnityEngine.UnityLogWriter).GetMethods(BindingFlags.Static | BindingFlags.Public))
  21. {
  22. if (MonoLookupInternalCall(methodInfo.MethodHandle.Value) == IntPtr.Zero)
  23. continue;
  24. WriteStringToUnityLog = (WriteStringToUnityLogDelegate) Delegate.CreateDelegate(typeof(WriteStringToUnityLogDelegate), methodInfo);
  25. break;
  26. }
  27. }
  28. /// <summary>
  29. /// Writes a string specifically to the game output log.
  30. /// </summary>
  31. /// <param name="value">The value to write.</param>
  32. public void WriteToLog(string value)
  33. {
  34. WriteStringToUnityLog?.Invoke(value);
  35. }
  36. protected void InternalWrite(string value)
  37. {
  38. Console.Write(value);
  39. WriteToLog(value);
  40. }
  41. /// <summary>
  42. /// Logs an entry to the Logger instance.
  43. /// </summary>
  44. /// <param name="level">The level of the entry.</param>
  45. /// <param name="entry">The textual value of the entry.</param>
  46. public override void Log(LogLevel level, object entry)
  47. {
  48. Kon.ForegroundColor = level.GetConsoleColor();
  49. base.Log(level, entry);
  50. Kon.ForegroundColor = ConsoleColor.Gray;
  51. // If the display level got ignored, still write it to the log
  52. if ((DisplayedLevels & level) == LogLevel.None)
  53. WriteToLog($"[{level.GetHighestLevel()}] {entry}\r\n");
  54. }
  55. public override void WriteLine(string value) => InternalWrite($"{value}\r\n");
  56. public override void Write(char value) => InternalWrite(value.ToString());
  57. public override void Write(string value) => InternalWrite(value);
  58. /// <summary>
  59. /// Start listening to Unity's log message events and sending the messages to BepInEx logger.
  60. /// </summary>
  61. public static void ListenUnityLogs()
  62. {
  63. Type application = typeof(Application);
  64. EventInfo logEvent = application.GetEvent("logMessageReceived", BindingFlags.Public | BindingFlags.Static);
  65. if (logEvent != null)
  66. {
  67. logEvent.AddEventHandler(null, new Application.LogCallback(OnUnityLogMessageReceived));
  68. }
  69. else
  70. {
  71. MethodInfo registerLogCallback = application.GetMethod("RegisterLogCallback", BindingFlags.Public | BindingFlags.Static);
  72. registerLogCallback.Invoke(null, new object[] { new Application.LogCallback(OnUnityLogMessageReceived) });
  73. }
  74. }
  75. private static void OnUnityLogMessageReceived(string message, string stackTrace, LogType type)
  76. {
  77. LogLevel logLevel = LogLevel.Message;
  78. switch (type)
  79. {
  80. case LogType.Error:
  81. case LogType.Assert:
  82. case LogType.Exception:
  83. logLevel = LogLevel.Error;
  84. break;
  85. case LogType.Warning:
  86. logLevel = LogLevel.Warning;
  87. break;
  88. case LogType.Log:
  89. default:
  90. logLevel = LogLevel.Info;
  91. break;
  92. }
  93. Logger.Log(logLevel, message);
  94. if (type == LogType.Exception)
  95. {
  96. Logger.Log(logLevel, $"Stack trace:\n{stackTrace}");
  97. }
  98. }
  99. }
  100. }
  101. namespace UnityEngine
  102. {
  103. internal sealed class UnityLogWriter
  104. {
  105. [MethodImpl(MethodImplOptions.InternalCall)]
  106. public static extern void WriteStringToUnityLogImpl(string s);
  107. [MethodImpl(MethodImplOptions.InternalCall)]
  108. public static extern void WriteStringToUnityLog(string s);
  109. }
  110. }