Ejemplo n.º 1
0
        internal static void Patch()
        {
            try
            {
                if (patched)
                {
                    Logger.Warn("Patch method was called multiple times!");
                    return; // Halt patching
                }

                Patched = true;

                Logger.Info($"Loading QModManager v{Assembly.GetExecutingAssembly().GetName().Version.ToStringParsed()}...");
                Logger.Info($"Today is {DateTime.Today:dd-MMMM-yyyy}");

                if (QModBaseDir == null)
                {
                    Logger.Fatal("A fatal error has occurred.");
                    Logger.Fatal("There was an error with the QMods directory");
                    Logger.Fatal("Please make sure that you ran Subnautica from Steam/Epic/Discord, and not from the executable file!");

                    Dialog.Show("A fatal error has occurred. QModManager could not be initialized.", Dialog.Button.close, Dialog.Button.Disabled, false);

                    return;
                }

                try
                {
                    Logger.Info($"Folder structure:\n{IOUtilities.GetFolderStructureAsTree()}\n");
                }
                catch (Exception e)
                {
                    Logger.Error("There was an error while trying to display the folder structure.");
                    Logger.Exception(e);
                }

                Logger.Info($"Loading QModManager v{Assembly.GetExecutingAssembly().GetName().Version.ToStringParsed()}...");

                PirateCheck.IsPirate(Environment.CurrentDirectory);

                var gameDetector = new GameDetector();

                if (!gameDetector.IsValidGameRunning)
                {
                    return;
                }

                CurrentlyRunningGame = gameDetector.CurrentlyRunningGame;

                PatchHarmony();

                if (NitroxCheck.IsInstalled)
                {
                    Logger.Fatal($"Nitrox was detected!");

                    Dialog.Show("Both QModManager and Nitrox detected. QModManager is not compatible with Nitrox. Please uninstall one of them.", Dialog.Button.Disabled, Dialog.Button.Disabled, false);

                    return;
                }

                VersionCheck.Check();

                Logger.Info("Started loading mods");

                AddAssemblyResolveEvent();

                IQModFactory modFactory = new QModFactory();
                List <QMod>  modsToLoad = modFactory.BuildModLoadingList(QModBaseDir);

                QModServices.LoadKnownMods(modsToLoad);

                var initializer = new Initializer(CurrentlyRunningGame);
                initializer.InitializeMods(modsToLoad);

                int loadedMods  = 0;
                int erroredMods = 0;
                foreach (QMod mod in modsToLoad)
                {
                    if (mod.IsLoaded)
                    {
                        loadedMods++;
                    }
                    else if (mod.Enable)
                    {
                        erroredMods++;
                    }
                }

                ErrorModCount = erroredMods;

                Logger.Info($"Finished loading QModManager. Loaded {loadedMods} mods");

                if (ErrorModCount > 0)
                {
                    string msg = $"A total of {ErrorModCount} mods failed to load";
                    Logger.Warn(msg);
                    Dialog.Show(msg + "\nSee log file for details.", Dialog.Button.close, Dialog.Button.Disabled, false);
                }

                SummaryLogger.LogSummaries(modsToLoad);
            }
            catch (FatalPatchingException pEx)
            {
                Logger.Fatal($"A fatal patching exception has been caught! Patching ended prematurely!");
                Logger.Exception(pEx);

                Dialog.Show("A fatal patching exception has been caught. QModManager could not be initialized.", Dialog.Button.close, Dialog.Button.Disabled, false);
            }
            catch (Exception e)
            {
                Logger.Fatal("An unhandled exception has been caught! - Patching ended prematurely!");
                Logger.Exception(e);

                Dialog.Show("An unhandled exception has been caught. QModManager could not be initialized.", Dialog.Button.close, Dialog.Button.Disabled, false);
            }
        }
