Пример #1
0
        internal static void Check()
        {
            if (PlayerPrefs.GetInt("QModManager_EnableUpdateCheck", 1) == 0)
            {
                Logger.Info("Update check disabled");
                return;
            }

            if (!NetworkUtilities.CheckConnection())
            {
                Logger.Warn("Cannot check for updates, internet disabled");
                return;
            }

            ServicePointManager.ServerCertificateValidationCallback = NetworkUtilities.CustomSCVC;

            using (WebClient client = new WebClient())
            {
                client.DownloadStringCompleted += (sender, e) =>
                {
                    if (e.Error != null)
                    {
                        Logger.Error("There was an error retrieving the latest version from GitHub!");
                        Logger.Exception(e.Error);
                        return;
                    }
                    Parse(e.Result);
                };

                Logger.Debug("Getting the latest version...");
                client.DownloadStringAsync(new Uri(VersionURL));
            }
        }
Пример #2
0
        internal static bool LoadMod(QMod mod)
        {
            if (mod == null || mod.Loaded)
            {
                return(false);
            }

            try
            {
                string[] entryMethodSig = mod.EntryMethod.Split('.');
                string   entryType      = string.Join(".", entryMethodSig.Take(entryMethodSig.Length - 1).ToArray());
                string   entryMethod    = entryMethodSig[entryMethodSig.Length - 1];

                MethodInfo patchMethod = mod.LoadedAssembly.GetType(entryType).GetMethod(entryMethod);
                patchMethod.Invoke(mod.LoadedAssembly, new object[] { });
            }
            catch (ArgumentNullException e)
            {
                Logger.Error($"Could not parse entry method \"{mod.AssemblyName}\" for mod \"{mod.Id}\"");
                Logger.Exception(e);
                erroredMods.Add(mod);

                return(false);
            }
            catch (TargetInvocationException e)
            {
                Logger.Error($"Invoking the specified entry method \"{mod.EntryMethod}\" failed for mod \"{mod.Id}\"");
                Logger.Exception(e);
                return(false);
            }
            catch (Exception e)
            {
                Logger.Error($"An unexpected error occurred whilst trying to load mod \"{mod.Id}\"");
                Logger.Exception(e);
                return(false);
            }

            if (QModAPI.ErroredMods.Contains(mod?.LoadedAssembly))
            {
                Logger.Error($"Mod \"{mod.Id}\" could not be loaded.");
                QModAPI.ErroredMods.Remove(mod?.LoadedAssembly);
                return(false);
            }
            mod.Loaded = true;
            Logger.Info($"Loaded mod \"{mod.Id}\"");

            return(true);
        }
Пример #3
0
 internal static void Parse(string versionStr)
 {
     try
     {
         Version currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
         if (versionStr == null)
         {
             Logger.Error("There was an error retrieving the latest version from GitHub!");
             return;
         }
         Version latestVersion = new Version(versionStr);
         if (latestVersion == null)
         {
             Logger.Error("There was an error retrieving the latest version from GitHub!");
             return;
         }
         if (latestVersion > currentVersion)
         {
             Logger.Info($"Newer version found: {latestVersion.ToStringParsed()} (current version: {currentVersion.ToStringParsed()}");
             if (Patcher.erroredMods.Count <= 0)
             {
                 Dialog.Show(
                     $"There is a newer version of QModManager available: {latestVersion.ToStringParsed()} (current version: {currentVersion.ToStringParsed()})",
                     Dialog.Button.download, Dialog.Button.close, true);
             }
         }
         else
         {
             Logger.Info($"Recieved latest version from GitHub. We are up to date!");
         }
     }
     catch (Exception e)
     {
         Logger.Error("There was an error retrieving the latest version from GitHub!");
         Logger.Exception(e);
         return;
     }
 }
Пример #4
0
        internal static void Patch()
        {
            try
            {
                if (patched)
                {
                    Logger.Warn("Patch method was called multiple times!");
                    return;
                }
                patched = true;

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

                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!");
                    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);
                }

                QModHooks.Load();
#pragma warning disable CS0618 // Type or member is obsolete
                Hooks.Load();
#pragma warning restore CS0618 // Type or member is obsolete

                PirateCheck.IsPirate(Environment.CurrentDirectory);

                if (!DetectGame())
                {
                    return;
                }

                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;
                }

                StartLoadingMods();
                ShowErroredMods();

                VersionCheck.Check();

                QModHooks.Start += PrefabDebugger.Main;

                QModHooks.OnLoadEnd?.Invoke();
#pragma warning disable CS0618 // Type or member is obsolete
                Hooks.OnLoadEnd?.Invoke();
#pragma warning restore CS0618 // Type or member is obsolete

                Logger.Info($"Finished loading QModManager. Loaded {loadedMods.Count} mods");
            }
            catch (Exception e)
            {
                Logger.Error("EXCEPTION CAUGHT!");
                Logger.Exception(e);
            }
        }
