示例#1
0
        /// <summary>
        /// Used in the deployment chain to deploy mods with the BundledBA2 method.
        /// </summary>
        private static void DeployBundledArchives(ManagedMods mods, bool freezeArchives = false, bool invalidateFrozenArchives = true)
        {
            LogFile.WriteLine($"   Installing BundledBA2 mods...");
            DeployArchiveList archives = new DeployArchiveList(mods.GamePath);

            // We want to use frozen archives but haven't invalidated them...
            // ... so just copy bundled archives if available:
            if (freezeArchives && !invalidateFrozenArchives)
            {
                CopyFrozenBundledArchives(mods.Resources, archives);
                return;
            }

            // Otherwise iterate over each enabled mod...
            foreach (ManagedMod mod in mods)
            {
                if (mod.Enabled && mod.Method == ManagedMod.DeploymentMethod.BundledBA2)
                {
                    LogFile.WriteLine($"      Copy files of mod '{mod.Title}' to temp folder...");

                    // ... copy it's files into temporary folders ...
                    CopyFilesToTempSorted(mod, archives);
                    mod.Deployed       = true;
                    mod.PreviousMethod = ManagedMod.DeploymentMethod.BundledBA2;
                }
            }

            // ... and pack those folders to archives.
            PackBundledArchives(mods.Resources, archives, freezeArchives);
        }
示例#2
0
        public static void RemoveAll(ManagedMods mods)
        {
            LogFile.WriteLine("Removing all installed mods");

            // Delete bundled archives:
            DeployArchiveList deployArchives = new DeployArchiveList(mods.GamePath);

            foreach (DeployArchive deployArchive in deployArchives)
            {
                LogFile.WriteLine($"   Removing {deployArchive.ArchiveName}");
                if (File.Exists(deployArchive.GetArchivePath()))
                {
                    File.Delete(deployArchive.GetArchivePath());
                }
                mods.Resources.Remove(deployArchive.ArchiveName);
            }
            LogFile.WriteLine($"   Deleting temporary folders");
            deployArchives.DeleteTempFolder();

            // Remove mods:
            foreach (ManagedMod mod in mods)
            {
                LogFile.WriteLine($"   Removing mod {mod.Title}");
                ModDeployment.Remove(mod, mods.Resources, mods.GamePath);
            }

            mods.Save();
        }
