Fixed an issue with plthook application being used earlier than logging initialization resulting in lost error logs

This commit is contained in:
Herp Derpinstine
2026-09-30 17:50:01 -05:00
parent b983882e46
commit c9b24bd46e
5 changed files with 74 additions and 41 deletions
+15 -12
View File
@@ -51,19 +51,7 @@ internal static class ConsoleHandler
if (!string.IsNullOrEmpty(title))
Console.Title = title;
#if LINUX
PltHook.InstallHooks(
[
("fclose", Marshal.GetFunctionPointerForDelegate(HookFCloseDelegate))
]);
#endif
#if WINDOWS
PltHook.InstallHooks(
[
("CloseHandle", Marshal.GetFunctionPointerForDelegate(HookCloseHandleDelegate)),
]);
Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true });
Console.SetError(new StreamWriter(Console.OpenStandardError()) { AutoFlush = true });
Console.SetIn(new StreamReader(Console.OpenStandardInput()));
@@ -77,6 +65,21 @@ internal static class ConsoleHandler
IsOpen = true;
}
public static void InstallHooks()
{
#if LINUX
PltHook.InstallHooks(
[
("fclose", Marshal.GetFunctionPointerForDelegate(HookFCloseDelegate))
]);
#elif WINDOWS
PltHook.InstallHooks(
[
("CloseHandle", Marshal.GetFunctionPointerForDelegate(HookCloseHandleDelegate)),
]);
#endif
}
public static void NullHandles()
{
#if WINDOWS
+3 -1
View File
@@ -105,6 +105,8 @@ internal static class MelonLogger
{
Core.Logger.Error("Failed to create any log files. Logging to console only");
}
ConsoleHandler.InstallHooks();
if (LoaderConfig.Current.Loader.CapturePlayerLogs)
{
@@ -131,7 +133,7 @@ internal static class MelonLogger
file.WriteLine(log);
}
}
public static void Log(ColorARGB msgColor, ReadOnlySpan<char> msg, ReadOnlySpan<char> strippedMessage)
{
var time = DateTime.Now.ToString(timeFormat);
@@ -159,7 +159,7 @@ internal static class DotnetHandler
catch (Exception ex)
{
if (LoaderConfig.Current.Loader.DebugMode)
MelonLogger.LogError(ex.ToString());
Core.Logger.Error(ex.ToString());
return false;
}
@@ -174,7 +174,7 @@ internal static class DotnetHandler
catch (Exception ex)
{
if (LoaderConfig.Current.Loader.DebugMode)
MelonLogger.LogError(ex.ToString());
Core.Logger.Error(ex.ToString());
return false;
}
@@ -199,7 +199,7 @@ internal static class DotnetHandler
catch (Exception ex)
{
if (LoaderConfig.Current.Loader.DebugMode)
MelonLogger.LogError(ex.ToString());
Core.Logger.Error(ex.ToString());
}
// Restore Original Root and Path
@@ -211,7 +211,7 @@ internal static class DotnetHandler
catch (Exception ex)
{
if (LoaderConfig.Current.Loader.DebugMode)
MelonLogger.LogError(ex.ToString());
Core.Logger.Error(ex.ToString());
}
return false;
+48 -24
View File
@@ -1,7 +1,6 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using MelonLoader.Bootstrap.Logging;
namespace MelonLoader.Bootstrap;
@@ -36,19 +35,21 @@ internal static partial class PltHook
private static partial nint PlthookError();
private static bool WasError;
private static string? PlayerFileName;
private static string? PlayerFilePath;
private static nint PlayerModuleHandle;
private const string UnityPlayerLibName = "UnityPlayer";
internal static void InstallHooks(List<(string functionName, nint hookFunctionPtr)> hooks)
{
if (!EnsureUnityPlayerLibrary())
if (!FindUnityPlayerLibrary()
|| !LoadUnityPlayerLibrary())
return;
nint pltHook = IntPtr.Zero;
if (PlthookOpen(ref pltHook, PlayerFileName) != 0)
if (PlthookOpenByHandle(ref pltHook, PlayerModuleHandle) != 0)
{
MelonLogger.LogError($"plthook_open error: {Marshal.PtrToStringAuto(PlthookError())}");
PlayerFileName = null;
Core.Logger.Error($"plthook_open error: {Marshal.PtrToStringAuto(PlthookError())}");
PlayerFilePath = null;
WasError = true;
return;
}
@@ -68,21 +69,45 @@ internal static partial class PltHook
PlthookClose(pltHook);
}
private static bool EnsureUnityPlayerLibrary()
private static bool LoadUnityPlayerLibrary()
{
if (WasError)
return false;
if (PlayerModuleHandle != IntPtr.Zero)
return true;
MelonDebug.Log($"Attempting to use UnityPlayer: '{PlayerFilePath}'");
#if WINDOWS
PlayerModuleHandle = WindowsNative.LoadLibrary(PlayerFilePath!);
#else
PlayerModuleHandle = LibcNative.Dlopen(PlayerFilePath!, LibcNative.RtldLazy | LibcNative.RtldNoLoad);
#endif
if (PlayerModuleHandle == IntPtr.Zero)
{
Core.Logger.Error($"Failed to load {PlayerFilePath}, cannot apply plt hooks");
PlayerModuleHandle = IntPtr.Zero;
PlayerFilePath = null;
WasError = true;
return false;
}
Core.Logger.Msg($"Using UnityPlayer: '{PlayerFilePath}'");
return true;
}
private static bool FindUnityPlayerLibrary()
{
if (WasError)
return false;
if (!string.IsNullOrEmpty(PlayerFileName))
if (!string.IsNullOrEmpty(PlayerFilePath))
return true;
PlayerFileName = Process.GetCurrentProcess().Modules.OfType<ProcessModule>()
PlayerFilePath = Process.GetCurrentProcess().Modules.OfType<ProcessModule>()
.FirstOrDefault(x => x.FileName.Contains(UnityPlayerLibName))?.FileName;
if (!string.IsNullOrEmpty(PlayerFileName))
{
MelonDebug.Log($"Attempting to use UnityPlayer: '{PlayerFileName}'");
if (!string.IsNullOrEmpty(PlayerFilePath))
return true;
}
string processModulePath = Process.GetCurrentProcess().MainModule!.FileName;
string parentPlayerPath = Path.GetDirectoryName(processModulePath)!;
@@ -90,37 +115,36 @@ internal static partial class PltHook
#if OSX
string libName = $"{UnityPlayerLibName}.dylib";
parentPlayerPath = Path.Combine(Path.GetDirectoryName(parentPlayerPath)!, "Frameworks");
PlayerFileName = Path.Combine(parentPlayerPath, libName);
PlayerFilePath = Path.Combine(parentPlayerPath, libName);
#elif LINUX
string libName = $"{UnityPlayerLibName}.so";
PlayerFileName = Path.Combine(parentPlayerPath, libName);
PlayerFilePath = Path.Combine(parentPlayerPath, libName);
#elif WINDOWS
string libName = $"{UnityPlayerLibName}.dll";
PlayerFileName = Path.Combine(parentPlayerPath, libName);
PlayerFilePath = Path.Combine(parentPlayerPath, libName);
#endif
#if !WINDOWS
if (!File.Exists(PlayerFileName))
if (!File.Exists(PlayerFilePath))
{
libName = $"lib{UnityPlayerLibName}.so";
PlayerFileName = Path.Combine(parentPlayerPath, libName);
PlayerFilePath = Path.Combine(parentPlayerPath, libName);
}
if (!File.Exists(PlayerFileName))
if (!File.Exists(PlayerFilePath))
{
libName = $"Lib{UnityPlayerLibName}.so";
PlayerFileName = Path.Combine(parentPlayerPath, libName);
PlayerFilePath = Path.Combine(parentPlayerPath, libName);
}
#endif
if (!File.Exists(PlayerFileName))
if (!File.Exists(PlayerFilePath))
{
MelonLogger.LogError($"Unable to find {UnityPlayerLibName} library to apply plthook");
PlayerFileName = null;
Core.Logger.Error($"Unable to find {UnityPlayerLibName} library to apply plthook");
PlayerFilePath = null;
WasError = true;
return false;
}
MelonDebug.Log($"Attempting to use UnityPlayer: '{PlayerFileName}'");
return true;
}
}
+4
View File
@@ -13,6 +13,10 @@ internal static partial class WindowsNative
[LibraryImport("kernel32.dll", EntryPoint = "GetProcAddress", StringMarshalling = StringMarshalling.Utf8)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]
internal static partial nint GetProcAddress(nint hModule, string lpProcName);
[LibraryImport("kernel32.dll", EntryPoint = "LoadLibraryA", StringMarshalling = StringMarshalling.Utf8)]
[UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]
internal static partial nint LoadLibrary(string lpLibFileName);
[LibraryImport("kernel32.dll")]
[UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]