Пример #5
0
        internal static void LoadAllMods()
        {
            string toWrite = "Loaded mods:\n";

            List <QMod> loadingErrorMods = new List <QMod>();
            QMod        smlHelper        = null;

            foreach (QMod mod in sortedMods)
            {
                if (mod != null && !mod.Loaded)
                {
                    if (mod.Id != "SMLHelper")
                    {
                        if (!LoadMod(mod))
                        {
                            if (!erroredMods.Contains(mod))
                            {
                                erroredMods.Add(mod);
                            }

                            if (!loadingErrorMods.Contains(mod))
                            {
                                loadingErrorMods.Add(mod);
                            }

                            continue;
                        }
                        else
                        {
                            toWrite += $"- {mod.DisplayName} ({mod.Id})\n";
                            loadedMods.Add(mod);
                        }
                    }
                    else
                    {
                        smlHelper = mod;
                    }
                }
            }
            if (smlHelper != null)
            {
                if (!LoadMod(smlHelper))
                {
                    if (!erroredMods.Contains(smlHelper))
                    {
                        erroredMods.Add(smlHelper);
                    }

                    if (!loadingErrorMods.Contains(smlHelper))
                    {
                        loadingErrorMods.Add(smlHelper);
                    }
                }
                else
                {
                    toWrite += $"- {smlHelper.DisplayName} ({smlHelper.Id})\n";
                    loadedMods.Add(smlHelper);
                }
            }

            if (loadingErrorMods.Count != 0)
            {
                string write = "The following mods could not be loaded:\n";

                foreach (QMod mod in loadingErrorMods)
                {
                    write += $"- {mod.DisplayName} ({mod.Id})\n";
                }

                Logger.Error(write);
            }

            Logger.Info(toWrite);

            CheckOldHarmony();
        }
Пример #6
0
        internal static void StartLoadingMods()
        {
            Logger.Info("Started loading mods");

            AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
            {
                FileInfo[] allDlls = new DirectoryInfo(QModBaseDir).GetFiles("*.dll", SearchOption.AllDirectories);
                foreach (FileInfo dll in allDlls)
                {
                    if (args.Name.Contains(Path.GetFileNameWithoutExtension(dll.Name)))
                    {
                        return(Assembly.LoadFrom(dll.FullName));
                    }
                }

                return(null);
            };

            Logger.Debug("Added AssemblyResolve event");

            if (!Directory.Exists(QModBaseDir))
            {
                Logger.Info("QMods directory was not found! Creating...");

                return;
            }

            string[] subDirs = Directory.GetDirectories(QModBaseDir);

            foreach (string subDir in subDirs)
            {
                if (Directory.GetFiles(subDir, "*.dll", SearchOption.TopDirectoryOnly).Length < 1)
                {
                    continue;
                }

                string folderName = new DirectoryInfo(subDir).Name;
                string jsonFile   = Path.Combine(subDir, "mod.json");

                if (!File.Exists(jsonFile))
                {
                    Logger.Error($"No \"mod.json\" file found for mod located in folder \"{subDir}\". A template file will be created");
                    File.WriteAllText(jsonFile, JsonConvert.SerializeObject(new QMod()));
                    erroredMods.Add(QMod.CreateFakeQMod(folderName));
                    continue;
                }

                QMod mod = QMod.FromJsonFile(Path.Combine(subDir, "mod.json"));

                if (!QMod.QModValid(mod, folderName))
                {
                    erroredMods.Add(QMod.CreateFakeQMod(folderName));

                    continue;
                }

                if (mod.Enable == false)
                {
                    Logger.Info($"Mod \"{mod.DisplayName}\" is disabled via config, skipping...");

                    continue;
                }

                string modAssemblyPath = Path.Combine(subDir, mod.AssemblyName);

                if (!File.Exists(modAssemblyPath))
                {
                    Logger.Error($"No matching dll found at \"{modAssemblyPath}\" for mod \"{mod.DisplayName}\"");
                    erroredMods.Add(mod);

                    continue;
                }

                mod.LoadedAssembly  = Assembly.LoadFrom(modAssemblyPath);
                mod.ModAssemblyPath = modAssemblyPath;
                //mod.MessageReceivers = GetMessageRecievers(mod.LoadedAssembly);

                foundMods.Add(mod);
            }

            // Add the found mods into the sortedMods list
            sortedMods.AddRange(foundMods);

            // Disable mods that are not for the detected game
            // (Disable Subnautica mods if Below Zero is detected and disable Below Zero mods if Subnautica is detected)
            DisableNonApplicableMods();

            // Remove mods with duplicate mod ids if any are found
            RemoveDuplicateModIDs();

            // Sort the mods based on their LoadBefore and LoadAfter properties
            // If any mods break (i.e., a loop is found), they are removed from the list so that they aren't loaded
            // And are outputted into the log.
            SortMods();

            // Check if all the mods' dependencies are present
            // If a mod's dependecies aren't present, that mods isn't loaded and it is outputted in the log.
            CheckForDependencies();

            // Finally, load all the mods after sorting and checking for dependencies.
            // If anything goes wrong during loading, it is outputted in the log.
            LoadAllMods();
        }