示例#3
0
 /// <summary>
 /// Deletes all files of the mod and removes it from the list.
 /// Saves the xml file afterwards.
 /// </summary>
 public static void DeleteMod(ManagedMods mods, int index, Action <Progress> ProgressChanged = null)
 {
     ModActions.DeleteFiles(mods[index]);
     mods.RemoveAt(index);
     mods.Save();
     ProgressChanged?.Invoke(Progress.Done("Mod deleted."));
 }
        /// <summary>
        /// Extracts the archive and adds the mod to the list.
        /// Saves the xml file afterwards.
        /// </summary>
        /// <param name="useSourceBA2Archive">When false, creates a new "frozen" mod.</param>
        public static void InstallArchive(ManagedMods mods, string filePath, bool useSourceBA2Archive = false, Action <Progress> ProgressChanged = null)
        {
            ManagedMod newMod = ModInstallations.FromArchive(mods.GamePath, filePath, useSourceBA2Archive, ProgressChanged);

            mods.Add(newMod);
            mods.Save();
            ProgressChanged?.Invoke(Progress.Done("Mod archive installed."));
        }
 /// <summary>
 /// Freezes the mods.
 /// </summary>
 public static void Freeze(ManagedMods mods, IEnumerable <int> indices)
 {
     foreach (int index in indices)
     {
         ModActions.Freeze(mods[index]);
     }
     mods.Save();
 }
        /// <summary>
        /// Copies the folder and adds the mod to the list.
        /// Saves the xml file afterwards.
        /// </summary>
        public static void InstallFolder(ManagedMods mods, string folderPath, Action <Progress> ProgressChanged = null)
        {
            ManagedMod newMod = ModInstallations.FromFolder(mods.GamePath, folderPath, ProgressChanged);

            mods.Add(newMod);
            mods.Save();
            ProgressChanged?.Invoke(Progress.Done("Mod folder installed."));
        }
        /// <summary>
        /// Adds a new blank mod.
        /// </summary>
        public static void InstallBlank(ManagedMods mods)
        {
            ManagedMod newMod = new ManagedMod(mods.GamePath);

            newMod.Title       = "Untitled";
            newMod.ArchiveName = "untitled.ba2";
            Directory.CreateDirectory(newMod.ManagedFolderPath);
            mods.Add(newMod);
            mods.Save();
        }
        /// <summary>
        /// Deletes multiple mods and removes them from the list.
        /// Saves the xml file afterwards.
        /// </summary>
        public static void DeleteMods(ManagedMods mods, List <int> indices, Action <Progress> ProgressChanged = null)
        {
            indices = indices.OrderByDescending(i => i).ToList();
            int fi    = 0;
            int count = indices.Count();

            foreach (int index in indices)
            {
                ProgressChanged?.Invoke(Progress.Ongoing($"Deleting mod {++fi} of {count}.", (float)(fi - 1) / (float)count));
                ModActions.DeleteMod(mods, index);
            }
            ProgressChanged?.Invoke(Progress.Done($"{count} mods deleted."));
        }
        /// <summary>
        /// Unfreezes the mods.
        /// </summary>
        public static void Unfreeze(ManagedMods mods, IEnumerable <int> indices, Action <Progress> ProgressChanged = null)
        {
            int count = indices.Count();
            int n     = 1;

            foreach (int index in indices)
            {
                ModActions.Unfreeze(mods[index]);
                ProgressChanged?.Invoke(Progress.Ongoing($"Unfreezing {n} of {count} mod(s)...", (float)n++ / (float)count));
            }
            mods.Save();
            ProgressChanged?.Invoke(Progress.Done($"{count} mod(s) thawed."));
        }
        /// <summary>
        /// Downloads and installs a mod from NexusMods. (by using NXM links)
        /// </summary>
        /// <param name="useSourceBA2Archive">When false, creates a new "frozen" mod.</param>
        public static bool InstallRemote(ManagedMods mods, string nxmLinkStr, bool useSourceBA2Archive = false, Action <Progress> ProgressChanged = null)
        {
            NXMLink nxmLink = NXMHandler.ParseLink(nxmLinkStr);

            // Get the download link from NexusMods:
            ProgressChanged(Progress.Indetermined("Requesting mod download link..."));
            string dlLinkStr = NMMod.RequestDownloadLink(nxmLink);

            if (dlLinkStr == null)
            {
                ProgressChanged?.Invoke(Progress.Aborted("Couldn't retrieve download link..."));
                return(false);
            }
            Uri    dlLink     = new Uri(dlLinkStr);
            string dlFileName = dlLink.Segments.Last();
            string dlPath     = Path.Combine(Shared.DownloadsFolder, dlFileName);

            // Download mod, unless we already have it:
            if (!File.Exists(dlPath))
            {
                DownloadFile(dlLink.OriginalString, dlPath, ProgressChanged);
            }

            if (!File.Exists(dlPath))
            {
                ProgressChanged?.Invoke(Progress.Aborted("Download failed."));
                return(false);
            }

            // Get remote mod info:
            ProgressChanged(Progress.Indetermined("Requesting mod information and thumbnail..."));
            NMMod nmMod = NexusMods.RequestModInformation(nxmLink.modId);

            // Install mod:
            ProgressChanged(Progress.Indetermined($"Installing '{nmMod.Title}'..."));
            ManagedMod newMod = ModInstallations.FromArchive(mods.GamePath, dlPath, useSourceBA2Archive, ProgressChanged);

            newMod.Title   = nmMod.Title;
            newMod.Version = nmMod.LatestVersion;
            newMod.URL     = nmMod.URL;
            mods.Add(newMod);
            mods.Save();
            ProgressChanged?.Invoke(Progress.Done($"'{nmMod.Title}' installed."));

            return(true);
        }
