示例#1
0
        private static void InstallPendingSelfUpdates()
        {
            var path = Path.Combine(BeatSaber.InstallPath, "IPA.exe");

            if (!File.Exists(path))
            {
                return;
            }

            var ipaVersion  = new Version(FileVersionInfo.GetVersionInfo(path).FileVersion);
            var selfVersion = Assembly.GetExecutingAssembly().GetName().Version;

            if (ipaVersion > selfVersion)
            {
                Process.Start(new ProcessStartInfo
                {
                    FileName        = path,
                    Arguments       = $"\"-nw={Process.GetCurrentProcess().Id},s={string.Join(" ", Environment.GetCommandLineArgs().Skip(1).StrJP()).Replace("\\", "\\\\").Replace(",", "\\,")}\"",
                    UseShellExecute = false
                });

                updater.Info("Updating BSIPA...");
                Environment.Exit(0);
            }
        }
示例#2
0
        internal static Assembly LoadLibrary(AssemblyName asmName)
        {
            Log(Logger.Level.Debug, $"Resolving library {asmName}");

            SetupAssemblyFilenames();

            var testFile = $"{asmName.Name}.{asmName.Version}.dll";

            Log(Logger.Level.Debug, $"Looking for file {testFile}");

            if (FilenameLocations.TryGetValue(testFile, out var path))
            {
                Log(Logger.Level.Debug, $"Found file {testFile} as {path}");
                if (File.Exists(path))
                {
                    return(Assembly.LoadFrom(path));
                }

                Log(Logger.Level.Critical, $"but {path} no longer exists!");
            }
            else if (FilenameLocations.TryGetValue(testFile = $"{asmName.Name}.dll", out path))
            {
                Log(Logger.Level.Debug, $"Found file {testFile} as {path}");
                if (File.Exists(path))
                {
                    return(Assembly.LoadFrom(path));
                }

                Log(Logger.Level.Critical, $"but {path} no longer exists!");
            }

            Log(Logger.Level.Critical, $"No library {asmName} found");

            return(null);
        }
        public override AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
        {
            LibLoader.SetupAssemblyFilenames();

            if (name.Name == CurrentAssemblyName)
            {
                return(AssemblyDefinition.ReadAssembly(CurrentAssemblyPath, parameters));
            }

            if (LibLoader.FilenameLocations.TryGetValue($"{name.Name}.dll", out var path))
            {
                if (File.Exists(path))
                {
                    return(AssemblyDefinition.ReadAssembly(path, parameters));
                }
            }
            else if (LibLoader.FilenameLocations.TryGetValue($"{name.Name}.{name.Version}.dll", out path))
            {
                if (File.Exists(path))
                {
                    return(AssemblyDefinition.ReadAssembly(path, parameters));
                }
            }


            return(base.Resolve(name, parameters));
        }
