mirror of
https://github.com/BepInEx/BepInEx.git
synced 2026-10-19 15:51:45 +00:00
Survive stripped UnityEngine.Application members during chainloader init (#1391)
Two related failures on aggressively stripped Unity Mono builds: 1. InitializeLoggers reads Application.unityVersion, which the managed code stripper can remove. The version is only used for an informational log line, but a MissingMethodException there aborts the rest of chainloader initialisation. Read it defensively instead. 2. UnityChainloader.Initialize caught every exception, logged it as Fatal, and returned normally. StaticStart then called Execute() on a chainloader that was never initialised, so BepInEx logged "Chainloader startup complete" while every plugin silently never ran. Rethrow so a failed init cannot be mistaken for a successful one. Verified on Beacon Pines (Unity 2021.3.45f1, Mono, x64), which strips both Application.unityVersion and the log-callback members. Co-authored-by: ManlyMarco <39247311+ManlyMarco@users.noreply.github.com>
This commit is contained in:
1 parent
6d82b2e5fc
commit
7cb1246fcc
1 file changed
+36
-5
@@ -60,6 +60,26 @@ public class UnityChainloader : BaseChainloader<BaseUnityPlugin>
|
|||||||
get => Application.unityVersion;
|
get => Application.unityVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the runtime Unity version, returning null if it is unavailable.
|
||||||
|
/// Unity's managed code stripper can remove Application.unityVersion entirely, in which case
|
||||||
|
/// touching it throws MissingMethodException. The version is only used for an informational
|
||||||
|
/// log line, so it must not be able to abort chainloader initialisation.
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
private static string TryGetUnityVersion()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return UnityVersion;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Log(LogLevel.Debug, $"Could not read the runtime Unity version: {e.Message}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Obsolete("This method is public due to a limitation with Unity 4.x. DO NOT CALL", true)]
|
[Obsolete("This method is public due to a limitation with Unity 4.x. DO NOT CALL", true)]
|
||||||
public static void StaticStart(string gameExePath = null)
|
public static void StaticStart(string gameExePath = null)
|
||||||
{
|
{
|
||||||
@@ -116,6 +136,12 @@ public class UnityChainloader : BaseChainloader<BaseUnityPlugin>
|
|||||||
{
|
{
|
||||||
Logger.Log(LogLevel.Fatal, $"Unable to complete chainloader init: {ex.Message}");
|
Logger.Log(LogLevel.Fatal, $"Unable to complete chainloader init: {ex.Message}");
|
||||||
Logger.Log(LogLevel.Fatal, ex.StackTrace);
|
Logger.Log(LogLevel.Fatal, ex.StackTrace);
|
||||||
|
|
||||||
|
// Rethrow so callers do not go on to Execute() a chainloader that was never
|
||||||
|
// initialised. Swallowing here produces a far worse failure mode than crashing:
|
||||||
|
// the loader carries on to log "Chainloader startup complete" while every plugin
|
||||||
|
// silently never runs, which is extremely hard to diagnose.
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,11 +151,16 @@ public class UnityChainloader : BaseChainloader<BaseUnityPlugin>
|
|||||||
|
|
||||||
Logger.Listeners.Add(new UnityLogListener());
|
Logger.Listeners.Add(new UnityLogListener());
|
||||||
|
|
||||||
// Update version info from runtime in case it wasn't set yet
|
// Update version info from runtime in case it wasn't set yet.
|
||||||
var prevVersion = UnityInfo.Version;
|
// May be unavailable on aggressively stripped builds; it is informational only.
|
||||||
UnityInfo.SetRuntimeUnityVersion(UnityVersion);
|
var runtimeUnityVersion = TryGetUnityVersion();
|
||||||
if (UnityInfo.Version != prevVersion)
|
if (runtimeUnityVersion != null)
|
||||||
Logger.Log(LogLevel.Info, $"UnityPlayer version: {UnityInfo.Version}");
|
{
|
||||||
|
var prevVersion = UnityInfo.Version;
|
||||||
|
UnityInfo.SetRuntimeUnityVersion(runtimeUnityVersion);
|
||||||
|
if (UnityInfo.Version != prevVersion)
|
||||||
|
Logger.Log(LogLevel.Info, $"UnityPlayer version: {UnityInfo.Version}");
|
||||||
|
}
|
||||||
|
|
||||||
if (!ConfigDiskWriteUnityLog.Value) DiskLogListener.BlacklistedSources.Add("Unity Log");
|
if (!ConfigDiskWriteUnityLog.Value) DiskLogListener.BlacklistedSources.Add("Unity Log");
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user