public void CreateModStatusList_EarlyErrorsCombineWithSuccessfullMods() { // Arange var factory = new QModFactory(); var earlyErrors = new List <QMod> { new QMod { Id = "1", Status = ModStatus.CanceledByUser }, new QMod { Id = "2", Status = ModStatus.InvalidCoreInfo }, new QMod { Id = "3", Status = ModStatus.MissingAssemblyFile }, new QMod { Id = "4", Status = ModStatus.MissingDependency }, new QMod { Id = "5", Status = ModStatus.MissingPatchMethod }, }; var modsToLoad = new List <QMod> { new QMod { Id = "6", Status = ModStatus.Success }, new QMod { Id = "7", Status = ModStatus.Success }, new QMod { Id = "8", Status = ModStatus.Success }, }; // Act List <QMod> combinedList = factory.CreateModStatusList(earlyErrors, modsToLoad); Assert.AreEqual(earlyErrors.Count + modsToLoad.Count, combinedList.Count); foreach (QMod erroredMod in earlyErrors) { Assert.IsTrue(combinedList.Contains(erroredMod)); } foreach (QMod readyMod in modsToLoad) { Assert.IsTrue(combinedList.Contains(readyMod)); } }
public void CreateModStatusList_WhenMissingVersionDependencies_StatusUpdates(string missingOrOutdatedMod, ModStatus expectedStatus) { // Arange var factory = new QModFactory(new DummyPluginCollection(), new DummyValidator()) { }; var noModsRequired = new RequiredQMod[0]; var earlyErrors = new List <QMod> { new QMod { Id = "5", Status = ModStatus.MissingPatchMethod, RequiredMods = noModsRequired }, }; var modToInspect = new QMod { Id = "8", Status = ModStatus.Success, RequiredMods = new List <RequiredQMod> { new RequiredQMod(missingOrOutdatedMod, "1.0.2") } }; var modsToLoad = new List <QMod> { new QMod { Id = "6", Status = ModStatus.Success, RequiredMods = noModsRequired }, new QMod { Id = "7", Status = ModStatus.Success, ParsedVersion = new Version(1, 0, 1), LoadedAssembly = Assembly.GetExecutingAssembly(), RequiredMods = noModsRequired }, modToInspect }; // Act List <QMod> combinedList = factory.CreateModStatusList(earlyErrors, modsToLoad); // Assert Assert.AreEqual(expectedStatus, modToInspect.Status); }
public void CreateModStatusList_WhenMissingVersionDependencies_StatusUpdates(string missingOrOutdatedMod, ModStatus expectedStatus) { // Arange var earlyErrors = new List <QMod> { new QMod { Id = "5", Status = ModStatus.MissingPatchMethod }, }; var modToInspect = new QMod { Id = "8", Status = ModStatus.Success, RequiredMods = new List <RequiredQMod> { new RequiredQMod(missingOrOutdatedMod, new Version(1, 0, 2)) } }; var modsToLoad = new List <QMod> { new QMod { Id = "6", Status = ModStatus.Success }, new QMod { Id = "7", Status = ModStatus.Success, ParsedVersion = new Version(1, 0, 1) }, modToInspect }; // Act List <QMod> combinedList = QModFactory.CreateModStatusList(earlyErrors, modsToLoad); // Assert Assert.AreEqual(expectedStatus, modToInspect.Status); }
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()); } }