using IPA.Loader; using IPA.Logging; using System; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using UnityEngine; using static IPA.Logging.Logger; namespace IPA.Injector { public static class Injector { private static bool injected = false; public static void Inject() { if (!injected) { injected = true; #region Add Library load locations AppDomain.CurrentDomain.AssemblyResolve += AssemblyLibLoader; try { if (!SetDllDirectory(Path.Combine(Environment.CurrentDirectory, "Libs", "Native"))) { libLoader.Warn("Unable to add native library path to load path"); } } catch (Exception) { } #endregion var bootstrapper = new GameObject("Bootstrapper").AddComponent(); bootstrapper.Destroyed += Bootstrapper_Destroyed; } } [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool SetDllDirectory(string lpPathName); #region Managed library loader private static string libsDir; private static Assembly AssemblyLibLoader(object source, ResolveEventArgs e) { if (libsDir == null) libsDir = Path.Combine(Environment.CurrentDirectory, "Libs"); var asmName = new AssemblyName(e.Name); Log(Level.Debug, $"Resolving library {asmName}"); var testFilen = Path.Combine(libsDir, $"{asmName.Name}.{asmName.Version}.dll"); Log(Level.Debug, $"Looking for file {testFilen}"); if (File.Exists(testFilen)) return Assembly.LoadFile(testFilen); Log(Level.Critical, $"Could not load library {asmName}"); return null; } private static void Log(Level lvl, string message) { // multiple proxy methods to delay loading of assemblies until it's done if (LogCreated) AssemblyLibLoaderCallLogger(lvl, message); else if (((byte)lvl & (byte)StandardLogger.PrintFilter) != 0) Console.WriteLine($"[{lvl}] {message}"); } private static void AssemblyLibLoaderCallLogger(Level lvl, string message) { libLoader.Log(lvl, message); } #endregion private static void Bootstrapper_Destroyed() { PluginComponent.Create(); } } }