Ejemplo n.º 2
0
        internal static void Patch()
        {
            try
            {
                if (Patched)
                {
                    Logger.Warn("Patch method was called multiple times!");
                    return; // Halt patching
                }

                Patched = true;

                Logger.Info("Game Version: " + SNUtils.GetPlasticChangeSetOfBuild() + " Build Date: " + SNUtils.GetDateTimeOfBuild().ToLongDateString());
                Logger.Info($"Loading QModManager v{Assembly.GetExecutingAssembly().GetName().Version.ToStringParsed()}...");
                Logger.Info($"Today is {DateTime.Today:dd-MMMM-yyyy}");

                if (QModBaseDir == null)
                {
                    Logger.Fatal("A fatal error has occurred.");
                    Logger.Fatal("There was an error with the QMods directory");
                    Logger.Fatal("Please make sure that you ran Subnautica from Steam/Epic/Discord, and not from the executable file!");

                    new Dialog()
                    {
                        message     = "A fatal error has occurred. QModManager could not be initialized.",
                        color       = Dialog.DialogColor.Red,
                        leftButton  = Dialog.Button.SeeLog,
                        rightButton = Dialog.Button.Close,
                    }.Show();

                    return;
                }

                try
                {
                    Logger.Info($"Folder structure:\n{IOUtilities.GetFolderStructureAsTree()}\n");
                }
                catch (Exception e)
                {
                    Logger.Error("There was an error while trying to display the folder structure.");
                    Logger.Exception(e);
                }

                PirateCheck.IsPirate(Environment.CurrentDirectory);

                var gameDetector = new GameDetector();

                if (!gameDetector.IsValidGameRunning)
                {
                    return;
                }

                CurrentlyRunningGame = gameDetector.CurrentlyRunningGame;

                try
                {
                    PatchHarmony();
                }
                catch (Exception e)
                {
                    Logger.Error("There was an error while trying to apply Harmony patches.");
                    Logger.Exception(e);
                }

                if (NitroxCheck.IsInstalled)
                {
                    Logger.Fatal($"Nitrox was detected!");

                    new Dialog()
                    {
                        message     = "Both QModManager and Nitrox detected. QModManager is not compatible with Nitrox. Please uninstall one of them.",
                        leftButton  = Dialog.Button.Disabled,
                        rightButton = Dialog.Button.Disabled,
                        color       = Dialog.DialogColor.Red,
                    }.Show();

                    return;
                }

                VersionCheck.Check();

                Logger.Info("Started loading mods");

                AddAssemblyResolveEvent();

                IQModFactory modFactory = new QModFactory();
                List <QMod>  modsToLoad = modFactory.BuildModLoadingList(QModBaseDir);

                QModServices.LoadKnownMods(modsToLoad);

                var initializer = new Initializer(CurrentlyRunningGame);
                initializer.InitializeMods(modsToLoad);

                SummaryLogger.ReportIssues(modsToLoad);

                SummaryLogger.LogSummaries(modsToLoad);
            }
            catch (FatalPatchingException pEx)
            {
                Logger.Fatal($"A fatal patching exception has been caught! Patching ended prematurely!");
                Logger.Exception(pEx);

                new Dialog()
                {
                    message    = "A fatal patching exception has been caught. QModManager could not be initialized.",
                    color      = Dialog.DialogColor.Red,
                    leftButton = Dialog.Button.SeeLog,
                }.Show();
            }
            catch (Exception e)
            {
                Logger.Fatal("An unhandled exception has been caught! Patching ended prematurely!");
                Logger.Exception(e);

                new Dialog()
                {
                    message    = "An unhandled exception has been caught. QModManager could not be initialized.",
                    color      = Dialog.DialogColor.Red,
                    leftButton = Dialog.Button.SeeLog,
                }.Show();
            }
        }