示例#4
0
        public static bool IsInvalid(string path)
        {
            var dataPlugins = Path.Combine(GameVersionEarly.ResolveDataPath(path), "Plugins");

            try
            {
                var userDir = GetPath(new Guid("374DE290-123F-4565-9164-39C4925E467B"),
                                      KnownFolderFlags.AliasOnly | KnownFolderFlags.DontVerify);
                var userDir2 = GetPath(new Guid("7d83ee9b-2244-4e70-b1f5-5393042af1e4"),
                                       KnownFolderFlags.AliasOnly | KnownFolderFlags.DontVerify);

                var curdir = Environment.CurrentDirectory;

                if (curdir.IsSubPathOf(userDir) ||
                    curdir.IsSubPathOf(userDir2))
                {
                    return(false);
                }
            }
            catch { }

            // To the guys that maintain a fork that removes this code: I would greatly appreciate if we could talk
            //   about this for a little bit. Please message me on Discord at DaNike#6223
            return
                (File.Exists(Path.Combine(path, "IGG-GAMES.COM.url")) ||
                 File.Exists(Path.Combine(path, "SmartSteamEmu.ini")) ||
                 File.Exists(Path.Combine(path, "GAMESTORRENT.CO.url")) ||
                 File.Exists(Path.Combine(dataPlugins, "BSteam crack.dll")) ||
                 File.Exists(Path.Combine(dataPlugins, "HUHUVR_steam_api64.dll")) ||
                 Directory.GetFiles(dataPlugins, "*.ini", SearchOption.TopDirectoryOnly).Length > 0);
        }
        private static Tuple <IEnumerable <PluginInfo>, IEnumerable <IPlugin> > LoadPluginsFromFile(string file)
        {
            List <IPlugin> ipaPlugins = new List <IPlugin>();

            if (!File.Exists(file) || !file.EndsWith(".dll", true, null))
            {
                return(new Tuple <IEnumerable <PluginInfo>, IEnumerable <IPlugin> >(null, ipaPlugins));
            }

            T OptionalGetPlugin <T>(Type t) where T : class
            {
                // use typeof() to allow for easier renaming (in an ideal world this compiles to a string, but ¯\_(ツ)_/¯)
                if (t.GetInterface(typeof(T).Name) != null)
                {
                    try
                    {
                        T pluginInstance = Activator.CreateInstance(t) as T;
                        return(pluginInstance);
                    }
                    catch (Exception e)
                    {
                        Logger.loader.Error($"Could not load plugin {t.FullName} in {Path.GetFileName(file)}! {e}");
                    }
                }

                return(null);
            }

            try
            {
                Assembly assembly = Assembly.LoadFrom(file);

                foreach (Type t in assembly.GetTypes())
                {
                    IPlugin ipaPlugin = OptionalGetPlugin <IPlugin>(t);
                    if (ipaPlugin != null)
                    {
                        ipaPlugins.Add(ipaPlugin);
                    }
                }
            }
            catch (ReflectionTypeLoadException e)
            {
                Logger.loader.Error($"Could not load the following types from {Path.GetFileName(file)}:");
                Logger.loader.Error($"  {string.Join("\n  ", e.LoaderExceptions?.Select(e1 => e1?.Message).StrJP() ?? new string[0])}");
            }
            catch (Exception e)
            {
                Logger.loader.Error($"Could not load {Path.GetFileName(file)}!");
                Logger.loader.Error(e);
            }

            return(new Tuple <IEnumerable <PluginInfo>, IEnumerable <IPlugin> >(null, ipaPlugins));
        }
示例#6
0
        public static bool IsInvalid(string path)
        {
            var dataPlugins = Path.Combine(GameVersionEarly.ResolveDataPath(path), "Plugins");

            return
                (File.Exists(Path.Combine(path, "IGG-GAMES.COM.url")) ||
                 File.Exists(Path.Combine(path, "SmartSteamEmu.ini")) ||
                 File.Exists(Path.Combine(path, "GAMESTORRENT.CO.url")) ||
                 File.Exists(Path.Combine(dataPlugins, "BSteam crack.dll")) ||
                 File.Exists(Path.Combine(dataPlugins, "HUHUVR_steam_api64.dll")) ||
                 Directory.GetFiles(dataPlugins, "*.ini", SearchOption.TopDirectoryOnly).Length > 0);
        }
示例#7
0
        internal static string GetGameVersion()
        {
            var mgr = GlobalGameManagers(UnityGame.InstallPath);

            using (var stream = File.OpenRead(mgr))
                using (var reader = new BinaryReader(stream, Encoding.UTF8))
                {
                    const string key = "public.app-category.games";
                    int          pos = 0;

                    while (stream.Position < stream.Length && pos < key.Length)
                    {
                        if (reader.ReadByte() == key[pos])
                        {
                            pos++;
                        }
                        else
                        {
                            pos = 0;
                        }
                    }

                    if (stream.Position == stream.Length) // we went through the entire stream without finding the key
                    {
                        throw new KeyNotFoundException("Could not find key '" + key + "' in " + mgr);
                    }

                    while (stream.Position < stream.Length)
                    {
                        var current = (char)reader.ReadByte();
                        if (char.IsDigit(current))
                        {
                            break;
                        }
                    }

                    var rewind = -sizeof(int) - sizeof(byte);
                    stream.Seek(rewind, SeekOrigin.Current); // rewind to the string length

                    var strlen   = reader.ReadInt32();
                    var strbytes = reader.ReadBytes(strlen);

                    return(Encoding.UTF8.GetString(strbytes));
                }
        }
