From c29a95c64d12a3f03b6ef58c26f77f624815330c Mon Sep 17 00:00:00 2001 From: slxdy Date: Sat, 8 Jun 2024 14:31:24 +0200 Subject: [PATCH] Added support for Mono --- TweaksLauncher.Game/Dobby.cs | 6 +- TweaksLauncher.Game/Logger.cs | 4 +- TweaksLauncher.Game/Mono.cs | 55 ++++++++++++ TweaksLauncher.Game/MonoHandler.cs | 84 ++++++++++++++++++ TweaksLauncher.Game/Program.cs | 6 +- TweaksLauncher.ModHandler/Dobby.cs | 5 +- TweaksLauncher.ModHandler/IMod.cs | 24 ++++- .../Il2Cpp/DobbyDetourProvider.cs | 9 +- TweaksLauncher.ModHandler/LoadedMod.cs | 31 ++++++- TweaksLauncher.ModHandler/ModHandler.cs | 87 +++++++++++++------ TweaksLauncher.ModHandler/ModInterface.cs | 12 ++- TweaksLauncher.ModHandler/NativeMethods.txt | 10 --- .../TweaksLauncher.ModHandler.csproj | 11 +-- TweaksLauncher.ModHandler/UnityEvents.cs | 4 +- .../UnitySingletonAttribute.cs | 4 +- TweaksLauncher.ModHandler/UnityTools.cs | 23 +++-- 16 files changed, 302 insertions(+), 73 deletions(-) create mode 100644 TweaksLauncher.Game/Mono.cs create mode 100644 TweaksLauncher.Game/MonoHandler.cs delete mode 100644 TweaksLauncher.ModHandler/NativeMethods.txt diff --git a/TweaksLauncher.Game/Dobby.cs b/TweaksLauncher.Game/Dobby.cs index b072375..9dead3b 100644 --- a/TweaksLauncher.Game/Dobby.cs +++ b/TweaksLauncher.Game/Dobby.cs @@ -8,13 +8,13 @@ namespace TweaksLauncher; public unsafe static partial class Dobby { [LibraryImport("dobby", EntryPoint = "DobbyPrepare")] - public static partial int Prepare(nint target, nint detour, nint* original); + private static partial int Prepare(nint target, nint detour, nint* original); [LibraryImport("dobby", EntryPoint = "DobbyCommit")] - public static partial int Commit(nint target); + private static partial int Commit(nint target); [LibraryImport("dobby", EntryPoint = "DobbyDestroy")] - public static partial int Destroy(nint target); + private static partial int Destroy(nint target); public static nint Prepare(nint target, nint detour) { diff --git a/TweaksLauncher.Game/Logger.cs b/TweaksLauncher.Game/Logger.cs index fc68571..caf0cf0 100644 --- a/TweaksLauncher.Game/Logger.cs +++ b/TweaksLauncher.Game/Logger.cs @@ -54,7 +54,7 @@ public static void Log(string? message, Color baseColor = default, string? modul if (message != string.Empty) { - if (baseColor == default) + if (baseColor.A == 0) baseColor = Color.LightCyan; message = message.Pastel(baseColor); @@ -63,7 +63,7 @@ public static void Log(string? message, Color baseColor = default, string? modul var consoleLog = $"[{time.Pastel(Color.DarkGray)}]"; if (moduleName != null) { - if (moduleColor == default) + if (moduleColor.A == 0) moduleColor = Color.Magenta; consoleLog += $"[{moduleName.Pastel(moduleColor)}]"; diff --git a/TweaksLauncher.Game/Mono.cs b/TweaksLauncher.Game/Mono.cs new file mode 100644 index 0000000..e43f96c --- /dev/null +++ b/TweaksLauncher.Game/Mono.cs @@ -0,0 +1,55 @@ +using System.Runtime.InteropServices; + +namespace TweaksLauncher; + +internal static unsafe class Mono +{ + public static void Init() + { + var lib = NativeLibrary.Load(Program.runtimePath); + + mono_domain_assembly_open = Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(lib, "mono_domain_assembly_open")); + mono_assembly_get_image = Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(lib, "mono_assembly_get_image")); + mono_class_from_name = Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(lib, "mono_class_from_name")); + mono_class_get_method_from_name = Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(lib, "mono_class_get_method_from_name")); + mono_runtime_invoke = Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(lib, "mono_runtime_invoke")); + mono_string_new = Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(lib, "mono_string_new")); + mono_add_internal_call = Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(lib, "mono_add_internal_call")); + mono_string_to_utf16 = Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(lib, "mono_string_to_utf16")); + } + +#pragma warning disable IDE1006 // Naming Styles + internal static mono_domain_assembly_open_sig mono_domain_assembly_open { get; private set; } = null!; + internal static mono_assembly_get_image_sig mono_assembly_get_image { get; private set; } = null!; + internal static mono_class_from_name_sig mono_class_from_name { get; private set; } = null!; + internal static mono_class_get_method_from_name_sig mono_class_get_method_from_name { get; private set; } = null!; + internal static mono_runtime_invoke_sig mono_runtime_invoke { get; private set; } = null!; + internal static mono_string_new_sig mono_string_new { get; private set; } = null!; + internal static mono_add_internal_call_sig mono_add_internal_call { get; private set; } = null!; + internal static mono_string_to_utf16_sig mono_string_to_utf16 { get; private set; } = null!; +#pragma warning restore IDE1006 // Naming Styles + + [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)] + internal delegate nint mono_domain_assembly_open_sig(nint domain, string name); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate nint mono_assembly_get_image_sig(nint assembly); + + [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)] + internal delegate nint mono_class_from_name_sig(nint image, string nameSpace, string name); + + [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)] + internal delegate nint mono_class_get_method_from_name_sig(nint clas, string name, int argsCount); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + internal delegate nint mono_runtime_invoke_sig(nint method, nint obj, nint* args, nint* exception); + + [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)] + internal delegate nint mono_string_new_sig(nint domain, string value); + + [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)] + internal delegate nint mono_add_internal_call_sig(string methodName, nint func); + + [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)] + internal delegate string? mono_string_to_utf16_sig(nint monoString); +} diff --git a/TweaksLauncher.Game/MonoHandler.cs b/TweaksLauncher.Game/MonoHandler.cs new file mode 100644 index 0000000..669c476 --- /dev/null +++ b/TweaksLauncher.Game/MonoHandler.cs @@ -0,0 +1,84 @@ +using System.Diagnostics.CodeAnalysis; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace TweaksLauncher; + +internal static unsafe class MonoHandler +{ + [NotNull] private static Dobby.Patch? monoJitInit = null; + + private static LogImplSig? logImpl; + + internal static int Start() + { + monoJitInit = Dobby.CreatePatch(Program.runtimePath, "mono_jit_init_version", OnDomainInit); + + return GameManager.Start(); + } + + private static void LoadModHandler(nint domain) + { + var handlerPath = Path.Combine(Program.baseDir, "bin", "Mono", "TweaksLauncher.dll"); + if (!File.Exists(handlerPath)) + { + Logger.Log($"Could not find the mod handler. Please reinstall TweaksLauncher.", Color.Red); + return; + } + + Mono.Init(); + + var modHandlerAsm = Mono.mono_domain_assembly_open(domain, handlerPath); + if (modHandlerAsm == 0) + { + Logger.Log($"Failed to load Mod Handler into the Mono domain.", Color.Red); + return; + } + + var modHandlerImg = Mono.mono_assembly_get_image(modHandlerAsm); + var modHandlerClass = Mono.mono_class_from_name(modHandlerImg, "TweaksLauncher", "ModHandler"); + var startMethod = Mono.mono_class_get_method_from_name(modHandlerClass, "Start", 3); + + if (startMethod == 0) + { + Logger.Log($"Failed to get the Mod Handler's Start method'.", Color.Red); + return; + } + + logImpl = new LogImplSig(LogImpl); + var logImplPtr = Marshal.GetFunctionPointerForDelegate(logImpl); + Mono.mono_add_internal_call("TweaksLauncher.ModHandler::LogInternal", logImplPtr); + + var baseDir = Mono.mono_string_new(domain, Program.baseDir); + var gameName = Mono.mono_string_new(domain, Program.gameName); + var gameDir = Mono.mono_string_new(domain, Program.gamePath); + + var args = stackalloc nint[3]; + args[0] = baseDir; + args[1] = gameName; + args[2] = gameDir; + + Mono.mono_runtime_invoke(startMethod, 0, args, null); + } + + private static void LogImpl(nint monoMessage, int baseColor, nint monoModuleName, int moduleColor) + { + Logger.Log(monoMessage == 0 ? null : Mono.mono_string_to_utf16(monoMessage), Color.FromArgb(baseColor), monoModuleName == 0 ? null : Mono.mono_string_to_utf16(monoModuleName), Color.FromArgb(moduleColor)); + } + + private static nint OnDomainInit(nint domainName, nint a) + { + monoJitInit.Destroy(); + + Logger.Log("Creating Mono Domain"); + + var domain = monoJitInit.Original(domainName, a); + + LoadModHandler(domain); + + return domain; + } + + internal delegate nint MonoJitInitSig(nint domainName, nint a); + private delegate void LogImplSig(nint monoMessage, int baseColor, nint monoModuleName, int moduleColor); +} diff --git a/TweaksLauncher.Game/Program.cs b/TweaksLauncher.Game/Program.cs index 5750cd9..57f0187 100644 --- a/TweaksLauncher.Game/Program.cs +++ b/TweaksLauncher.Game/Program.cs @@ -5,7 +5,7 @@ namespace TweaksLauncher; internal static class Program { - internal static readonly string baseDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", ".."); + internal static readonly string baseDir = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", "..")); internal static string runtimePath = null!; internal static string gamePath = null!; @@ -117,6 +117,10 @@ private static int Main(string[] args) case RuntimeType.Il2Cpp: return Il2CppHandler.Start(); + case RuntimeType.Mono: + case RuntimeType.OldMono: + return MonoHandler.Start(); + default: Logger.Log($"Game runtime not supported.", Color.Red); return 8; diff --git a/TweaksLauncher.ModHandler/Dobby.cs b/TweaksLauncher.ModHandler/Dobby.cs index ef0e780..9ad4577 100644 --- a/TweaksLauncher.ModHandler/Dobby.cs +++ b/TweaksLauncher.ModHandler/Dobby.cs @@ -1,4 +1,6 @@ -using System.Runtime.InteropServices; +#if NETCOREAPP +using System; +using System.Runtime.InteropServices; namespace TweaksLauncher; @@ -95,3 +97,4 @@ public void Destroy() } } } +#endif \ No newline at end of file diff --git a/TweaksLauncher.ModHandler/IMod.cs b/TweaksLauncher.ModHandler/IMod.cs index 9bd30b8..9d71dea 100644 --- a/TweaksLauncher.ModHandler/IMod.cs +++ b/TweaksLauncher.ModHandler/IMod.cs @@ -2,12 +2,34 @@ /// /// The main interface that defines a mod type. Gives the mod the opportunity to initialize early. Multiple mod types are allowed. +/// +/// Requires a Initialize( mod) method implementation. +/// +/// +/// Example: +/// +/// ; +///



