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;
|
||||
}
|
||||
|
||||
/// <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)]
|
||||
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, 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());
|
||||
|
||||
// Update version info from runtime in case it wasn't set yet
|
||||
var prevVersion = UnityInfo.Version;
|
||||
UnityInfo.SetRuntimeUnityVersion(UnityVersion);
|
||||
if (UnityInfo.Version != prevVersion)
|
||||
Logger.Log(LogLevel.Info, $"UnityPlayer version: {UnityInfo.Version}");
|
||||
// Update version info from runtime in case it wasn't set yet.
|
||||
// May be unavailable on aggressively stripped builds; it is informational only.
|
||||
var runtimeUnityVersion = TryGetUnityVersion();
|
||||
if (runtimeUnityVersion != null)
|
||||
{
|
||||
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");
|
||||
|
||||
|
||||
Reference in new issue
Block a user