示例#8
0
        private static void InstallPendingSelfUpdates()
        {
            var path = Path.Combine(UnityGame.InstallPath, "IPA.exe");

            if (!File.Exists(path))
            {
                return;
            }

            var ipaVersion  = new Version(FileVersionInfo.GetVersionInfo(path).FileVersion);
            var selfVersion = Assembly.GetExecutingAssembly().GetName().Version;

            if (ipaVersion > selfVersion)
            {
                var scanResult = AntiMalwareEngine.Engine.ScanFile(new FileInfo(path));
                if (scanResult == ScanResult.Detected)
                {
                    Updater.Error("Scan of BSIPA installer found malware; not updating");
                    return;
                }
                if (!SelfConfig.AntiMalware_.RunPartialThreatCode_ && scanResult is not ScanResult.KnownSafe and not ScanResult.NotDetected)
                {
                    Updater.Error("Scan of BSIPA installer returned partial threat; not updating. To allow this, enable AntiMalware.RunPartialThreatCode in the config.");
                    return;
                }

                _ = Process.Start(new ProcessStartInfo
                {
                    FileName  = path,
                    Arguments = $"\"-nw={Process.GetCurrentProcess().Id}," +
                                $"s={string.Join(" ", Environment.GetCommandLineArgs().Skip(1).StrJP()).Replace("\\", "\\\\").Replace(",", "\\,")}\"",
                    UseShellExecute = false
                });

                Updater.Info("Updating BSIPA...");
                Environment.Exit(0);
            }
        }
示例#9
0
        internal static string GetGameVersion()
        {
            var mgr = GlobalGameManagers(BeatSaber.InstallPath);

            using (var stream = File.OpenRead(mgr))
                using (var reader = new BinaryReader(stream, Encoding.UTF8))
                {
                    const string key = "public.app-category.games";
                    int          pos = 0;

                    while (stream.Position < stream.Length && pos < key.Length)
                    {
                        if (reader.ReadByte() == key[pos])
                        {
                            pos++;
                        }
                        else
                        {
                            pos = 0;
                        }
                    }

                    if (stream.Position == stream.Length) // we went through the entire stream without finding the key
                    {
                        throw new KeyNotFoundException("Could not find key '" + key + "' in " + mgr);
                    }

                    // otherwise pos == key.Length, which means we found it
                    int offset = 136 - key.Length - sizeof(int);
                    stream.Seek(offset, SeekOrigin.Current); // advance past junk to beginning of string

                    int strlen   = reader.ReadInt32();       // assumes LE
                    var strbytes = reader.ReadBytes(strlen);

                    return(Encoding.UTF8.GetString(strbytes));
                }
        }
