Example #1
0
        private static QMod CreateFromJsonManifestFile(string subDirectory)
        {
            string jsonFile = Path.Combine(subDirectory, "mod.json");

            if (!File.Exists(jsonFile))
            {
                return(null);
            }

            try
            {
                var settings = new JsonSerializerSettings
                {
                    MissingMemberHandling = MissingMemberHandling.Ignore
                };

                string jsonText = File.ReadAllText(jsonFile);

                QMod mod = JsonConvert.DeserializeObject <QMod>(jsonText);

                mod.SubDirectory = subDirectory;

                return(mod);
            }
            catch (Exception e)
            {
                Logger.Error($"\"mod.json\" deserialization failed for file \"{jsonFile}\"!");
                Logger.Exception(e);

                return(null);
            }
        }
        private static QMod CreateFromJsonManifestFile(string subDirectory)
        {
            string jsonFile = Path.Combine(subDirectory, "mod.json");

            if (!File.Exists(jsonFile))
            {
                return(null);
            }

            try
            {
                var deserializer = new JsonSerializer
                {
                    NullValueHandling     = NullValueHandling.Ignore,
                    MissingMemberHandling = MissingMemberHandling.Ignore
                };

                string jsonText = File.ReadAllText(jsonFile);

                using StreamReader sr   = new StreamReader(jsonFile);
                using JsonReader reader = new JsonTextReader(sr);
                QMod mod = deserializer.Deserialize <QMod>(reader);

                mod.SubDirectory = subDirectory;

                return(mod);
            }
            catch (Exception e)
            {
                Logger.Error($"\"mod.json\" deserialization failed for file \"{jsonFile}\"!");
                Logger.Exception(e);

                return(null);
            }
        }
        public void LoadAssembly(QMod mod)
        {
            string modAssemblyPath = Path.Combine(mod.SubDirectory, mod.AssemblyName);

            if (string.IsNullOrEmpty(modAssemblyPath) || !File.Exists(modAssemblyPath))
            {
                Logger.Debug($"Did not find a DLL at {modAssemblyPath}");
                mod.Status = ModStatus.MissingAssemblyFile;
                return;
            }
            else
            {
                try
                {
                    mod.LoadedAssembly = Assembly.LoadFrom(modAssemblyPath);
                }
                catch (Exception aEx)
                {
                    Logger.Error($"Failed loading the dll found at \"{modAssemblyPath}\" for mod \"{mod.DisplayName}\"");
                    Logger.Exception(aEx);
                    mod.Status = ModStatus.FailedLoadingAssemblyFile;
                    return;
                }
            }
        }
