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