示例#10
0
        private static void InstallPendingModUpdates()
        {
            var pendingDir = Path.Combine(BeatSaber.InstallPath, "IPA", "Pending");

            if (!Directory.Exists(pendingDir))
            {
                return;
            }

            // there are pending updates, install
            updater.Info("Installing pending updates");

            var toDelete = new string[0];
            var delFn    = Path.Combine(pendingDir, DeleteFileName);

            if (File.Exists(delFn))
            {
                toDelete = File.ReadAllLines(delFn);
                File.Delete(delFn);
            }

            foreach (var file in toDelete)
            {
                try
                {
                    File.Delete(Path.Combine(BeatSaber.InstallPath, file));
                }
                catch (Exception e)
                {
                    updater.Error("While trying to install pending updates: Error deleting file marked for deletion");
                    updater.Error(e);
                }
            }

            #region Self Protection

            string path;
            if (Directory.Exists(path = Path.Combine(pendingDir, "IPA")))
            {
                var dirs = new Stack <string>(20);

                dirs.Push(path);

                while (dirs.Count > 0)
                {
                    var      currentDir = dirs.Pop();
                    string[] subDirs;
                    string[] files;
                    try
                    {
                        subDirs = Directory.GetDirectories(currentDir);
                        files   = Directory.GetFiles(currentDir);
                    }
                    catch (UnauthorizedAccessException e)
                    {
                        updater.Error(e);
                        continue;
                    }
                    catch (DirectoryNotFoundException e)
                    {
                        updater.Error(e);
                        continue;
                    }

                    foreach (var file in files)
                    {
                        try
                        {
                            if (!Utils.GetRelativePath(file, path).Split(Path.PathSeparator).Contains("Pending"))
                            {
                                File.Delete(file);
                            }
                        }
                        catch (FileNotFoundException e)
                        {
                            updater.Error(e);
                        }
                    }

                    foreach (var str in subDirs)
                    {
                        dirs.Push(str);
                    }
                }
            }
            if (File.Exists(path = Path.Combine(pendingDir, "IPA.exe")))
            {
                File.Delete(path);
                if (File.Exists(path = Path.Combine(pendingDir, "Mono.Cecil.dll")))
                {
                    File.Delete(path);
                }
            }

            #endregion

            try
            {
                Utils.CopyAll(new DirectoryInfo(pendingDir), new DirectoryInfo(BeatSaber.InstallPath), onCopyException: (e, f) =>
                {
                    updater.Error($"Error copying file {Utils.GetRelativePath(f.FullName, pendingDir)} from Pending:");
                    updater.Error(e);
                    return(true);
                });
            }
            catch (Exception e)
            {
                updater.Error("While trying to install pending updates: Error copying files in");
                updater.Error(e);
            }

            try
            {
                Directory.Delete(pendingDir, true);
            }
            catch (Exception e)
            {
                updater.Error("Something went wrong performing an operation that should never fail!");
                updater.Error(e);
            }
        }
        internal static void LoadMetadata()
        {
            string[] plugins = Directory.GetFiles(UnityGame.PluginsPath, "*.dll");

            try
            {
                var selfMeta = new PluginMetadata
                {
                    Assembly   = Assembly.GetExecutingAssembly(),
                    File       = new FileInfo(Path.Combine(UnityGame.InstallPath, "IPA.exe")),
                    PluginType = null,
                    IsSelf     = true
                };

                string manifest;
                using (var manifestReader =
                           new StreamReader(
                               selfMeta.Assembly.GetManifestResourceStream(typeof(PluginLoader), "manifest.json") ??
                               throw new InvalidOperationException()))
                    manifest = manifestReader.ReadToEnd();

                selfMeta.Manifest = JsonConvert.DeserializeObject <PluginManifest>(manifest);

                PluginsMetadata.Add(selfMeta);
                SelfMeta = selfMeta;
            }
            catch (Exception e)
            {
                Logger.loader.Critical("Error loading own manifest");
                Logger.loader.Critical(e);
            }

            var resolver = new CecilLibLoader();

            resolver.AddSearchDirectory(UnityGame.LibraryPath);
            resolver.AddSearchDirectory(UnityGame.PluginsPath);
            foreach (var plugin in plugins)
            {
                var metadata = new PluginMetadata
                {
                    File   = new FileInfo(Path.Combine(UnityGame.PluginsPath, plugin)),
                    IsSelf = false
                };

                try
                {
                    var pluginModule = AssemblyDefinition.ReadAssembly(plugin, new ReaderParameters
                    {
                        ReadingMode      = ReadingMode.Immediate,
                        ReadWrite        = false,
                        AssemblyResolver = resolver
                    }).MainModule;

                    string pluginNs = "";

                    foreach (var resource in pluginModule.Resources)
                    {
                        const string manifestSuffix = ".manifest.json";
                        if (!(resource is EmbeddedResource embedded) ||
                            !embedded.Name.EndsWith(manifestSuffix))
                        {
                            continue;
                        }

                        pluginNs = embedded.Name.Substring(0, embedded.Name.Length - manifestSuffix.Length);

                        string manifest;
                        using (var manifestReader = new StreamReader(embedded.GetResourceStream()))
                            manifest = manifestReader.ReadToEnd();

                        metadata.Manifest = JsonConvert.DeserializeObject <PluginManifest>(manifest);
                        break;
                    }

                    if (metadata.Manifest == null)
                    {
#if DIRE_LOADER_WARNINGS
                        Logger.loader.Error($"Could not find manifest.json for {Path.GetFileName(plugin)}");
#else
                        Logger.loader.Notice($"No manifest.json in {Path.GetFileName(plugin)}");
#endif
                        continue;
                    }

                    void TryGetNamespacedPluginType(string ns, PluginMetadata meta)
                    {
                        foreach (var type in pluginModule.Types)
                        {
                            if (type.Namespace != ns)
                            {
                                continue;
                            }

                            if (type.HasCustomAttributes)
                            {
                                var attr = type.CustomAttributes.FirstOrDefault(a => a.Constructor.DeclaringType.FullName == typeof(PluginAttribute).FullName);
                                if (attr != null)
                                {
                                    if (!attr.HasConstructorArguments)
                                    {
                                        Logger.loader.Warn($"Attribute plugin found in {type.FullName}, but attribute has no arguments");
                                        return;
                                    }

                                    var args = attr.ConstructorArguments;
                                    if (args.Count != 1)
                                    {
                                        Logger.loader.Warn($"Attribute plugin found in {type.FullName}, but attribute has unexpected number of arguments");
                                        return;
                                    }
                                    var rtOptionsArg = args[0];
                                    if (rtOptionsArg.Type.FullName != typeof(RuntimeOptions).FullName)
                                    {
                                        Logger.loader.Warn($"Attribute plugin found in {type.FullName}, but first argument is of unexpected type {rtOptionsArg.Type.FullName}");
                                        return;
                                    }

                                    var rtOptionsValInt = (int)rtOptionsArg.Value; // `int` is the underlying type of RuntimeOptions

                                    meta.RuntimeOptions = (RuntimeOptions)rtOptionsValInt;
                                    meta.PluginType     = type;
                                    return;
                                }
                            }
                        }
                    }

                    var hint = metadata.Manifest.Misc?.PluginMainHint;

                    if (hint != null)
                    {
                        var type = pluginModule.GetType(hint);
                        if (type != null)
                        {
                            TryGetNamespacedPluginType(hint, metadata);
                        }
                    }

                    if (metadata.PluginType == null)
                    {
                        TryGetNamespacedPluginType(pluginNs, metadata);
                    }

                    if (metadata.PluginType == null)
                    {
                        Logger.loader.Error($"No plugin found in the manifest {(hint != null ? $"hint path ({hint}) or " : "")}namespace ({pluginNs}) in {Path.GetFileName(plugin)}");
                        continue;
                    }

                    Logger.loader.Debug($"Adding info for {Path.GetFileName(plugin)}");
                    PluginsMetadata.Add(metadata);
                }
                catch (Exception e)
                {
                    Logger.loader.Error($"Could not load data for plugin {Path.GetFileName(plugin)}");
                    Logger.loader.Error(e);
                    ignoredPlugins.Add(metadata, new IgnoreReason(Reason.Error)
                    {
                        ReasonText = "An error ocurred loading the data",
                        Error      = e
                    });
                }
            }

            IEnumerable <string> bareManifests = Directory.GetFiles(UnityGame.PluginsPath, "*.json");
            bareManifests = bareManifests.Concat(Directory.GetFiles(UnityGame.PluginsPath, "*.manifest"));
            foreach (var manifest in bareManifests)
            {
                try
                {
                    var metadata = new PluginMetadata
                    {
                        File   = new FileInfo(Path.Combine(UnityGame.PluginsPath, manifest)),
                        IsSelf = false,
                        IsBare = true,
                    };

                    metadata.Manifest = JsonConvert.DeserializeObject <PluginManifest>(File.ReadAllText(manifest));

                    if (metadata.Manifest.Files.Length < 1)
                    {
                        Logger.loader.Warn($"Bare manifest {Path.GetFileName(manifest)} does not declare any files. " +
                                           $"Dependency resolution and verification cannot be completed.");
                    }

                    Logger.loader.Debug($"Adding info for bare manifest {Path.GetFileName(manifest)}");
                    PluginsMetadata.Add(metadata);
                }
                catch (Exception e)
                {
                    Logger.loader.Error($"Could not load data for bare manifest {Path.GetFileName(manifest)}");
                    Logger.loader.Error(e);
                }
            }

            foreach (var meta in PluginsMetadata)
            { // process description include
                var lines = meta.Manifest.Description.Split('\n');
                var m     = embeddedTextDescriptionPattern.Match(lines[0]);
                if (m.Success)
                {
                    if (meta.IsBare)
                    {
                        Logger.loader.Warn($"Bare manifest cannot specify description file");
                        meta.Manifest.Description = string.Join("\n", lines.Skip(1).StrJP()); // ignore first line
                        continue;
                    }

                    var    name = m.Groups[1].Value;
                    string description;
                    if (!meta.IsSelf)
                    {
                        var resc = meta.PluginType.Module.Resources.Select(r => r as EmbeddedResource)
                                   .NonNull()
                                   .FirstOrDefault(r => r.Name == name);
                        if (resc == null)
                        {
                            Logger.loader.Warn($"Could not find description file for plugin {meta.Name} ({name}); ignoring include");
                            meta.Manifest.Description = string.Join("\n", lines.Skip(1).StrJP()); // ignore first line
                            continue;
                        }

                        using var reader = new StreamReader(resc.GetResourceStream());
                        description      = reader.ReadToEnd();
                    }
                    else
                    {
                        using var descriptionReader = new StreamReader(meta.Assembly.GetManifestResourceStream(name));
                        description = descriptionReader.ReadToEnd();
                    }

                    meta.Manifest.Description = description;
                }
            }
        }
        internal static void Load()
        {
            string pluginDirectory = BeatSaber.PluginsPath;

            // Process.GetCurrentProcess().MainModule crashes the game and Assembly.GetEntryAssembly() is NULL,
            // so we need to resort to P/Invoke
            string exeName = Path.GetFileNameWithoutExtension(AppInfo.StartupPath);

            _bsPlugins  = new List <PluginInfo>();
            _ipaPlugins = new List <IPlugin>();

            if (!Directory.Exists(pluginDirectory))
            {
                return;
            }

            string cacheDir = Path.Combine(pluginDirectory, ".cache");

            if (!Directory.Exists(cacheDir))
            {
                Directory.CreateDirectory(cacheDir);
            }
            else
            {
                foreach (string plugin in Directory.GetFiles(cacheDir, "*"))
                {
                    File.Delete(plugin);
                }
            }

            // initialize BSIPA plugins first
            _bsPlugins.AddRange(PluginLoader.LoadPlugins());

            //Copy plugins to .cache
            string[] originalPlugins = Directory.GetFiles(pluginDirectory, "*.dll");
            foreach (string s in originalPlugins)
            {
                if (PluginsMetadata.Select(m => m.File.FullName).Contains(s))
                {
                    continue;
                }
                string pluginCopy = Path.Combine(cacheDir, Path.GetFileName(s));

                #region Fix assemblies for refactor

                var module = ModuleDefinition.ReadModule(Path.Combine(pluginDirectory, s));
                foreach (var @ref in module.AssemblyReferences)
                { // fix assembly references
                    if (@ref.Name == "IllusionPlugin" || @ref.Name == "IllusionInjector")
                    {
                        @ref.Name = "IPA.Loader";
                    }
                }

                foreach (var @ref in module.GetTypeReferences())
                { // fix type references
                    if (@ref.FullName == "IllusionPlugin.IPlugin")
                    {
                        @ref.Namespace = "IPA.Old";                                            //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.IEnhancedPlugin")
                    {
                        @ref.Namespace = "IPA.Old";                                                    //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.IBeatSaberPlugin")
                    {
                        @ref.Namespace = "IPA";                                                     //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.IEnhancedBeatSaberPlugin")
                    {
                        @ref.Namespace = "IPA";                                                             //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.BeatSaber.ModsaberModInfo")
                    {
                        @ref.Namespace = "IPA";                                                              //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.IniFile")
                    {
                        @ref.Namespace = "IPA.Config";                                            //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.IModPrefs")
                    {
                        @ref.Namespace = "IPA.Config";                                              //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.ModPrefs")
                    {
                        @ref.Namespace = "IPA.Config";                                             //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.Utils.ReflectionUtil")
                    {
                        @ref.Namespace = "IPA.Utilities";                                                         //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.Logging.Logger")
                    {
                        @ref.Namespace = "IPA.Logging";                                                   //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionPlugin.Logging.LogPrinter")
                    {
                        @ref.Namespace = "IPA.Logging";                                                       //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.PluginManager")
                    {
                        @ref.Namespace = "IPA.Loader";                                                    //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.PluginComponent")
                    {
                        @ref.Namespace = "IPA.Loader";                                                      //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.CompositeBSPlugin")
                    {
                        @ref.Namespace = "IPA.Loader.Composite";                                                        //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.CompositeIPAPlugin")
                    {
                        @ref.Namespace = "IPA.Loader.Composite";                                                         //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.Logging.UnityLogInterceptor")
                    {
                        @ref.Namespace = "IPA.Logging";                                                                  //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.Logging.StandardLogger")
                    {
                        @ref.Namespace = "IPA.Logging";                                                             //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.Updating.SelfPlugin")
                    {
                        @ref.Namespace = "IPA.Updating";                                                          //@ref.Name = "";
                    }
                    if (@ref.FullName == "IllusionInjector.Updating.Backup.BackupUnit")
                    {
                        @ref.Namespace = "IPA.Updating.Backup";                                                                 //@ref.Name = "";
                    }
                    if (@ref.Namespace == "IllusionInjector.Utilities")
                    {
                        @ref.Namespace = "IPA.Utilities";                                                 //@ref.Name = "";
                    }
                    if (@ref.Namespace == "IllusionInjector.Logging.Printers")
                    {
                        @ref.Namespace = "IPA.Logging.Printers";                                                        //@ref.Name = "";
                    }
                    if (@ref.Namespace == "IllusionInjector.Updating.ModsaberML")
                    {
                        @ref.Namespace = "IPA.Updating.ModSaber";                                                           //@ref.Name = "";
                    }
                }
                module.Write(pluginCopy);

                #endregion
            }

            //Load copied plugins
            string[] copiedPlugins = Directory.GetFiles(cacheDir, "*.dll");
            foreach (string s in copiedPlugins)
            {
                var result = LoadPluginsFromFile(s);
                _ipaPlugins.AddRange(result.Item2);
            }

            Logger.log.Info(exeName);
            Logger.log.Info($"Running on Unity {Application.unityVersion}");
            Logger.log.Info($"Game version {BeatSaber.GameVersion}");
            Logger.log.Info("-----------------------------");
            Logger.log.Info($"Loading plugins from {Utils.GetRelativePath(pluginDirectory, Environment.CurrentDirectory)} and found {_bsPlugins.Count + _ipaPlugins.Count}");
            Logger.log.Info("-----------------------------");
            foreach (var plugin in _bsPlugins)
            {
                Logger.log.Info($"{plugin.Metadata.Name} ({plugin.Metadata.Id}): {plugin.Metadata.Version}");
            }
            Logger.log.Info("-----------------------------");
            foreach (var plugin in _ipaPlugins)
            {
                Logger.log.Info($"{plugin.Name}: {plugin.Version}");
            }
            Logger.log.Info("-----------------------------");
        }