예제 #1
0
        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));
            }
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
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());
            }
        }