From ee44f575350cf137420a2f9a0ec9e2c778528436 Mon Sep 17 00:00:00 2001 From: Kaede Date: Fri, 10 Nov 2023 01:04:30 +0200 Subject: [PATCH] Add support for patch-specific logging that is not a Console.Writeline in the patch itself. --- Marsey/MarseyPatcher.cs | 2 ++ Marsey/PatchAssemblyManager.cs | 36 ++++++++++++++++++++++++++++------ Marsey/Utility.cs | 28 ++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/Marsey/MarseyPatcher.cs b/Marsey/MarseyPatcher.cs index c7f69a2..5d5a961 100644 --- a/Marsey/MarseyPatcher.cs +++ b/Marsey/MarseyPatcher.cs @@ -30,6 +30,8 @@ public static void Boot(Assembly? robClientAssembly) FileHandler.LoadAssemblies(new []{"Marsey", "Enabled"}); + PatchAssemblyManager.InitLogger(); + GameAssemblyManager.PatchProc(); } } diff --git a/Marsey/PatchAssemblyManager.cs b/Marsey/PatchAssemblyManager.cs index 743674d..16534f7 100644 --- a/Marsey/PatchAssemblyManager.cs +++ b/Marsey/PatchAssemblyManager.cs @@ -20,14 +20,12 @@ public abstract class PatchAssemblyManager /// Initializes a given assembly, validates its structure, and adds it to the list of patch assemblies /// /// The assembly to initialize - /// Excepts if MarseyPatch is not present in the assembly - /// Excepts if "TargetAssembly" is present in the assembly MarseyPatch type" - /// Excepts if GetPatchAssemblyFields returns null + /// Excepts if MarseyPatch is not present in the assembly + /// Excepts if "TargetAssembly" is present in the assembly MarseyPatch type" + /// Excepts if GetPatchAssemblyFields returns null public static void InitAssembly(Assembly assembly) { - Type marseyPatchType = assembly.GetType("MarseyPatch") ?? throw new PatchAssemblyException("Loaded assembly does not have MarseyPatch type."); - - if (marseyPatchType.GetField("TargetAssembly") != null) throw new PatchAssemblyException($"{assembly.FullName} cannot be loaded because it uses an outdated patch!"); + Type marseyPatchType = assembly.GetType("MarseyPatch") ?? throw new PatchAssemblyException("Loaded assembly does not have MarseyPatch type. Most likely because MarseyPatch is under a namespace, or you provided a non-patch dll."); List targets = GetPatchAssemblyFields(marseyPatchType) ?? throw new PatchAssemblyException($"Couldn't get assembly fields on {assembly.FullName}."); @@ -51,6 +49,32 @@ public static void InitAssembly(Assembly assembly) } + /// + /// Initializes logger class in patches that have it. + /// Executed only by the loader. + /// MarseyLogger example can be found in the Rethemer MarseyPatch example. + /// + public static void InitLogger() + { + foreach (MarseyPatch patch in _patchAssemblies) + { + Assembly assembly = patch.Asm; + + // Check for a logger class + Type? marseyLoggerType = assembly.GetType("MarseyLogger"); + + if (marseyLoggerType != null) + { + //Utility.Log(Utility.LogType.DEBG, $"{assembly.GetName().Name} has a MarseyLogger class"); + Utility.SetupLogger(assembly); + } + else + { + Utility.Log(Utility.LogType.DEBG, $"{assembly.GetName().Name} has no MarseyLogger class"); + } + } + } + /// /// Obtains fields for each of the game's assemblies. /// Returns null if any of the fields is null. diff --git a/Marsey/Utility.cs b/Marsey/Utility.cs index ba11c31..3bca045 100644 --- a/Marsey/Utility.cs +++ b/Marsey/Utility.cs @@ -1,4 +1,5 @@ using System; +using System.Reflection; namespace Marsey; @@ -11,8 +12,35 @@ public enum LogType FATL, DEBG } + + // Loader logs public static void Log(LogType logType, string message) { Console.WriteLine($"[MARSEY] [{logType.ToString()}] {message}"); } + + // Patch logs + public static void Log(AssemblyName asm, string message) + { + Console.WriteLine($"[{asm.Name}] {message}"); + } + + /// + /// Sets patch delegate to Utility::Log(AssemblyName, string) + /// Executed only by the Loader. + /// + /// + /// Assembly from MarseyPatch + public static void SetupLogger(Assembly patch) + { + Type marseyLoggerType = patch.GetType("MarseyLogger")!; + + Type logDelegateType = marseyLoggerType.GetNestedType("Forward", BindingFlags.Public)!; + + MethodInfo logMethod = typeof(Utility).GetMethod("Log", new []{typeof(AssemblyName), typeof(string)})!; + + Delegate logDelegate = Delegate.CreateDelegate(logDelegateType, null, logMethod); + + marseyLoggerType.GetField("logDelegate", BindingFlags.Public | BindingFlags.Static).SetValue(null, logDelegate); + } }