Example #4
0
        /// <summary>
        /// Searches through all folders in the provided directory and returns an ordered list of mods to load.<para/>
        /// Mods that cannot be loaded will have an unsuccessful <see cref="QMod.Status"/> value.
        /// </summary>
        /// <param name="qmodsDirectory">The QMods directory</param>
        /// <returns>A new, sorted <see cref="List{QMod}"/> ready to be initialized or skipped.</returns>
        public List <QMod> BuildModLoadingList(string qmodsDirectory)
        {
            if (!Directory.Exists(qmodsDirectory))
            {
                Logger.Info("QMods directory was not found! Creating...");
                Directory.CreateDirectory(qmodsDirectory);

                return(new List <QMod>(0));
            }

            string[] subDirectories = Directory.GetDirectories(qmodsDirectory);
            var      modSorter      = new SortedCollection <string, QMod>();
            var      earlyErrors    = new List <QMod>(subDirectories.Length);

            foreach (string subDir in subDirectories)
            {
                string[] dllFiles = Directory.GetFiles(subDir, "*.dll", SearchOption.TopDirectoryOnly);

                if (dllFiles.Length < 1)
                {
                    continue;
                }

                string jsonFile = Path.Combine(subDir, "mod.json");

                string folderName = new DirectoryInfo(subDir).Name;

                if (!File.Exists(jsonFile))
                {
                    Logger.Error($"Unable to set up mod in folder \"{folderName}\"");
                    earlyErrors.Add(new QModPlaceholder(folderName, ModStatus.InvalidCoreInfo));
                    continue;
                }

                QMod mod = CreateFromJsonManifestFile(subDir);

                ModStatus status = Validator.ValidateManifest(mod, subDir);

                if (status != ModStatus.Success)
                {
                    Logger.Debug($"Mod '{mod.Id}' will not be loaded");
                    earlyErrors.Add(mod);
                    continue;
                }

                Logger.Debug($"Sorting mod {mod.Id}");
                bool added = modSorter.AddSorted(mod);
                if (!added)
                {
                    Logger.Debug($"DuplicateId on mod {mod.Id}");
                    mod.Status = ModStatus.DuplicateIdDetected;
                    earlyErrors.Add(mod);
                }
            }

            List <QMod> modsToLoad = modSorter.GetSortedList();

            return(CreateModStatusList(earlyErrors, modsToLoad));
        }
        internal ModStatus FindPatchMethods(QMod qMod)
        {
            if (!string.IsNullOrEmpty(qMod.EntryMethod))
            {
                // Legacy
                string[] entryMethodSig = qMod.EntryMethod.Split('.');
                string   entryType      = string.Join(".", entryMethodSig.Take(entryMethodSig.Length - 1).ToArray());
                string   entryMethod    = entryMethodSig[entryMethodSig.Length - 1];

                MethodInfo jsonPatchMethod = qMod.LoadedAssembly.GetType(entryType).GetMethod(entryMethod, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);

                if (jsonPatchMethod != null && jsonPatchMethod.GetParameters().Length == 0)
                {
                    qMod.PatchMethods[PatchingOrder.NormalInitialize] = new QModPatchMethod(jsonPatchMethod, qMod, PatchingOrder.NormalInitialize);
                }
            }

            // QMM 3.0
            foreach (Type type in qMod.LoadedAssembly.GetTypes())
            {
                foreach (QModCoreAttribute core in type.GetCustomAttributes(typeof(QModCoreAttribute), false))
                {
                    foreach (MethodInfo method in type.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance))
                    {
                        foreach (QModPatchAttributeBase patch in method.GetCustomAttributes(typeof(QModPatchAttributeBase), false))
                        {
                            switch (patch.PatchOrder)
                            {
                            case PatchingOrder.MetaPreInitialize:
                            case PatchingOrder.MetaPostInitialize:
                                patch.ValidateSecretPassword(method, qMod);
                                break;
                            }

                            if (qMod.PatchMethods.TryGetValue(patch.PatchOrder, out QModPatchMethod extra))
                            {
                                if (extra.Method.Name != method.Name)
                                {
                                    return(ModStatus.TooManyPatchMethods);
                                }
                            }
                            else
                            {
                                qMod.PatchMethods[patch.PatchOrder] = new QModPatchMethod(method, qMod, patch.PatchOrder);
                            }
                        }
                    }
                }
            }

            if (qMod.PatchMethods.Count == 0)
            {
                return(ModStatus.MissingPatchMethod);
            }

            return(ModStatus.Success);
        }