示例#11
0
 /// <summary>
 /// Searches through each mod.LooseFiles entry to find if the file belongs to a mod.
 /// </summary>
 /// <param name="mods"></param>
 /// <param name="fullPath">Has to be a full path, not a relative path</param>
 /// <returns>true, if a mod has installed this file. false otherwise.</returns>
 private static bool DoesLooseFileBelongToMod(ManagedMods mods, string fullPath)
 {
     foreach (ManagedMod mod in mods)
     {
         if (mod.PreviousMethod == ManagedMod.DeploymentMethod.LooseFiles)
         {
             foreach (string relPath in mod.LooseFiles)
             {
                 string installedPath = Path.Combine(mods.GamePath, mod.RootFolder, relPath);
                 if (installedPath == fullPath)
                 {
                     return(true);
                 }
             }
         }
     }
     return(false);
 }
示例#12
0
        /// <summary>
        /// Used in the deployment chain to deploy a single mod with the Loose method.
        /// </summary>
        private static void DeployLooseFiles(ManagedMods mods, ManagedMod mod, String GamePath)
        {
            LogFile.WriteLine($"   Installing mod '{mod.Title}' as LooseFiles");

            mod.LooseFiles.Clear();

            // Iterate over each file in the managed folder ...
            foreach (string filePath in Directory.EnumerateFiles(mod.ManagedFolderPath, "*.*", SearchOption.AllDirectories))
            {
                // ... extract the relative path ...
                string relPath = Utils.MakeRelativePath(mod.ManagedFolderPath, filePath);
                mod.LooseFiles.Add(relPath);

                // ... determine the full destination path ...
                string   destinationPath = Path.Combine(GamePath, mod.RootFolder, relPath);
                FileInfo destInfo        = new FileInfo(destinationPath);
                Directory.CreateDirectory(destInfo.DirectoryName);

                // ... make a backup if the file already exists ...
                if (File.Exists(destinationPath) && !DoesLooseFileBelongToMod(mods, destinationPath) && !File.Exists(destinationPath + ".old"))
                {
                    File.Move(destinationPath, destinationPath + ".old");
                }

                // ... and copy the file (and replace it if necessary).
                LogFile.WriteLine($"      Copying: \"{relPath}\"");
                if (Configuration.bUseHardlinks)
                {
                    Utils.CreateHardLink(filePath, destinationPath, true);
                }
                else
                {
                    File.Copy(filePath, destinationPath, true);
                }
            }

            mod.CurrentRootFolder = mod.RootFolder;
            mod.Deployed          = true;
            mod.PreviousMethod    = ManagedMod.DeploymentMethod.LooseFiles;
        }
