UnityChainloader.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. using BepInEx.Configuration;
  2. using BepInEx.Logging;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Reflection;
  6. using System.Runtime.CompilerServices;
  7. using System.Text;
  8. using BepInEx.Bootstrap;
  9. using BepInEx.Preloader.Core.Logging;
  10. using BepInEx.Unity.Logging;
  11. using MonoMod.Utils;
  12. using UnityEngine;
  13. using Logger = BepInEx.Logging.Logger;
  14. namespace BepInEx.Unity.Bootstrap
  15. {
  16. /// <summary>
  17. /// The manager and loader for all plugins, and the entry point for BepInEx plugin system.
  18. /// </summary>
  19. public class UnityChainloader : BaseChainloader<BaseUnityPlugin>
  20. {
  21. /// <summary>
  22. /// The GameObject that all plugins are attached to as components.
  23. /// </summary>
  24. public static GameObject ManagerObject { get; private set; }
  25. private static void StaticStart(string gameExePath = null)
  26. {
  27. var instance = new UnityChainloader();
  28. instance.Initialize(gameExePath);
  29. instance.Execute();
  30. }
  31. private string _consoleTitle;
  32. protected override string ConsoleTitle => _consoleTitle;
  33. // In some rare cases calling Application.unityVersion seems to cause MissingMethodException
  34. // if a preloader patch applies Harmony patch to Chainloader.Initialize.
  35. // The issue could be related to BepInEx being compiled against Unity 5.6 version of UnityEngine.dll,
  36. // but the issue is apparently present with both official Harmony and HarmonyX
  37. // We specifically prevent inlining to prevent early resolving
  38. // TODO: Figure out better version obtaining mechanism (e.g. from globalmanagers)
  39. private static string UnityVersion
  40. {
  41. [MethodImpl(MethodImplOptions.NoInlining)]
  42. get => Application.unityVersion;
  43. }
  44. public override void Initialize(string gameExePath = null)
  45. {
  46. UnityTomlTypeConverters.AddUnityEngineConverters();
  47. ThreadingHelper.Initialize();
  48. ManagerObject = new GameObject("BepInEx_Manager");
  49. UnityEngine.Object.DontDestroyOnLoad(ManagerObject);
  50. var productNameProp = typeof(Application).GetProperty("productName", BindingFlags.Public | BindingFlags.Static);
  51. _consoleTitle = $"{CurrentAssemblyName} {CurrentAssemblyVersion} - {productNameProp?.GetValue(null, null) ?? Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().ProcessName)}";
  52. base.Initialize(gameExePath);
  53. }
  54. protected override void InitializeLoggers()
  55. {
  56. base.InitializeLoggers();
  57. Logger.Listeners.Add(new UnityLogListener());
  58. if (!PlatformHelper.Is(Platform.Windows))
  59. {
  60. Logger.LogInfo($"Detected Unity version: v{UnityVersion}");
  61. }
  62. if (!ConfigDiskWriteUnityLog.Value)
  63. {
  64. DiskLogListener.BlacklistedSources.Add("Unity Log");
  65. }
  66. ChainloaderLogHelper.RewritePreloaderLogs();
  67. if (ConfigUnityLogging.Value)
  68. Logger.Sources.Add(new UnityLogSource());
  69. }
  70. public override BaseUnityPlugin LoadPlugin(PluginInfo pluginInfo, Assembly pluginAssembly)
  71. {
  72. return (BaseUnityPlugin)ManagerObject.AddComponent(pluginAssembly.GetType(pluginInfo.TypeName));
  73. }
  74. private static readonly ConfigEntry<bool> ConfigUnityLogging = ConfigFile.CoreConfig.Bind(
  75. "Logging", "UnityLogListening",
  76. true,
  77. "Enables showing unity log messages in the BepInEx logging system.");
  78. private static readonly ConfigEntry<bool> ConfigDiskWriteUnityLog = ConfigFile.CoreConfig.Bind(
  79. "Logging.Disk", "WriteUnityLog",
  80. false,
  81. "Include unity log messages in log file output.");
  82. }
  83. }