Example #6
0
        internal static List <QMod> CreateModStatusList(List <QMod> earlyErrors, List <QMod> modsToLoad)
        {
            var modList = new List <QMod>(modsToLoad.Count + earlyErrors.Count);

            foreach (QMod mod in modsToLoad)
            {
                Logger.Debug($"{mod.Id} ready to load");
                modList.Add(mod);
            }

            foreach (QMod erroredMod in earlyErrors)
            {
                Logger.Debug($"{erroredMod.Id} had an early error");
                modList.Add(erroredMod);
            }

            foreach (QMod mod in modList)
            {
                if (mod.Status != ModStatus.Success)
                {
                    continue;
                }

                if (mod.RequiredMods == null)
                {
                    continue;
                }

                foreach (RequiredQMod requiredMod in mod.RequiredMods)
                {
                    QMod dependency = modsToLoad.Find(d => d.Id == requiredMod.Id);

                    if (dependency == null || dependency.Status != ModStatus.Success)
                    {
                        mod.Status = ModStatus.MissingDependency;
                        break;
                    }

                    if (dependency.ParsedVersion < requiredMod.MinimumVersion)
                    {
                        mod.Status = ModStatus.OutOfDateDependency;
                        break;
                    }
                }
            }

            return(modList);
        }
        private void ValidateDependencies(List <QMod> modsToLoad, QMod mod)
        {
            // Check the mod dependencies
            foreach (RequiredQMod requiredMod in mod.RequiredMods)
            {
                QMod dependencyQMod = modsToLoad.Find(d => d.Id == requiredMod.Id);

                if (dependencyQMod == null) // QMod for dependency was not found
                {
                    if (PluginCollection.IsKnownPlugin(mod.Id))
                    {
                        PluginCollection.MarkAsRequired(mod.Id);
                        continue;// Dependency is a BenInEx plugin, not a QMod, and can be ignored here
                    }
                    else
                    {
                        // Dependency not found
                        Logger.Error($"{mod.Id} cannot be loaded because it is missing a dependency. Missing mod: '{requiredMod.Id}'");
                        mod.Status = ModStatus.MissingDependency;
                        break;
                    }
                }

                if (dependencyQMod.HasDependencies)
                {
                    // If the dependency has any dependencies itself, make sure they are also okay
                    ValidateDependencies(modsToLoad, dependencyQMod);
                }

                if (dependencyQMod.Status != ModStatus.Success)
                {
                    // Dependency failed - treat as missing
                    Logger.Error($"{mod.Id} cannot be loaded because one or more of its dependencies failed to load. Failed dependency: '{requiredMod.Id}'");
                    mod.Status = ModStatus.MissingDependency;
                    break;
                }

                if (dependencyQMod.ParsedVersion < requiredMod.MinimumVersion)
                {
                    // Dependency version is older than the version required by this mod
                    Logger.Error($"{mod.Id} cannot be loaded because its dependency is out of date. Outdated mod: {requiredMod.Id}");
                    mod.Status = ModStatus.OutOfDateDependency;
                    break;
                }
            }
        }
        internal void LoadModsFromDirectories(string[] subDirectories, SortedCollection <string, QMod> modSorter, List <QMod> earlyErrors)
        {
            foreach (string subDir in subDirectories.Where(subDir => (new DirectoryInfo(subDir).Attributes & FileAttributes.Hidden) != FileAttributes.Hidden)) // exclude hidden directories
            {
                string[] dllFiles = Directory.GetFiles(subDir, "*.dll", SearchOption.TopDirectoryOnly);

                if (dllFiles.Length < 1)
                {
                    continue;
                }

                string jsonFile = Path.Combine(subDir, "mod.json");

                string folderName = new DirectoryInfo(subDir).Name;

                if (!File.Exists(jsonFile))
                {
                    Logger.Error($"Unable to set up mod in folder \"{folderName}\"");
                    earlyErrors.Add(new QModPlaceholder(folderName, ModStatus.MissingCoreInfo));
                    continue;
                }

                QMod mod = CreateFromJsonManifestFile(subDir);

                if (mod == null)
                {
                    Logger.Error($"Unable to set up mod in folder \"{folderName}\"");
                    earlyErrors.Add(new QModPlaceholder(folderName, ModStatus.MissingCoreInfo));
                    continue;
                }

                this.Validator.CheckRequiredMods(mod);

                Logger.Debug($"Sorting mod {mod.Id}");
                bool added = modSorter.AddSorted(mod);
                if (!added)
                {
                    Logger.Debug($"DuplicateId on mod {mod.Id}");
                    mod.Status = ModStatus.DuplicateIdDetected;
                    earlyErrors.Add(mod);
                }
            }
        }
