Ejemplo n.º 1
0
        /// <summary>
        /// install mods as an asynchronous operation.
        /// </summary>
        /// <param name="statusToRetain">The status to retain.</param>
        /// <returns>Task&lt;System.Boolean&gt;.</returns>
        public virtual async Task <IReadOnlyCollection <IModInstallationResult> > InstallModsAsync(IEnumerable <IMod> statusToRetain)
        {
            var game = GameService.GetSelected();

            if (game == null)
            {
                return(null);
            }
            var mods              = GetInstalledModsInternal(game, false);
            var descriptors       = new List <IModInstallationResult>();
            var userDirectoryMods = GetAllModDescriptors(Path.Combine(game.UserDirectory, Shared.Constants.ModDirectory), ModSource.Local);

            if (userDirectoryMods?.Count() > 0)
            {
                descriptors.AddRange(userDirectoryMods);
            }
            var workshopDirectoryMods = GetAllModDescriptors(game.WorkshopDirectory, ModSource.Steam);

            if (workshopDirectoryMods?.Count() > 0)
            {
                descriptors.AddRange(workshopDirectoryMods);
            }
            var diffs = descriptors.Where(p => p.Mod != null && !mods.Any(m => m.DescriptorFile.Equals(p.Mod.DescriptorFile, StringComparison.OrdinalIgnoreCase))).ToList();

            if (diffs.Count > 0)
            {
                var result = new List <IModInstallationResult>();
                await ModWriter.CreateModDirectoryAsync(new ModWriterParameters()
                {
                    RootDirectory = game.UserDirectory,
                    Path          = Shared.Constants.ModDirectory
                });

                var tasks = new List <Task>();
                foreach (var diff in diffs.GroupBy(p => p.Mod.DescriptorFile))
                {
                    var installResult = diff.FirstOrDefault();
                    var localDiff     = diff.FirstOrDefault().Mod;
                    if (IsPatchModInternal(localDiff))
                    {
                        continue;
                    }
                    tasks.Add(Task.Run(async() =>
                    {
                        bool shouldLock = CheckIfModShouldBeLocked(game, localDiff);
                        if (statusToRetain != null && !shouldLock)
                        {
                            var mod = statusToRetain.FirstOrDefault(p => p.DescriptorFile.Equals(localDiff.DescriptorFile, StringComparison.OrdinalIgnoreCase));
                            if (mod != null)
                            {
                                shouldLock = mod.IsLocked;
                            }
                        }
                        await ModWriter.WriteDescriptorAsync(new ModWriterParameters()
                        {
                            Mod            = localDiff,
                            RootDirectory  = game.UserDirectory,
                            Path           = localDiff.DescriptorFile,
                            LockDescriptor = shouldLock
                        }, IsPatchModInternal(localDiff));;
                    }));
                    installResult.Installed = true;
                    result.Add(installResult);
                }
                if (tasks.Count > 0)
                {
                    await Task.WhenAll(tasks);

                    Cache.Invalidate(ModsCachePrefix, ConstructModsCacheKey(game, true), ConstructModsCacheKey(game, false));
                }
                if (descriptors.Any(p => p.Invalid))
                {
                    result.AddRange(descriptors.Where(p => p.Invalid));
                }
                return(result);
            }
            if (descriptors.Any(p => p.Invalid))
            {
                return(descriptors.Where(p => p.Invalid).ToList());
            }
            return(null);
        }
Ejemplo n.º 2
0
 /// <summary>
 /// Gets the installed mods internal.
 /// </summary>
 /// <param name="game">The game.</param>
 /// <param name="ignorePatchMods">if set to <c>true</c> [ignore patch mods].</param>
 /// <returns>IEnumerable&lt;IMod&gt;.</returns>
 protected virtual IEnumerable <IMod> GetInstalledModsInternal(string game, bool ignorePatchMods)
 {
     return(GetInstalledModsInternal(GameService.Get().FirstOrDefault(p => p.Type.Equals(game)), ignorePatchMods));
 }