+/// MyMod; +///



+/// Main :

+///{ +/// // Runs early, when Unity has initialized, but before the first game scene is loaded. +/// Initialize( mod) +/// { +/// .Log("Hello World!"); +/// } +///} +///
+///
///
public interface IMod { +#if NETCOREAPP /// /// Runs early, when Unity has initialized, but before the first game scene is loaded /// - /// The returned mod instance + /// The current mod instance public static abstract void Initialize(LoadedMod mod); +#endif } diff --git a/TweaksLauncher.ModHandler/Il2Cpp/DobbyDetourProvider.cs b/TweaksLauncher.ModHandler/Il2Cpp/DobbyDetourProvider.cs index d6130ae..ff3cad7 100644 --- a/TweaksLauncher.ModHandler/Il2Cpp/DobbyDetourProvider.cs +++ b/TweaksLauncher.ModHandler/Il2Cpp/DobbyDetourProvider.cs @@ -1,6 +1,7 @@ #if IL2CPP using Il2CppInterop.Runtime.Injection; +using System; using System.Runtime.InteropServices; namespace TweaksLauncher.Il2Cpp; @@ -37,16 +38,18 @@ public void Apply() IsPrepared = true; } - Dobby.Commit(Target); + _ = Dobby.Commit(Target); IsApplied = true; } - public void Dispose() + void IDisposable.Dispose() { + GC.SuppressFinalize(this); + if (!IsApplied) return; - Dobby.Destroy(Target); + _ = Dobby.Destroy(Target); IsApplied = false; } diff --git a/TweaksLauncher.ModHandler/LoadedMod.cs b/TweaksLauncher.ModHandler/LoadedMod.cs index 159964f..836e98b 100644 --- a/TweaksLauncher.ModHandler/LoadedMod.cs +++ b/TweaksLauncher.ModHandler/LoadedMod.cs @@ -1,9 +1,16 @@ using HarmonyLib; -using Il2CppInterop.Runtime.Injection; -using Il2CppInterop.Runtime.InteropTypes; +using System; using System.Collections.ObjectModel; +using System.Drawing; using System.Reflection; + + +#if IL2CPP +using Il2CppInterop.Runtime.Injection; +using Il2CppInterop.Runtime.InteropTypes; +#endif + namespace TweaksLauncher; public class LoadedMod @@ -36,6 +43,7 @@ internal LoadedMod(string name, string modPath, Assembly modAssembly, ReadOnlyCo ModPath = modPath; ModAssembly = modAssembly; +#if IL2CPP // Automatically register Il2Cpp types foreach (var type in modAssembly.GetTypes()) { @@ -44,6 +52,7 @@ internal LoadedMod(string name, string modPath, Assembly modAssembly, ReadOnlyCo ClassInjector.RegisterTypeInIl2Cpp(type); } } +#endif // Automatically register all Harmony patches Harmony = Harmony.CreateAndPatchAll(modAssembly, modAssembly.FullName); @@ -54,14 +63,28 @@ internal LoadedMod(string name, string modPath, Assembly modAssembly, ReadOnlyCo public void Init() { foreach (var iMod in ModInterfaces) - iMod.Initialize(this); + { + try + { + iMod.Initialize(this); + } + catch (MissingMethodException) + { + ModHandler.Log($"Mod interface doesn't implement an 'Initialize' method: '{iMod.InterfaceType.FullName}'", Color.Red); + } + catch (Exception ex) + { + ModHandler.Log($"Mod interface failed to initialize: '{iMod.InterfaceType.FullName}'", Color.Red); + ModHandler.Log(ex.ToString(), Color.Red); + } + } } public void InitUnitySingletons() { foreach (var type in ModAssembly.GetTypes()) { - if (type.GetCustomAttribute() != null && type.IsAssignableTo(UnityTools.MonoBehaviour)) + if (type.GetCustomAttributes(typeof(UnitySingletonAttribute), false).Length != 0 && UnityTools.MonoBehaviour.IsAssignableFrom(type)) { UnityTools.CreateComponentSingleton(type); } diff --git a/TweaksLauncher.ModHandler/ModHandler.cs b/TweaksLauncher.ModHandler/ModHandler.cs index 97e03c3..6ba3f6e 100644 --- a/TweaksLauncher.ModHandler/ModHandler.cs +++ b/TweaksLauncher.ModHandler/ModHandler.cs @@ -1,23 +1,34 @@ using HarmonyLib; +using System; +using System.Collections.Generic; using System.Diagnostics; using System.Drawing; +using System.IO; using System.Reflection; - #if IL2CPP using TweaksLauncher.Il2Cpp; using Il2CppInterop.HarmonySupport; using Il2CppInterop.Runtime.Startup; #endif +#if MONO +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +#endif + namespace TweaksLauncher; public unsafe static class ModHandler { +#if !MONO private static Action logFunc = null!; +#endif + private static bool initSceneLoaded; private static Harmony harmony = null!; private static bool modsInited; + private static bool firstSceneLoaded; private static readonly List loadedMods = []; public static string BaseDirectory { get; private set; } = null!; @@ -32,26 +43,36 @@ public unsafe static class ModHandler public static string ProxiesDirectory { get; private set; } = null!; #endif - internal static void Start(Action logFunc, string baseDir, string gameName, string gameDir) + internal static void Start(string baseDir, string gameName, string gameDir +#if !MONO + , Action logFunc +#endif + ) { +#if !MONO ModHandler.logFunc = logFunc; +#endif Log("Initializing Mod Handler"); var unityPlayerPath = Path.Combine(gameDir, "UnityPlayer.dll"); - if (!Version.TryParse(FileVersionInfo.GetVersionInfo(unityPlayerPath).FileVersion, out var unityVersion)) + + try + { + UnityVersion = new Version(FileVersionInfo.GetVersionInfo(unityPlayerPath).FileVersion!); + } + catch { Log($"Could not find the Unity version.", Color.Red); return; } - UnityVersion = unityVersion; BaseDirectory = baseDir; GameName = gameName; GameDirectory = gameDir; GlobalModsDirectory = Path.Combine(baseDir, "GlobalMods"); - LauncherGameDirectory = Path.Combine(baseDir, "Games", gameName); + LauncherGameDirectory = Path.Combine(Path.Combine(baseDir, "Games"), gameName); ModsDirectory = Path.Combine(LauncherGameDirectory, "Mods"); #if IL2CPP @@ -64,7 +85,7 @@ internal static void Start(Action logFunc, strin Il2CppInteropRuntime.Create(new() { - UnityVersion = unityVersion, + UnityVersion = UnityVersion, DetourProvider = new DobbyDetourProvider() }) .AddHarmonySupport() @@ -82,11 +103,23 @@ internal static void Start(Action logFunc, strin internal static void Log(string? message, Color baseColor = default, string? moduleName = null, Color moduleColor = default) { +#if MONO + LogInternal(message, baseColor.ToArgb(), moduleName, moduleColor.ToArgb()); +#else logFunc(message, baseColor, moduleName, moduleColor); +#endif } +#if MONO + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void LogInternal(string? message, int baseColor, string? moduleName, int moduleColor); +#endif + private static void OnInternalActiveSceneChanged() { + if (firstSceneLoaded) + return; + if (!initSceneLoaded) { initSceneLoaded = true; @@ -94,7 +127,7 @@ private static void OnInternalActiveSceneChanged() } else { - harmony.UnpatchSelf(); + firstSceneLoaded = true; FirstSceneLoaded(); } } @@ -108,18 +141,7 @@ private static void InitMods() foreach (var mod in loadedMods) { - foreach (var iMod in mod.ModInterfaces) - { - try - { - iMod.Initialize(mod); - } - catch (Exception ex) - { - Log($"Mod interface failed to initialize: '{iMod.InterfaceType.FullName}'", Color.Red); - Log(ex.ToString(), Color.Red); - } - } + mod.Init(); } } @@ -136,12 +158,12 @@ private static void LoadModsFromPath(string modsDir) if (!Directory.Exists(modsDir)) return; - foreach (var dll in Directory.EnumerateFiles(modsDir, "*.dll")) + foreach (var dll in Directory.GetFiles(modsDir, "*.dll")) { TryLoadMod(dll); } - foreach (var modDir in Directory.EnumerateDirectories(modsDir)) + foreach (var modDir in Directory.GetDirectories(modsDir)) { var dirName = Path.GetFileName(modDir); var modPath = Path.Combine(modDir, dirName + ".dll"); @@ -171,27 +193,40 @@ private static void LoadModsFromPath(string modsDir) } Assembly modAssembly; + string? name; try { modAssembly = Assembly.LoadFrom(path); + name = modAssembly.GetName().Name; + if (name == null) + { + Log($"Could not load mod from: {path}", Color.Red); + Log($"Mod's assembly does not have a name.", Color.Red); + return null; + } } catch { Log($"Could not load mod from: {path}", Color.Red); - Log($"Mod is not a .net assembly.", Color.Red); + Log($"Invalid .net assembly.", Color.Red); return null; } - var name = modAssembly.GetName().Name; - if (name == null) + Type[] types; + + try + { + types = modAssembly.GetTypes(); + } + catch { Log($"Could not load mod from: {path}", Color.Red); - Log($"Mod's assembly does not have a name.", Color.Red); + Log($"Something went wrong while reading the assembly. The assembly might be targetting the wrong .net runtime version.", Color.Red); return null; } var modInterfaces = new List(); - foreach (var type in modAssembly.GetTypes()) + foreach (var type in types) { var mi = ModInterface.GetFromType(type); if (mi == null) diff --git a/TweaksLauncher.ModHandler/ModInterface.cs b/TweaksLauncher.ModHandler/ModInterface.cs index 00c62f9..ec90d1f 100644 --- a/TweaksLauncher.ModHandler/ModInterface.cs +++ b/TweaksLauncher.ModHandler/ModInterface.cs @@ -1,4 +1,6 @@ -namespace TweaksLauncher; +using System; + +namespace TweaksLauncher; internal abstract class ModInterface { @@ -6,7 +8,7 @@ internal abstract class ModInterface public static ModInterface? GetFromType(Type type) { - if (!type.IsAssignableTo(typeof(IMod))) + if (!typeof(IMod).IsAssignableFrom(type)) return null; var resultType = typeof(ModInterface<>).MakeGenericType(type); @@ -23,6 +25,12 @@ internal class ModInterface : ModInterface where T : IMod public override void Initialize(LoadedMod mod) { +#if NETCOREAPP T.Initialize(mod); +#else + InterfaceType.InvokeMember("Initialize", + System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static, + null, null, [mod]); +#endif } } \ No newline at end of file diff --git a/TweaksLauncher.ModHandler/NativeMethods.txt b/TweaksLauncher.ModHandler/NativeMethods.txt deleted file mode 100644 index bf89c6b..0000000 --- a/TweaksLauncher.ModHandler/NativeMethods.txt +++ /dev/null @@ -1,10 +0,0 @@ -SetStdHandle -GetModuleFileName -GetProcessId -Module32First -Module32Next -Module32FirstW -Module32NextW -GetModuleHandle -SetDllDirectory -RtlCopyUnicodeString \ No newline at end of file diff --git a/TweaksLauncher.ModHandler/TweaksLauncher.ModHandler.csproj b/TweaksLauncher.ModHandler/TweaksLauncher.ModHandler.csproj index 67bedbf..45cc1ed 100644 --- a/TweaksLauncher.ModHandler/TweaksLauncher.ModHandler.csproj +++ b/TweaksLauncher.ModHandler/TweaksLauncher.ModHandler.csproj @@ -1,10 +1,9 @@  - net8.0 + net8.0;net35 win-x64;win-x86 CA1416;CA1401;CA1869 - enable enable true TweaksLauncher @@ -28,12 +27,14 @@ - + + + + - - + \ No newline at end of file diff --git a/TweaksLauncher.ModHandler/UnityEvents.cs b/TweaksLauncher.ModHandler/UnityEvents.cs index 9b11fb6..4338d94 100644 --- a/TweaksLauncher.ModHandler/UnityEvents.cs +++ b/TweaksLauncher.ModHandler/UnityEvents.cs @@ -1,4 +1,6 @@ -namespace TweaksLauncher; +using System; + +namespace TweaksLauncher; /// /// Common Unity events that can be used in mods diff --git a/TweaksLauncher.ModHandler/UnitySingletonAttribute.cs b/TweaksLauncher.ModHandler/UnitySingletonAttribute.cs index d71e7db..2748612 100644 --- a/TweaksLauncher.ModHandler/UnitySingletonAttribute.cs +++ b/TweaksLauncher.ModHandler/UnitySingletonAttribute.cs @@ -1,4 +1,6 @@ -namespace TweaksLauncher; +using System; + +namespace TweaksLauncher; /// /// Automatically loads a Unity component after the first game scene load diff --git a/TweaksLauncher.ModHandler/UnityTools.cs b/TweaksLauncher.ModHandler/UnityTools.cs index 08ce9f8..f1029fd 100644 --- a/TweaksLauncher.ModHandler/UnityTools.cs +++ b/TweaksLauncher.ModHandler/UnityTools.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System; using System.Reflection; namespace TweaksLauncher; @@ -7,16 +7,13 @@ internal static class UnityTools { private static Assembly? coreModule = null; - [NotNull] - private static Type? gameObject = null; - [NotNull] - private static MethodInfo? dontDestroyOnLoad = null; - [NotNull] - private static MethodInfo? addComponent1 = null; + private static Type gameObject = null!; + private static MethodInfo dontDestroyOnLoad = null!; + private static MethodInfo addComponent1 = null!; public static MethodInfo? Internal_ActiveSceneChanged { get; private set; } - public static Type? MonoBehaviour { get; private set; } + public static Type MonoBehaviour { get; private set; } = null!; public static void Init() { @@ -27,13 +24,13 @@ public static void Init() if (coreModule == null) return; - gameObject = coreModule.GetType("UnityEngine.GameObject"); - addComponent1 = gameObject?.GetMethod("AddComponent", 1, []); - dontDestroyOnLoad = coreModule.GetType("UnityEngine.Object")?.GetMethod("DontDestroyOnLoad"); + gameObject = coreModule.GetType("UnityEngine.GameObject")!; + addComponent1 = gameObject?.GetMethod("AddComponent", [])!; + dontDestroyOnLoad = coreModule.GetType("UnityEngine.Object")?.GetMethod("DontDestroyOnLoad")!; - Internal_ActiveSceneChanged = coreModule.GetType("UnityEngine.SceneManagement.SceneManager")?.GetMethod("Internal_ActiveSceneChanged"); + Internal_ActiveSceneChanged = coreModule.GetType("UnityEngine.SceneManagement.SceneManager")?.GetMethod("Internal_ActiveSceneChanged", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); - MonoBehaviour = coreModule?.GetType("UnityEngine.MonoBehaviour"); + MonoBehaviour = coreModule?.GetType("UnityEngine.MonoBehaviour")!; } public static object? CreateGameObject()