Example #9
0
        public void CheckRequiredMods(QMod mod)
        {
            foreach (string item in mod.Dependencies)
            {
                mod.RequiredDependencies.Add(item);
            }

            foreach (string item in mod.LoadBefore)
            {
                mod.LoadBeforePreferences.Add(item);
            }

            foreach (string item in mod.LoadAfter)
            {
                mod.LoadAfterPreferences.Add(item);
            }

            if (mod.VersionDependencies.Count > 0)
            {
                var versionedDependencies = new List <RequiredQMod>(mod.VersionDependencies.Count);
                foreach (KeyValuePair <string, string> item in mod.VersionDependencies)
                {
                    string cleanVersion = VersionRegex.Matches(item.Value)?[0]?.Value;

                    if (string.IsNullOrEmpty(cleanVersion))
                    {
                        versionedDependencies.Add(new RequiredQMod(item.Key));
                    }
                    else if (Version.TryParse(cleanVersion, out Version version))
                    {
                        versionedDependencies.Add(new RequiredQMod(item.Key, version));
                    }
                    else
                    {
                        versionedDependencies.Add(new RequiredQMod(item.Key));
                    }

                    mod.RequiredDependencies.Add(item.Key);
                }

                mod.RequiredMods = versionedDependencies;
            }
        }
