From 5c18fafea1b41aed5a66d2302cfc9ccecc364f2e Mon Sep 17 00:00:00 2001 From: Drew Mochak Date: Tue, 1 Sep 2026 00:55:49 -0400 Subject: [PATCH] v5: Don't kill the chainloader when Unity log callbacks are stripped (#1392) UnityLogSource's static constructor falls back to Application.RegisterLogCallback when Application.logMessageReceived is absent. Unity's managed code stripper can remove both, in which case GetMethod returns null and the unguarded Invoke throws a NullReferenceException out of the static constructor. That exception propagates through Chainloader.Initialize, so the chainloader never starts and no plugins load. The failure is close to undiagnosable: LogOutput.log ends at "Preloader finished" with no error, and the exception only appears on stdout. Unity log forwarding is optional, so warn and continue instead. Backport of the same fix proposed for master in #1389. --- BepInEx/Logging/UnityLogSource.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/BepInEx/Logging/UnityLogSource.cs b/BepInEx/Logging/UnityLogSource.cs index 937722c..fa8dc34 100644 --- a/BepInEx/Logging/UnityLogSource.cs +++ b/BepInEx/Logging/UnityLogSource.cs @@ -59,6 +59,20 @@ namespace BepInEx.Logging else { MethodInfo registerLogCallback = typeof(Application).GetMethod("RegisterLogCallback", BindingFlags.Public | BindingFlags.Static); + + // Unity's managed code stripper can remove both Application.logMessageReceived and the + // legacy Application.RegisterLogCallback. Invoking a null MethodInfo here throws out of + // this static constructor, which propagates through Chainloader.Initialize and silently + // prevents the chainloader (and therefore every plugin) from starting. Unity log + // forwarding is optional, so degrade instead of taking the whole loader down. + if (registerLogCallback == null) + { + Logger.LogWarning("Unity log forwarding is unavailable: neither Application.logMessageReceived " + + "nor Application.RegisterLogCallback exist in this build (they were most likely " + + "stripped). Unity log messages will not appear in the BepInEx log."); + return; + } + registerLogCallback.Invoke(null, new object[] { callback }); //UnsubscribeAction = () => registerLogCallback.Invoke(null, new object[] { null }); }