Ejemplo n.º 3
0
        public static void TypeLoaderFindPluginTypesPostfix(ref Dictionary <string, List <PluginInfo> > __result, string directory)
        {
            if (directory != Paths.PluginPath)
            {
                return;
            }

            if (!(__result.Values.SelectMany(x => x).SingleOrDefault(x => x.Metadata.GUID == "QModManager.QMMLoader") is PluginInfo qmmLoaderPluginInfo))
            {
                return;
            }

            try
            {
                var result = new Dictionary <string, List <PluginInfo> >();

                QModPluginInfos        = new Dictionary <string, PluginInfo>();
                InitialisedQModPlugins = new List <PluginInfo>();

                IPluginCollection pluginCollection = new PluginCollection(__result.Values.SelectMany(x => x).ToList());

                IQModFactory factory = new QModFactory(pluginCollection);

                QModsToLoad = factory.BuildModLoadingList(QModsPath);
                QModServices.LoadKnownMods(QModsToLoad.ToList());
                QModsToLoadById = QModsToLoad.ToDictionary(qmod => qmod.Id);

                foreach (var mod in QModsToLoad.Where(mod => mod.Status == ModStatus.Success))
                {
                    var dll      = Path.Combine(mod.SubDirectory, mod.AssemblyName);
                    var manifest = Path.Combine(mod.SubDirectory, "mod.json");

                    if (PluginCache != null && PluginCache.TryGetValue(dll, out var cacheEntry))
                    {
                        var lastWrite = Math.Max(File.GetLastWriteTimeUtc(dll).Ticks, File.GetLastWriteTimeUtc(manifest).Ticks);
                        if (lastWrite == cacheEntry.Timestamp)
                        {
                            result[dll]             = cacheEntry.CacheItems;
                            QModPluginInfos[mod.Id] = cacheEntry.CacheItems.FirstOrDefault();
                            continue;
                        }
                    }

                    var loadBeforeQmodIds = mod.LoadBefore.Where(id => QModPluginInfos.ContainsKey(id));
                    foreach (var id in loadBeforeQmodIds)
                    {
                        QModPluginInfos[id].Dependencies.AddItem(new BepInDependency(mod.Id, BepInDependency.DependencyFlags.SoftDependency));
                    }
                    foreach (var id in mod.LoadBefore.Where(id => pluginCollection.AllPlugins.Select(x => x.Metadata.GUID).Contains(id)).Except(loadBeforeQmodIds))
                    {
                        if (__result.Values.SelectMany(x => x).SingleOrDefault(x => x.Metadata.GUID == id) is PluginInfo bepinexPlugin)
                        {
                            Traverse.Create(bepinexPlugin)
                            .Property <IEnumerable <BepInDependency> >(nameof(PluginInfo.Dependencies)).Value
                                = bepinexPlugin.Dependencies.Concat(new[] { new BepInDependency(mod.Id, BepInDependency.DependencyFlags.SoftDependency) });
                        }
                    }

                    var pluginInfo             = new PluginInfo();
                    var traverseablePluginInfo = Traverse.Create(pluginInfo);
                    traverseablePluginInfo.Property <IEnumerable <BepInDependency> >(nameof(PluginInfo.Dependencies)).Value
                        = new List <BepInDependency>(new[] { new BepInDependency(qmmLoaderPluginInfo.Metadata.GUID) });

                    foreach (var id in mod.Dependencies)
                    {
                        traverseablePluginInfo.Property <IEnumerable <BepInDependency> >(nameof(PluginInfo.Dependencies)).Value
                            = pluginInfo.Dependencies.AddItem(new BepInDependency(id, BepInDependency.DependencyFlags.HardDependency));
                    }

                    foreach (var versionDependency in mod.VersionDependencies)
                    {
                        var version = VersionParserService.GetVersion(versionDependency.Value);
                        traverseablePluginInfo.Property <IEnumerable <BepInDependency> >(nameof(PluginInfo.Dependencies)).Value
                            = pluginInfo.Dependencies.AddItem(new BepInDependency(versionDependency.Key, version.ToString()));
                    }
                    foreach (var id in mod.LoadAfter)
                    {
                        traverseablePluginInfo.Property <IEnumerable <BepInDependency> >(nameof(PluginInfo.Dependencies)).Value
                            = pluginInfo.Dependencies.AddItem(new BepInDependency(id, BepInDependency.DependencyFlags.SoftDependency));
                    }

                    traverseablePluginInfo.Property <IEnumerable <BepInProcess> >(nameof(PluginInfo.Processes)).Value = new BepInProcess[0];
                    traverseablePluginInfo.Property <IEnumerable <BepInIncompatibility> >(nameof(PluginInfo.Incompatibilities)).Value = new BepInIncompatibility[0];
                    traverseablePluginInfo.Property <BepInPlugin>(nameof(PluginInfo.Metadata)).Value = new BepInPlugin(mod.Id, mod.DisplayName, mod.ParsedVersion.ToString());
                    traverseablePluginInfo.Property <string>("TypeName").Value = typeof(QModPlugin).FullName;
                    traverseablePluginInfo.Property <Version>("TargettedBepInExVersion").Value
                        = Assembly.GetExecutingAssembly().GetReferencedAssemblies().FirstOrDefault(x => x.Name == "BepInEx").Version;

                    result.Add(dll, new[] { pluginInfo }.ToList());
                    QModPluginInfos.Add(mod.Id, pluginInfo);
                }

                __result[Assembly.GetExecutingAssembly().Location] = QModPluginInfos.Values.Distinct().ToList();

                TypeLoader.SaveAssemblyCache(GeneratedPluginCache, result);
            }
            catch (Exception ex)
            {
                Logger.LogFatal($"Failed to emulate QMods as plugins");
                Logger.LogFatal(ex.ToString());
            }
        }