Example #10
0
        private void ValidateDependencies(List <QMod> modsToLoad, QMod mod)
        {
            // Check the mod dependencies
            foreach (RequiredQMod requiredMod in mod.RequiredMods)
            {
                QMod dependency = modsToLoad.Find(d => d.Id == requiredMod.Id);

                if (dependency == null || dependency.Status != ModStatus.Success)
                {
                    // Dependency not found or failed
                    Logger.Error($"{mod.Id} cannot be loaded because it is missing a dependency. Missing mod: {requiredMod.Id}");
                    mod.Status = ModStatus.MissingDependency;
                    break;
                }

                if (dependency.LoadedAssembly == null)
                {
                    // Dependency hasn't been validated yet
                    this.Validator.ValidateManifest(dependency);
                }

                if (dependency.Status != ModStatus.Success)
                {
                    // Dependency failed to load successfully
                    // Treat it as missing
                    Logger.Error($"{mod.Id} cannot be loaded because its dependency failed to load. Failed mod: {requiredMod.Id}");
                    mod.Status = ModStatus.MissingDependency;
                    break;
                }

                if (dependency.ParsedVersion < requiredMod.MinimumVersion)
                {
                    // Dependency version is older than the version required by this mod
                    Logger.Error($"{mod.Id} cannot be loaded because its dependency is out of date. Outdated mod: {requiredMod.Id}");
                    mod.Status = ModStatus.OutOfDateDependency;
                    break;
                }
            }
        }
        public void ValidateBasicManifest(QMod mod)
        {
            if (mod.Status != ModStatus.Success)
            {
                return;
            }

            if (mod.PatchMethods.Count > 0)
            {
                return;
            }

            Logger.Debug($"Validating mod '{mod.Id}'");
            if (string.IsNullOrEmpty(mod.Id) ||
                string.IsNullOrEmpty(mod.DisplayName) ||
                string.IsNullOrEmpty(mod.Author))
            {
                mod.Status = ModStatus.MissingCoreInfo;
                return;
            }

            if (!mod.Enable)
            {
                mod.Status = ModStatus.CanceledByUser;
                return;
            }

            if (ProhibitedModIDs.TryGetValue(mod.Id, out ModStatus reason))
            {
                mod.Status = reason;
                return;
            }

            switch (mod.Game)
            {
            case "BelowZero":
                mod.SupportedGame = QModGame.BelowZero;
                break;

            case "Both":
                mod.SupportedGame = QModGame.Both;
                break;

            case "Subnautica":
                mod.SupportedGame = QModGame.Subnautica;
                break;

            default:
            {
                mod.Status = ModStatus.FailedIdentifyingGame;
                return;
            }
            }

            try
            {
                mod.ParsedVersion = VersionParserService.GetVersion(mod.Version);
            }
            catch (Exception vEx)
            {
                Logger.Error($"There was an error parsing version \"{mod.Version}\" for mod \"{mod.DisplayName}\"");
                Logger.Exception(vEx);

                mod.Status = ModStatus.InvalidCoreInfo;
                return;
            }
        }
        public void FindPatchMethods(QMod qMod)
        {
            try
            {
                if (!string.IsNullOrEmpty(qMod.EntryMethod))
                {
                    // Legacy
                    string[] entryMethodSig = qMod.EntryMethod.Split('.');
                    string   entryType      = string.Join(".", entryMethodSig.Take(entryMethodSig.Length - 1).ToArray());
                    string   entryMethod    = entryMethodSig[entryMethodSig.Length - 1];

                    MethodInfo jsonPatchMethod = qMod.LoadedAssembly.GetType(entryType)?.GetMethod(entryMethod, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);

                    if (jsonPatchMethod != null && jsonPatchMethod.GetParameters().Length == 0)
                    {
                        qMod.PatchMethods[PatchingOrder.NormalInitialize] = new QModPatchMethod(jsonPatchMethod, qMod, PatchingOrder.NormalInitialize);
                        qMod.Status = ModStatus.Success;
                        return;
                    }
                }

                // QMM 3.0
                foreach (Type type in qMod.LoadedAssembly.GetTypes())
                {
                    if (type.IsNotPublic || type.IsEnum || type.ContainsGenericParameters)
                    {
                        continue;
                    }

                    foreach (QModCoreAttribute core in type.GetCustomAttributes(typeof(QModCoreAttribute), false))
                    {
                        foreach (MethodInfo method in type.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance))
                        {
                            foreach (QModPatchAttributeBase patch in method.GetCustomAttributes(typeof(QModPatchAttributeBase), false))
                            {
                                switch (patch.PatchOrder)
                                {
                                case PatchingOrder.MetaPreInitialize:
                                case PatchingOrder.MetaPostInitialize:
                                    if (!patch.ValidateSecretPassword(method, qMod))
                                    {
                                        Logger.Error($"The mod {qMod.Id} has an invalid priority patching password.");
                                        qMod.PatchMethods.Clear();
                                        qMod.Status = ModStatus.InvalidCoreInfo;
                                        return;
                                    }
                                    break;
                                }

                                if (qMod.PatchMethods.TryGetValue(patch.PatchOrder, out QModPatchMethod extra))
                                {
                                    if (extra.Method.Name != method.Name)
                                    {
                                        qMod.Status = ModStatus.TooManyPatchMethods;
                                        return;
                                    }
                                }
                                else
                                {
                                    qMod.PatchMethods[patch.PatchOrder] = new QModPatchMethod(method, qMod, patch.PatchOrder);
                                    continue;
                                }
                            }
                        }
                    }
                }
            }
            catch (TypeLoadException tlEx)
            {
                Logger.Debug($"Unable to load types for '{qMod.Id}': " + tlEx.Message);
                qMod.Status = ModStatus.MissingDependency;
            }
            catch (MissingMethodException mmEx)
            {
                Logger.Debug($"Unable to find patch method for '{qMod.Id}': " + mmEx.Message);
                qMod.Status = ModStatus.MissingDependency;
            }
            catch (ReflectionTypeLoadException rtle)
            {
                Logger.Debug($"Unable to load types for '{qMod.Id}': \nInnerException: \n" + rtle.InnerException + "\n LoaderExceptions:\n" + string.Join("/n", rtle.LoaderExceptions.ToList()));
                qMod.Status = ModStatus.MissingDependency;
            }

            qMod.Status = qMod.PatchMethods.Count == 0
                ? ModStatus.MissingPatchMethod
                : ModStatus.Success;
        }
        public void CheckRequiredMods(QMod mod)
        {
            var requiredMods = new Dictionary <string, RequiredQMod>(mod.VersionDependencies.Count + mod.Dependencies.Length);

            foreach (string id in mod.Dependencies)
            {
                mod.RequiredDependencies.Add(id);
                requiredMods.Add(id, new RequiredQMod(id));
            }

            foreach (string id in mod.LoadBefore)
            {
                mod.LoadBeforePreferences.Add(id);
            }

            foreach (string id in mod.LoadAfter)
            {
                mod.LoadAfterPreferences.Add(id);
            }

            if (mod.VersionDependencies.Count > 0)
            {
                foreach (KeyValuePair <string, string> item in mod.VersionDependencies)
                {
                    string id            = item.Key;
                    string versionString = item.Value;

                    Version version = VersionParserService.GetVersion(versionString);

                    requiredMods[id] = new RequiredQMod(id, version);

                    mod.RequiredDependencies.Add(id);
                }
            }

            mod.RequiredMods = requiredMods.Values;

            if (Logger.DebugLogsEnabled)
            {
                string GetModList(IEnumerable <string> modIds)
                {
                    string modList = string.Empty;

                    foreach (var id in modIds)
                    {
                        modList += $"{id} ";
                    }

                    return(modList);
                }

                if (requiredMods.Count > 0)
                {
                    Logger.Debug($"{mod.Id} has required mods: {GetModList(mod.RequiredMods.Select(mod => mod.Id))}");
                }

                if (mod.LoadBeforePreferences.Count > 0)
                {
                    Logger.Debug($"{mod.Id} should load before: {GetModList(mod.LoadBeforePreferences)}");
                }

                if (mod.LoadAfterPreferences.Count > 0)
                {
                    Logger.Debug($"{mod.Id} should load after: {GetModList(mod.LoadAfterPreferences)}");
                }
            }
        }