示例#13
0
        /// <summary>
        /// Generates and saves a legacy "manifest.xml" for backwards-compatibility.
        /// </summary>
        /// <param name="mods">Generate a legacy xml for these mods.</param>
        public static void GenerateLegacyXML(ManagedMods mods)
        {
            // I ported the old Serialize methods of the old Mod and old ManagedMods classes.
            // It now uses the new format, but generates an *.xml that is compatible with older versions.
            // Since there is now way more information saved: It uses the current disk state, not the pending one. (PreviousMethod, CurrentArchiveName, etc.)
            // In case the user wants to downgrade, they can.

            XDocument xmlDoc  = new XDocument();
            XElement  xmlRoot = new XElement("Mods");

            xmlRoot.Add(new XAttribute("doNotImport", true));
            xmlDoc.Add(xmlRoot);

            xmlDoc.AddFirst(new XComment($"\n  This file has been generated by v{Shared.VERSION} for backwards-compatibility.\n  It not actually being used anymore.\n"));

            foreach (ManagedMod mod in mods)
            {
                XElement xmlMod = new XElement("Mod",
                                               new XAttribute("title", mod.Title),
                                               new XAttribute("enabled", mod.Deployed),
                                               new XAttribute("modFolder", mod.ManagedFolderName),
                                               new XAttribute("installType", GetLegacyInstallMethodName(mod)));

                if (mod.URL != "")
                {
                    xmlMod.Add(new XAttribute("url", mod.URL));
                }

                if (mod.Version != "")
                {
                    xmlMod.Add(new XAttribute("version", mod.Version));
                }

                if (mod.PreviousMethod == ManagedMod.DeploymentMethod.SeparateBA2 && mod.CurrentArchiveName != null)
                {
                    xmlMod.Add(new XAttribute("archiveName", mod.CurrentArchiveName));
                    xmlMod.Add(new XAttribute("compression", GetLegacyArchiveCompressionName(mod)));
                    xmlMod.Add(new XAttribute("format", GetLegacyArchiveFormatName(mod)));

                    // We can't set the frozen flag anymore, because we store frozen archives differently now:
                    //if (mod.Frozen)
                    //xmlMod.Add(new XAttribute("frozen", mod.Frozen));
                }

                if (mod.PreviousMethod == ManagedMod.DeploymentMethod.LooseFiles && mod.CurrentRootFolder != "")
                {
                    xmlMod.Add(new XAttribute("root", mod.CurrentRootFolder));
                }

                if (mod.PreviousMethod == ManagedMod.DeploymentMethod.LooseFiles && mod.Deployed)
                {
                    foreach (String filePath in mod.LooseFiles)
                    {
                        xmlMod.Add(new XElement("File", new XAttribute("path", filePath)));
                    }
                }

                xmlRoot.Add(xmlMod);
            }

            xmlDoc.Save(Path.Combine(mods.ModsPath, "manifest.xml"));
        }
 /// <summary>
 /// Unfreezes the mod.
 /// </summary>
 public static void Unfreeze(ManagedMods mods, int index, Action <Progress> ProgressChanged = null)
 {
     ModActions.Unfreeze(mods[index]);
     mods.Save();
     ProgressChanged?.Invoke(Progress.Done("Mod thawed."));
 }
示例#15
0
        public static void Deploy(ManagedMods mods, Action <Progress> ProgressChanged, bool invalidateBundledFrozenArchives = true)
        {
            LogFile.WriteLine("\n\n");
            LogFile.WriteTimeStamp();
            LogFile.WriteLine($"Version {Shared.VERSION}, deploying...");
            LogFile.WriteLine($"Game path: {mods.GamePath}");

            // TODO: More descriptive ProgressChanged
            ProgressChanged?.Invoke(Progress.Indetermined("Deploying..."));

            // Check for conflicts:
            LogFile.WriteLine("Checking for conflicting archive names...");
            List <ModHelpers.Conflict> conflicts = ModHelpers.GetConflictingArchiveNames(mods.Mods);

            if (conflicts.Count > 0)
            {
                LogFile.WriteLine("Conflicts found, abort.");
                foreach (ModHelpers.Conflict conflict in conflicts)
                {
                    LogFile.WriteLine($"   Conflict: {conflict.conflictText}");
                }
                throw new DeploymentFailedException("Conflicting archive names.");
            }

            // Restore *.dll files:
            RestoreAddedDLLs(mods.GamePath);

            // Remove all currently deployed mods:
            ProgressChanged?.Invoke(Progress.Indetermined("Removing mods..."));
            ModDeployment.RemoveAll(mods);
            mods.Save();

            // If mods are enabled:
            if (!mods.ModsDisabled)
            {
                LogFile.WriteLine("Installing mods...");

                // Deploy all SeparateBA2 and Loose mods:
                foreach (ManagedMod mod in mods)
                {
                    ProgressChanged?.Invoke(Progress.Indetermined($"Deploying {mod.Title}..."));
                    if (mod.Enabled &&
                        Directory.Exists(mod.ManagedFolderPath) &&
                        !Utils.IsDirectoryEmpty(mod.ManagedFolderPath))
                    {
                        switch (mod.Method)
                        {
                        case ManagedMod.DeploymentMethod.SeparateBA2:
                            DeploySeparateArchive(mod, mods.Resources);
                            mods.Save();
                            break;

                        case ManagedMod.DeploymentMethod.LooseFiles:
                            DeployLooseFiles(mods, mod, mods.GamePath);
                            mods.Save();
                            break;
                        }
                    }
                }

                // Deploy all BundledBA2 mods:
                ProgressChanged?.Invoke(Progress.Indetermined($"Building bundled archives..."));
                ModDeployment.DeployBundledArchives(mods, IniFiles.Config.GetBool("Mods", "bFreezeBundledArchives", false), invalidateBundledFrozenArchives);

                mods.Save();
                ProgressChanged?.Invoke(Progress.Done("Mods deployed."));
            }
            else
            {
                ProgressChanged?.Invoke(Progress.Done("Mods removed."));
            }

            LogFile.WriteLine("Deployment finished.");
            LogFile.WriteLine($"Resource list ({mods.Resources.Count} files): \"{mods.Resources}\"");
        }
 /// <summary>
 /// Freezes the mod.
 /// </summary>
 public static void Freeze(ManagedMods mods, int index)
 {
     ModActions.Freeze(mods[index]);
     mods.Save();
 }