Ejemplo n.º 3
0
        /// <summary>
        /// Evals the definition priority internal.
        /// </summary>
        /// <param name="definitions">The definitions.</param>
        /// <returns>IPriorityDefinitionResult.</returns>
        protected virtual IPriorityDefinitionResult EvalDefinitionPriorityInternal(IEnumerable <IDefinition> definitions)
        {
            // We're expecting properly ordered definitions based on load order.
            // In case of game being included this should be done by the calling method as well,
            // though there should not be any problems since it's all based on a list of strings modOrder.IndexOf(modName).
            // And the game is never a mod. If this changes this is going to be bad for me.
            var game   = GameService.GetSelected();
            var result = GetModelInstance <IPriorityDefinitionResult>();

            if (game != null && definitions?.Count() > 1)
            {
                // Handle localizations differently
                var file = definitions.FirstOrDefault().File ?? string.Empty;
                if (file.StartsWith(Shared.Constants.LocalizationDirectory))
                {
                    IEnumerable <IDefinition> filtered = null;
                    if (definitions.Any(p => p.FileCI.Contains(Shared.Constants.LocalizationReplaceDirectory, StringComparison.OrdinalIgnoreCase)))
                    {
                        var replaceDefinitions = definitions.Where(p => p.FileCI.Contains(Shared.Constants.LocalizationReplaceDirectory, StringComparison.OrdinalIgnoreCase));
                        if (replaceDefinitions.GroupBy(p => p.CustomPriorityOrder).Count() == 1)
                        {
                            filtered = replaceDefinitions.ToList();
                        }
                        else
                        {
                            var topPriority = replaceDefinitions.OrderByDescending(p => p.CustomPriorityOrder).FirstOrDefault().CustomPriorityOrder;
                            filtered = replaceDefinitions.Where(p => p.CustomPriorityOrder == topPriority);
                        }
                    }
                    else
                    {
                        if (definitions.GroupBy(p => p.CustomPriorityOrder).Count() == 1)
                        {
                            filtered = definitions.ToList();
                        }
                        else
                        {
                            var topPriority = definitions.OrderByDescending(p => p.CustomPriorityOrder).FirstOrDefault().CustomPriorityOrder;
                            filtered = definitions.Where(p => p.CustomPriorityOrder == topPriority);
                        }
                    }
                    var uniqueDefinitions = filtered.GroupBy(p => p.ModName).Select(p => p.OrderBy(f => Path.GetFileNameWithoutExtension(f.File), StringComparer.Ordinal).Last());
                    if (uniqueDefinitions.Count() == 1)
                    {
                        var definition = uniqueDefinitions.FirstOrDefault(p => !p.IsFromGame);
                        if (definition == null)
                        {
                            definition = uniqueDefinitions.FirstOrDefault();
                        }
                        result.Definition = definition;
                    }
                    else if (uniqueDefinitions.Count() > 1)
                    {
                        var modDefinitions = uniqueDefinitions.Where(p => !p.IsFromGame);
                        if (!modDefinitions.Any())
                        {
                            definitions = uniqueDefinitions;
                        }
                        result.Definition = modDefinitions.OrderBy(p => Path.GetFileNameWithoutExtension(p.File), StringComparer.Ordinal).Last();
                    }
                }
                else
                {
                    var validDefinitions = definitions.Where(p => p.ExistsInLastFile).ToList();
                    if (validDefinitions.Count == 1)
                    {
                        result.Definition = validDefinitions.FirstOrDefault();
                        // If it's the only valid one assume load order is responsible
                        result.PriorityType = DefinitionPriorityType.ModOrder;
                    }
                    else if (validDefinitions.Count > 1)
                    {
                        var  definitionEvals = new List <DefinitionEval>();
                        var  provider        = DefinitionInfoProviders.FirstOrDefault(p => p.CanProcess(game.Type));
                        bool isFios          = false;
                        if (provider != null)
                        {
                            bool overrideSkipped = false;
                            isFios = provider.DefinitionUsesFIOSRules(validDefinitions.First());
                            foreach (var item in validDefinitions)
                            {
                                var fileName     = isFios ? item.AdditionalFileNames.OrderBy(p => Path.GetFileNameWithoutExtension(p), StringComparer.Ordinal).First() : item.AdditionalFileNames.OrderBy(p => Path.GetFileNameWithoutExtension(p), StringComparer.Ordinal).Last();
                                var hasOverrides = validDefinitions.Any(p => !p.IsCustomPatch && p.Dependencies != null && p.Dependencies.Any(d => d.Equals(item.ModName)) &&
                                                                        (isFios ? p.AdditionalFileNames.OrderBy(p => Path.GetFileNameWithoutExtension(p), StringComparer.Ordinal).First().Equals(fileName) : p.AdditionalFileNames.OrderBy(p => Path.GetFileNameWithoutExtension(p), StringComparer.Ordinal).Last().Equals(fileName)));
                                if (hasOverrides)
                                {
                                    overrideSkipped = true;
                                    continue;
                                }
                                definitionEvals.Add(new DefinitionEval()
                                {
                                    Definition = item,
                                    FileName   = fileName
                                });
                            }
                            List <DefinitionEval> uniqueDefinitions;
                            if (isFios)
                            {
                                uniqueDefinitions = definitionEvals.GroupBy(p => p.Definition.ModName).Select(p => p.OrderBy(f => Path.GetFileNameWithoutExtension(f.FileName), StringComparer.Ordinal).First()).ToList();
                            }
                            else
                            {
                                uniqueDefinitions = definitionEvals.GroupBy(p => p.Definition.ModName).Select(p => p.OrderBy(f => Path.GetFileNameWithoutExtension(f.FileName), StringComparer.Ordinal).Last()).ToList();
                            }
                            // Filter out game definitions which might have the same filename
                            var filteredGameDefinitions = false;
                            var gameDefinitions         = uniqueDefinitions.GroupBy(p => p.FileNameCI).Where(p => p.Any(a => a.Definition.IsFromGame)).SelectMany(p => p.Where(w => w.Definition.IsFromGame));
                            if (gameDefinitions.Any())
                            {
                                filteredGameDefinitions = true;
                                foreach (var gameDef in gameDefinitions)
                                {
                                    uniqueDefinitions.Remove(gameDef);
                                }
                            }
                            if (uniqueDefinitions.Count == 1 && (overrideSkipped || filteredGameDefinitions))
                            {
                                var definition = definitionEvals.FirstOrDefault(p => !p.Definition.IsFromGame);
                                if (definition == null)
                                {
                                    definition = definitionEvals.FirstOrDefault();
                                }
                                result.Definition = definition.Definition;
                                if (overrideSkipped)
                                {
                                    result.PriorityType = DefinitionPriorityType.ModOverride;
                                }
                                else if (filteredGameDefinitions)
                                {
                                    result.PriorityType = DefinitionPriorityType.ModOrder;
                                }
                            }
                            else if (uniqueDefinitions.Count > 1)
                            {
                                // Has same filenames?
                                if (uniqueDefinitions.GroupBy(p => p.FileNameCI).Count() == 1)
                                {
                                    if (uniqueDefinitions.Any(p => p.Definition.IsCustomPatch))
                                    {
                                        result.Definition   = uniqueDefinitions.FirstOrDefault(p => p.Definition.IsCustomPatch).Definition;
                                        result.PriorityType = DefinitionPriorityType.ModOrder;
                                    }
                                    else
                                    {
                                        result.Definition   = uniqueDefinitions.Last().Definition;
                                        result.PriorityType = DefinitionPriorityType.ModOrder;
                                    }
                                }
                                else
                                {
                                    // Using FIOS or LIOS?
                                    if (isFios)
                                    {
                                        result.Definition   = uniqueDefinitions.OrderBy(p => Path.GetFileNameWithoutExtension(p.FileName), StringComparer.Ordinal).First().Definition;
                                        result.PriorityType = DefinitionPriorityType.FIOS;
                                    }
                                    else
                                    {
                                        result.Definition   = uniqueDefinitions.OrderBy(p => Path.GetFileNameWithoutExtension(p.FileName), StringComparer.Ordinal).Last().Definition;
                                        result.PriorityType = DefinitionPriorityType.LIOS;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (result.Definition == null)
            {
                var definition = definitions?.FirstOrDefault(p => !p.IsFromGame);
                if (definition == null && (definitions?.Any()).GetValueOrDefault())
                {
                    definition = definitions.FirstOrDefault();
                }
                result.Definition = definition;
            }
            return(result);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// install mods as an asynchronous operation.
        /// </summary>
        /// <param name="statusToRetain">The status to retain.</param>
        /// <returns>Task&lt;System.Boolean&gt;.</returns>
        public virtual async Task <IReadOnlyCollection <IModInstallationResult> > InstallModsAsync(IEnumerable <IMod> statusToRetain)
        {
            var game = GameService.GetSelected();

            if (game == null)
            {
                return(null);
            }
            var mods              = GetInstalledModsInternal(game, false);
            var descriptors       = new List <IModInstallationResult>();
            var userDirectoryMods = GetAllModDescriptors(Path.Combine(game.UserDirectory, Shared.Constants.ModDirectory), ModSource.Local);

            if (userDirectoryMods?.Count() > 0)
            {
                descriptors.AddRange(userDirectoryMods);
            }
            if (!string.IsNullOrWhiteSpace(game.CustomModDirectory))
            {
                var customMods = GetAllModDescriptors(GetModDirectoryRootPath(game), ModSource.Local);
                if (customMods != null && customMods.Any())
                {
                    descriptors.AddRange(customMods);
                }
            }
            var workshopDirectoryMods = game.WorkshopDirectory.SelectMany(p => GetAllModDescriptors(p, ModSource.Steam));

            if (workshopDirectoryMods.Any())
            {
                descriptors.AddRange(workshopDirectoryMods);
            }
            var filteredDescriptors = new List <IModInstallationResult>();
            var grouped             = descriptors.GroupBy(p => p.ParentDirectory);

            foreach (var item in grouped)
            {
                if (item.Any())
                {
                    if (item.All(p => p.IsFile))
                    {
                        filteredDescriptors.AddRange(item);
                    }
                    else
                    {
                        filteredDescriptors.AddRange(item.Where(p => !p.IsFile));
                    }
                }
            }
            var diffs = filteredDescriptors.Where(p => p.Mod != null && !mods.Any(m => m.DescriptorFile.Equals(p.Mod.DescriptorFile, StringComparison.OrdinalIgnoreCase) && m.Version.Equals(p.Mod.Version) && m.Name.Equals(p.Mod.Name))).ToList();

            if (diffs.Count > 0)
            {
                var result = new List <IModInstallationResult>();
                await ModWriter.CreateModDirectoryAsync(new ModWriterParameters()
                {
                    RootDirectory = game.UserDirectory,
                    Path          = Shared.Constants.ModDirectory
                });

                var tasks = new List <Task>();
                foreach (var diff in diffs.GroupBy(p => p.Mod.DescriptorFile))
                {
                    var installResult = diff.FirstOrDefault();
                    var localDiff     = diff.FirstOrDefault().Mod;
                    if (IsPatchModInternal(localDiff))
                    {
                        continue;
                    }
                    tasks.Add(Task.Run(async() =>
                    {
                        bool shouldLock = CheckIfModShouldBeLocked(game, localDiff);
                        if (statusToRetain != null && !shouldLock)
                        {
                            var mod = statusToRetain.FirstOrDefault(p => p.DescriptorFile.Equals(localDiff.DescriptorFile, StringComparison.OrdinalIgnoreCase));
                            if (mod != null)
                            {
                                shouldLock = mod.IsLocked;
                            }
                        }
                        await ModWriter.WriteDescriptorAsync(new ModWriterParameters()
                        {
                            Mod            = localDiff,
                            RootDirectory  = game.UserDirectory,
                            Path           = localDiff.DescriptorFile,
                            LockDescriptor = shouldLock
                        }, IsPatchModInternal(localDiff));
                    }));
                    installResult.Installed = true;
                    result.Add(installResult);
                }
                if (tasks.Count > 0)
                {
                    await Task.WhenAll(tasks);

                    Cache.Invalidate(new CacheInvalidateParameters()
                    {
                        Region = ModsCacheRegion, Prefix = game.Type, Keys = new List <string> {
                            GetModsCacheKey(true), GetModsCacheKey(false)
                        }
                    });
                }
                if (filteredDescriptors.Any(p => p.Invalid))
                {
                    result.AddRange(filteredDescriptors.Where(p => p.Invalid));
                }
                return(result);
            }
            if (filteredDescriptors.Any(p => p.Invalid))
            {
                return(filteredDescriptors.Where(p => p.Invalid).ToList());
            }
            return(null);
        }