Example #14
0
        public void ValidateManifest(QMod mod)
        {
            if (mod.Status != ModStatus.Success)
            {
                return;
            }

            if (mod.PatchMethods.Count > 0)
            {
                return;
            }

            Logger.Debug($"Validating mod in '{mod.SubDirectory}'");
            if (string.IsNullOrEmpty(mod.Id) ||
                string.IsNullOrEmpty(mod.DisplayName) ||
                string.IsNullOrEmpty(mod.Author))
            {
                mod.Status = ModStatus.MissingCoreInfo;
                return;
            }

            if (!mod.Enable)
            {
                mod.Status = ModStatus.CanceledByUser;
                return;
            }

            if (ProhibitedModIDs.TryGetValue(mod.Id, out ModStatus reason))
            {
                mod.Status = reason;
                return;
            }

            switch (mod.Game)
            {
            case "BelowZero":
                mod.SupportedGame = QModGame.BelowZero;
                break;

            case "Both":
                mod.SupportedGame = QModGame.Both;
                break;

            case "Subnautica":
                mod.SupportedGame = QModGame.Subnautica;
                break;

            default:
            {
                mod.Status = ModStatus.FailedIdentifyingGame;
                return;
            }
            }

            try
            {
                if (Version.TryParse(mod.Version, out Version version))
                {
                    mod.ParsedVersion = version;
                }
            }
            catch (Exception vEx)
            {
                Logger.Error($"There was an error parsing version \"{mod.Version}\" for mod \"{mod.DisplayName}\"");
                Logger.Exception(vEx);

                mod.Status = ModStatus.InvalidCoreInfo;
                return;
            }

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

            if (string.IsNullOrEmpty(modAssemblyPath) || !File.Exists(modAssemblyPath))
            {
                Logger.Debug($"Did not find a DLL at {modAssemblyPath}");
                mod.Status = ModStatus.MissingAssemblyFile;
                return;
            }
            else
            {
                try
                {
                    mod.LoadedAssembly = Assembly.LoadFrom(modAssemblyPath);
                }
                catch (Exception aEx)
                {
                    Logger.Error($"Failed loading the dll found at \"{modAssemblyPath}\" for mod \"{mod.DisplayName}\"");
                    Logger.Exception(aEx);
                    mod.Status = ModStatus.FailedLoadingAssemblyFile;
                    return;
                }
            }

            ModStatus patchMethodResults = FindPatchMethods(mod);

            if (patchMethodResults != ModStatus.Success)
            {
                mod.Status = patchMethodResults;
                return;
            }
        }
        public ModStatus ValidateManifest(QMod mod, string subDirectory)
        {
            Logger.Debug($"Validating mod in '{subDirectory}'");
            if (string.IsNullOrEmpty(mod.Id) ||
                string.IsNullOrEmpty(mod.DisplayName) ||
                string.IsNullOrEmpty(mod.Author))
            {
                return(mod.Status = ModStatus.MissingCoreInfo);
            }

            switch (mod.Game)
            {
            case "BelowZero":
                mod.SupportedGame = QModGame.BelowZero;
                break;

            case "Both":
                mod.SupportedGame = QModGame.Both;
                break;

            case "Subnautica":
                mod.SupportedGame = QModGame.Subnautica;
                break;

            default:
                return(mod.Status = ModStatus.FailedIdentifyingGame);
            }

            try
            {
                if (System.Version.TryParse(mod.Version, out Version version))
                {
                    mod.ParsedVersion = version;
                }
            }
            catch (Exception vEx)
            {
                Logger.Error($"There was an error parsing version \"{mod.Version}\" for mod \"{mod.DisplayName}\"");
                Logger.Exception(vEx);

                return(mod.Status = ModStatus.InvalidCoreInfo);
            }

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

            if (string.IsNullOrEmpty(modAssemblyPath) || !File.Exists(modAssemblyPath))
            {
                Logger.Debug($"Did not find a DLL at {modAssemblyPath}");
                return(mod.Status = ModStatus.MissingAssemblyFile);
            }
            else
            {
                try
                {
                    mod.LoadedAssembly = Assembly.LoadFrom(modAssemblyPath);
                }
                catch (Exception aEx)
                {
                    Logger.Error($"Failed loading the dll found at \"{modAssemblyPath}\" for mod \"{mod.DisplayName}\"");
                    Logger.Exception(aEx);
                    return(mod.Status = ModStatus.FailedLoadingAssemblyFile);
                }
            }

            try
            {
                ModStatus patchMethodResults = FindPatchMethods(mod);

                if (patchMethodResults != ModStatus.Success)
                {
                    return(mod.Status = patchMethodResults);
                }
            }
            catch (Exception ex)
            {
                Logger.Exception(ex);
                return(mod.Status = ModStatus.MissingPatchMethod);
            }

            foreach (string item in mod.Dependencies)
            {
                mod.RequiredDependencies.Add(item);
            }

            foreach (string item in mod.LoadBefore)
            {
                mod.LoadBeforePreferences.Add(item);
            }

            foreach (string item in mod.LoadAfter)
            {
                mod.LoadAfterPreferences.Add(item);
            }

            if (mod.VersionDependencies.Count > 0)
            {
                var versionedDependencies = new List <RequiredQMod>(mod.VersionDependencies.Count);
                foreach (KeyValuePair <string, string> item in mod.VersionDependencies)
                {
                    string cleanVersion = VersionRegex.Matches(item.Value)?[0]?.Value;

                    if (string.IsNullOrEmpty(cleanVersion))
                    {
                        versionedDependencies.Add(new RequiredQMod(item.Key));
                    }
                    else if (System.Version.TryParse(cleanVersion, out Version version))
                    {
                        versionedDependencies.Add(new RequiredQMod(item.Key, version));
                    }
                    else
                    {
                        versionedDependencies.Add(new RequiredQMod(item.Key));
                    }
                }
            }

            if (!mod.Enable)
            {
                return(mod.Status = ModStatus.CanceledByUser);
            }

            return(mod.Status = ModStatus.Success);
        }
Example #16
0
 internal QModPatchMethod(MethodInfo method, QMod qmod, PatchingOrder order)
 {
     this.Method = method;
     this.Origin = qmod;
     this.Order  = order;
 }