示例#17
0
        /// <summary>
        /// Loads and converts legacy managed mods to the new format.
        /// It adds them to an already existing ManagedMods object.
        /// </summary>
        public static void ConvertLegacy(ManagedMods mods, GameEdition edition, Action <Progress> ProgressChanged = null)
        {
            Directory.CreateDirectory(Path.Combine(mods.GamePath, "FrozenData"));

            XDocument xmlDoc = XDocument.Load(Path.Combine(mods.ModsPath, "manifest.xml"));

            // I added a doNotImport="true" attribute, so I can check, whether the manifest.xml has only been generated for backwards-compatibility.
            // If it exists, we can just skip the import:
            if (xmlDoc.Root.Attribute("doNotImport") != null)
            {
                ProgressChanged?.Invoke(Progress.Aborted("Import skipped."));
                return;
            }

            // Make backups:
            File.Copy(Path.Combine(mods.ModsPath, "manifest.xml"), Path.Combine(mods.ModsPath, "manifest.old.xml"), true);
            if (File.Exists(Path.Combine(mods.ModsPath, "managed.xml")))
            {
                File.Copy(Path.Combine(mods.ModsPath, "managed.xml"), Path.Combine(mods.ModsPath, "managed.old.xml"), true);
            }

            // Converting the legacy list will completely erase the current mod list:
            mods.Mods.Clear();

            /*
             * Converting:
             */
            int modCount = xmlDoc.Descendants("Mod").Count();
            int modIndex = 0;

            foreach (XElement xmlMod in xmlDoc.Descendants("Mod"))
            {
                modIndex++;

                if (xmlMod.Attribute("modFolder") == null)
                {
                    continue;
                }

                ManagedMod mod = new ManagedMod(mods.GamePath);

                string managedFolderName = xmlMod.Attribute("modFolder").Value;
                string managedFolderPath = Path.Combine(mods.ModsPath, managedFolderName);
                string frozenArchivePath = Path.Combine(mods.ModsPath, managedFolderName, "frozen.ba2");
                bool   isFrozen          = File.Exists(frozenArchivePath);

                mod.ManagedFolderName = managedFolderName;

                if (xmlMod.Attribute("title") != null)
                {
                    mod.Title = xmlMod.Attribute("title").Value;
                }

                string progressTitle      = $"Converting \"{mod.Title}\" ({modIndex} of {modCount})";
                float  progressPercentage = (float)modIndex / (float)modCount;

                // In case the mod was "frozen" before,
                // we'll need to move the *.ba2 archive into the FrozenData folder and then extract it.
                if (isFrozen)
                {
                    ProgressChanged?.Invoke(Progress.Ongoing($"{progressTitle}: Extracting *.ba2 archive...", progressPercentage));
                    File.Move(frozenArchivePath, mod.FrozenArchivePath);
                    Archive2.Extract(mod.FrozenArchivePath, managedFolderPath);
                    mod.Frozen = true;
                    mod.Freeze = true;
                }

                // OBSOLETE: We need to rename the old folder to fit with the new format.

                /*if (Directory.Exists(managedFolderPath))
                 * {
                 *  ProgressChanged?.Invoke(Progress.Ongoing($"{progressTitle}: Moving managed folder...", progressPercentage));
                 *  if (Directory.Exists(mod.ManagedFolderPath))
                 *      Directory.Delete(mod.ManagedFolderPath, true);
                 *  Directory.Move(managedFolderPath, mod.ManagedFolderPath);
                 * }*/

                ProgressChanged?.Invoke(Progress.Ongoing($"{progressTitle}: Parsing XML...", progressPercentage));

                if (xmlMod.Attribute("url") != null)
                {
                    mod.URL = xmlMod.Attribute("url").Value;
                }

                if (xmlMod.Attribute("version") != null)
                {
                    mod.Version = xmlMod.Attribute("version").Value;
                }

                if (xmlMod.Attribute("enabled") != null)
                {
                    try
                    {
                        mod.Deployed = XmlConvert.ToBoolean(xmlMod.Attribute("enabled").Value);
                    }
                    catch
                    {
                        mod.Deployed = false;
                    }
                    mod.Enabled = mod.Deployed;
                }

                if (xmlMod.Attribute("installType") != null)
                {
                    switch (xmlMod.Attribute("installType").Value)
                    {
                    case "Loose":
                        mod.PreviousMethod = ManagedMod.DeploymentMethod.LooseFiles;
                        break;

                    case "SeparateBA2":
                        mod.PreviousMethod = ManagedMod.DeploymentMethod.SeparateBA2;
                        break;

                    case "BA2Archive":         // Backward compatibility
                    case "BundledBA2":
                    case "BundledBA2Textures": // Backward compatibility
                    default:
                        mod.PreviousMethod = ManagedMod.DeploymentMethod.BundledBA2;
                        break;
                    }
                    mod.Method = mod.PreviousMethod;
                }

                if (xmlMod.Attribute("format") != null)
                {
                    switch (xmlMod.Attribute("format").Value)
                    {
                    case "General":
                        mod.CurrentFormat = ManagedMod.ArchiveFormat.General;
                        break;

                    case "DDS":     // Backward compatibility
                    case "Textures":
                        mod.CurrentFormat = ManagedMod.ArchiveFormat.Textures;
                        break;

                    case "Auto":
                    default:
                        mod.CurrentFormat = ManagedMod.ArchiveFormat.Auto;
                        break;
                    }
                    mod.Format = mod.CurrentFormat;
                }

                if (xmlMod.Attribute("compression") != null)
                {
                    switch (xmlMod.Attribute("compression").Value)
                    {
                    case "Default":     // Backward compatibility
                    case "Compressed":
                        mod.CurrentCompression = ManagedMod.ArchiveCompression.Compressed;
                        break;

                    case "None":     // Backward compatibility
                    case "Uncompressed":
                        mod.CurrentCompression = ManagedMod.ArchiveCompression.Uncompressed;
                        break;

                    case "Auto":
                    default:
                        mod.CurrentCompression = ManagedMod.ArchiveCompression.Auto;
                        break;
                    }
                    mod.Compression = mod.CurrentCompression;
                }

                if (xmlMod.Attribute("archiveName") != null)
                {
                    mod.CurrentArchiveName = xmlMod.Attribute("archiveName").Value;
                    mod.ArchiveName        = mod.CurrentArchiveName;
                }

                if (xmlMod.Attribute("root") != null)
                {
                    mod.CurrentRootFolder = xmlMod.Attribute("root").Value;
                    mod.RootFolder        = mod.CurrentRootFolder;
                    foreach (XElement xmlFile in xmlMod.Descendants("File"))
                    {
                        if (xmlFile.Attribute("path") != null)
                        {
                            mod.LooseFiles.Add(xmlFile.Attribute("path").Value);
                        }
                    }
                }

                /*if (xmlMod.Attribute("frozen") != null)
                 * {
                 *  frozen = XmlConvert.ToBoolean(xmlMod.Attribute("frozen").Value);
                 * }*/

                mods.Add(mod);
            }

            // Legacy resource list:
            if (IniFiles.Config.GetBool("Preferences", "bMultipleGameEditionsUsed", false))
            {
                string backedUpList = IniFiles.Config.GetString("Mods", $"sResourceIndexFileList{edition}", "");
                string actualList   = IniFiles.F76Custom.GetString("Archive", "sResourceIndexFileList", "");
                if (backedUpList != "")
                {
                    mods.Resources.ReplaceRange(ResourceList.FromString(backedUpList));
                }
                else if (actualList != "")
                {
                    mods.Resources.ReplaceRange(ResourceList.FromString(actualList));
                }
            }

            ProgressChanged?.Invoke(Progress.Ongoing("Saving XML...", 1f));
            mods.Save();

            ProgressChanged?.Invoke(Progress.Done("Legacy mods imported."));
        }
        /// <summary>
        /// Looks through the resource lists in the *.ini and imports *.ba2 archives.
        /// </summary>
        public static void ImportInstalledMods(ManagedMods mods, Action <Progress> ProgressChanged = null)
        {
            // TODO: ProgressChanged for ImportInstalledMods
            ProgressChanged?.Invoke(Progress.Indetermined("Importing already installed mods..."));

            // Get all archives:
            ResourceList IndexFileList = ResourceList.GetResourceIndexFileList();
            ResourceList Archive2List  = ResourceList.GetResourceArchive2List();

            /*
             * Prepare list:
             */

            // Add all archives:
            List <string> installedMods = new List <string>();

            installedMods.AddRange(IndexFileList);
            installedMods.AddRange(Archive2List);
            installedMods.AddRange(mods.Resources);

            // Remove bundled archives:
            installedMods = installedMods.FindAll(e => !e.ToLower().Contains("bundled"));

            // Remove currently managed archives:
            foreach (ManagedMod mod in mods)
            {
                if (mod.PreviousMethod == ManagedMod.DeploymentMethod.SeparateBA2)
                {
                    installedMods.Remove(mod.CurrentArchiveName);
                }
            }

            // Ignore any game files ("SeventySix - *.ba2"):
            foreach (string archiveName in IndexFileList)
            {
                if (archiveName.Trim().ToLower().StartsWith("seventysix"))
                {
                    installedMods.Remove(archiveName);
                }
            }
            foreach (string archiveName in Archive2List)
            {
                if (archiveName.Trim().ToLower().StartsWith("seventysix"))
                {
                    installedMods.Remove(archiveName);
                }
            }
            foreach (string archiveName in mods.Resources)
            {
                if (archiveName.Trim().ToLower().StartsWith("seventysix"))
                {
                    installedMods.Remove(archiveName);
                }
            }

            /*
             * Import installed mods:
             */

            foreach (string archiveName in installedMods)
            {
                string path = Path.Combine(mods.GamePath, "Data", archiveName);
                if (File.Exists(path) && !archiveName.Trim().ToLower().StartsWith("seventysix"))
                {
                    // Import archive:
                    ModInstallations.InstallArchive(mods, path, true);
                    File.Delete(path);

                    // Remove from lists:
                    IndexFileList.Remove(archiveName);
                    Archive2List.Remove(archiveName);
                }
            }

            // Save *.ini files:
            IndexFileList.CommitToINI();
            Archive2List.CommitToINI();
            //IniFiles.Instance.SaveAll();

            mods.Save();
        }