Beispiel #1
0
        private void BtnSaveToFile_Click(object sender, EventArgs eventArgs)
        {
            try
            {
                CopyDir.Copy(this.SelectedSave.SaveFolder, this.tbSaveLocation.Text);

                foreach (KeyValuePair <string, byte[]> convertSaveByte in this.SaveFilesDictionary)
                {
                    string saveTo = Directory.GetFiles(this.tbSaveLocation.Text, "*.sav", SearchOption.AllDirectories)
                                    .First(e => Path.GetFileName(convertSaveByte.Key) == "option.sav" ||
                                           Path.GetFileName(e) == Path.GetFileName(convertSaveByte.Key) &&
                                           Directory.GetParent(e).Name == Directory.GetParent(convertSaveByte.Key).Name);

                    File.WriteAllBytes(saveTo, convertSaveByte.Value);
                }

                this.SelectedSave = new Save(this.tbSaveLocation.Text, true);
            }
            catch (Exception exception)
            {
                File.WriteAllText(Path.Combine(Application.StartupPath, $"error-{DateTime.Now.ToFileTime()}.log"), exception.ToString());

                MessageBox.Show("Error writing save files to disk! Create an issue at https://github.com/JordanZeotni/BotW-Save-Manager with the error log **IF** you think its **NOT** a permission error.", exception.Message);

                return;
            }

            MessageBox.Show("Files written successfully!");
        }
Beispiel #2
0
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            _noExifPath = _folderPath + @"\" + NoExifsFolder + DateTime.Now.ToString("_yyyy-MM-dd_hhmmss");
            // Create file sansexif.
            var di = Directory.CreateDirectory(_noExifPath);

            backgroundWorker1.ReportProgress(10);

            // Côpy pict in folder.
            Copy();

            backgroundWorker1.ReportProgress(20);

            // Copy the exif exec.
            CopyExec();// File.Copy(@"C:\_NICO\perso\winform\exiftool.exe", _noExifPath);

            backgroundWorker1.ReportProgress(30);

            var command       = "start exiftool.exe -all= *.jpg";
            var removeBatPath = MakeBatFile(command, BatNameSup);

            backgroundWorker1.ReportProgress(40);

            System.Diagnostics.Process.Start(removeBatPath);

            backgroundWorker1.ReportProgress(50);

            /* var artist = string.IsNullOrEmpty(textBoxArtist.Text) ? @"Sortido Pict" : textBoxArtist.Text;
             * var copyrights = string.IsNullOrEmpty(textBoxCopyrights.Text) ? @"sortidopict" : textBoxCopyrights.Text;*/

            command = "start exiftool -artist=\"" + _artist + "\" -copyright=\"" + _copyrights + "\" *.jpg";

            var addBatPath = MakeBatFile(command, BatNameAdd);

            backgroundWorker1.ReportProgress(60);

            System.Diagnostics.Process.Start(addBatPath);

            backgroundWorker1.ReportProgress(70);

            // After delete all the tmp files.
            deleteFilesTmp();

            backgroundWorker1.ReportProgress(80);

            if (!string.IsNullOrEmpty(_nasPath))
            {
                var sourceDirectory = _noExifPath;
                var targetDirectory = _nasPath + @"\" + DateTime.Now.ToString("yyyy-MM-dd_hhmmss");

                CopyDir.Copy(sourceDirectory, targetDirectory);
            }

            backgroundWorker1.ReportProgress(90);
            backgroundWorker1.ReportProgress(100);
        }
        public void CopyAllFilesAndSubdirectories(MockFileSystem mockFileSystem, string sourceDir, string destinationDir, MockFileSystem expectedMockFileSystem)
        {
            var copyDir = new CopyDir(mockFileSystem);

            copyDir.CopyAll(sourceDir, destinationDir);

            //TO-DO: Replace with proper equality comparer
            Assert.Equal(mockFileSystem.AllPaths.OrderBy(s => s), expectedMockFileSystem.AllPaths.OrderBy(s => s));
            Assert.Equal(mockFileSystem.AllFiles.Select(filePath => mockFileSystem.GetFile(filePath).TextContents).OrderBy(s => s), expectedMockFileSystem.AllFiles.Select(filePath => expectedMockFileSystem.GetFile(filePath).TextContents).OrderBy(s => s));
        }
Beispiel #4
0
        //public static string WINDOWS = "windows";
        //public static string MAC = "mac";
        //public static string LINUX = "linux";

        public Project(string file = "")
        {
            passages = new List <Passage>();
            events   = new List <GameEvent>();
            if (file != "")
            {
                this.file = file;
                path      = file.Substring(0, file.LastIndexOf("\\"));
                CopyDir.Copy("engine/", path + "/engine/");
            }
        }
Beispiel #5
0
        public bool ExportAllDatabases(string destinationDir = null)
        {
            DataBaseParam param = this.InitializeAndGetDataBaseParams(destinationDir);

            CleanDirectoryForBackUp(param);

            CopyDir.Copy(param.DbStorageLocation, param.ExportDir);
            CopyDir.Copy(param.DestinationFilesStorage, param.ExportDir + "\\" + param.DestinationFilesStorageName);

            string dest = param.BackUpDir + "\\" + param.ExportDirName + "-" + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss-fff") + ".zip";

            ZipFile.CreateFromDirectory(param.ExportDir, dest);

            return(true);
        }
Beispiel #6
0
        public static void ClassInit(TestContext TC)
        {
            mTC = TC;
            string sampleSolutionFolder = TestResources.GetTestResourcesFolder(@"Solutions\EnvsTest");

            SolutionFolder = TestResources.getGingerUnitTesterTempFolder(@"Solutions\EnvsTest");
            if (Directory.Exists(SolutionFolder))
            {
                Directory.Delete(SolutionFolder, true);
            }
            CopyDir.Copy(sampleSolutionFolder, SolutionFolder);

            mGingerAutomator = GingerAutomator.StartSession();
            mGingerAutomator.OpenSolution(SolutionFolder);
        }
Beispiel #7
0
        public static void ClassInit(TestContext testContext)
        {
            //Arrange
            string name        = "MyNewPOM";
            string description = "MyDescription";

            string sampleSolutionFolder = TestResources.GetTestResourcesFolder(@"Solutions\POMsTest");
            string SolutionFolder       = TestResources.GetTestTempFolder(@"Solutions\POMsTest");

            if (Directory.Exists(SolutionFolder))
            {
                Directory.Delete(SolutionFolder, true);
            }

            CopyDir.Copy(sampleSolutionFolder, SolutionFolder);
            GingerAutomator mGingerAutomator = GingerAutomator.StartSession();

            mGingerAutomator.OpenSolution(SolutionFolder);

            mPOMsPOM = mGingerAutomator.MainWindowPOM.GotoPOMs();

            Agent mChromeAgent = (from x in WorkSpace.Instance.SolutionRepository.GetAllRepositoryItems <Agent>() where x.Name == "ChromeAgent" select x).SingleOrDefault();

            //Act
            prioritizedLocatorsList = new List <ElementLocator>()
            {
                new ElementLocator()
                {
                    Active = false, LocateBy = eLocateBy.ByName
                },
                new ElementLocator()
                {
                    Active = true, LocateBy = eLocateBy.ByID
                },
                new ElementLocator()
                {
                    Active = false, LocateBy = eLocateBy.ByXPath
                },
                new ElementLocator()
                {
                    Active = true, LocateBy = eLocateBy.ByRelXPath
                }
            };
            mLearnedPOM = mPOMsPOM.CreatePOM(name, description, "MyWebApp", mChromeAgent, @"HTML\HTMLControls.html", new List <eElementType>()
            {
                eElementType.HyperLink, eElementType.Table, eElementType.ListItem
            }, prioritizedLocatorsList);
        }
Beispiel #8
0
 private void setupBid()
 {
     if (IsFileLocked(BidLog))
     {
         MessageBox.Show("Please close the bid log before proceeding.");
     }
     else if (!File.Exists(BidFolder + @"\Proposal Opening Form.docx"))
     {
         MessageBox.Show("Please provide a reference fodler with a propopsal opening form.");
     }
     else
     {
         CopyDir.Copy(ReferenceFolder, BidFolder);
         writeToProposalOpening();
         writeToBidLog(BidLog);
         setupEvent(BidNumber, ProjectName, DueDate);
     }
 }
Beispiel #9
0
        private static void CreateTestSolution()
        {
            string sourceFolder = TestResources.GetTestResourcesFolder(@"Solutions\ReportSR");

            solutionFolder = TestResources.getGingerUnitTesterTempFolder(@"Solutions\ReportSR");
            if (Directory.Exists(solutionFolder))
            {
                Directory.Delete(solutionFolder, true);
            }
            CopyDir.Copy(sourceFolder, solutionFolder);

            SolutionRepository SR = new SolutionRepository();

            SR = Ginger.App.CreateGingerSolutionRepository();
            SR.Open(solutionFolder);

            SR.Close();
        }
Beispiel #10
0
        public static void ClassInit(TestContext TC)
        {
            mTC = TC;
            mGingerAutomator.StartGinger();

            string sampleSolutionFolder = TestResources.GetTestResourcesFolder(@"Solutions\EnvsTest");

            SolutionFolder = TestResources.getGingerUnitTesterTempFolder(@"Solutions\EnvsTest");
            if (Directory.Exists(SolutionFolder))
            {
                Directory.Delete(SolutionFolder, true);
            }

            CopyDir.Copy(sampleSolutionFolder, SolutionFolder);

            mGingerAutomator.OpenSolution(SolutionFolder);

            LogFile = mTC.TestLogsDir + @"\GingerWPF_BasicsTest.txt";
        }
Beispiel #11
0
        static public void Main(string[] args)
        {
            if (args.Length == 1)
            {
                RenameFiles.Rename(args[0]);
            }
            else if (args.Length == 2)
            {
                string sourceDirectory = args[0];
                string targetDirectory = args[1];

                DirectoryInfo diSource = new DirectoryInfo(sourceDirectory);
                DirectoryInfo diTarget = new DirectoryInfo(targetDirectory);

                CopyDir.CopyAll(diSource, diTarget);
            }
            else
            {
                Console.WriteLine("Illegal arguments.");
            }
        }
Beispiel #12
0
    public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
    {
        var sourceDirectory     = "TestAssets/Clean";
        var destDirectory       = new FileInfo(pathToBuiltProject).Directory.FullName;
        var sourceDirectoryInfo = new DirectoryInfo(sourceDirectory);

        foreach (var sourceSubDirectory in sourceDirectoryInfo.GetDirectories())
        {
            var destSubDirectory = Path.Combine(destDirectory, sourceSubDirectory.Name);
            CopyDir.Copy(sourceSubDirectory.FullName, destSubDirectory);
        }

        foreach (var file in sourceDirectoryInfo.GetFiles())
        {
            var destFile = Path.Combine(destDirectory, file.Name);
            if (!File.Exists(destFile))
            {
                File.Copy(file.FullName, destFile);
            }
        }
    }
Beispiel #13
0
        public static void ClassInit(TestContext TC)
        {
            TC.WriteLine("@@@@@@@@@@@@@@@@@@@@@@ ClassInit @@@@@@@@@@@@@@@@@@@@@@@@@@@@");
            mTC = TC;
            Console.WriteLine("===> Starting Ginger");
            mGingerAutomator = new GingerAutomator();
            mGingerAutomator.StartGinger();
            string sampleSolutionFolder = TestResources.GetTestResourcesFolder(@"Solutions\EnvsTest");

            SolutionFolder = TestResources.getGingerUnitTesterTempFolder(@"Solutions\EnvsTest");
            if (Directory.Exists(SolutionFolder))
            {
                Directory.Delete(SolutionFolder, true);
            }

            CopyDir.Copy(sampleSolutionFolder, SolutionFolder);

            Console.WriteLine("===> Open solution");
            TC.WriteLine("@@@@@@@@@@@@@@@@@@@@@@ Open solution @@@@@@@@@@@@@@@@@@@@@@@@@@@@");
            mGingerAutomator.OpenSolution(SolutionFolder);

            LogFile = mTC.TestLogsDir + @"\Ginger_BasicsTest.txt";
        }
        private void InstallModBackgroundThread(object sender, DoWorkEventArgs e)
        {
            Log.Information($"Mod Installer Background thread starting");
            var installationJobs = ModBeingInstalled.InstallationJobs;
            var gamePath         = gameTarget.TargetPath;
            var gameDLCPath      = MEDirectories.DLCPath(gameTarget);

            Directory.CreateDirectory(gameDLCPath); //me1/me2 missing dlc might not have this folder

            //Check we can install
            var missingRequiredDLC = ModBeingInstalled.ValidateRequiredModulesAreInstalled(gameTarget);

            if (missingRequiredDLC.Count > 0)
            {
                e.Result = (ModInstallCompletedStatus.INSTALL_FAILED_REQUIRED_DLC_MISSING, missingRequiredDLC);
                return;
            }


            //Check/warn on official headers
            if (!PrecheckHeaders(gameDLCPath, installationJobs))
            {
                e.Result = ModInstallCompletedStatus.INSTALL_FAILED_USER_CANCELED_MISSING_MODULES;
                return;
            }

            //todo: If statment on this
            Utilities.InstallBinkBypass(gameTarget); //Always install binkw32, don't bother checking if it is already ASI version.

            //Prepare queues
            (Dictionary <ModJob, (Dictionary <string, string> fileMapping, List <string> dlcFoldersBeingInstalled)> unpackedJobMappings,
             List <(ModJob job, string sfarPath, Dictionary <string, string> sfarInstallationMapping)> sfarJobs)installationQueues =
                ModBeingInstalled.GetInstallationQueues(gameTarget);

            if (gameTarget.ALOTInstalled)
            {
                //Check if any packages are being installed. If there are, we will block this installation.
                bool installsPackageFile = false;
                foreach (var jobMappings in installationQueues.unpackedJobMappings)
                {
                    installsPackageFile |= jobMappings.Value.fileMapping.Keys.Any(x => x.EndsWith(".pcc", StringComparison.InvariantCultureIgnoreCase));
                    installsPackageFile |= jobMappings.Value.fileMapping.Keys.Any(x => x.EndsWith(".u", StringComparison.InvariantCultureIgnoreCase));
                    installsPackageFile |= jobMappings.Value.fileMapping.Keys.Any(x => x.EndsWith(".upk", StringComparison.InvariantCultureIgnoreCase));
                    installsPackageFile |= jobMappings.Value.fileMapping.Keys.Any(x => x.EndsWith(".sfm", StringComparison.InvariantCultureIgnoreCase));
                }

                foreach (var jobMappings in installationQueues.sfarJobs)
                {
                    installsPackageFile |= jobMappings.sfarInstallationMapping.Keys.Any(x => x.EndsWith(".pcc", StringComparison.InvariantCultureIgnoreCase));
                    installsPackageFile |= jobMappings.sfarInstallationMapping.Keys.Any(x => x.EndsWith(".u", StringComparison.InvariantCultureIgnoreCase));
                    installsPackageFile |= jobMappings.sfarInstallationMapping.Keys.Any(x => x.EndsWith(".upk", StringComparison.InvariantCultureIgnoreCase));
                    installsPackageFile |= jobMappings.sfarInstallationMapping.Keys.Any(x => x.EndsWith(".sfm", StringComparison.InvariantCultureIgnoreCase));
                }

                if (installsPackageFile)
                {
                    if (Settings.DeveloperMode)
                    {
                        Log.Warning("ALOT is installed and user is attemping to install a mod (in developer mode). Prompting user to cancel installation");

                        bool cancel = false;
                        Application.Current.Dispatcher.Invoke(delegate
                        {
                            var res = Xceed.Wpf.Toolkit.MessageBox.Show(Window.GetWindow(this), $"ALOT is installed and this mod installs package files. Continuing to install this mod will likely cause broken textures to occur or game crashes due to invalid texture pointers and possibly empty mips. It will also put your ALOT installation into an unsupported configuration.\n\nContinue to install {ModBeingInstalled.ModName}? You have been warned.", $"Broken textures warning", MessageBoxButton.YesNo, MessageBoxImage.Error, MessageBoxResult.No);
                            cancel  = res == MessageBoxResult.No;
                        });
                        if (cancel)
                        {
                            e.Result = ModInstallCompletedStatus.USER_CANCELED_INSTALLATION;
                            return;
                        }
                        Log.Warning("User installing mod anyways even with ALOT installed");
                    }
                    else
                    {
                        Log.Error("ALOT is installed. Installing mods that install package files after installing ALOT is not permitted.");
                        //ALOT Installed, this is attempting to install a package file
                        e.Result = ModInstallCompletedStatus.INSTALL_FAILED_ALOT_BLOCKING;
                        return;
                    }
                }
            }
            Action            = $"Installing";
            PercentVisibility = Visibility.Visible;
            Percent           = 0;

            int numdone = 0;

            //Calculate number of installation tasks beforehand
            int numFilesToInstall = installationQueues.unpackedJobMappings.Select(x => x.Value.fileMapping.Count).Sum();

            numFilesToInstall += installationQueues.sfarJobs.Select(x => x.sfarInstallationMapping.Count).Sum() * (ModBeingInstalled.IsInArchive ? 2 : 1); //*2 as we have to extract and install
            Debug.WriteLine("Number of expected installation tasks: " + numFilesToInstall);
            void FileInstalledCallback(string target)
            {
                numdone++;
                Debug.WriteLine("Installed: " + target);
                Action = "Installing";
                var now = DateTime.Now;

                if (numdone > numFilesToInstall)
                {
                    Debug.WriteLine($"Percentage calculated is wrong. Done: {numdone} NumToDoTotal: {numFilesToInstall}");
                }
                if ((now - lastPercentUpdateTime).Milliseconds > PERCENT_REFRESH_COOLDOWN)
                {
                    //Don't update UI too often. Once per second is enough.
                    Percent = (int)(numdone * 100.0 / numFilesToInstall);
                    lastPercentUpdateTime = now;
                }
            }

            //Stage: Unpacked files build map
            Dictionary <string, string> fullPathMappingDisk      = new Dictionary <string, string>();
            Dictionary <int, string>    fullPathMappingArchive   = new Dictionary <int, string>();
            SortedSet <string>          customDLCsBeingInstalled = new SortedSet <string>();

            foreach (var unpackedQueue in installationQueues.unpackedJobMappings)
            {
                foreach (var originalMapping in unpackedQueue.Value.fileMapping)
                {
                    //always unpacked
                    //if (unpackedQueue.Key == ModJob.JobHeader.CUSTOMDLC || unpackedQueue.Key == ModJob.JobHeader.BALANCE_CHANGES || unpackedQueue.Key == ModJob.JobHeader.BASEGAME)
                    //{

                    string sourceFile;
                    if (unpackedQueue.Key.JobDirectory == null)
                    {
                        sourceFile = FilesystemInterposer.PathCombine(ModBeingInstalled.IsInArchive, ModBeingInstalled.ModPath, originalMapping.Value);
                    }
                    else
                    {
                        sourceFile = FilesystemInterposer.PathCombine(ModBeingInstalled.IsInArchive, ModBeingInstalled.ModPath, unpackedQueue.Key.JobDirectory, originalMapping.Value);
                    }



                    if (unpackedQueue.Key.Header == ModJob.JobHeader.ME1_CONFIG)
                    {
                        var destFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "BioWare", "Mass Effect", "Config", originalMapping.Key);
                        if (ModBeingInstalled.IsInArchive)
                        {
                            int archiveIndex = ModBeingInstalled.Archive.ArchiveFileNames.IndexOf(sourceFile, StringComparer.InvariantCultureIgnoreCase);
                            fullPathMappingArchive[archiveIndex] = destFile; //used for extraction indexing
                            if (archiveIndex == -1)
                            {
                                Log.Error("Archive Index is -1 for file " + sourceFile + ". This will probably throw an exception!");
                                Debugger.Break();
                            }
                            fullPathMappingDisk[sourceFile] = destFile; //used for redirection
                        }
                        else
                        {
                            fullPathMappingDisk[sourceFile] = destFile;
                        }
                    }
                    else
                    {
                        var destFile = Path.Combine(unpackedQueue.Key.Header == ModJob.JobHeader.CUSTOMDLC ? MEDirectories.DLCPath(gameTarget) : gameTarget.TargetPath, originalMapping.Key); //official

                        //Extract Custom DLC name
                        if (unpackedQueue.Key.Header == ModJob.JobHeader.CUSTOMDLC)
                        {
                            var custDLC        = destFile.Substring(gameDLCPath.Length, destFile.Length - gameDLCPath.Length).TrimStart('\\', '/');
                            var nextSlashIndex = custDLC.IndexOf('\\');
                            if (nextSlashIndex == -1)
                            {
                                nextSlashIndex = custDLC.IndexOf('/');
                            }
                            if (nextSlashIndex != -1)
                            {
                                custDLC = custDLC.Substring(0, nextSlashIndex);
                                customDLCsBeingInstalled.Add(custDLC);
                            }
                        }

                        if (ModBeingInstalled.IsInArchive)
                        {
                            int archiveIndex = ModBeingInstalled.Archive.ArchiveFileNames.IndexOf(sourceFile, StringComparer.InvariantCultureIgnoreCase);
                            fullPathMappingArchive[archiveIndex] = destFile; //used for extraction indexing
                            if (archiveIndex == -1)
                            {
                                Log.Error("Archive Index is -1 for file " + sourceFile + ". This will probably throw an exception!");
                                Debugger.Break();
                            }
                            fullPathMappingDisk[sourceFile] = destFile; //used for redirection
                        }
                        else
                        {
                            fullPathMappingDisk[sourceFile] = destFile;
                        }
                    }

                    //}
                }
            }

            //Substage: Add SFAR staging targets
            string sfarStagingDirectory = (ModBeingInstalled.IsInArchive && installationQueues.sfarJobs.Count > 0) ? Directory.CreateDirectory(Path.Combine(Utilities.GetTempPath(), "SFARJobStaging")).FullName : null; //don't make directory if we don't need one

            if (sfarStagingDirectory != null)
            {
                foreach (var sfarJob in installationQueues.sfarJobs)
                {
                    foreach (var fileToInstall in sfarJob.sfarInstallationMapping)
                    {
                        string sourceFile   = FilesystemInterposer.PathCombine(ModBeingInstalled.IsInArchive, ModBeingInstalled.ModPath, sfarJob.job.JobDirectory, fileToInstall.Value);
                        int    archiveIndex = ModBeingInstalled.Archive.ArchiveFileNames.IndexOf(sourceFile, StringComparer.InvariantCultureIgnoreCase);
                        if (archiveIndex == -1)
                        {
                            Log.Error("Archive Index is -1 for file " + sourceFile + ". This will probably throw an exception!");
                            Debugger.Break();
                        }
                        string destFile = Path.Combine(sfarStagingDirectory, sfarJob.job.JobDirectory, fileToInstall.Value);
                        fullPathMappingArchive[archiveIndex] = destFile; //used for extraction indexing
                        fullPathMappingDisk[sourceFile]      = destFile; //used for redirection
                        Debug.WriteLine($"SFAR Disk Staging: {fileToInstall.Key} => {destFile}");
                    }
                }
            }

            foreach (var cdbi in customDLCsBeingInstalled)
            {
                var path = Path.Combine(gameDLCPath, cdbi);
                if (Directory.Exists(path))
                {
                    Log.Information("Deleting existing DLC directory: " + path);
                    Utilities.DeleteFilesAndFoldersRecursively(path);
                }
            }

            //Stage: Unpacked files installation
            if (!ModBeingInstalled.IsInArchive)
            {
                //Direct copy
                Log.Information($"Installing {fullPathMappingDisk.Count} unpacked files into game directory");
                CopyDir.CopyFiles_ProgressBar(fullPathMappingDisk, FileInstalledCallback);
            }
            else
            {
                Action = "Loading mod archive";
                //Extraction to destination
                string installationRedirectCallback(ArchiveFileInfo info)
                {
                    var inArchivePath  = info.FileName;
                    var redirectedPath = fullPathMappingDisk[inArchivePath];

                    Debug.WriteLine($"Redirecting {inArchivePath} to {redirectedPath}");
                    return(redirectedPath);
                }

                ModBeingInstalled.Archive.FileExtractionStarted += (sender, args) =>
                {
                    //CLog.Information("Extracting mod file for installation: " + args.FileInfo.FileName, Settings.LogModInstallation);
                };
                List <string> filesInstalled = new List <string>();
                List <string> filesToInstall = installationQueues.unpackedJobMappings.SelectMany(x => x.Value.fileMapping.Keys).ToList();
                ModBeingInstalled.Archive.FileExtractionFinished += (sender, args) =>
                {
                    if (args.FileInfo.IsDirectory)
                    {
                        return;                            //ignore
                    }
                    if (!fullPathMappingArchive.ContainsKey(args.FileInfo.Index))
                    {
                        return;                                                           //archive extracted this file (in memory) but did not do anything with this file (7z)
                    }
                    FileInstalledCallback(args.FileInfo.FileName);
                    filesInstalled.Add(args.FileInfo.FileName);
                    //Debug.WriteLine($"{args.FileInfo.FileName} as file { numdone}");
                    //Debug.WriteLine(numdone);
                };
                ModBeingInstalled.Archive.ExtractFiles(gameTarget.TargetPath, installationRedirectCallback, fullPathMappingArchive.Keys.ToArray()); //directory parameter shouldn't be used here as we will be redirecting everything
                //filesInstalled.Sort();
                //filesToInstall.Sort();
                //Debug.WriteLine("Files installed:");
                //foreach (var f in filesInstalled)
                //{
                //    Debug.WriteLine(f);
                //}
                //Debug.WriteLine("Files expected:");
                //foreach (var f in filesToInstall)
                //{
                //    Debug.WriteLine(f);
                //}
            }

            //Write MetaCMM
            List <string> addedDLCFolders = new List <string>();

            foreach (var v in installationQueues.unpackedJobMappings)
            {
                addedDLCFolders.AddRange(v.Value.dlcFoldersBeingInstalled);
            }
            foreach (var addedDLCFolder in addedDLCFolders)
            {
                var metacmm = Path.Combine(addedDLCFolder, "_metacmm.txt");
                ModBeingInstalled.HumanReadableCustomDLCNames.TryGetValue(Path.GetFileName(addedDLCFolder), out var assignedDLCName);
                string contents = $"{assignedDLCName ?? ModBeingInstalled.ModName}\n{ModBeingInstalled.ModVersionString}\n{App.BuildNumber}\n{Guid.NewGuid().ToString()}";
                File.WriteAllText(metacmm, contents);
            }

            //Stage: SFAR Installation
            foreach (var sfarJob in installationQueues.sfarJobs)
            {
                InstallIntoSFAR(sfarJob, ModBeingInstalled, FileInstalledCallback, ModBeingInstalled.IsInArchive ? sfarStagingDirectory : null);
            }


            //Main installation step has completed
            CLog.Information("Main stage of mod installation has completed", Settings.LogModInstallation);
            Percent = (int)(numdone * 100.0 / numFilesToInstall);

            //Remove outdated custom DLC
            foreach (var outdatedDLCFolder in ModBeingInstalled.OutdatedCustomDLC)
            {
                var outdatedDLCInGame = Path.Combine(gameDLCPath, outdatedDLCFolder);
                if (Directory.Exists(outdatedDLCInGame))
                {
                    Log.Information("Deleting outdated custom DLC folder: " + outdatedDLCInGame);
                    Utilities.DeleteFilesAndFoldersRecursively(outdatedDLCInGame);
                }
            }

            //Install supporting ASI files if necessary
            //Todo: Upgrade to version detection code from ME3EXP to prevent conflicts

            Action = "Installing support files";
            CLog.Information("Installing supporting ASI files", Settings.LogModInstallation);
            if (ModBeingInstalled.Game == Mod.MEGame.ME1)
            {
                Utilities.InstallEmbeddedASI("ME1-DLC-ModEnabler-v1.0", 1.0, gameTarget);
            }
            else if (ModBeingInstalled.Game == Mod.MEGame.ME2)
            {
                //None right now
            }
            else
            {
                //Todo: Port detection code from ME3Exp
                //Utilities.InstallEmbeddedASI("ME3Logger_truncating-v1.0", 1.0, gameTarget);
                if (ModBeingInstalled.GetJob(ModJob.JobHeader.BALANCE_CHANGES) != null)
                {
                    Utilities.InstallEmbeddedASI("BalanceChangesReplacer-v2.0", 2.0, gameTarget);
                }
            }

            if (sfarStagingDirectory != null)
            {
                Utilities.DeleteFilesAndFoldersRecursively(Utilities.GetTempPath());
            }

            if (numFilesToInstall == numdone)
            {
                e.Result = ModInstallCompletedStatus.INSTALL_SUCCESSFUL;
                Action   = "Installed";
            }
            else
            {
                Log.Warning($"Number of completed items does not equal the amount of items to install! Number installed {numdone} Number expected: {numFilesToInstall}");
                e.Result = ModInstallCompletedStatus.INSTALL_WRONG_NUMBER_OF_COMPLETED_ITEMS;
            }
        }
Beispiel #15
0
            private void BeginBackup()
            {
                if (Utilities.IsGameRunning(BackupSourceTarget.Game))
                {
                    M3L.ShowDialog(window, M3L.GetString(M3L.string_interp_cannotBackupGameWhileRunning, Utilities.GetGameName(BackupSourceTarget.Game)), M3L.GetString(M3L.string_gameRunning), MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }
                NamedBackgroundWorker bw = new NamedBackgroundWorker(Game.ToString() + @"Backup");

                bw.DoWork += (a, b) =>
                {
                    BackupInProgress = true;
                    List <string> nonVanillaFiles = new List <string>();
                    void nonVanillaFileFoundCallback(string filepath)
                    {
                        Log.Error($@"Non-vanilla file found: {filepath}");
                        nonVanillaFiles.Add(filepath);
                    }

                    List <string> inconsistentDLC = new List <string>();
                    void inconsistentDLCFoundCallback(string filepath)
                    {
                        if (BackupSourceTarget.Supported)
                        {
                            Log.Error($@"DLC is in an inconsistent state: {filepath}");
                            inconsistentDLC.Add(filepath);
                        }
                        else
                        {
                            Log.Error(@"Detected an inconsistent DLC, likely due to an unofficial copy of the game");
                        }
                    }

                    ProgressVisible       = true;
                    ProgressIndeterminate = true;
                    BackupStatus          = M3L.GetString(M3L.string_validatingBackupSource);
                    VanillaDatabaseService.LoadDatabaseFor(Game);
                    bool          isVanilla        = VanillaDatabaseService.ValidateTargetAgainstVanilla(BackupSourceTarget, nonVanillaFileFoundCallback);
                    bool          isDLCConsistent  = VanillaDatabaseService.ValidateTargetDLCConsistency(BackupSourceTarget, inconsistentDLCCallback: inconsistentDLCFoundCallback);
                    List <string> dlcModsInstalled = VanillaDatabaseService.GetInstalledDLCMods(BackupSourceTarget);
                    List <string> installedDLC     = VanillaDatabaseService.GetInstalledOfficialDLC(BackupSourceTarget);
                    List <string> allOfficialDLC   = MEDirectories.OfficialDLC(BackupSourceTarget.Game);

                    bool end = false;

                    if (installedDLC.Count() < allOfficialDLC.Count())
                    {
                        var dlcList = string.Join("\n - ", allOfficialDLC.Except(installedDLC).Select(x => $@"{MEDirectories.OfficialDLCNames(BackupSourceTarget.Game)[x]} ({x})")); //do not localize
                        dlcList = @" - " + dlcList;
                        Application.Current.Dispatcher.Invoke(delegate
                        {
                            var cancelDueToNotAllDLC = M3L.ShowDialog(window, M3L.GetString(M3L.string_dialog_notAllDLCInstalled, dlcList), M3L.GetString(M3L.string_someDlcNotInstalled), MessageBoxButton.YesNo, MessageBoxImage.Warning);
                            if (cancelDueToNotAllDLC == MessageBoxResult.No)
                            {
                                end = true;
                                EndBackup();
                                return;
                            }
                        });
                    }

                    if (!end)
                    {
                        if (isVanilla && isDLCConsistent && dlcModsInstalled.Count == 0)
                        {
                            BackupStatus = M3L.GetString(M3L.string_waitingForUserInput);

                            string backupPath = null;
                            Application.Current.Dispatcher.Invoke(delegate
                            {
                                Log.Information(@"Prompting user to select backup destination");

                                CommonOpenFileDialog m = new CommonOpenFileDialog
                                {
                                    IsFolderPicker   = true,
                                    EnsurePathExists = true,
                                    Title            = M3L.GetString(M3L.string_selectBackupDestination)
                                };
                                if (m.ShowDialog() == CommonFileDialogResult.Ok)
                                {
                                    backupPath = m.FileName;
                                    Log.Information(@"Backup path chosen: " + backupPath);

                                    //Check empty
                                    if (Directory.Exists(backupPath))
                                    {
                                        if (Directory.GetFiles(backupPath).Length > 0 ||
                                            Directory.GetDirectories(backupPath).Length > 0)
                                        {
                                            //Directory not empty
                                            Log.Error(@"Selected backup directory is not empty.");
                                            M3L.ShowDialog(window,
                                                           M3L.GetString(M3L.string_directoryIsNotEmptyMustBeEmpty),
                                                           M3L.GetString(M3L.string_directoryNotEmpty), MessageBoxButton.OK,
                                                           MessageBoxImage.Error);
                                            end = true;
                                            EndBackup();
                                            return;
                                        }
                                    }

                                    //Check space
                                    Utilities.GetDiskFreeSpaceEx(backupPath, out var freeBytes, out var totalBytes,
                                                                 out var totalFreeBytes);
                                    var requiredSpace =
                                        Utilities.GetSizeOfDirectory(BackupSourceTarget.TargetPath) * 1.1; //10% buffer

                                    if (freeBytes < requiredSpace)
                                    {
                                        //Not enough space.
                                        Log.Error(
                                            $@"Not enough disk spcae to create backup at {backupPath}. Required space: {ByteSize.FromBytes(requiredSpace)} Free space: {ByteSize.FromBytes(freeBytes)}");
                                        M3L.ShowDialog(window,
                                                       M3L.GetString(M3L.string_dialogInsufficientDiskSpace,
                                                                     Path.GetPathRoot(backupPath), ByteSize.FromBytes(freeBytes).ToString(),
                                                                     ByteSize.FromBytes(requiredSpace).ToString()),
                                                       M3L.GetString(M3L.string_insufficientDiskSpace), MessageBoxButton.OK,
                                                       MessageBoxImage.Error);
                                        end = true;
                                        EndBackup();
                                        return;
                                    }

                                    //Check it is not subdirectory of the game (we might want ot check its not subdir of a target)
                                    foreach (var target in AvailableBackupSources)
                                    {
                                        if (backupPath.IsSubPathOf(target.TargetPath))
                                        {
                                            //Not enough space.
                                            Log.Error(
                                                $@"A backup cannot be created in a subdirectory of a game. {backupPath} is a subdir of {BackupSourceTarget.TargetPath}");
                                            M3L.ShowDialog(window,
                                                           M3L.GetString(M3L.string_dialogBackupCannotBeSubdirectoryOfGame,
                                                                         backupPath, target.TargetPath),
                                                           M3L.GetString(M3L.string_cannotCreateBackup), MessageBoxButton.OK,
                                                           MessageBoxImage.Error);
                                            end = true;
                                            EndBackup();
                                            return;
                                        }
                                    }
                                }
                                else
                                {
                                    end = true;
                                    EndBackup();
                                    return;
                                }
                            });
                            if (end)
                            {
                                return;
                            }

                            #region callbacks

                            void fileCopiedCallback()
                            {
                                ProgressValue++;
                            }

                            string dlcFolderpath   = MEDirectories.DLCPath(BackupSourceTarget) + '\\';
                            int    dlcSubStringLen = dlcFolderpath.Length;

                            bool aboutToCopyCallback(string file)
                            {
                                try
                                {
                                    if (file.Contains(@"\cmmbackup\"))
                                    {
                                        return(false);                               //do not copy cmmbackup files
                                    }
                                    if (file.StartsWith(dlcFolderpath))
                                    {
                                        //It's a DLC!
                                        string dlcname = file.Substring(dlcSubStringLen);
                                        dlcname = dlcname.Substring(0, dlcname.IndexOf('\\'));
                                        if (MEDirectories.OfficialDLCNames(BackupSourceTarget.Game)
                                            .TryGetValue(dlcname, out var hrName))
                                        {
                                            BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, hrName);
                                        }
                                        else
                                        {
                                            BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, dlcname);
                                        }
                                    }
                                    else
                                    {
                                        //It's basegame
                                        if (file.EndsWith(@".bik"))
                                        {
                                            BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX,
                                                                              M3L.GetString(M3L.string_movies));
                                        }
                                        else if (new FileInfo(file).Length > 52428800)
                                        {
                                            BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX,
                                                                              Path.GetFileName(file));
                                        }
                                        else
                                        {
                                            BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX,
                                                                              M3L.GetString(M3L.string_basegame));
                                        }
                                    }
                                }
                                catch (Exception e)
                                {
                                    Crashes.TrackError(e, new Dictionary <string, string>()
                                    {
                                        { @"dlcFolderpath", dlcFolderpath },
                                        { @"dlcSubStringLen", dlcSubStringLen.ToString() },
                                        { @"file", file }
                                    });
                                }

                                return(true);
                            }

                            void totalFilesToCopyCallback(int total)
                            {
                                ProgressValue         = 0;
                                ProgressIndeterminate = false;
                                ProgressMax           = total;
                            }

                            #endregion

                            BackupStatus = M3L.GetString(M3L.string_creatingBackup);

                            Log.Information($@"Backing up {BackupSourceTarget.TargetPath} to {backupPath}");

                            CopyDir.CopyAll_ProgressBar(new DirectoryInfo(BackupSourceTarget.TargetPath),
                                                        new DirectoryInfo(backupPath),
                                                        totalItemsToCopyCallback: totalFilesToCopyCallback,
                                                        aboutToCopyCallback: aboutToCopyCallback,
                                                        fileCopiedCallback: fileCopiedCallback,
                                                        ignoredExtensions: new[] { @"*.pdf", @"*.mp3" });
                            switch (Game)
                            {
                            case Mod.MEGame.ME1:
                            case Mod.MEGame.ME2:
                                Utilities.WriteRegistryKey(App.BACKUP_REGISTRY_KEY, Game + @"VanillaBackupLocation",
                                                           backupPath);
                                break;

                            case Mod.MEGame.ME3:
                                Utilities.WriteRegistryKey(App.REGISTRY_KEY_ME3CMM, @"VanillaCopyLocation",
                                                           backupPath);
                                break;
                            }
                            Log.Information($@"Writing cmm_vanilla");

                            File.Create(Path.Combine(backupPath, "cmm_vanilla")).Close();

                            Log.Information($@"Backup completed.");

                            Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>()
                            {
                                { @"Game", Game.ToString() },
                                { @"Result", @"Success" }
                            });

                            EndBackup();
                            return;
                        }
        private void BtnSaveToFile_Click(object sender, EventArgs eventArgs)
        {
            try
            {
                Logger.Info($"Initiating write process for converted save with projected folder {this.tbSaveLocation.Text}.");

                Logger.Info("Making duplicate of original folder to preserve non-save files.");
                CopyDir.Copy(this.SelectedSave.SaveFolder, this.tbSaveLocation.Text);
            }
            catch (Exception exception)
            {
                Logger.Error("Generic exception caught while duplicating save files.");
                Logger.Error(exception);

                MessageBox.Show("Error writing save files to disk! Create an issue at https://github.com/JordanZeotni/BotW-Save-Manager with the error log **IF** you think its **NOT** a permission error.", exception.Message);

                return;
            }

            foreach (KeyValuePair <string, byte[]> convertSaveByte in this.SaveFilesDictionary)
            {
                Logger.Info($"Generating output path from original file {convertSaveByte.Key}");

                string saveTo;
                try
                {
                    saveTo = Directory.GetFiles(this.tbSaveLocation.Text, "*.sav", SearchOption.AllDirectories)
                             .First(e => Path.GetFileName(convertSaveByte.Key) == "option.sav" ||
                                    Path.GetFileName(e) == Path.GetFileName(convertSaveByte.Key) &&
                                    Directory.GetParent(e).Name == Directory.GetParent(convertSaveByte.Key).Name);
                }
                catch (InvalidOperationException e)
                {
                    Logger.Error("Unexpected .sav file in the save directory. Full exception:");
                    Logger.Error(e);

                    MessageBox.Show($"Unexpected file \"{convertSaveByte.Key}\" was unable to be converted. " +
                                    $"Try first deleting it from the original save folder, then restarting this application, and finally retrying the conversion. " +
                                    $"If that doesn't work, make an issue with your log at https://github.com/JordanZeotni/BotW-Save-Manager.", e.Message);

                    return;
                }
                catch (Exception e)
                {
                    Logger.Error("Generic exception caught while finding the output for a .sav file.");
                    Logger.Error(e);

                    MessageBox.Show("Error writing save files to disk! Create an issue at https://github.com/JordanZeotni/BotW-Save-Manager with the error log **IF** you think its **NOT** a permission error.", e.Message);

                    return;
                }

                Logger.Info($"Writing save file {saveTo}.");

                try
                {
                    File.WriteAllBytes(saveTo, convertSaveByte.Value);
                }
                catch (Exception e)
                {
                    Logger.Error($"Generic exception caught while writing .sav file {convertSaveByte.Key}.");
                    Logger.Error(e);

                    MessageBox.Show("Error writing a save file to disk! Create an issue at https://github.com/JordanZeotni/BotW-Save-Manager with the error log **IF** you think its **NOT** a permission error.", e.Message);

                    return;
                }
            }

            Logger.Info("Loading converted save as the selected save.");

            try
            {
                this.SelectedSave = new Save(this.tbSaveLocation.Text, true);
            }
            catch (Exception e)
            {
                Logger.Error("Failed to load converted save. Alerting user that the save may be corrupt but could be potentially still usable.");
                Logger.Error(e);

                MessageBox.Show("The converted save was unable to be verified. The save may still work on the intended system, " +
                                "but if it doesn't please make an issue at https://github.com/JordanZeotni/BotW-Save-Manager with your log.");

                Logger.Info("Process complete. Application entering standby.\nInkling is the best Smash Ultimate character :)\n" +
                            Encoding.UTF8.GetString(Convert.FromBase64String(Program.SS)));

                return;
            }

            Logger.Info("Process complete. Application entering standby.\nInkling is the best Smash Ultimate character :)\n" +
                        Encoding.UTF8.GetString(Convert.FromBase64String(Program.SS)));

            MessageBox.Show("Files written successfully!");
        }
        private void ImportDLCFolder_BackgroundThread(object sender, DoWorkEventArgs e)
        {
            OperationInProgress = true;
            var sourceDir = Path.Combine(M3Directories.GetDLCPath(SelectedTarget), SelectedDLCFolder.DLCFolderName);

            // Check for MEMI, we will not allow importing files with MEMI
            foreach (var file in Directory.GetFiles(sourceDir, @"*.*", SearchOption.AllDirectories))
            {
                if (file.RepresentsPackageFilePath() && Utilities.HasALOTMarker(file))
                {
                    Log.Error($@"Found a file marked as texture modded: {file}. These files cannot be imported into mod manager");
                    Application.Current.Dispatcher.Invoke(delegate
                    {
                        M3L.ShowDialog(window, M3L.GetString(M3L.string_dialog_cannotImportModTextureMarkersFound), M3L.GetString(M3L.string_cannotImportMod), MessageBoxButton.OK, MessageBoxImage.Error);
                    });
                    return;
                }
            }



            var library         = Utilities.GetModDirectoryForGame(SelectedTarget.Game);
            var destinationName = Utilities.SanitizePath(ModNameText);
            var modFolder       = Path.Combine(library, destinationName);
            var copyDestination = Path.Combine(modFolder, SelectedDLCFolder.DLCFolderName);
            var outInfo         = Directory.CreateDirectory(copyDestination);

            Log.Information($@"Importing mod: {sourceDir} -> {copyDestination}");

            int numToDo = 0;
            int numDone = 0;

            void totalItemToCopyCallback(int total)
            {
                numToDo        = total;
                ProgressBarMax = total;
            }

            void fileCopiedCallback()
            {
                numDone++;
                ProgressBarValue = numDone;
            }

            CopyDir.CopyAll_ProgressBar(new DirectoryInfo(sourceDir), outInfo, totalItemToCopyCallback, fileCopiedCallback);

            //Write a moddesc
            IniData ini = new IniData();

            ini[@"ModManager"][@"cmmver"]    = App.HighestSupportedModDesc.ToString(CultureInfo.InvariantCulture); //prevent commas
            ini[@"ModInfo"][@"game"]         = SelectedTarget.Game.ToString();
            ini[@"ModInfo"][@"modname"]      = ModNameText;
            ini[@"ModInfo"][@"moddev"]       = M3L.GetString(M3L.string_importedFromGame);
            ini[@"ModInfo"][@"moddesc"]      = M3L.GetString(M3L.string_defaultDescriptionForImportedMod, Utilities.GetGameName(SelectedTarget.Game), DateTime.Now);
            ini[@"ModInfo"][@"modver"]       = M3L.GetString(M3L.string_unknown);
            ini[@"ModInfo"][@"unofficial"]   = @"true";
            ini[@"ModInfo"][@"importedby"]   = App.BuildNumber.ToString();
            ini[@"CUSTOMDLC"][@"sourcedirs"] = SelectedDLCFolder.DLCFolderName;
            ini[@"CUSTOMDLC"][@"destdirs"]   = SelectedDLCFolder.DLCFolderName;


            var moddescPath = Path.Combine(modFolder, @"moddesc.ini");

            File.WriteAllText(moddescPath, ini.ToString());

            //Generate and load mod
            var m = new Mod(moddescPath, MEGame.ME3);

            e.Result = m;
            Log.Information(@"Mod import complete.");
            Analytics.TrackEvent(@"Imported already installed mod", new Dictionary <string, string>()
            {
                { @"Mod name", m.ModName },
                { @"Game", SelectedTarget.Game.ToString() },
                { @"Folder name", SelectedDLCFolder.DLCFolderName }
            });

            if (!CurrentModInTPMI)
            {
                //Submit telemetry to ME3Tweaks
                try
                {
                    TPMITelemetrySubmissionForm.TelemetryPackage tp = TPMITelemetrySubmissionForm.GetTelemetryPackageForDLC(SelectedTarget.Game,
                                                                                                                            M3Directories.GetDLCPath(SelectedTarget),
                                                                                                                            SelectedDLCFolder.DLCFolderName,
                                                                                                                            SelectedDLCFolder.DLCFolderName, //same as foldername as this is already installed
                                                                                                                            ModNameText,
                                                                                                                            @"N/A",
                                                                                                                            ModSiteText,
                                                                                                                            null
                                                                                                                            );

                    tp.SubmitPackage();
                }
                catch (Exception ex)
                {
                    Log.Error(@"Cannot submit telemetry: " + ex.Message);
                }
            }
        }
            private void BeginRestore()
            {
                if (Utilities.IsGameRunning(Game))
                {
                    M3L.ShowDialog(window, M3L.GetString(M3L.string_interp_dialogCannotRestoreXWhileItIsRunning, Game.ToGameName()), M3L.GetString(M3L.string_gameRunning), MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }

                var useNewMethod = M3L.ShowDialog(window,
                                                  M3L.GetString(M3L.string_beta_useNewRestoreMethod),
                                                  M3L.GetString(M3L.string_useBetaFeatureQuestion), MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes;

                bool restore = RestoreTarget.IsCustomOption || useNewMethod; //custom option is restore to custom location

                restore = restore || M3L.ShowDialog(window, M3L.GetString(M3L.string_dialog_restoringXWillDeleteGameDir, Game.ToGameName()), M3L.GetString(M3L.string_gameTargetWillBeDeleted), MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes;
                if (restore)
                {
                    NamedBackgroundWorker nbw = new NamedBackgroundWorker(Game + @"-Restore");
                    nbw.WorkerReportsProgress = true;
                    nbw.ProgressChanged      += (a, b) =>
                    {
                        if (b.UserState is double d)
                        {
                            TaskbarHelper.SetProgress(d);
                        }
                    };
                    nbw.DoWork += (a, b) =>
                    {
                        RestoreInProgress = true;
                        // Nuke the LODs
                        if (!RestoreTarget.IsCustomOption && RestoreTarget.Game.IsOTGame())
                        {
                            Log.Information($@"Resetting LODs for {RestoreTarget.Game}");
                            Utilities.SetLODs(RestoreTarget, false, false, false);
                        }

                        string restoreTargetPath = b.Argument as string;
                        string backupPath        = BackupLocation;

                        if (!useNewMethod)
                        {
                            BackupStatusLine2 = M3L.GetString(M3L.string_deletingExistingGameInstallation);
                            if (Directory.Exists(restoreTargetPath))
                            {
                                if (Directory.GetFiles(restoreTargetPath).Any() ||
                                    Directory.GetDirectories(restoreTargetPath).Any())
                                {
                                    Log.Information(@"Deleting existing game directory: " + restoreTargetPath);
                                    try
                                    {
                                        bool deletedDirectory =
                                            Utilities.DeleteFilesAndFoldersRecursively(restoreTargetPath);
                                        if (deletedDirectory != true)
                                        {
                                            b.Result = RestoreResult.ERROR_COULD_NOT_DELETE_GAME_DIRECTORY;
                                            return;
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        //todo: handle this better
                                        Log.Error(
                                            $@"Exception deleting game directory: {restoreTargetPath}: {ex.Message}");
                                        b.Result = RestoreResult.EXCEPTION_DELETING_GAME_DIRECTORY;
                                        return;
                                    }
                                }
                            }
                            else
                            {
                                Log.Error(@"Game directory not found! Was it removed while the app was running?");
                            }

                            var created = Utilities.CreateDirectoryWithWritePermission(restoreTargetPath);
                            if (!created)
                            {
                                b.Result = RestoreResult.ERROR_COULD_NOT_CREATE_DIRECTORY;
                                return;
                            }
                        }

                        BackupStatusLine2 = M3L.GetString(M3L.string_restoringGameFromBackup);
                        if (restoreTargetPath != null)
                        {
                            //callbacks

                            #region callbacks

                            void fileCopiedCallback()
                            {
                                ProgressValue++;
                                if (ProgressMax != 0)
                                {
                                    nbw.ReportProgress(0, ProgressValue * 1.0 / ProgressMax);
                                }
                            }

                            string dlcFolderpath   = MEDirectories.GetDLCPath(Game, backupPath) + '\\'; //\ at end makes sure we are restoring a subdir
                            int    dlcSubStringLen = dlcFolderpath.Length;
                            Debug.WriteLine(@"DLC Folder: " + dlcFolderpath);
                            Debug.Write(@"DLC Folder path len:" + dlcFolderpath);

                            bool aboutToCopyCallback(string fileBeingCopied)
                            {
                                if (fileBeingCopied.Contains(@"\cmmbackup\"))
                                {
                                    return(false);                                          //do not copy cmmbackup files
                                }
                                Debug.WriteLine(fileBeingCopied);
                                if (fileBeingCopied.StartsWith(dlcFolderpath, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    //It's a DLC!
                                    string dlcname = fileBeingCopied.Substring(dlcSubStringLen);
                                    int    index   = dlcname.IndexOf('\\');
                                    if (index > 0) //Files directly in the DLC directory won't have path sep
                                    {
                                        try
                                        {
                                            dlcname = dlcname.Substring(0, index);
                                            if (MEDirectories.OfficialDLCNames(RestoreTarget.Game).TryGetValue(dlcname, out var hrName))
                                            {
                                                BackupStatusLine2 = M3L.GetString(M3L.string_interp_restoringX, hrName);
                                            }
                                            else
                                            {
                                                BackupStatusLine2 = M3L.GetString(M3L.string_interp_restoringX, dlcname);
                                            }
                                        }
                                        catch (Exception e)
                                        {
                                            Crashes.TrackError(e, new Dictionary <string, string>()
                                            {
                                                { @"Source", @"Restore UI display callback" },
                                                { @"Value", fileBeingCopied },
                                                { @"DLC Folder path", dlcFolderpath }
                                            });
                                        }
                                    }
                                }
                                else
                                {
                                    //It's basegame
                                    if (fileBeingCopied.EndsWith(@".bik"))
                                    {
                                        BackupStatusLine2 = M3L.GetString(M3L.string_restoringMovies);
                                    }
                                    else if (new FileInfo(fileBeingCopied).Length > 52428800)
                                    {
                                        BackupStatusLine2 = M3L.GetString(M3L.string_interp_restoringX, Path.GetFileName(fileBeingCopied));
                                    }
                                    else
                                    {
                                        BackupStatusLine2 = M3L.GetString(M3L.string_restoringBasegame);
                                    }
                                }

                                return(true);
                            }

                            void totalFilesToCopyCallback(int total)
                            {
                                ProgressValue         = 0;
                                ProgressIndeterminate = false;
                                ProgressMax           = total;
                            }

                            #endregion

                            BackupStatus = M3L.GetString(M3L.string_restoringGame);

                            // LE: Backup Config file so settings don't get lost
                            string configText = null;
                            var    configPath = RestoreTarget.Game.IsLEGame() ? M3Directories.GetLODConfigFile(RestoreTarget) : null;
                            if (File.Exists(configPath))
                            {
                                configText = File.ReadAllText(configPath); // backup to memory
                            }

                            Log.Information($@"Copying backup to game directory: {backupPath} -> {restoreTargetPath}");
                            if (useNewMethod)
                            {
                                string      CurrentRCFile = null;
                                RoboCommand rc            = new RoboCommand();
                                rc.CopyOptions.Destination = restoreTargetPath;
                                rc.CopyOptions.Source      = backupPath;
                                rc.CopyOptions.Mirror      = true;
                                rc.CopyOptions.MultiThreadedCopiesCount = 2;
                                rc.OnCopyProgressChanged += (sender, args) =>
                                {
                                    ProgressIndeterminate = false;
                                    ProgressValue         = (int)args.CurrentFileProgress;
                                    ProgressMax           = 100;
                                };
                                rc.OnFileProcessed += (sender, args) =>
                                {
                                    if (args.ProcessedFile.Name.StartsWith(backupPath) && args.ProcessedFile.Name.Length > backupPath.Length)
                                    {
                                        CurrentRCFile     = args.ProcessedFile.Name.Substring(backupPath.Length + 1);
                                        BackupStatusLine2 = M3L.GetString(M3L.string_interp_copyingX, CurrentRCFile);
                                    }
                                };
                                rc.Start().Wait();
                            }
                            else
                            {
                                CopyDir.CopyAll_ProgressBar(new DirectoryInfo(backupPath),
                                                            new DirectoryInfo(restoreTargetPath),
                                                            totalItemsToCopyCallback: totalFilesToCopyCallback,
                                                            aboutToCopyCallback: aboutToCopyCallback,
                                                            fileCopiedCallback: fileCopiedCallback,
                                                            ignoredExtensions: new[] { @"*.pdf", @"*.mp3" });
                            }

                            Log.Information(@"Restore of game data has completed");

                            if (configText != null)
                            {
                                // Restore config file
                                try
                                {
                                    Directory.CreateDirectory(Directory.GetParent(configPath).FullName);
                                    File.WriteAllText(configPath, configText);
                                    Log.Information(@"Restored config file");
                                }
                                catch (Exception e)
                                {
                                    Log.Error($@"Could not restore config file: {e.Message}");
                                }
                            }
                            BackupCopyFinished(restoreTargetPath);
                        }
                    };
                    nbw.RunWorkerCompleted += (a, b) =>
                    {
                        if (b.Error != null)
                        {
                            Log.Error($@"Exception occurred in {nbw.Name} thread: {b.Error.Message}");
                        }
                        TaskbarHelper.SetProgressState(TaskbarProgressBarState.NoProgress);
                        if (b.Result is RestoreResult result)
                        {
                            switch (result)
                            {
                            case RestoreResult.ERROR_COULD_NOT_CREATE_DIRECTORY:
                                Analytics.TrackEvent(@"Restored game", new Dictionary <string, string>()
                                {
                                    { @"Game", Game.ToString() },
                                    { @"Result", @"Failure, Could not create target directory" }
                                });
                                M3L.ShowDialog(window, M3L.GetString(M3L.string_dialogCouldNotCreateGameDirectoryAfterDeletion), M3L.GetString(M3L.string_errorRestoringGame), MessageBoxButton.OK, MessageBoxImage.Error);
                                break;

                            case RestoreResult.ERROR_COULD_NOT_DELETE_GAME_DIRECTORY:
                                Analytics.TrackEvent(@"Restored game", new Dictionary <string, string>()
                                {
                                    { @"Game", Game.ToString() },
                                    { @"Result", @"Failure, Could not delete existing game directory" }
                                });
                                M3L.ShowDialog(window, M3L.GetString(M3L.string_dialogcouldNotFullyDeleteGameDirectory), M3L.GetString(M3L.string_errorRestoringGame), MessageBoxButton.OK, MessageBoxImage.Error);
                                break;

                            case RestoreResult.EXCEPTION_DELETING_GAME_DIRECTORY:
                                Analytics.TrackEvent(@"Restored game", new Dictionary <string, string>()
                                {
                                    { @"Game", Game.ToString() },
                                    { @"Result", @"Failure, Exception deleting existing game directory" }
                                });
                                M3L.ShowDialog(window, M3L.GetString(M3L.string_dialogErrorOccuredDeletingGameDirectory), M3L.GetString(M3L.string_errorRestoringGame), MessageBoxButton.OK, MessageBoxImage.Error);
                                break;

                            case RestoreResult.RESTORE_OK:
                                Analytics.TrackEvent(@"Restored game", new Dictionary <string, string>()
                                {
                                    { @"Game", Game.ToString() },
                                    { @"Result", @"Success" }
                                });
                                break;
                            }
                        }

                        EndRestore();
                        CommandManager.InvalidateRequerySuggested();
                    };
                    var restoreTargetPath = RestoreTarget.TargetPath;
                    if (RestoreTarget.IsCustomOption)
                    {
                        CommonOpenFileDialog m = new CommonOpenFileDialog
                        {
                            IsFolderPicker   = true,
                            EnsurePathExists = true,
                            Title            = M3L.GetString(M3L.string_selectNewRestoreDestination)
                        };
                        if (m.ShowDialog() == CommonFileDialogResult.Ok)
                        {
                            //Check empty
                            restoreTargetPath = m.FileName;
                            if (Directory.Exists(restoreTargetPath))
                            {
                                if (Directory.GetFiles(restoreTargetPath).Length > 0 || Directory.GetDirectories(restoreTargetPath).Length > 0)
                                {
                                    Log.Warning($@"The selected restore directory is not empty: {restoreTargetPath}");
                                    //Directory not empty
                                    if (!useNewMethod)
                                    {
                                        M3L.ShowDialog(window,
                                                       M3L.GetString(M3L
                                                                     .string_dialogDirectoryIsNotEmptyLocationToRestoreToMustBeEmpty),
                                                       M3L.GetString(M3L.string_cannotRestoreToThisLocation), MessageBoxButton.OK,
                                                       MessageBoxImage.Error);
                                        return;
                                    }
                                    else
                                    {
                                        // Warn user
                                        var shouldContinue = MessageBoxResult.Yes == M3L.ShowDialog(window,
                                                                                                    M3L.GetString(M3L.string_interp_directoryNotEmptyWillDeleteEverything, restoreTargetPath),
                                                                                                    M3L.GetString(M3L.string_directoryNotEmpty), MessageBoxButton.YesNo, MessageBoxImage.Warning);
                                        if (!shouldContinue)
                                        {
                                            return;
                                        }
                                        Log.Warning($@"The user is continuing to new-gen restore on existing directory anyways");
                                    }
                                }

                                //TODO: PREVENT RESTORING TO DOCUMENTS/BIOWARE
                            }

                            Analytics.TrackEvent(@"Chose to restore game to custom location", new Dictionary <string, string>()
                            {
                                { @"Game", Game.ToString() },
                                { @"New-gen", useNewMethod.ToString() }
                            });
                        }
                        else
                        {
                            return;
                        }
                    }

                    RefreshTargets = true;
                    TaskbarHelper.SetProgress(0);
                    TaskbarHelper.SetProgressState(TaskbarProgressBarState.Normal);
                    nbw.RunWorkerAsync(restoreTargetPath);
                }
            }
Beispiel #19
0
            private void BeginRestore()
            {
                if (Utilities.IsGameRunning(Game))
                {
                    Xceed.Wpf.Toolkit.MessageBox.Show(window, $"Cannot restore {Utilities.GetGameName(Game)} while it is running.", $"Game is running", MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }
                NamedBackgroundWorker bw = new NamedBackgroundWorker(Game.ToString() + "Backup");

                bw.DoWork += (a, b) =>
                {
                    RestoreInProgress = true;


                    string restoreTargetPath = b.Argument as string;
                    string backupPath        = BackupLocation;
                    BackupStatusLine2 = "Deleting existing game installation";
                    if (Directory.Exists(restoreTargetPath))
                    {
                        if (Directory.GetFiles(restoreTargetPath).Any() || Directory.GetDirectories(restoreTargetPath).Any())
                        {
                            Log.Information("Deleting existing game directory: " + restoreTargetPath);
                            try
                            {
                                bool deletedDirectory = Utilities.DeleteFilesAndFoldersRecursively(restoreTargetPath);
                                if (deletedDirectory != true)
                                {
                                    b.Result = RestoreResult.ERROR_COULD_NOT_DELETE_GAME_DIRECTORY;
                                    return;
                                }
                            }
                            catch (Exception ex)
                            {
                                //todo: handle this better
                                Log.Error("Exception deleting game directory: " + restoreTargetPath + ": " + ex.Message);
                                b.Result = RestoreResult.EXCEPTION_DELETING_GAME_DIRECTORY;
                                return;
                            }
                        }
                    }
                    else
                    {
                        Log.Error("Game directory not found! Was it removed while the app was running?");
                    }

                    //Todo: Revert LODs, remove IndirectSound settings (MEUITM)
                    //Log.Information("Reverting lod settings");
                    //string exe = BINARY_DIRECTORY + MEM_EXE_NAME;
                    //string args = "--remove-lods --gameid " + BACKUP_THREAD_GAME;
                    //Utilities.runProcess(exe, args);

                    //if (BACKUP_THREAD_GAME == 1)
                    //{
                    //    string iniPath = IniSettingsHandler.GetConfigIniPath(1);
                    //    if (File.Exists(iniPath))
                    //    {
                    //        Log.Information("Reverting Indirect Sound ini fix for ME1");
                    //        IniFile engineConf = new IniFile(iniPath);
                    //        engineConf.DeleteKey("DeviceName", "ISACTAudio.ISACTAudioDevice");
                    //    }
                    //}

                    var created = Utilities.CreateDirectoryWithWritePermission(restoreTargetPath);
                    if (!created)
                    {
                        b.Result = RestoreResult.ERROR_COULD_NOT_CREATE_DIRECTORY;
                        return;
                    }
                    BackupStatusLine2 = "Restoring game from backup";
                    if (restoreTargetPath != null)
                    {
                        //callbacks
                        #region callbacks
                        void fileCopiedCallback()
                        {
                            ProgressValue++;
                        }

                        string dlcFolderpath   = MEDirectories.DLCPath(backupPath, Game) + '\\'; //\ at end makes sure we are restoring a subdir
                        int    dlcSubStringLen = dlcFolderpath.Length;
                        Debug.WriteLine("DLC Folder: " + dlcFolderpath);
                        Debug.Write("DLC Fodler path len:" + dlcFolderpath);
                        bool aboutToCopyCallback(string fileBeingCopied)
                        {
                            if (fileBeingCopied.Contains("\\cmmbackup\\"))
                            {
                                return(false);                                           //do not copy cmmbackup files
                            }
                            Debug.WriteLine(fileBeingCopied);
                            if (fileBeingCopied.StartsWith(dlcFolderpath, StringComparison.InvariantCultureIgnoreCase))
                            {
                                //It's a DLC!
                                string dlcname = fileBeingCopied.Substring(dlcSubStringLen);
                                int    index   = dlcname.IndexOf('\\');
                                try
                                {
                                    dlcname = dlcname.Substring(0, index);
                                    if (MEDirectories.OfficialDLCNames(RestoreTarget.Game).TryGetValue(dlcname, out var hrName))
                                    {
                                        BackupStatusLine2 = "Restoring " + hrName;
                                    }
                                    else
                                    {
                                        BackupStatusLine2 = "Restoring " + dlcname;
                                    }
                                }
                                catch (Exception e)
                                {
                                    Crashes.TrackError(e, new Dictionary <string, string>()
                                    {
                                        { "Source", "Restore UI display callback" },
                                        { "Value", fileBeingCopied },
                                        { "DLC Folder path", dlcFolderpath }
                                    });
                                }
                            }
                            else
                            {
                                //It's basegame
                                if (fileBeingCopied.EndsWith(".bik"))
                                {
                                    BackupStatusLine2 = "Restoring Movies";
                                }
                                else if (new FileInfo(fileBeingCopied).Length > 52428800)
                                {
                                    BackupStatusLine2 = "Restoring " + Path.GetFileName(fileBeingCopied);
                                }
                                else
                                {
                                    BackupStatusLine2 = "Restoring BASEGAME";
                                }
                            }
                            return(true);
                        }

                        void totalFilesToCopyCallback(int total)
                        {
                            ProgressValue         = 0;
                            ProgressIndeterminate = false;
                            ProgressMax           = total;
                        }

                        #endregion
                        BackupStatus = "Restoring game";
                        Log.Information("Copying backup to game directory: " + backupPath + " -> " + restoreTargetPath);
                        CopyDir.CopyAll_ProgressBar(new DirectoryInfo(backupPath), new DirectoryInfo(restoreTargetPath),
                                                    totalItemsToCopyCallback: totalFilesToCopyCallback,
                                                    aboutToCopyCallback: aboutToCopyCallback,
                                                    fileCopiedCallback: fileCopiedCallback,
                                                    ignoredExtensions: new[] { "*.pdf", "*.mp3" });
                        Log.Information("Restore of game data has completed");
                    }

                    //Check for cmmvanilla file and remove it present

                    string cmmVanilla = Path.Combine(restoreTargetPath, "cmm_vanilla");
                    if (File.Exists(cmmVanilla))
                    {
                        Log.Information("Removing cmm_vanilla file");
                        File.Delete(cmmVanilla);
                    }

                    Log.Information("Restore thread wrapping up");
                    b.Result = RestoreResult.RESTORE_OK;
                };
                bw.RunWorkerCompleted += (a, b) =>
                {
                    if (b.Result is RestoreResult result)
                    {
                        switch (result)
                        {
                        case RestoreResult.ERROR_COULD_NOT_CREATE_DIRECTORY:
                            Analytics.TrackEvent("Restored game", new Dictionary <string, string>()
                            {
                                { "Game", Game.ToString() },
                                { "Result", "Failure, Could not create target directory" }
                            });
                            Xceed.Wpf.Toolkit.MessageBox.Show("Could not create the game directory after it was deleted due to an error. View the logs from the help menu for more information.", "Error restoring game", MessageBoxButton.OK, MessageBoxImage.Error);
                            break;

                        case RestoreResult.ERROR_COULD_NOT_DELETE_GAME_DIRECTORY:
                            Analytics.TrackEvent("Restored game", new Dictionary <string, string>()
                            {
                                { "Game", Game.ToString() },
                                { "Result", "Failure, Could not delete existing game directory" }
                            });
                            Xceed.Wpf.Toolkit.MessageBox.Show("Could not fully delete the game directory. It may have files or folders still open from various programs. Part of the game may have been deleted. View the logs from the help menu for more information.", "Error restoring game", MessageBoxButton.OK, MessageBoxImage.Error);
                            break;

                        case RestoreResult.EXCEPTION_DELETING_GAME_DIRECTORY:
                            Analytics.TrackEvent("Restored game", new Dictionary <string, string>()
                            {
                                { "Game", Game.ToString() },
                                { "Result", "Failure, Excpetion deleting existing game directory" }
                            });
                            Xceed.Wpf.Toolkit.MessageBox.Show("An error occured while deleting the game directory. View the logs from the help menu for more information.", "Error restoring game", MessageBoxButton.OK, MessageBoxImage.Error);
                            break;

                        case RestoreResult.RESTORE_OK:
                            Analytics.TrackEvent("Restored game", new Dictionary <string, string>()
                            {
                                { "Game", Game.ToString() },
                                { "Result", "Success" }
                            });
                            break;
                        }
                    }

                    EndRestore();
                    CommandManager.InvalidateRequerySuggested();
                };
                var restTarget = RestoreTarget.TargetPath;
                if (RestoreTarget.IsCustomOption)
                {
                    CommonOpenFileDialog m = new CommonOpenFileDialog
                    {
                        IsFolderPicker   = true,
                        EnsurePathExists = true,
                        Title            = "Select new restore destination"
                    };
                    if (m.ShowDialog() == CommonFileDialogResult.Ok)
                    {
                        //Check empty
                        restTarget = m.FileName;
                        if (Directory.Exists(restTarget))
                        {
                            if (Directory.GetFiles(restTarget).Length > 0 || Directory.GetDirectories(restTarget).Length > 0)
                            {
                                //Directory not empty
                                Xceed.Wpf.Toolkit.MessageBox.Show("Directory is not empty. Location to restore to must be empty.", "Cannot restore to this location", MessageBoxButton.OK, MessageBoxImage.Error);
                                return;
                            }
                        }

                        Analytics.TrackEvent("Chose to restore game to custom location", new Dictionary <string, string>()
                        {
                            { "Game", Game.ToString() }
                        });
                    }
                    else
                    {
                        return;
                    }
                }

                RefreshTargets = true;
                bw.RunWorkerAsync(restTarget);
            }
        private void Migration_ContentRendered(object sender, EventArgs e)
        {
            NamedBackgroundWorker nbw = new NamedBackgroundWorker(@"ME3CMMMigration");

            nbw.DoWork += (a, b) =>
            {
                Log.Information(@">>>> ME3CMMMigration Thread");
                Log.Information(@"Validate ME3CMM folders and files");
                var exeDir = Utilities.GetMMExecutableDirectory();
                //DEBUG ONLY

                //exeDir = @"E:\ME3CMM";

                var modsDir = Path.Combine(exeDir, @"mods");
                var dataDir = Path.Combine(exeDir, @"data");
                if (Directory.Exists(modsDir) && Directory.Exists(dataDir))
                {
                    Log.Information(@"mods and data dir exist.");
                    // 1. MIGRATE MODS
                    Log.Information(@"Step 1: Migrate mods");
                    MigratingModsTask.SetInProgress();

                    var targetModLibrary = Utilities.GetModsDirectory();
                    //DEBUG ONLY
                    //targetModLibrary = @"E:\ME3CMM\mods";

                    targetModLibrary = Path.Combine(targetModLibrary, @"ME3");
                    if (!Directory.Exists(targetModLibrary))
                    {
                        Log.Information(@"Creating target mod library directory: " + targetModLibrary);
                        Directory.CreateDirectory(targetModLibrary);
                    }

                    var sameRoot = Path.GetPathRoot(targetModLibrary) == Path.GetPathRoot(modsDir);

                    var directoriesInModsDir = Directory.GetDirectories(modsDir);

                    var numToMigrate = directoriesInModsDir.Count(x => File.Exists(Path.Combine(x, @"moddesc.ini")));
                    var numMigrated  = 0;

                    foreach (var modDirToMove in directoriesInModsDir)
                    {
                        var moddesc = Path.Combine(modDirToMove, @"moddesc.ini");
                        if (File.Exists(moddesc))
                        {
                            numMigrated++;
                            MigratingModsTask.TaskText = $"Migrating mods [{numMigrated}/{numToMigrate}]";
                            //Migrate this folder
                            var targetDir = Path.Combine(modsDir, @"ME3", Path.GetFileName(modDirToMove));
                            Log.Information($@"Migrating mod into ME3 directory: {modDirToMove} -> {targetDir}");
                            if (!Directory.Exists(targetDir))
                            {
                                if (sameRoot)
                                {
                                    Directory.Move(modDirToMove, targetDir);
                                }
                                else
                                {
                                    Log.Information(@"Copying existing mod directory");
                                    Directory.CreateDirectory(targetDir);
                                    CopyDir.CopyAll_ProgressBar(new DirectoryInfo(modDirToMove), new DirectoryInfo(targetDir));
                                    Log.Information(@"Deleting existing directory");
                                    Utilities.DeleteFilesAndFoldersRecursively(modDirToMove);
                                }

                                Log.Information($@"Migrated {modDirToMove}");
                                //Thread.Sleep(200);
                            }
                            else
                            {
                                Log.Warning(@"Target directory already exists! Not migrating this directory.");
                            }
                        }
                    }

                    MigratingModsTask.SetDone();
                    Log.Information(@"Step 1: Finished mod migration");


                    // 2. MIGRATE SETTINGS
                    MigratingSettings.SetInProgress();
                    Log.Information(@"Step 2: Begin settings migration");
                    var me3cmminif = Path.Combine(exeDir, @"me3cmm.ini");
                    if (File.Exists(me3cmminif))
                    {
                        Log.Information(@"Migrating me3cmm.ini settings");
                        IniData me3cmmini = new FileIniDataParser().ReadFile(me3cmminif);
                        var     updaterServiceUsername = me3cmmini[@"UpdaterService"][@"username"];
                        if (string.IsNullOrWhiteSpace(Settings.UpdaterServiceUsername) && !string.IsNullOrWhiteSpace(updaterServiceUsername))
                        {
                            Settings.UpdaterServiceUsername = updaterServiceUsername;
                            Log.Information(@"Migrated Updater Service Username: "******"UpdaterService"][@"manifestspath"];
                        if (string.IsNullOrWhiteSpace(Settings.UpdaterServiceManifestStoragePath) && !string.IsNullOrWhiteSpace(manifestsPath))
                        {
                            Settings.UpdaterServiceManifestStoragePath = manifestsPath;
                            Log.Information(@"Migrated Updater Service Manifests Path: " + manifestsPath);
                        }

                        var lzmaStoragePath = me3cmmini[@"UpdaterService"][@"lzmastoragepath"];
                        if (string.IsNullOrWhiteSpace(Settings.UpdaterServiceLZMAStoragePath) && !string.IsNullOrWhiteSpace(lzmaStoragePath))
                        {
                            Settings.UpdaterServiceLZMAStoragePath = updaterServiceUsername;
                            Log.Information(@"Migrated Updater Service LZMA Storage Path: " + lzmaStoragePath);
                        }

                        //TODO: MODMAKER CONTROLLER AUTO-ADDINS

                        Settings.Save();
                    }

                    //Migrate BIOGAME_DIRECTORIES
                    var biogameDirsF = Path.Combine(dataDir, @"BIOGAME_DIRECTORIES");
                    if (File.Exists(biogameDirsF))
                    {
                        var biodirs = File.ReadAllLines(biogameDirsF);
                        foreach (var line in biodirs)
                        {
                            var gamepath = Directory.GetParent(line).FullName;
                            Log.Information(@"Validating ME3CMM target: " + gamepath);
                            GameTarget t             = new GameTarget(Mod.MEGame.ME3, gamepath, false);
                            var        failureReason = t.ValidateTarget();
                            if (failureReason == null)
                            {
                                Utilities.AddCachedTarget(t);
                            }
                            else
                            {
                                Log.Error($@"Not migrating invalid target {gamepath}: {failureReason}");
                            }
                        }
                    }

                    //Migrate ALOT Installer, if found
                    var alotInstallerDir = Path.Combine(dataDir, @"ALOTInstaller");
                    if (Directory.Exists(alotInstallerDir))
                    {
                        Log.Information(@"Migrating ALOTInstaller tool");
                        var externalToolsALOTInstaller = Path.Combine(dataDir, @"ExternalTools", @"ALOTInstaller");
                        Directory.CreateDirectory(Path.Combine(dataDir, @"ExternalTools"));
                        Directory.Move(alotInstallerDir, externalToolsALOTInstaller);
                        Log.Information(@"Migrated ALOTInstaller to ExternalTools");
                    }

                    //Migrate ME3Explorer, if found
                    var me3explorerDir = Path.Combine(dataDir, @"ME3Explorer");
                    if (Directory.Exists(me3explorerDir))
                    {
                        Log.Information(@"Migrating ME3Explorer tool");
                        var externalToolsME3ExplorerDir = Path.Combine(dataDir, @"ExternalTools", @"ME3Explorer");
                        Directory.CreateDirectory(Path.Combine(dataDir, @"ExternalTools"));
                        Directory.Move(me3explorerDir, externalToolsME3ExplorerDir);
                        Log.Information(@"Migrated ME3Explorer to ExternalTools");
                    }

                    //MIGRATE 7z.dll - this will only perform an interim fix as we use 19.0 and ME3MM used 18.05
                    var me3mm7z  = Path.Combine(dataDir, @"tools\ModManagerCommandLine\x64\7z.dll");
                    var target7z = Utilities.Get7zDllPath();
                    if (File.Exists(me3mm7z) && !File.Exists(target7z))
                    {
                        Log.Information($@"Copying ME3CMM 7z.dll to ME3Tweaks Mod Manager dll location: {me3mm7z} -> {target7z}");
                        File.Copy(me3mm7z, target7z, true);
                        Log.Information(@"Copied ME3MM 7z dll");
                    }

                    //MIGRATE MOD GROUPS (batch install queues)/
                    //Migrate ME3Explorer, if found
                    var modGroupsDir = Path.Combine(dataDir, @"modgroups");
                    if (Directory.Exists(modGroupsDir))
                    {
                        Log.Information(@"Migrating batch mod groups");
                        var queues = Directory.EnumerateFiles(modGroupsDir, @"*.txt").ToList();
                        foreach (var queue in queues)
                        {
                            var biqDest = Path.Combine(Utilities.GetBatchInstallGroupsFolder(), Path.GetFileName(queue));
                            Log.Information($@"Migrating mod install group: {queue} -> {biqDest}");
                            File.Move(queue, biqDest, true);
                            Log.Information(@"Migrated " + Path.GetFileName(queue));
                        }
                    }

                    MigratingSettings.SetDone();

                    Log.Information(@"Step 2: Finished settings migration");
                    // 3. CLEANUP
                    Log.Information(@"Step 3: Cleaning up");
                    CleaningUpTask.SetInProgress();
                    CleaningUpTask.SetDone();
                    Log.Information(@"Step 3: Cleaned up");
                    Thread.Sleep(3000);
                }
                else
                {
                    Log.Error(@"mods and/or data dir don't exist! We will not attempt migration.");
                }

                Log.Information(@"<<<< Exiting ME3CMMMigration Thread");
            };
            nbw.RunWorkerCompleted += (a, b) =>
            {
                Log.Information(@"Migration has completed.");
                Close();
            };
            nbw.RunWorkerAsync();
        }
Beispiel #21
0
        // parameter recipe가 아니라, parameter back-up 용도로 사용한다. 뭐 여하튼 필요할 수도 있는 기능이니까..
        public void parameterRecipeOpenDialog()
        {
            // Default Directory : C:\Users\protec\Documents\PROTEC\PSA\Recipe\
            FolderBrowserDialog opDlg = new FolderBrowserDialog();

            opDlg.SelectedPath        = "C:\\PROTEC\\BackUp";
            opDlg.ShowNewFolderButton = false;
            DialogResult rst = opDlg.ShowDialog();

            if (rst == DialogResult.OK)
            {
                try
                {
                    string selected = opDlg.SelectedPath;
                    mc.para.read(out ret.b, selected);
                    if (!ret.b)
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, String.Format(textResource.MB_ETC_FILE_LOAD_FAIL, "Parameter"));
                        return;
                    }

                    if (!mc.hd.tool.X.config.read(selected))
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "Gantry X Motion Parameter Read ERROR!"); return;
                    }
                    if (!mc.hd.tool.Y.config.read(selected))
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "Gantry Y Motion Parameter Read ERROR!"); return;
                    }
                    for (int i = 0; i < mc.activate.headCnt; i++)
                    {
                        if (!mc.hd.tool.Z[i].config.read(selected))
                        {
                            EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "Gantry Z Motion Parameter Read ERROR!" + " #" + i.ToString()); return;
                        }
                        if (!mc.hd.tool.T[i].config.read(selected))
                        {
                            EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "Gantry T Motion Parameter Read ERROR!" + " #" + i.ToString()); return;
                        }
                    }

                    if (!mc.sf.Z2.config.read(selected))
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "StackFeeder Z2 Motion Parameter Read ERROR!"); return;
                    }
                    if (!mc.sf.Z.config.read(selected))
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "StackFeeder Z Motion Parameter Read ERROR!"); return;
                    }

                    if (!mc.cv.W.config.read(selected))
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "Conveyor W homing para write error"); return;
                    }

                    selected += "\\Vision";

                    CopyDir.Copy(selected, "C:\\PROTEC\\Data\\Vision");

                    for (int i = 0; i < mc.hdc.cam.MODEL_MAX_CNT; i++)
                    {
                        mc.hdc.cam.readModel(i);
                    }
                    //mc.hdc.cam.readGrabber();
                    mc.hdc.cam.readIntensity();
                    mc.hdc.cam.readCircleCenter();
                    mc.hdc.cam.readRectangleCenter();
                    mc.hdc.cam.readCornerEdge();

                    for (int i = 0; i < mc.ulc.cam.MODEL_MAX_CNT; i++)
                    {
                        mc.ulc.cam.readModel(i);
                    }
                    //mc.ulc.cam.readGrabber();
                    mc.ulc.cam.readIntensity();
                    mc.ulc.cam.readCircleCenter();
                    mc.ulc.cam.readRectangleCenter();
                    mc.ulc.cam.readCornerEdge();

                    if (ret.b)
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.INFORMATION, String.Format(textResource.MB_ETC_FILE_LOAD_OK, "Parameter"));
                    }
                    else
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, String.Format(textResource.MB_ETC_FILE_LOAD_FAIL, "Parameter"));
                    }
                }
                catch
                {
                    EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, String.Format(textResource.MB_ETC_FILE_LOAD_FAIL, "Parameter"));
                }
            }
        }
        private void Migration_ContentRendered(object sender, EventArgs e)
        {
            NamedBackgroundWorker nbw = new NamedBackgroundWorker(@"ME3CMMMigration");

            nbw.DoWork += (a, b) =>
            {
                bool cleanup  = false;
                bool migrated = true;
                Log.Information(@">>>> ME3CMMMigration Thread");
                Log.Information(@"Validate ME3CMM folders and files");
                var exeDir = Utilities.GetMMExecutableDirectory();


                var modsDir = Path.Combine(exeDir, @"mods");
                var dataDir = Path.Combine(exeDir, @"data");
                try
                {
                    if (Directory.Exists(modsDir) && Directory.Exists(dataDir))
                    {
                        Log.Information(@"mods and data dir exist.");
                        // 1. MIGRATE MODS
                        Log.Information(@"Step 1: Migrate mods");
                        MigratingModsTask.SetInProgress();

                        var targetModLibrary = Utilities.GetModsDirectory();

                        targetModLibrary = Path.Combine(targetModLibrary, @"ME3");
                        if (!Directory.Exists(targetModLibrary))
                        {
                            Log.Information(@"Creating target mod library directory: " + targetModLibrary);
                            Directory.CreateDirectory(targetModLibrary);
                        }

                        var sameRoot = Path.GetPathRoot(targetModLibrary) == Path.GetPathRoot(modsDir);

                        var directoriesInModsDir = Directory.GetDirectories(modsDir);

                        var numToMigrate = directoriesInModsDir.Count(x => File.Exists(Path.Combine(x, @"moddesc.ini")));
                        var numMigrated  = 0;

                        foreach (var modDirToMove in directoriesInModsDir)
                        {
                            var moddesc = Path.Combine(modDirToMove, @"moddesc.ini");
                            if (File.Exists(moddesc))
                            {
                                numMigrated++;
                                MigratingModsTask.TaskText = M3L.GetString(M3L.string_interp_migratingModsXoFY, numMigrated, numToMigrate);
                                //Migrate this folder
                                var targetDir = Path.Combine(targetModLibrary, Path.GetFileName(modDirToMove));
                                Log.Information($@"Migrating mod into ME3 directory: {modDirToMove} -> {targetDir}");
                                if (!Directory.Exists(targetDir))
                                {
                                    if (sameRoot)
                                    {
                                        Directory.Move(modDirToMove, targetDir);
                                    }
                                    else
                                    {
                                        Log.Information(@" >> Copying existing mod directory");
                                        Directory.CreateDirectory(targetDir);
                                        CopyDir.CopyAll_ProgressBar(new DirectoryInfo(modDirToMove), new DirectoryInfo(targetDir));
                                        Log.Information(@" >> Deleting existing directory");
                                        Utilities.DeleteFilesAndFoldersRecursively(modDirToMove);
                                    }

                                    Log.Information($@"Migrated {modDirToMove}");
                                }
                                else
                                {
                                    Log.Warning(@"Target directory already exists! Not migrating this directory.");
                                }
                            }
                        }

                        MigratingModsTask.SetDone();
                        Log.Information(@"Step 1: Finished mod migration");

                        // 2. MIGRATE SETTINGS
                        MigratingSettings.SetInProgress();
                        Log.Information(@"Step 2: Begin settings migration");
                        var me3cmminif = Path.Combine(exeDir, @"me3cmm.ini");
                        if (File.Exists(me3cmminif))
                        {
                            Log.Information(@"Migrating me3cmm.ini settings");
                            IniData me3cmmini = new FileIniDataParser().ReadFile(me3cmminif);
                            var     updaterServiceUsername = me3cmmini[@"UpdaterService"][@"username"];
                            if (string.IsNullOrWhiteSpace(Settings.UpdaterServiceUsername) && !string.IsNullOrWhiteSpace(updaterServiceUsername))
                            {
                                Settings.UpdaterServiceUsername = updaterServiceUsername;
                                Log.Information(@"Migrated Updater Service Username: "******"UpdaterService"][@"manifestspath"];
                            if (string.IsNullOrWhiteSpace(Settings.UpdaterServiceManifestStoragePath) && !string.IsNullOrWhiteSpace(manifestsPath))
                            {
                                Settings.UpdaterServiceManifestStoragePath = manifestsPath;
                                Log.Information(@"Migrated Updater Service Manifests Path: " + manifestsPath);
                            }

                            var lzmaStoragePath = me3cmmini[@"UpdaterService"][@"lzmastoragepath"];
                            if (string.IsNullOrWhiteSpace(Settings.UpdaterServiceLZMAStoragePath) && !string.IsNullOrWhiteSpace(lzmaStoragePath))
                            {
                                Settings.UpdaterServiceLZMAStoragePath = lzmaStoragePath;
                                Log.Information(@"Migrated Updater Service LZMA Storage Path: " + lzmaStoragePath);
                            }

                            //Modmaker Auto Injections
                            var controllerModOption = me3cmmini[@"Settings"][@"controllermoduser"];
                            if (Settings.ModMakerControllerModOption == false && controllerModOption == "1")
                            {
                                Settings.ModMakerControllerModOption = true; //Set to true (default is false)
                                Log.Information(@"Migrated Auto install controller mixins for ModMaker (true)");
                            }

                            var keybindsInjectionOption = me3cmmini[@"Settings"][@"autoinjectkeybinds"];
                            if (Settings.ModMakerAutoInjectCustomKeybindsOption == false && keybindsInjectionOption == "1")
                            {
                                Settings.ModMakerAutoInjectCustomKeybindsOption = true; //Set to true (default is false)
                                Log.Information(@"Migrated Auto inject keybinds for ModMaker (true)");
                            }

                            //Settings.Save();
                        }

                        //Migrate BIOGAME_DIRECTORIES
                        var biogameDirsF = Path.Combine(dataDir, @"BIOGAME_DIRECTORIES");
                        if (File.Exists(biogameDirsF))
                        {
                            var biodirs = File.ReadAllLines(biogameDirsF);
                            foreach (var line in biodirs)
                            {
                                var gamepath = Directory.GetParent(line).FullName;
                                Log.Information(@"Validating ME3CMM target: " + gamepath);
                                GameTarget t             = new GameTarget(MEGame.ME3, gamepath, false);
                                var        failureReason = t.ValidateTarget();
                                if (failureReason == null)
                                {
                                    Utilities.AddCachedTarget(t);
                                }
                                else
                                {
                                    Log.Error($@"Not migrating invalid target {gamepath}: {failureReason}");
                                }
                            }
                        }

                        //Migrate ALOT Installer, if found
                        var alotInstallerDir = Path.Combine(dataDir, @"ALOTInstaller");
                        if (Directory.Exists(alotInstallerDir))
                        {
                            Log.Information(@"Migrating ALOTInstaller tool");
                            var externalToolsALOTInstaller = Path.Combine(dataDir, @"ExternalTools", @"ALOTInstaller");
                            Directory.CreateDirectory(Path.Combine(dataDir, @"ExternalTools"));
                            Directory.Move(alotInstallerDir, externalToolsALOTInstaller);
                            Log.Information(@"Migrated ALOTInstaller to ExternalTools");
                        }

                        //Migrate ME3Explorer, if found
                        var me3explorerDir = Path.Combine(dataDir, @"ME3Explorer");
                        if (Directory.Exists(me3explorerDir))
                        {
                            Log.Information(@"Migrating ME3Explorer tool");
                            var externalToolsME3ExplorerDir = Path.Combine(dataDir, @"ExternalTools", @"ME3Explorer");
                            Directory.CreateDirectory(Path.Combine(dataDir, @"ExternalTools"));
                            Directory.Move(me3explorerDir, externalToolsME3ExplorerDir);
                            Log.Information(@"Migrated ME3Explorer to ExternalTools");
                        }

                        //Migrate cached modmaker mods
                        var modmakerCacheDir = Path.Combine(dataDir, @"modmaker", @"cache");
                        if (Directory.Exists(modmakerCacheDir))
                        {
                            var modmakerXmls = Directory.GetFiles(modmakerCacheDir, @"*.xml");
                            if (modmakerXmls.Any())
                            {
                                var mmNewCacheDir = Utilities.GetModmakerDefinitionsCache();
                                Log.Information(@"Migrating ME3Tweaks ModMaker cached files");
                                foreach (var f in modmakerXmls)
                                {
                                    var fname    = Path.GetFileName(f);
                                    var destName = Path.Combine(mmNewCacheDir, fname);
                                    if (!File.Exists(destName))
                                    {
                                        Log.Information(@"Migrating modmaker mod delta definition file " + fname);
                                        File.Move(f, destName);
                                    }
                                }

                                Log.Information(@"Migrated ModMaker cached files");
                            }
                        }


                        //MIGRATE 7z.dll - this will only perform an interim fix (maybe network failure?) as we use 19.0 and ME3MM used 18.05
                        var me3mm7z  = Path.Combine(dataDir, @"tools\ModManagerCommandLine\x64\7z.dll");
                        var target7z = Utilities.Get7zDllPath();
                        if (File.Exists(me3mm7z) && !File.Exists(target7z))
                        {
                            Log.Information($@"Copying ME3MM 7z.dll to ME3Tweaks Mod Manager dll location: {me3mm7z} -> {target7z}");
                            File.Copy(me3mm7z, target7z, true);
                            Log.Information(@"Copied ME3MM 7z dll");
                        }

                        // Migrate DLC_AUTH_FAIL
                        var me3mmAuthFail  = Path.Combine(dataDir, @"help\DLC_AUTH_FAIL.png");
                        var targetAuthFail = Path.Combine(Utilities.GetLocalHelpResourcesDirectory(), @"DLC_AUTH_FAIL.png");
                        if (File.Exists(me3mmAuthFail) && !File.Exists(targetAuthFail))
                        {
                            Log.Information($@"Copying DLC_AUTH_FAIL help resource to ME3Tweaks Mod Manager help resources location: {me3mmAuthFail} -> {targetAuthFail}");
                            File.Copy(me3mmAuthFail, targetAuthFail, true);
                            Log.Information(@"Copied DLC_AUTH_FAIL");
                        }

                        //MIGRATE MOD GROUPS (batch install queues)
                        var modGroupsDir = Path.Combine(dataDir, @"modgroups");
                        if (Directory.Exists(modGroupsDir))
                        {
                            Log.Information(@"Migrating batch mod groups");
                            var queues = Directory.EnumerateFiles(modGroupsDir, @"*.txt").ToList();
                            foreach (var queue in queues)
                            {
                                var biqDest = Path.Combine(Utilities.GetBatchInstallGroupsFolder(), Path.GetFileName(queue));
                                Log.Information($@"Migrating mod install group: {queue} -> {biqDest}");
                                File.Move(queue, biqDest, true);
                                Log.Information(@"Migrated " + Path.GetFileName(queue));
                            }
                        }


                        // MIGRATE override
                        var overrideDir = Path.Combine(dataDir, @"override");
                        if (Directory.Exists(overrideDir))
                        {
                            Log.Information(@"Migrating override");
                            var filesInKBDir = Directory.EnumerateFiles(overrideDir, @"*.xml").ToList();
                            foreach (var file in filesInKBDir)
                            {
                                var keybindDir = Path.Combine(Utilities.GetKeybindsOverrideFolder(), @"me3-" + Path.GetFileName(file));
                                Log.Information($@"Migrating keybinds override: {file} -> {keybindDir}");
                                File.Move(file, keybindDir, true);
                                Log.Information(@"Migrated " + Path.GetFileName(file));
                            }
                        }

                        MigratingSettings.SetDone();

                        Log.Information(@"Step 2: Finished settings migration");
                        // 3. CLEANUP
                        App.Current.Dispatcher.Invoke(delegate { cleanup = M3L.ShowDialog(null, M3L.GetString(M3L.string_dialog_performMe3cmmCleanup), M3L.GetString(M3L.string_performCleanupQuestion), MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.Yes) == MessageBoxResult.Yes; });
                        if (cleanup)
                        {
                            Log.Information(@"Step 3: Cleaning up");
                            CleaningUpTask.SetInProgress();
                            var directoriesInDataDir = Directory.GetFileSystemEntries(dataDir);
                            foreach (var entry in directoriesInDataDir)
                            {
                                var name = Path.GetFileName(entry);
                                if (Directory.Exists(entry))
                                {
                                    switch (name.ToLower())
                                    {
                                    case @"deployed mods":
                                    case @"externaltools": // Created by M3 at this point
                                    case @"patch_001_extracted":
                                    case @"pccdumps":      //guess these might be useful
                                        continue;

                                    default:
                                        try
                                        {
                                            Log.Information(@"Deleting directory: " + entry);
                                            Utilities.DeleteFilesAndFoldersRecursively(entry, true);
                                        }
                                        catch (Exception e)
                                        {
                                            Log.Error($@"Unable to delete item in data directory: {entry}, reason: {e.Message}");
                                        }

                                        break;
                                    }
                                }
                                else if (File.Exists(entry))
                                {
                                    try
                                    {
                                        Log.Information(@"Cleanup: Deleting file " + entry);
                                        File.Delete(entry);
                                    }
                                    catch (Exception e)
                                    {
                                        Log.Error($@"Unable to delete {entry}: {e.Message}");
                                    }
                                }
                            }

                            // Install redirect to ensure user shortcuts continue to work
                            var me3cmmPath = Path.Combine(exeDir, @"ME3CMM.exe");
                            Log.Information(@"Writing redirector to " + me3cmmPath);
                            Utilities.ExtractInternalFile(@"MassEffectModManagerCore.updater.ME3CMM.exe", me3cmmPath, true);
                        }
                        else
                        {
                            Log.Information(@"Skipping step 3: cleanup due to user request.");
                        }

                        CleaningUpTask.SetDone();
                        Log.Information(@"Step 3: Cleaned up");
                        Thread.Sleep(3000);
                    }
                    else
                    {
                        migrated = false;
                        Log.Error(@"mods and/or data dir don't exist! We will not attempt migration.");
                    }
                }
                catch (Exception e)
                {
                    migrated = false;
                    Log.Error(@"Error in migration: " + e.Message);
                    Crashes.TrackError(e);
                }
                Analytics.TrackEvent(@"ME3CMM Migration", new Dictionary <string, string>()
                {
                    { @"Migrated", migrated.ToString() },
                    { @"Cleaned up", cleanup.ToString() },
                });
                Log.Information(@"<<<< Exiting ME3CMMMigration Thread");
            };
            nbw.RunWorkerCompleted += (a, b) =>
            {
                if (b.Error != null)
                {
                    Log.Error($@"Exception occurred in {nbw.Name} thread: {b.Error.Message}");
                }
                Log.Information(@"Migration has completed.");
                M3L.ShowDialog(null, M3L.GetString(M3L.string_dialog_me3cmmMigrationCompleted));
                Close();
            };
            nbw.RunWorkerAsync();
        }
Beispiel #23
0
        public void parameterRecipeSaveDialog()
        {
            FolderBrowserDialog svDlg = new FolderBrowserDialog();

            svDlg.SelectedPath        = "C:\\PROTEC\\BackUp";
            svDlg.ShowNewFolderButton = true;
            DialogResult rst = svDlg.ShowDialog();

            if (rst == DialogResult.OK)
            {
                try
                {
                    string selected = svDlg.SelectedPath;
                    mc.para.write(out ret.b, selected);
                    if (!ret.b)
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, String.Format(textResource.MB_ETC_FILE_SAVE_FAIL, "Parameter"));
                        return;
                    }

                    if (!mc.hd.tool.X.config.write(selected))
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "Gantry X Motion Parameter Write ERROR!"); return;
                    }
                    if (!mc.hd.tool.Y.config.write(selected))
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "Gantry Y Motion Parameter Write ERROR!"); return;
                    }
                    for (int i = 0; i < mc.activate.headCnt; i++)
                    {
                        if (!mc.hd.tool.Z[i].config.write(selected))
                        {
                            EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "Gantry Z Motion Parameter Write ERROR!"); return;
                        }
                        if (!mc.hd.tool.T[i].config.write(selected))
                        {
                            EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "Gantry T Motion Parameter Write ERROR!"); return;
                        }
                    }

                    //if (!mc.pd.X.config.write(selected)) { EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "Pedestal X Motion Parameter Write ERROR!"); return; }
                    //if (!mc.pd.Y.config.write(selected)) { EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "Pedestal Y Motion Parameter Write ERROR!"); return; }
                    //if (!mc.pd.W.config.write(selected)) { EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "Pedestal W Motion Parameter Write ERROR!"); return; }

                    if (!mc.sf.Z2.config.write(selected))
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "StackFeeder Z2 Motion Parameter Write ERROR!"); return;
                    }
                    if (!mc.sf.Z.config.write(selected))
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "StackFeeder Z Motion Parameter Write ERROR!"); return;
                    }

                    if (!mc.cv.W.config.write(selected))
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, "Conveyor W homing para write error"); return;
                    }

                    selected += "\\Vision";

                    CopyDir.Copy("C:\\PROTEC\\Data\\Vision", selected);

                    if (ret.b)
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.INFORMATION, String.Format(textResource.MB_ETC_FILE_SAVE_OK, "Parameter"));
                    }
                    else
                    {
                        EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, String.Format(textResource.MB_ETC_FILE_SAVE_FAIL, "Parameter"));
                    }
                }
                catch
                {
                    EVENT.userDialogMessage(DIAG_SEL_MODE.OK, DIAG_ICON_MODE.FAILURE, String.Format(textResource.MB_ETC_FILE_SAVE_FAIL, "Parameter"));
                }
            }
        }
Beispiel #24
0
        public static void Main(string[] args)
        {
            Console.WriteLine("Breath of the Wild Save Manager by Jordan Zeotni, fork of https://github.com/WemI0/BOTW_SaveConv");
            Console.Write("Enter the path of the save folder in your save folder or press enter if the application is in the root of the save folder: ");
            string folderLocation = Console.ReadLine()?.Trim('"');

            if (string.IsNullOrWhiteSpace(folderLocation))
            {
                if (Directory.GetFiles(Globals.AppPath, "*.sav").First() == null)
                {
                    Console.WriteLine("There are no files with the extension *.sav in this folder. Either place this application in the same folder as option.sav or enter the save folder's path.");
                    Main(args);
                    return;
                }

                folderLocation = Path.Combine(Globals.AppPath, Directory.GetFiles(Globals.AppPath, "*.sav").First());
            }
            else if (!Directory.Exists(folderLocation))
            {
                Console.WriteLine("The directory does not exist at this path. Either place this application in the root directory or enter the path of the save folder.");
                Main(args);
                return;
            }

            Save selectedSave;

            try
            {
                selectedSave = new Save(folderLocation);
            }
            catch (UnsupportedSaveException e)
            {
                if (e.IsSwitch)
                {
                    Console.Write("Cannot find switch version from save. If you would like to attempt to use this file anyways, enter \"Y\": ");

                    if (Console.ReadKey().Key == ConsoleKey.Y)
                    {
                        selectedSave = new Save(folderLocation, true);
                        Console.WriteLine();
                    }
                    else
                    {
                        Console.WriteLine();
                        Console.WriteLine("This save is not supported. If you think this is an error report the following stacktrace:");
                        Console.WriteLine(e);
                        Console.WriteLine();
                        Console.WriteLine();
                        Main(args);
                        return;
                    }
                }
                else
                {
                    Console.WriteLine("This save is not supported. If you think this is an error report the following stacktrace:");
                    Console.WriteLine(e);
                    Console.WriteLine();
                    Console.WriteLine();
                    Main(args);
                    return;
                }
            }

            Console.WriteLine(selectedSave.SaveConsoleType + " - Versions:");
            Console.WriteLine(string.Join("\n", selectedSave.SaveVersionList));
            Console.WriteLine("Press any key to begin conversion, or ESC to cancel...");
            ConsoleKeyInfo consoleKeyInfo = Console.ReadKey(true);

            if (consoleKeyInfo.Key == ConsoleKey.Escape)
            {
                return;
            }

            Dictionary <string, byte[]> convertSaveBytes = selectedSave.ConvertSave();

            Console.Write("Enter a folder to write the save to, or press enter to overwrite the existing save with the converted version: ");
            string saveLocation = Console.ReadLine()?.Trim('"');

            try
            {
                if (string.IsNullOrWhiteSpace(saveLocation))
                {
                    foreach (KeyValuePair <string, byte[]> convertSaveByte in convertSaveBytes)
                    {
                        File.WriteAllBytes(convertSaveByte.Key, convertSaveByte.Value);
                    }
                }
                else
                {
                    CopyDir.Copy(selectedSave.SaveFolder, saveLocation);

                    foreach (KeyValuePair <string, byte[]> convertSaveByte in convertSaveBytes)
                    {
                        string saveTo = Directory.GetFiles(saveLocation, "*.sav", SearchOption.AllDirectories)
                                        .First(e => Path.GetFileName(convertSaveByte.Key) == "option.sav" ||
                                               Path.GetFileName(e) == Path.GetFileName(convertSaveByte.Key) &&
                                               Directory.GetParent(e).Name == Directory.GetParent(convertSaveByte.Key).Name);

                        File.WriteAllBytes(saveTo, convertSaveByte.Value);
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("The files cannot be saved at this path. If you think this is an error report the following stacktrace:");
                Console.WriteLine(e);
                Console.WriteLine();
                Console.WriteLine();
                Main(args);
                return;
            }

            Console.WriteLine($"Files saved successfully! \nPress any key to close...");
            Console.ReadKey(true);
        }
            private void BeginBackup()
            {
                if (Utilities.IsGameRunning(BackupSourceTarget.Game))
                {
                    Xceed.Wpf.Toolkit.MessageBox.Show(window, $"Cannot backup {Utilities.GetGameName(BackupSourceTarget.Game)} while it is running.", $"Game is running", MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }
                NamedBackgroundWorker bw = new NamedBackgroundWorker(Game.ToString() + "Backup");

                bw.DoWork += (a, b) =>
                {
                    BackupInProgress = true;
                    List <string> nonVanillaFiles = new List <string>();
                    void nonVanillaFileFoundCallback(string filepath)
                    {
                        Log.Error("Non-vanilla file found: " + filepath);
                        nonVanillaFiles.Add(filepath);
                    }

                    List <string> inconsistentDLC = new List <string>();
                    void inconsistentDLCFoundCallback(string filepath)
                    {
                        if (BackupSourceTarget.Supported)
                        {
                            Log.Error("DLC is in an inconsistent state: " + filepath);
                            inconsistentDLC.Add(filepath);
                        }
                        else
                        {
                            Log.Error("Detected an inconsistent DLC, likely due to an unofficial copy of the game");
                        }
                    }

                    ProgressVisible       = true;
                    ProgressIndeterminate = true;
                    BackupStatus          = "Validating backup source";
                    VanillaDatabaseService.LoadDatabaseFor(Game);
                    bool          isVanilla        = VanillaDatabaseService.ValidateTargetAgainstVanilla(BackupSourceTarget, nonVanillaFileFoundCallback);
                    bool          isDLCConsistent  = VanillaDatabaseService.ValidateTargetDLCConsistency(BackupSourceTarget, inconsistentDLCCallback: inconsistentDLCFoundCallback);
                    List <string> dlcModsInstalled = VanillaDatabaseService.GetInstalledDLCMods(BackupSourceTarget);


                    if (isVanilla && isDLCConsistent && dlcModsInstalled.Count == 0)
                    {
                        BackupStatus = "Waiting for user input";
                        string backupPath = null;
                        bool   end        = false;
                        Application.Current.Dispatcher.Invoke(delegate
                        {
                            CommonOpenFileDialog m = new CommonOpenFileDialog
                            {
                                IsFolderPicker   = true,
                                EnsurePathExists = true,
                                Title            = "Select backup destination"
                            };
                            if (m.ShowDialog() == CommonFileDialogResult.Ok)
                            {
                                //Check empty
                                backupPath = m.FileName;
                                if (Directory.Exists(backupPath))
                                {
                                    if (Directory.GetFiles(backupPath).Length > 0 || Directory.GetDirectories(backupPath).Length > 0)
                                    {
                                        //Directory not empty
                                        MessageBox.Show("Directory is not empty. A backup destination must be empty.");
                                        end = true;
                                        EndBackup();
                                        return;
                                    }
                                }
                            }
                            else
                            {
                                end = true;
                                EndBackup();
                                return;
                            }
                        });
                        if (end)
                        {
                            return;
                        }

                        #region callbacks
                        void fileCopiedCallback()
                        {
                            ProgressValue++;
                        }

                        string dlcFolderpath   = MEDirectories.DLCPath(BackupSourceTarget) + '\\';
                        int    dlcSubStringLen = dlcFolderpath.Length;
                        bool aboutToCopyCallback(string file)
                        {
                            if (file.Contains("\\cmmbackup\\"))
                            {
                                return(false);                                //do not copy cmmbackup files
                            }
                            if (file.StartsWith(dlcFolderpath))
                            {
                                //It's a DLC!
                                string dlcname = file.Substring(dlcSubStringLen);
                                dlcname = dlcname.Substring(0, dlcname.IndexOf('\\'));
                                if (MEDirectories.OfficialDLCNames(BackupSourceTarget.Game).TryGetValue(dlcname, out var hrName))
                                {
                                    BackupStatusLine2 = "Backing up " + hrName;
                                }
                                else
                                {
                                    BackupStatusLine2 = "Backing up " + dlcname;
                                }
                            }
                            else
                            {
                                //It's basegame
                                if (file.EndsWith(".bik"))
                                {
                                    BackupStatusLine2 = "Backing up Movies";
                                }
                                else if (new FileInfo(file).Length > 52428800)
                                {
                                    BackupStatusLine2 = "Backing up " + Path.GetFileName(file);
                                }
                                else
                                {
                                    BackupStatusLine2 = "Backing up BASEGAME";
                                }
                            }
                            return(true);
                        }

                        void totalFilesToCopyCallback(int total)
                        {
                            ProgressValue         = 0;
                            ProgressIndeterminate = false;
                            ProgressMax           = total;
                        }

                        #endregion
                        BackupStatus = "Creating backup";

                        CopyDir.CopyAll_ProgressBar(new DirectoryInfo(BackupSourceTarget.TargetPath), new DirectoryInfo(backupPath),
                                                    totalItemsToCopyCallback: totalFilesToCopyCallback,
                                                    aboutToCopyCallback: aboutToCopyCallback,
                                                    fileCopiedCallback: fileCopiedCallback,
                                                    ignoredExtensions: new[] { "*.pdf", "*.mp3" });
                        switch (Game)
                        {
                        case Mod.MEGame.ME1:
                        case Mod.MEGame.ME2:
                            Utilities.WriteRegistryKey(App.BACKUP_REGISTRY_KEY, Game + "VanillaBackupLocation", backupPath);
                            break;

                        case Mod.MEGame.ME3:
                            Utilities.WriteRegistryKey(App.REGISTRY_KEY_ME3CMM, "VanillaCopyLocation", backupPath);
                            break;
                        }
                        Analytics.TrackEvent("Created a backup", new Dictionary <string, string>()
                        {
                            { "Game", Game.ToString() },
                            { "Result", "Success" }
                        });

                        EndBackup();
                        return;
                    }

                    if (!isVanilla)
                    {
                        //Show UI for non vanilla
                        Analytics.TrackEvent("Created a backup", new Dictionary <string, string>()
                        {
                            { "Game", Game.ToString() },
                            { "Result", "Failure, Game modified" }
                        });
                        b.Result = (nonVanillaFiles, "Cannot backup modified game", "The following files do not match the vanilla database and appear to be modified. Due to these files being modified, a backup cannot be taken of this installation.");
                    }
                    else if (!isDLCConsistent)
                    {
                        Analytics.TrackEvent("Created a backup", new Dictionary <string, string>()
                        {
                            { "Game", Game.ToString() },
                            { "Result", "Failure, DLC inconsistent" }
                        });
                        if (BackupSourceTarget.Supported)
                        {
                            b.Result = (inconsistentDLC, "Inconsistent DLC detected", "The following DLC are in an inconsistent state; they have a packed SFAR file but contain unpacked game files. The configuration of these DLC are not supported, the unpacked files must be manually removed.");
                        }
                        else
                        {
                            b.Result = ("Inconsistent DLC detected", "Inconsistent DLC was detected. This may be due to using an unofficial copy of the game.");
                        }
                    }
                    else if (dlcModsInstalled.Count > 0)
                    {
                        Analytics.TrackEvent("Created a backup", new Dictionary <string, string>()
                        {
                            { "Game", Game.ToString() },
                            { "Result", "Failure, DLC mods found" }
                        });
                        b.Result = (dlcModsInstalled, "DLC mods are installed", "The following DLC folders were detected that are not part of the official game by BioWare. Backups cannot include DLC mods - the game must be unmodified.");
                    }
                    EndBackup();
                };
                bw.RunWorkerCompleted += (a, b) =>
                {
                    if (b.Result is (List <string> listItems, string title, string text))
                    {
                        ListDialog ld = new ListDialog(listItems, title, text, window);
                        ld.Show();
                    }
                    else if (b.Result is (string errortitle, string message))
                    {
                        Xceed.Wpf.Toolkit.MessageBox.Show(message, errortitle, MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    CommandManager.InvalidateRequerySuggested();
                };
                bw.RunWorkerAsync();
            }
Beispiel #26
0
        public App() : base()
        {
            string[]         args                  = Environment.GetCommandLineArgs();
            List <string>    preLogMessages        = new List <string>();
            Parsed <Options> parsedCommandLineArgs = null;
            string           loggingBasePath       = System.AppDomain.CurrentDomain.BaseDirectory;
            string           updateDestinationPath = null;

            if (args.Length > 1)
            {
                var result = Parser.Default.ParseArguments <Options>(args);
                if (result.GetType() == typeof(Parsed <Options>))
                {
                    //Parsing succeeded - have to do update check to keep logs in order...
                    parsedCommandLineArgs = (Parsed <Options>)result;
                    if (parsedCommandLineArgs.Value.UpdateDest != null)
                    {
                        if (Directory.Exists(parsedCommandLineArgs.Value.UpdateDest))
                        {
                            updateDestinationPath = parsedCommandLineArgs.Value.UpdateDest;
                            loggingBasePath       = updateDestinationPath;
                        }
                        else
                        {
                            preLogMessages.Add("Directory doesn't exist for update: " + parsedCommandLineArgs.Value.UpdateDest);
                        }
                    }
                    if (parsedCommandLineArgs.Value.BootMEUITMMode)
                    {
                        Log.Information("We are booting into MEUITM mode.");
                        BootMEUITMMode = true;
                    }
                    if (parsedCommandLineArgs.Value.ME3Path != null && Directory.Exists(parsedCommandLineArgs.Value.ME3Path))
                    {
                        PreloadedME3Path = parsedCommandLineArgs.Value.ME3Path;
                        //get MassEffectModder.ini
                        string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                                                   "MassEffectModder");
                        string _iniPath = Path.Combine(path, "MassEffectModder.ini");
                        if (!Directory.Exists(path))
                        {
                            preLogMessages.Add("Preset ME3 path, ini folder doesn't exist, creating.");
                            Directory.CreateDirectory(path);
                        }
                        if (!File.Exists(_iniPath))
                        {
                            preLogMessages.Add("Preset ME3 path, ini doesn't exist, creating.");
                            File.Create(_iniPath);
                        }

                        IniFile ini = new IniFile(_iniPath);
                        ini.Write("ME3", parsedCommandLineArgs.Value.ME3Path, "GameDataPath");
                        preLogMessages.Add("Wrote preset ME3 path to " + parsedCommandLineArgs.Value.ME3Path);
                    }
                    if (parsedCommandLineArgs.Value.BootingNewUpdate)
                    {
                        Log.Information("Booting an update");
                        preLogMessages.Add("Booting an update.");
                        foreach (string file in Directory.GetFiles(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location), "*.pdb", SearchOption.AllDirectories))
                        {
                            File.Delete(file);
                        }
                    }
                }
            }

            Directory.CreateDirectory(loggingBasePath + "\\logs");
            Log.Logger = new LoggerConfiguration()
                         .MinimumLevel.Debug()
                         .WriteTo.RollingFile(loggingBasePath + "\\logs\\alotinstaller-{Date}.txt", flushToDiskInterval: new TimeSpan(0, 0, 15))
                         .CreateLogger();
            this.Dispatcher.UnhandledException += OnDispatcherUnhandledException;
            POST_STARTUP = true;
            Log.Information("=====================================================");
            Log.Information("Logger Started for ALOT Installer.");
            preLogMessages.ForEach(x => Log.Information("Prelogger boot message: " + x));
            if (args.Length > 0)
            {
                string commandlineargs = "";
                for (int i = 0; i < args.Length; i++)
                {
                    commandlineargs += args[i] + " ";
                }
                Log.Information("Command line arguments: " + commandlineargs);
            }
            Log.Information("Working directory: " + Directory.GetCurrentDirectory());

            //Update Mode
            if (updateDestinationPath != null)
            {
                Thread.Sleep(2000); //SLEEP WHILE WE WAIT FOR PARENT PROCESS TO STOP.
                Log.Information("In update mode. Update destination: " + updateDestinationPath);
                int i = 0;
                while (i < 5)
                {
                    i++;
                    try
                    {
                        Log.Information("Applying update");
                        CopyDir.CopyAll(new DirectoryInfo(System.AppDomain.CurrentDomain.BaseDirectory), new DirectoryInfo(updateDestinationPath));
                        break;
                    }
                    catch (Exception e)
                    {
                        Log.Error("Error applying update: " + e.Message);
                        if (i < 5)
                        {
                            Thread.Sleep(1000);
                            Log.Information("Attempt #" + (i + 1));
                        }
                        else
                        {
                            Log.Fatal("Unable to apply update after 5 attempts. We are giving up.");
                            MessageBox.Show("Update was unable to apply. See the logs directory for more information. If this continues to happen please come to the ALOT discord or download a new copy from GitHub.");
                            Environment.Exit(1);
                        }
                    }
                }
                Log.Information("Update files have been applied.");
                updateDestinationPath += "\\"; //add slash
                Log.Information("Performing update migrations...");
                if (Directory.Exists(updateDestinationPath + "MEM_Packages") && !Directory.Exists(updateDestinationPath + @"Data\MEM_Packages"))
                {
                    Log.Information("Migrating MEM_Packages folder into subfolder");
                    Directory.Move(updateDestinationPath + "MEM_Packages", updateDestinationPath + @"Data\MEM_Packages");
                }


                if (Directory.Exists(updateDestinationPath + "music") && !Directory.Exists(updateDestinationPath + @"Data\Music"))
                {
                    Log.Information("Migrating music folder into subfolder");
                    Directory.Move(updateDestinationPath + "music", updateDestinationPath + @"Data\Music");
                }

                if (Directory.Exists(updateDestinationPath + "bin"))
                {
                    Log.Information("Deleting old top level bin folder: " + (updateDestinationPath + "bin"));
                    Utilities.DeleteFilesAndFoldersRecursively(updateDestinationPath + "bin");
                }

                if (Directory.Exists(updateDestinationPath + "lib"))
                {
                    Log.Information("Deleting old top level lib folder");
                    Utilities.DeleteFilesAndFoldersRecursively(updateDestinationPath + "lib");
                }

                if (Directory.Exists(updateDestinationPath + "Extracted_Mods"))
                {
                    Log.Information("Deleting leftover Extracted_Mods folder");
                    Utilities.DeleteFilesAndFoldersRecursively(updateDestinationPath + "Extracted_Mods");
                }

                if (File.Exists(updateDestinationPath + "manifest.xml"))
                {
                    Log.Information("Deleting leftover manifest.xml file");
                    File.Delete(updateDestinationPath + "manifest.xml");
                }

                if (File.Exists(updateDestinationPath + "ALOTInstaller.exe.config"))
                {
                    Log.Information("Deleting leftover config file");
                    File.Delete(updateDestinationPath + "ALOTInstaller.exe.config");
                }

                if (File.Exists(updateDestinationPath + "manifest-bundled.xml"))
                {
                    Log.Information("Deleting leftover manifest-bundled.xml file");
                    File.Delete(updateDestinationPath + "manifest-bundled.xml");
                }

                if (File.Exists(updateDestinationPath + "DEV_MODE"))
                {
                    Log.Information("Pulling application out of developer mode");
                    File.Delete(updateDestinationPath + "DEV_MODE");
                }
                Log.Information("Rebooting into normal mode to complete update: " + updateDestinationPath + System.AppDomain.CurrentDomain.FriendlyName);
                ProcessStartInfo psi = new ProcessStartInfo(updateDestinationPath + System.AppDomain.CurrentDomain.FriendlyName);
                psi.WorkingDirectory = updateDestinationPath;
                psi.Arguments        = "--completing-update";
                if (BootMEUITMMode)
                {
                    psi.Arguments += " --meuitm-mode"; //pass through
                }
                Process.Start(psi);
                Environment.Exit(0);
                System.Windows.Application.Current.Shutdown();
            }

            //Normal Mode
            ToolTipService.ShowDurationProperty.OverrideMetadata(typeof(UIElement),
                                                                 new FrameworkPropertyMetadata(15000));
            ToolTipService.ShowOnDisabledProperty.OverrideMetadata(
                typeof(Control),
                new FrameworkPropertyMetadata(true));
            if (Directory.Exists(loggingBasePath + "Update"))
            {
                Thread.Sleep(1000);
                Log.Information("Removing Update directory");
                Directory.Delete(loggingBasePath + "Update", true);
            }
            if (File.Exists(loggingBasePath + "ALOTAddonBuilder.exe"))
            {
                Log.Information("Deleting Update Shim ALOTAddonBuilder.exe");
                File.Delete(loggingBasePath + "ALOTAddonBuilder.exe");
            }

            if (parsedCommandLineArgs != null && parsedCommandLineArgs.Value != null && parsedCommandLineArgs.Value.BootingNewUpdate)
            {
                //turn off debug mode
                Utilities.WriteRegistryKey(Registry.CurrentUser, AlotAddOnGUI.MainWindow.REGISTRY_KEY, AlotAddOnGUI.MainWindow.SETTINGSTR_DEBUGLOGGING, 0);
            }

            Log.Information("Program Version: " + System.Reflection.Assembly.GetEntryAssembly().GetName().Version);
            try
            {
                Log.Information("System information:\n" + Utilities.GetOperatingSystemInfo());
                Utilities.GetAntivirusInfo();
            }
            catch (Exception e)
            {
                Log.Error("UNABLE TO GET SYSTEM INFORMATION OR ANTIVIRUS INFO. This is indiciative that system may not be stable or that WMI is corrupt.");
                Log.Error(App.FlattenException(e));
            }
            //string releaseId = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ReleaseId", "").ToString();
        }
Beispiel #27
0
            private void BeginBackup()
            {
                var targetToBackup = BackupSourceTarget;

                if (!targetToBackup.IsCustomOption)
                {
                    if (Utilities.IsGameRunning(targetToBackup.Game))
                    {
                        M3L.ShowDialog(window, M3L.GetString(M3L.string_interp_cannotBackupGameWhileRunning, Utilities.GetGameName(BackupSourceTarget.Game)), M3L.GetString(M3L.string_gameRunning), MessageBoxButton.OK, MessageBoxImage.Error);
                        return;
                    }
                }
                else
                {
                    // Point to existing game installation
                    Log.Information(@"BeginBackup() with IsCustomOption.");
                    var linkWarning = M3L.ShowDialog(window,
                                                     M3L.GetString(M3L.string_dialog_linkTargetWontBeModdable), M3L.GetString(M3L.string_linkWarning), MessageBoxButton.OKCancel, MessageBoxImage.Warning);
                    if (linkWarning == MessageBoxResult.Cancel)
                    {
                        Log.Information(@"User aborted linking due to dialog");
                        return;
                    }

                    Log.Information(@"Prompting user to select executable of link target");
                    var gameexe = Utilities.PromptForGameExecutable(new[] { Game });
                    if (gameexe == null)
                    {
                        return;
                    }
                    targetToBackup = new GameTarget(Game, Utilities.GetGamePathFromExe(Game, gameexe), false, true);
                    if (AvailableBackupSources.Any(x => x.TargetPath.Equals(targetToBackup.TargetPath, StringComparison.InvariantCultureIgnoreCase)))
                    {
                        // Can't point to an existing modding target
                        Log.Error(@"This target is not valid to point to as a backup: It is listed a modding target already, it must be removed as a target first");
                        M3L.ShowDialog(window, M3L.GetString(M3L.string_interp_dialog_linkFailedAlreadyATarget), M3L.GetString(M3L.string_cannotLinkGameCopy), MessageBoxButton.OK, MessageBoxImage.Error);
                        return;
                    }

                    var validationFailureReason = targetToBackup.ValidateTarget(ignoreCmmVanilla: true);
                    if (!targetToBackup.IsValid)
                    {
                        Log.Error(@"This installation is not valid to point to as a backup: " + validationFailureReason);
                        M3L.ShowDialog(window, M3L.GetString(M3L.string_interp_dialog_linkFailedInvalidTarget, validationFailureReason), M3L.GetString(M3L.string_invalidGameCopy), MessageBoxButton.OK, MessageBoxImage.Error);
                        return;
                    }
                }

                NamedBackgroundWorker nbw = new NamedBackgroundWorker(Game + @"Backup");

                nbw.WorkerReportsProgress = true;
                nbw.ProgressChanged      += (a, b) =>
                {
                    if (b.UserState is double d)
                    {
                        window.TaskBarItemInfoHandler.ProgressValue = d;
                    }
                    else if (b.UserState is TaskbarItemProgressState tbs)
                    {
                        window.TaskBarItemInfoHandler.ProgressState = tbs;
                    }
                };
                nbw.DoWork += (a, b) =>
                {
                    Log.Information(@"Starting the backup thread. Checking path: " + targetToBackup.TargetPath);
                    BackupInProgress = true;
                    bool end = false;

                    List <string> nonVanillaFiles = new List <string>();

                    void nonVanillaFileFoundCallback(string filepath)
                    {
                        Log.Error($@"Non-vanilla file found: {filepath}");
                        nonVanillaFiles.Add(filepath);
                    }

                    List <string> inconsistentDLC = new List <string>();

                    void inconsistentDLCFoundCallback(string filepath)
                    {
                        if (targetToBackup.Supported)
                        {
                            Log.Error($@"DLC is in an inconsistent state: {filepath}");
                            inconsistentDLC.Add(filepath);
                        }
                        else
                        {
                            Log.Error(@"Detected an inconsistent DLC, likely due to an unofficial copy of the game");
                        }
                    }

                    ProgressVisible       = true;
                    ProgressIndeterminate = true;
                    BackupStatus          = M3L.GetString(M3L.string_validatingBackupSource);
                    Log.Information(@"Checking target is vanilla");
                    bool isVanilla = VanillaDatabaseService.ValidateTargetAgainstVanilla(targetToBackup, nonVanillaFileFoundCallback);

                    Log.Information(@"Checking DLC consistency");
                    bool isDLCConsistent = VanillaDatabaseService.ValidateTargetDLCConsistency(targetToBackup, inconsistentDLCCallback: inconsistentDLCFoundCallback);

                    Log.Information(@"Checking only vanilla DLC is installed");
                    List <string> dlcModsInstalled = VanillaDatabaseService.GetInstalledDLCMods(targetToBackup).Select(x =>
                    {
                        var tpmi = ThirdPartyServices.GetThirdPartyModInfo(x, targetToBackup.Game);
                        if (tpmi != null)
                        {
                            return($@"{x} ({tpmi.modname})");
                        }
                        return(x);
                    }).ToList();
                    List <string> installedDLC   = VanillaDatabaseService.GetInstalledOfficialDLC(targetToBackup);
                    List <string> allOfficialDLC = MEDirectories.OfficialDLC(targetToBackup.Game);

                    if (installedDLC.Count() < allOfficialDLC.Count())
                    {
                        var dlcList = string.Join("\n - ", allOfficialDLC.Except(installedDLC).Select(x => $@"{MEDirectories.OfficialDLCNames(targetToBackup.Game)[x]} ({x})")); //do not localize
                        dlcList = @" - " + dlcList;
                        Log.Information(@"The following dlc will be missing in the backup if user continues: " + dlcList);

                        Application.Current.Dispatcher.Invoke(delegate
                        {
                            var cancelDueToNotAllDLC = M3L.ShowDialog(window, M3L.GetString(M3L.string_dialog_notAllDLCInstalled, dlcList), M3L.GetString(M3L.string_someDlcNotInstalled), MessageBoxButton.YesNo, MessageBoxImage.Warning);
                            if (cancelDueToNotAllDLC == MessageBoxResult.No)
                            {
                                end = true;
                                EndBackup();
                                return;
                            }
                        });
                    }

                    if (end)
                    {
                        return;
                    }
                    if (isVanilla && isDLCConsistent && dlcModsInstalled.Count == 0)
                    {
                        BackupStatus = M3L.GetString(M3L.string_waitingForUserInput);

                        string backupPath = null;
                        if (!targetToBackup.IsCustomOption)
                        {
                            // Creating a new backup
                            nbw.ReportProgress(0, TaskDialogProgressBarState.Paused);

                            Application.Current.Dispatcher.Invoke(delegate
                            {
                                Log.Information(@"Prompting user to select backup destination");

                                CommonOpenFileDialog m = new CommonOpenFileDialog
                                {
                                    IsFolderPicker   = true,
                                    EnsurePathExists = true,
                                    Title            = M3L.GetString(M3L.string_selectBackupDestination)
                                };
                                if (m.ShowDialog() == CommonFileDialogResult.Ok)
                                {
                                    backupPath = m.FileName;
                                    Log.Information(@"Backup path chosen: " + backupPath);

                                    bool okToBackup = validateBackupPath(backupPath, targetToBackup);
                                    if (!okToBackup)
                                    {
                                        end = true;
                                        EndBackup();
                                        return;
                                    }
                                }
                                else
                                {
                                    end = true;
                                    EndBackup();
                                    return;
                                }
                            });
                            if (end)
                            {
                                return;
                            }
                            nbw.ReportProgress(0, TaskbarItemProgressState.Indeterminate);
                        }
                        else
                        {
                            Log.Information(@"Linking existing backup at " + targetToBackup.TargetPath);
                            backupPath = targetToBackup.TargetPath;
                            // Linking existing backup
                            Application.Current.Dispatcher.Invoke(delegate
                            {
                                bool okToBackup = validateBackupPath(targetToBackup.TargetPath, targetToBackup);
                                if (!okToBackup)
                                {
                                    end = true;
                                    EndBackup();
                                    return;
                                }
                            });
                        }

                        if (end)
                        {
                            return;
                        }

                        if (!targetToBackup.IsCustomOption)
                        {
                            #region callbacks and copy code

                            // Copy to new backup
                            void fileCopiedCallback()
                            {
                                ProgressValue++;
                                if (ProgressMax > 0)
                                {
                                    nbw.ReportProgress(0, ProgressValue * 1.0 / ProgressMax);
                                }
                            }

                            string dlcFolderpath   = MEDirectories.DLCPath(targetToBackup) + '\\';
                            int    dlcSubStringLen = dlcFolderpath.Length;

                            bool aboutToCopyCallback(string file)
                            {
                                try
                                {
                                    if (file.Contains(@"\cmmbackup\"))
                                    {
                                        return(false);                               //do not copy cmmbackup files
                                    }
                                    if (file.StartsWith(dlcFolderpath, StringComparison.InvariantCultureIgnoreCase))
                                    {
                                        //It's a DLC!
                                        string dlcname             = file.Substring(dlcSubStringLen);
                                        var    dlcFolderNameEndPos = dlcname.IndexOf('\\');
                                        if (dlcFolderNameEndPos > 0)
                                        {
                                            dlcname = dlcname.Substring(0, dlcFolderNameEndPos);
                                            if (MEDirectories.OfficialDLCNames(targetToBackup.Game)
                                                .TryGetValue(dlcname, out var hrName))
                                            {
                                                BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX,
                                                                                  hrName);
                                            }
                                            else
                                            {
                                                BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX,
                                                                                  dlcname);
                                            }
                                        }
                                        else
                                        {
                                            // Loose files in the DLC folder
                                            BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX,
                                                                              M3L.GetString(M3L.string_basegame));
                                        }
                                    }
                                    else
                                    {
                                        //It's basegame
                                        if (file.EndsWith(@".bik"))
                                        {
                                            BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX,
                                                                              M3L.GetString(M3L.string_movies));
                                        }
                                        else if (new FileInfo(file).Length > 52428800)
                                        {
                                            BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX,
                                                                              Path.GetFileName(file));
                                        }
                                        else
                                        {
                                            BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX,
                                                                              M3L.GetString(M3L.string_basegame));
                                        }
                                    }
                                }
                                catch (Exception e)
                                {
                                    Crashes.TrackError(e, new Dictionary <string, string>()
                                    {
                                        { @"dlcFolderpath", dlcFolderpath },
                                        { @"dlcSubStringLen", dlcSubStringLen.ToString() },
                                        { @"file", file }
                                    });
                                }

                                return(true);
                            }

                            void totalFilesToCopyCallback(int total)
                            {
                                ProgressValue         = 0;
                                ProgressIndeterminate = false;
                                ProgressMax           = total;
                                nbw.ReportProgress(0, TaskbarItemProgressState.Normal);
                            }

                            BackupStatus = M3L.GetString(M3L.string_creatingBackup);
                            Log.Information($@"Backing up {targetToBackup.TargetPath} to {backupPath}");
                            nbw.ReportProgress(0, TaskbarItemProgressState.Normal);
                            CopyDir.CopyAll_ProgressBar(new DirectoryInfo(targetToBackup.TargetPath),
                                                        new DirectoryInfo(backupPath),
                                                        totalItemsToCopyCallback: totalFilesToCopyCallback,
                                                        aboutToCopyCallback: aboutToCopyCallback,
                                                        fileCopiedCallback: fileCopiedCallback,
                                                        ignoredExtensions: new[] { @"*.pdf", @"*.mp3" });
                            #endregion
                        }

                        // Write key
                        switch (Game)
                        {
                        case Mod.MEGame.ME1:
                        case Mod.MEGame.ME2:
                            Utilities.WriteRegistryKey(App.BACKUP_REGISTRY_KEY, Game + @"VanillaBackupLocation",
                                                       backupPath);
                            break;

                        case Mod.MEGame.ME3:
                            Utilities.WriteRegistryKey(App.REGISTRY_KEY_ME3CMM, @"VanillaCopyLocation",
                                                       backupPath);
                            break;
                        }

                        var cmmvanilla = Path.Combine(backupPath, @"cmm_vanilla");
                        if (!File.Exists(cmmvanilla))
                        {
                            Log.Information($@"Writing cmm_vanilla to " + cmmvanilla);
                            File.Create(cmmvanilla).Close();
                        }

                        Log.Information($@"Backup completed.");

                        Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>()
                        {
                            { @"Game", Game.ToString() },
                            { @"Result", @"Success" },
                            { @"Type", targetToBackup.IsCustomOption ? @"Linked" : @"Copy" }
                        });

                        EndBackup();
                        return;
                    }


                    if (!isVanilla)
                    {
                        //Show UI for non vanilla
                        Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>()
                        {
                            { @"Game", Game.ToString() },
                            { @"Result", @"Failure, Game modified" }
                        });
                        b.Result = (nonVanillaFiles, M3L.GetString(M3L.string_cannotBackupModifiedGame),
                                    M3L.GetString(M3L.string_followingFilesDoNotMatchTheVanillaDatabase));
                    }
                    else if (!isDLCConsistent)
                    {
                        Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>()
                        {
                            { @"Game", Game.ToString() },
                            { @"Result", @"Failure, DLC inconsistent" }
                        });
                        if (targetToBackup.Supported)
                        {
                            b.Result = (inconsistentDLC, M3L.GetString(M3L.string_inconsistentDLCDetected),
                                        M3L.GetString(M3L.string_dialogTheFollowingDLCAreInAnInconsistentState));
                        }
                        else
                        {
                            b.Result = (M3L.GetString(M3L.string_inconsistentDLCDetected),
                                        M3L.GetString(M3L.string_inconsistentDLCDetectedUnofficialGame));
                        }
                    }
                    else if (dlcModsInstalled.Count > 0)
                    {
                        Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>()
                        {
                            { @"Game", Game.ToString() },
                            { @"Result", @"Failure, DLC mods found" }
                        });
                        b.Result = (dlcModsInstalled, M3L.GetString(M3L.string_dlcModsAreInstalled),
                                    M3L.GetString(M3L.string_dialogDLCModsWereDetectedCannotBackup));
                    }
                    EndBackup();
                };
                nbw.RunWorkerCompleted += (a, b) =>
                {
                    if (b.Error != null)
                    {
                        Log.Error($@"Exception occured in {nbw.Name} thread: {b.Error.Message}");
                    }
                    window.TaskBarItemInfoHandler.ProgressState = TaskbarItemProgressState.None;
                    if (b.Result is (List <string> listItems, string title, string text))
                    {
                        ListDialog ld = new ListDialog(listItems, title, text, window);
                        ld.Show();
                    }
                    else if (b.Result is (string errortitle, string message))
                    {
                        M3L.ShowDialog(window, message, errortitle, MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    CommandManager.InvalidateRequerySuggested();
                };
                nbw.RunWorkerAsync();
            }
        private void InstallModBackgroundThread(object sender, DoWorkEventArgs e)
        {
            Log.Information(@"Mod Installer Background thread starting");
            var installationJobs = ModBeingInstalled.InstallationJobs;
            var gameDLCPath      = MEDirectories.DLCPath(gameTarget);

            Directory.CreateDirectory(gameDLCPath); //me1/me2 missing dlc might not have this folder

            //Check we can install
            var missingRequiredDLC = ModBeingInstalled.ValidateRequiredModulesAreInstalled(gameTarget);

            if (missingRequiredDLC.Count > 0)
            {
                e.Result = (ModInstallCompletedStatus.INSTALL_FAILED_REQUIRED_DLC_MISSING, missingRequiredDLC);
                return;
            }


            //Check/warn on official headers
            if (!PrecheckHeaders(installationJobs))
            {
                e.Result = ModInstallCompletedStatus.INSTALL_FAILED_USER_CANCELED_MISSING_MODULES;
                return;
            }

            //todo: If statment on this
            Utilities.InstallBinkBypass(gameTarget); //Always install binkw32, don't bother checking if it is already ASI version.

            if (ModBeingInstalled.Game == Mod.MEGame.ME2 && ModBeingInstalled.GetJob(ModJob.JobHeader.ME2_RCWMOD) != null && installationJobs.Count == 1)
            {
                e.Result = InstallAttachedRCWMod();
                return;
            }

            //Prepare queues
            (Dictionary <ModJob, (Dictionary <string, string> fileMapping, List <string> dlcFoldersBeingInstalled)> unpackedJobMappings,
             List <(ModJob job, string sfarPath, Dictionary <string, string> sfarInstallationMapping)> sfarJobs)installationQueues =
                ModBeingInstalled.GetInstallationQueues(gameTarget);

            var readOnlyTargets = ModBeingInstalled.GetAllRelativeReadonlyTargets(me1ConfigReadOnlyOption.IsSelected);

            if (gameTarget.ALOTInstalled)
            {
                //Check if any packages are being installed. If there are, we will block this installation.
                bool installsPackageFile = false;
                foreach (var jobMappings in installationQueues.unpackedJobMappings)
                {
                    installsPackageFile |= jobMappings.Value.fileMapping.Keys.Any(x => x.EndsWith(@".pcc", StringComparison.InvariantCultureIgnoreCase));
                    installsPackageFile |= jobMappings.Value.fileMapping.Keys.Any(x => x.EndsWith(@".u", StringComparison.InvariantCultureIgnoreCase));
                    installsPackageFile |= jobMappings.Value.fileMapping.Keys.Any(x => x.EndsWith(@".upk", StringComparison.InvariantCultureIgnoreCase));
                    installsPackageFile |= jobMappings.Value.fileMapping.Keys.Any(x => x.EndsWith(@".sfm", StringComparison.InvariantCultureIgnoreCase));
                }

                foreach (var jobMappings in installationQueues.sfarJobs)
                {
                    installsPackageFile |= jobMappings.sfarInstallationMapping.Keys.Any(x => x.EndsWith(@".pcc", StringComparison.InvariantCultureIgnoreCase));
                    installsPackageFile |= jobMappings.sfarInstallationMapping.Keys.Any(x => x.EndsWith(@".u", StringComparison.InvariantCultureIgnoreCase));
                    installsPackageFile |= jobMappings.sfarInstallationMapping.Keys.Any(x => x.EndsWith(@".upk", StringComparison.InvariantCultureIgnoreCase));
                    installsPackageFile |= jobMappings.sfarInstallationMapping.Keys.Any(x => x.EndsWith(@".sfm", StringComparison.InvariantCultureIgnoreCase));
                }

                if (installsPackageFile)
                {
                    if (Settings.DeveloperMode)
                    {
                        Log.Warning(@"ALOT is installed and user is attempting to install a mod (in developer mode). Prompting user to cancel installation");

                        bool cancel = false;
                        Application.Current.Dispatcher.Invoke(delegate
                        {
                            var res = M3L.ShowDialog(Window.GetWindow(this), M3L.GetString(M3L.string_interp_devModeAlotInstalledWarning, ModBeingInstalled.ModName), M3L.GetString(M3L.string_brokenTexturesWarning), MessageBoxButton.YesNo, MessageBoxImage.Error, MessageBoxResult.No);
                            cancel  = res == MessageBoxResult.No;
                        });
                        if (cancel)
                        {
                            e.Result = ModInstallCompletedStatus.USER_CANCELED_INSTALLATION;
                            return;
                        }
                        Log.Warning(@"User installing mod anyways even with ALOT installed");
                    }
                    else
                    {
                        Log.Error(@"ALOT is installed. Installing mods that install package files after installing ALOT is not permitted.");
                        //ALOT Installed, this is attempting to install a package file
                        e.Result = ModInstallCompletedStatus.INSTALL_FAILED_ALOT_BLOCKING;
                        return;
                    }
                }
            }

            Action            = M3L.GetString(M3L.string_installing);
            PercentVisibility = Visibility.Visible;
            Percent           = 0;

            int numdone = 0;

            //Calculate number of installation tasks beforehand
            int numFilesToInstall = installationQueues.unpackedJobMappings.Select(x => x.Value.fileMapping.Count).Sum();

            numFilesToInstall += installationQueues.sfarJobs.Select(x => x.sfarInstallationMapping.Count).Sum() * (ModBeingInstalled.IsInArchive ? 2 : 1); //*2 as we have to extract and install
            Debug.WriteLine(@"Number of expected installation tasks: " + numFilesToInstall);
            void FileInstalledCallback(string target)
            {
                numdone++;
                Debug.WriteLine(@"Installed: " + target);
                Action = M3L.GetString(M3L.string_installing);
                var now = DateTime.Now;

                if (numdone > numFilesToInstall)
                {
                    Debug.WriteLine($@"Percentage calculated is wrong. Done: {numdone} NumToDoTotal: {numFilesToInstall}");
                }
                if ((now - lastPercentUpdateTime).Milliseconds > PERCENT_REFRESH_COOLDOWN)
                {
                    //Don't update UI too often. Once per second is enough.
                    Percent = (int)(numdone * 100.0 / numFilesToInstall);
                    lastPercentUpdateTime = now;
                }
            }

            //Stage: Unpacked files build map


            Dictionary <string, string> fullPathMappingDisk      = new Dictionary <string, string>();
            Dictionary <int, string>    fullPathMappingArchive   = new Dictionary <int, string>();
            SortedSet <string>          customDLCsBeingInstalled = new SortedSet <string>();
            List <string> mappedReadOnlyTargets = new List <string>();

            foreach (var unpackedQueue in installationQueues.unpackedJobMappings)
            {
                foreach (var originalMapping in unpackedQueue.Value.fileMapping)
                {
                    //always unpacked
                    //if (unpackedQueue.Key == ModJob.JobHeader.CUSTOMDLC || unpackedQueue.Key == ModJob.JobHeader.BALANCE_CHANGES || unpackedQueue.Key == ModJob.JobHeader.BASEGAME)
                    //{

                    //Resolve source file path
                    string sourceFile;
                    if (unpackedQueue.Key.JobDirectory == null)
                    {
                        sourceFile = FilesystemInterposer.PathCombine(ModBeingInstalled.IsInArchive, ModBeingInstalled.ModPath, originalMapping.Value);
                    }
                    else
                    {
                        sourceFile = FilesystemInterposer.PathCombine(ModBeingInstalled.IsInArchive, ModBeingInstalled.ModPath, unpackedQueue.Key.JobDirectory, originalMapping.Value);
                    }



                    if (unpackedQueue.Key.Header == ModJob.JobHeader.ME1_CONFIG)
                    {
                        var destFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), @"BioWare", @"Mass Effect", @"Config", originalMapping.Key);
                        if (ModBeingInstalled.IsInArchive)
                        {
                            int archiveIndex = ModBeingInstalled.Archive.ArchiveFileNames.IndexOf(sourceFile, StringComparer.InvariantCultureIgnoreCase);
                            fullPathMappingArchive[archiveIndex] = destFile; //used for extraction indexing
                            if (archiveIndex == -1)
                            {
                                Log.Error($@"Archive Index is -1 for file {sourceFile}. This will probably throw an exception!");
                                Debugger.Break();
                            }
                            fullPathMappingDisk[sourceFile] = destFile; //used for redirection
                        }
                        else
                        {
                            fullPathMappingDisk[sourceFile] = destFile;
                        }
                    }
                    else
                    {
                        var destFile = Path.Combine(unpackedQueue.Key.Header == ModJob.JobHeader.CUSTOMDLC ? MEDirectories.DLCPath(gameTarget) : gameTarget.TargetPath, originalMapping.Key); //official

                        //Extract Custom DLC name
                        if (unpackedQueue.Key.Header == ModJob.JobHeader.CUSTOMDLC)
                        {
                            var custDLC        = destFile.Substring(gameDLCPath.Length, destFile.Length - gameDLCPath.Length).TrimStart('\\', '/');
                            var nextSlashIndex = custDLC.IndexOf('\\');
                            if (nextSlashIndex == -1)
                            {
                                nextSlashIndex = custDLC.IndexOf('/');
                            }
                            if (nextSlashIndex != -1)
                            {
                                custDLC = custDLC.Substring(0, nextSlashIndex);
                                customDLCsBeingInstalled.Add(custDLC);
                            }
                        }

                        if (ModBeingInstalled.IsInArchive)
                        {
                            int archiveIndex = ModBeingInstalled.Archive.ArchiveFileNames.IndexOf(sourceFile, StringComparer.InvariantCultureIgnoreCase);
                            fullPathMappingArchive[archiveIndex] = destFile; //used for extraction indexing
                            if (archiveIndex == -1)
                            {
                                Log.Error($@"Archive Index is -1 for file {sourceFile}. This will probably throw an exception!");
                                Debugger.Break();
                            }
                        }
                        fullPathMappingDisk[sourceFile] = destFile; //archive also uses this for redirection
                    }

                    if (readOnlyTargets.Contains(originalMapping.Key))
                    {
                        CLog.Information(@"Adding resolved read only target: " + originalMapping.Key + @" -> " + fullPathMappingDisk[sourceFile], Settings.LogModInstallation);
                        mappedReadOnlyTargets.Add(fullPathMappingDisk[sourceFile]);
                    }
                    //}
                }
            }

            //Substage: Add SFAR staging targets
            string sfarStagingDirectory = (ModBeingInstalled.IsInArchive && installationQueues.sfarJobs.Count > 0) ? Directory.CreateDirectory(Path.Combine(Utilities.GetTempPath(), @"SFARJobStaging")).FullName : null; //don't make directory if we don't need one

            if (sfarStagingDirectory != null)
            {
                foreach (var sfarJob in installationQueues.sfarJobs)
                {
                    foreach (var fileToInstall in sfarJob.sfarInstallationMapping)
                    {
                        string sourceFile   = FilesystemInterposer.PathCombine(ModBeingInstalled.IsInArchive, ModBeingInstalled.ModPath, sfarJob.job.JobDirectory, fileToInstall.Value);
                        int    archiveIndex = ModBeingInstalled.Archive.ArchiveFileNames.IndexOf(sourceFile, StringComparer.InvariantCultureIgnoreCase);
                        if (archiveIndex == -1)
                        {
                            Log.Error($@"Archive Index is -1 for file {sourceFile}. This will probably throw an exception!");
                            Debugger.Break();
                        }
                        string destFile = Path.Combine(sfarStagingDirectory, sfarJob.job.JobDirectory, fileToInstall.Value);
                        fullPathMappingArchive[archiveIndex] = destFile; //used for extraction indexing
                        fullPathMappingDisk[sourceFile]      = destFile; //used for redirection
                        Debug.WriteLine($@"SFAR Disk Staging: {fileToInstall.Key} => {destFile}");
                    }
                }
            }

            //Check we have enough disk space
            long requiredSpaceToInstall = 0L;

            if (ModBeingInstalled.IsInArchive)
            {
                foreach (var f in ModBeingInstalled.Archive.ArchiveFileData)
                {
                    if (fullPathMappingArchive.ContainsKey(f.Index))
                    {
                        //we are installing this file
                        requiredSpaceToInstall += (long)f.Size;
                    }
                }
            }
            else
            {
                foreach (var file in fullPathMappingDisk)
                {
                    requiredSpaceToInstall += new FileInfo(file.Key).Length;
                }
            }

            Utilities.DriveFreeBytes(gameTarget.TargetPath, out var freeSpaceOnTargetDisk);
            requiredSpaceToInstall = (long)(requiredSpaceToInstall * 1.05); //+5% for some overhead
            if (requiredSpaceToInstall > (long)freeSpaceOnTargetDisk && freeSpaceOnTargetDisk != 0)
            {
                string driveletter = Path.GetPathRoot(gameTarget.TargetPath);
                Log.Error($@"Insufficient disk space to install mod. Required: {ByteSize.FromBytes(requiredSpaceToInstall)}, available on {driveletter}: {ByteSize.FromBytes(freeSpaceOnTargetDisk)}");
                Application.Current.Dispatcher.Invoke(() =>
                {
                    string message = M3L.GetString(M3L.string_interp_dialogNotEnoughSpaceToInstall, driveletter, ModBeingInstalled.ModName, ByteSize.FromBytes(requiredSpaceToInstall).ToString(), ByteSize.FromBytes(freeSpaceOnTargetDisk).ToString());
                    Xceed.Wpf.Toolkit.MessageBox.Show(window, message, M3L.GetString(M3L.string_insufficientDiskSpace), MessageBoxButton.OK, MessageBoxImage.Error);
                });
                e.Result = ModInstallCompletedStatus.INSTALL_ABORTED_NOT_ENOUGH_SPACE;
                return;
            }

            //Delete existing custom DLC mods with same name
            foreach (var cdbi in customDLCsBeingInstalled)
            {
                var path = Path.Combine(gameDLCPath, cdbi);
                if (Directory.Exists(path))
                {
                    Log.Information($@"Deleting existing DLC directory: {path}");
                    Utilities.DeleteFilesAndFoldersRecursively(path);
                }
            }

            //Stage: Unpacked files installation
            if (!ModBeingInstalled.IsInArchive)
            {
                //Direct copy
                Log.Information($@"Installing {fullPathMappingDisk.Count} unpacked files into game directory");
                CopyDir.CopyFiles_ProgressBar(fullPathMappingDisk, FileInstalledCallback);
            }
            else
            {
                Action = M3L.GetString(M3L.string_loadingModArchive);
                //Extraction to destination
                string installationRedirectCallback(ArchiveFileInfo info)
                {
                    var inArchivePath  = info.FileName;
                    var redirectedPath = fullPathMappingDisk[inArchivePath];

                    Debug.WriteLine($@"Redirecting {inArchivePath} to {redirectedPath}");
                    return(redirectedPath);
                }

                ModBeingInstalled.Archive.FileExtractionStarted += (sender, args) =>
                {
                    //CLog.Information("Extracting mod file for installation: " + args.FileInfo.FileName, Settings.LogModInstallation);
                };
                List <string> filesInstalled = new List <string>();
                List <string> filesToInstall = installationQueues.unpackedJobMappings.SelectMany(x => x.Value.fileMapping.Keys).ToList();
                ModBeingInstalled.Archive.FileExtractionFinished += (sender, args) =>
                {
                    if (args.FileInfo.IsDirectory)
                    {
                        return;                            //ignore
                    }
                    if (!fullPathMappingArchive.ContainsKey(args.FileInfo.Index))
                    {
                        return;                                                           //archive extracted this file (in memory) but did not do anything with this file (7z)
                    }
                    FileInstalledCallback(args.FileInfo.FileName);
                    filesInstalled.Add(args.FileInfo.FileName);
                    //Debug.WriteLine($"{args.FileInfo.FileName} as file { numdone}");
                    //Debug.WriteLine(numdone);
                };
                ModBeingInstalled.Archive.ExtractFiles(gameTarget.TargetPath, installationRedirectCallback, fullPathMappingArchive.Keys.ToArray()); //directory parameter shouldn't be used here as we will be redirecting everything
            }

            //Write MetaCMM
            List <string> addedDLCFolders = new List <string>();

            foreach (var v in installationQueues.unpackedJobMappings)
            {
                addedDLCFolders.AddRange(v.Value.dlcFoldersBeingInstalled);
            }
            foreach (var addedDLCFolder in addedDLCFolders)
            {
                var metacmm = Path.Combine(addedDLCFolder, @"_metacmm.txt");
                ModBeingInstalled.HumanReadableCustomDLCNames.TryGetValue(Path.GetFileName(addedDLCFolder), out var assignedDLCName);
                string contents = $"{assignedDLCName ?? ModBeingInstalled.ModName}\n{ModBeingInstalled.ModVersionString}\n{App.BuildNumber}\n{Guid.NewGuid().ToString()}"; //Do not localize
                File.WriteAllText(metacmm, contents);
            }

            //Stage: SFAR Installation
            foreach (var sfarJob in installationQueues.sfarJobs)
            {
                InstallIntoSFAR(sfarJob, ModBeingInstalled, FileInstalledCallback, ModBeingInstalled.IsInArchive ? sfarStagingDirectory : null);
            }


            //Main installation step has completed
            CLog.Information(@"Main stage of mod installation has completed", Settings.LogModInstallation);
            Percent = (int)(numdone * 100.0 / numFilesToInstall);

            //Mark items read only
            foreach (var readonlytarget in mappedReadOnlyTargets)
            {
                CLog.Information(@"Setting file to read-only: " + readonlytarget, Settings.LogModInstallation);
                File.SetAttributes(readonlytarget, File.GetAttributes(readonlytarget) | FileAttributes.ReadOnly);
            }

            //Remove outdated custom DLC
            foreach (var outdatedDLCFolder in ModBeingInstalled.OutdatedCustomDLC)
            {
                var outdatedDLCInGame = Path.Combine(gameDLCPath, outdatedDLCFolder);
                if (Directory.Exists(outdatedDLCInGame))
                {
                    Log.Information(@"Deleting outdated custom DLC folder: " + outdatedDLCInGame);
                    Utilities.DeleteFilesAndFoldersRecursively(outdatedDLCInGame);
                }
            }

            //Install supporting ASI files if necessary
            //Todo: Upgrade to version detection code from ME3EXP to prevent conflicts

            Action            = M3L.GetString(M3L.string_installingSupportFiles);
            PercentVisibility = Visibility.Collapsed;
            CLog.Information(@"Installing supporting ASI files", Settings.LogModInstallation);
            if (ModBeingInstalled.Game == Mod.MEGame.ME1)
            {
                //Todo: Convert to ASI Manager installer
                Utilities.InstallASIByGroupID(gameTarget, @"DLC Mod Enabler", 16); //16 = DLC M -od Enabler

                //Utilities.InstallEmbeddedASI(@"ME1-DLC-ModEnabler-v1.0", 1.0, gameTarget); //Todo: Switch to ASI Manager
            }
            else if (ModBeingInstalled.Game == Mod.MEGame.ME2)
            {
                //None right now
            }
            else
            {
                if (ModBeingInstalled.GetJob(ModJob.JobHeader.BALANCE_CHANGES) != null)
                {
                    Utilities.InstallASIByGroupID(gameTarget, @"Balance Changes Replacer", 5);
                    //Utilities.InstallASIByGroupID(gameTarget, @"ME3Logger-Truncating", 5);
                    //Utilities.InstallEmbeddedASI(@"BalanceChangesReplacer-v2.0", 2.0, gameTarget); //todo: Switch to ASI Manager
                }
            }

            if (sfarStagingDirectory != null)
            {
                Utilities.DeleteFilesAndFoldersRecursively(Utilities.GetTempPath());
            }

            if (numFilesToInstall == numdone)
            {
                e.Result = ModInstallCompletedStatus.INSTALL_SUCCESSFUL;
                Action   = M3L.GetString(M3L.string_installed);
            }
            else
            {
                Log.Warning($@"Number of completed items does not equal the amount of items to install! Number installed {numdone} Number expected: {numFilesToInstall}");
                e.Result = ModInstallCompletedStatus.INSTALL_WRONG_NUMBER_OF_COMPLETED_ITEMS;
            }
        }
            private void BeginBackup()
            {
                if (Utilities.IsGameRunning(BackupSourceTarget.Game))
                {
                    M3L.ShowDialog(window, M3L.GetString(M3L.string_interp_cannotBackupGameWhileRunning, Utilities.GetGameName(BackupSourceTarget.Game)), M3L.GetString(M3L.string_gameRunning), MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }
                NamedBackgroundWorker bw = new NamedBackgroundWorker(Game.ToString() + @"Backup");

                bw.DoWork += (a, b) =>
                {
                    BackupInProgress = true;
                    List <string> nonVanillaFiles = new List <string>();
                    void nonVanillaFileFoundCallback(string filepath)
                    {
                        Log.Error($@"Non-vanilla file found: {filepath}");
                        nonVanillaFiles.Add(filepath);
                    }

                    List <string> inconsistentDLC = new List <string>();
                    void inconsistentDLCFoundCallback(string filepath)
                    {
                        if (BackupSourceTarget.Supported)
                        {
                            Log.Error($@"DLC is in an inconsistent state: {filepath}");
                            inconsistentDLC.Add(filepath);
                        }
                        else
                        {
                            Log.Error(@"Detected an inconsistent DLC, likely due to an unofficial copy of the game");
                        }
                    }

                    ProgressVisible       = true;
                    ProgressIndeterminate = true;
                    BackupStatus          = M3L.GetString(M3L.string_validatingBackupSource);
                    VanillaDatabaseService.LoadDatabaseFor(Game);
                    bool          isVanilla        = VanillaDatabaseService.ValidateTargetAgainstVanilla(BackupSourceTarget, nonVanillaFileFoundCallback);
                    bool          isDLCConsistent  = VanillaDatabaseService.ValidateTargetDLCConsistency(BackupSourceTarget, inconsistentDLCCallback: inconsistentDLCFoundCallback);
                    List <string> dlcModsInstalled = VanillaDatabaseService.GetInstalledDLCMods(BackupSourceTarget);


                    if (isVanilla && isDLCConsistent && dlcModsInstalled.Count == 0)
                    {
                        BackupStatus = M3L.GetString(M3L.string_waitingForUserInput);

                        string backupPath = null;
                        bool   end        = false;
                        Application.Current.Dispatcher.Invoke(delegate
                        {
                            Log.Error(@"Prompting user to select backup destination");

                            CommonOpenFileDialog m = new CommonOpenFileDialog
                            {
                                IsFolderPicker   = true,
                                EnsurePathExists = true,
                                Title            = M3L.GetString(M3L.string_selectBackupDestination)
                            };
                            if (m.ShowDialog() == CommonFileDialogResult.Ok)
                            {
                                //Check empty
                                backupPath = m.FileName;
                                if (Directory.Exists(backupPath))
                                {
                                    if (Directory.GetFiles(backupPath).Length > 0 || Directory.GetDirectories(backupPath).Length > 0)
                                    {
                                        //Directory not empty
                                        Log.Error(@"Selected backup directory is not empty.");
                                        M3L.ShowDialog(window, M3L.GetString(M3L.string_directoryIsNotEmptyMustBeEmpty), M3L.GetString(M3L.string_directoryNotEmpty), MessageBoxButton.OK, MessageBoxImage.Error);
                                        end = true;
                                        EndBackup();
                                        return;
                                    }
                                }
                            }
                            else
                            {
                                end = true;
                                EndBackup();
                                return;
                            }
                        });
                        if (end)
                        {
                            return;
                        }

                        #region callbacks
                        void fileCopiedCallback()
                        {
                            ProgressValue++;
                        }

                        string dlcFolderpath   = MEDirectories.DLCPath(BackupSourceTarget) + '\\';
                        int    dlcSubStringLen = dlcFolderpath.Length;
                        bool aboutToCopyCallback(string file)
                        {
                            if (file.Contains(@"\cmmbackup\"))
                            {
                                return(false);                               //do not copy cmmbackup files
                            }
                            if (file.StartsWith(dlcFolderpath))
                            {
                                //It's a DLC!
                                string dlcname = file.Substring(dlcSubStringLen);
                                dlcname = dlcname.Substring(0, dlcname.IndexOf('\\'));
                                if (MEDirectories.OfficialDLCNames(BackupSourceTarget.Game).TryGetValue(dlcname, out var hrName))
                                {
                                    BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, hrName);
                                }
                                else
                                {
                                    BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, dlcname);
                                }
                            }
                            else
                            {
                                //It's basegame
                                if (file.EndsWith(@".bik"))
                                {
                                    BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, M3L.string_movies);
                                }
                                else if (new FileInfo(file).Length > 52428800)
                                {
                                    BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, Path.GetFileName(file));
                                }
                                else
                                {
                                    BackupStatusLine2 = M3L.GetString(M3L.string_interp_backingUpX, M3L.string_basegame);
                                }
                            }
                            return(true);
                        }

                        void totalFilesToCopyCallback(int total)
                        {
                            ProgressValue         = 0;
                            ProgressIndeterminate = false;
                            ProgressMax           = total;
                        }

                        #endregion
                        BackupStatus = M3L.GetString(M3L.string_creatingBackup);


                        CopyDir.CopyAll_ProgressBar(new DirectoryInfo(BackupSourceTarget.TargetPath), new DirectoryInfo(backupPath),
                                                    totalItemsToCopyCallback: totalFilesToCopyCallback,
                                                    aboutToCopyCallback: aboutToCopyCallback,
                                                    fileCopiedCallback: fileCopiedCallback,
                                                    ignoredExtensions: new[] { @"*.pdf", @"*.mp3" });
                        switch (Game)
                        {
                        case Mod.MEGame.ME1:
                        case Mod.MEGame.ME2:
                            Utilities.WriteRegistryKey(App.BACKUP_REGISTRY_KEY, Game + @"VanillaBackupLocation", backupPath);
                            break;

                        case Mod.MEGame.ME3:
                            Utilities.WriteRegistryKey(App.REGISTRY_KEY_ME3CMM, @"VanillaCopyLocation", backupPath);
                            break;
                        }
                        Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>()
                        {
                            { @"Game", Game.ToString() },
                            { @"Result", @"Success" }
                        });

                        EndBackup();
                        return;
                    }

                    if (!isVanilla)
                    {
                        //Show UI for non vanilla
                        Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>()
                        {
                            { @"Game", Game.ToString() },
                            { @"Result", @"Failure, Game modified" }
                        });
                        b.Result = (nonVanillaFiles, M3L.GetString(M3L.string_cannotBackupModifiedGame), M3L.GetString(M3L.string_followingFilesDoNotMatchTheVanillaDatabase));
                    }
                    else if (!isDLCConsistent)
                    {
                        Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>()
                        {
                            { @"Game", Game.ToString() },
                            { @"Result", @"Failure, DLC inconsistent" }
                        });
                        if (BackupSourceTarget.Supported)
                        {
                            b.Result = (inconsistentDLC, M3L.GetString(M3L.string_inconsistentDLCDetected), M3L.GetString(M3L.string_dialogTheFollowingDLCAreInAnInconsistentState));
                        }
                        else
                        {
                            b.Result = (M3L.GetString(M3L.string_inconsistentDLCDetected), M3L.GetString(M3L.string_inconsistentDLCDetectedUnofficialGame));
                        }
                    }
                    else if (dlcModsInstalled.Count > 0)
                    {
                        Analytics.TrackEvent(@"Created a backup", new Dictionary <string, string>()
                        {
                            { @"Game", Game.ToString() },
                            { @"Result", @"Failure, DLC mods found" }
                        });
                        b.Result = (dlcModsInstalled, M3L.GetString(M3L.string_dlcModsAreInstalled), M3L.GetString(M3L.string_dialogDLCModsWereDetectedCannotBackup));
                    }
                    EndBackup();
                };
                bw.RunWorkerCompleted += (a, b) =>
                {
                    if (b.Result is (List <string> listItems, string title, string text))
                    {
                        ListDialog ld = new ListDialog(listItems, title, text, window);
                        ld.Show();
                    }
                    else if (b.Result is (string errortitle, string message))
                    {
                        M3L.ShowDialog(window, message, errortitle, MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    CommandManager.InvalidateRequerySuggested();
                };
                bw.RunWorkerAsync();
            }
Beispiel #30
0
            private void BeginRestore()
            {
                if (Utilities.IsGameRunning(Game))
                {
                    M3L.ShowDialog(window, M3L.GetString(M3L.string_interp_dialogCannotRestoreXWhileItIsRunning, Utilities.GetGameName(Game)), M3L.GetString(M3L.string_gameRunning), MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }

                bool restore = RestoreTarget.IsCustomOption; //custom option is restore to custom location

                restore = restore || M3L.ShowDialog(window, M3L.GetString(M3L.string_dialog_restoringXWillDeleteGameDir, Utilities.GetGameName(Game)), M3L.GetString(M3L.string_gameTargetWillBeDeleted), MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes;
                if (restore)
                {
                    NamedBackgroundWorker nbw = new NamedBackgroundWorker(Game + @"-Restore");
                    nbw.WorkerReportsProgress = true;
                    nbw.ProgressChanged      += (a, b) =>
                    {
                        if (b.UserState is double d)
                        {
                            TaskbarHelper.SetProgress(d);
                        }
                    };
                    nbw.DoWork += (a, b) =>
                    {
                        RestoreInProgress = true;


                        string restoreTargetPath = b.Argument as string;
                        string backupPath        = BackupLocation;
                        BackupStatusLine2 = M3L.GetString(M3L.string_deletingExistingGameInstallation);
                        if (Directory.Exists(restoreTargetPath))
                        {
                            if (Directory.GetFiles(restoreTargetPath).Any() || Directory.GetDirectories(restoreTargetPath).Any())
                            {
                                Log.Information(@"Deleting existing game directory: " + restoreTargetPath);
                                try
                                {
                                    bool deletedDirectory = Utilities.DeleteFilesAndFoldersRecursively(restoreTargetPath);
                                    if (deletedDirectory != true)
                                    {
                                        b.Result = RestoreResult.ERROR_COULD_NOT_DELETE_GAME_DIRECTORY;
                                        return;
                                    }
                                }
                                catch (Exception ex)
                                {
                                    //todo: handle this better
                                    Log.Error($@"Exception deleting game directory: {restoreTargetPath}: {ex.Message}");
                                    b.Result = RestoreResult.EXCEPTION_DELETING_GAME_DIRECTORY;
                                    return;
                                }
                            }
                        }
                        else
                        {
                            Log.Error(@"Game directory not found! Was it removed while the app was running?");
                        }

                        //Todo: Revert LODs, remove IndirectSound settings (MEUITM)

                        var created = Utilities.CreateDirectoryWithWritePermission(restoreTargetPath);
                        if (!created)
                        {
                            b.Result = RestoreResult.ERROR_COULD_NOT_CREATE_DIRECTORY;
                            return;
                        }

                        BackupStatusLine2 = M3L.GetString(M3L.string_restoringGameFromBackup);
                        if (restoreTargetPath != null)
                        {
                            //callbacks

                            #region callbacks

                            void fileCopiedCallback()
                            {
                                ProgressValue++;
                                if (ProgressMax != 0)
                                {
                                    nbw.ReportProgress(0, ProgressValue * 1.0 / ProgressMax);
                                }
                            }

                            string dlcFolderpath   = MEDirectories.DLCPath(backupPath, Game) + '\\'; //\ at end makes sure we are restoring a subdir
                            int    dlcSubStringLen = dlcFolderpath.Length;
                            Debug.WriteLine(@"DLC Folder: " + dlcFolderpath);
                            Debug.Write(@"DLC Fodler path len:" + dlcFolderpath);

                            bool aboutToCopyCallback(string fileBeingCopied)
                            {
                                if (fileBeingCopied.Contains(@"\cmmbackup\"))
                                {
                                    return(false);                                          //do not copy cmmbackup files
                                }
                                Debug.WriteLine(fileBeingCopied);
                                if (fileBeingCopied.StartsWith(dlcFolderpath, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    //It's a DLC!
                                    string dlcname = fileBeingCopied.Substring(dlcSubStringLen);
                                    int    index   = dlcname.IndexOf('\\');
                                    try
                                    {
                                        dlcname = dlcname.Substring(0, index);
                                        if (MEDirectories.OfficialDLCNames(RestoreTarget.Game).TryGetValue(dlcname, out var hrName))
                                        {
                                            BackupStatusLine2 = M3L.GetString(M3L.string_interp_restoringX, hrName);
                                        }
                                        else
                                        {
                                            BackupStatusLine2 = M3L.GetString(M3L.string_interp_restoringX, dlcname);
                                        }
                                    }
                                    catch (Exception e)
                                    {
                                        Crashes.TrackError(e, new Dictionary <string, string>()
                                        {
                                            { @"Source", @"Restore UI display callback" },
                                            { @"Value", fileBeingCopied },
                                            { @"DLC Folder path", dlcFolderpath }
                                        });
                                    }
                                }
                                else
                                {
                                    //It's basegame
                                    if (fileBeingCopied.EndsWith(@".bik"))
                                    {
                                        BackupStatusLine2 = M3L.GetString(M3L.string_restoringMovies);
                                    }
                                    else if (new FileInfo(fileBeingCopied).Length > 52428800)
                                    {
                                        BackupStatusLine2 = M3L.GetString(M3L.string_interp_restoringX, Path.GetFileName(fileBeingCopied));
                                    }
                                    else
                                    {
                                        BackupStatusLine2 = M3L.GetString(M3L.string_restoringBasegame);
                                    }
                                }

                                return(true);
                            }

                            void totalFilesToCopyCallback(int total)
                            {
                                ProgressValue         = 0;
                                ProgressIndeterminate = false;
                                ProgressMax           = total;
                            }

                            #endregion

                            BackupStatus = M3L.GetString(M3L.string_restoringGame);
                            Log.Information($@"Copying backup to game directory: {backupPath} -> {restoreTargetPath}");
                            CopyDir.CopyAll_ProgressBar(new DirectoryInfo(backupPath), new DirectoryInfo(restoreTargetPath),
                                                        totalItemsToCopyCallback: totalFilesToCopyCallback,
                                                        aboutToCopyCallback: aboutToCopyCallback,
                                                        fileCopiedCallback: fileCopiedCallback,
                                                        ignoredExtensions: new[] { @"*.pdf", @"*.mp3" });
                            Log.Information(@"Restore of game data has completed");
                        }

                        //Check for cmmvanilla file and remove it present

                        string cmmVanilla = Path.Combine(restoreTargetPath, @"cmm_vanilla");
                        if (File.Exists(cmmVanilla))
                        {
                            Log.Information(@"Removing cmm_vanilla file");
                            File.Delete(cmmVanilla);
                        }

                        Log.Information(@"Restore thread wrapping up");
                        RestoreTarget.ReloadGameTarget();
                        b.Result = RestoreResult.RESTORE_OK;
                    };
                    nbw.RunWorkerCompleted += (a, b) =>
                    {
                        if (b.Error != null)
                        {
                            Log.Error($@"Exception occurred in {nbw.Name} thread: {b.Error.Message}");
                        }
                        TaskbarHelper.SetProgressState(TaskbarProgressBarState.NoProgress);
                        if (b.Result is RestoreResult result)
                        {
                            switch (result)
                            {
                            case RestoreResult.ERROR_COULD_NOT_CREATE_DIRECTORY:
                                Analytics.TrackEvent(@"Restored game", new Dictionary <string, string>()
                                {
                                    { @"Game", Game.ToString() },
                                    { @"Result", @"Failure, Could not create target directory" }
                                });
                                M3L.ShowDialog(window, M3L.GetString(M3L.string_dialogCouldNotCreateGameDirectoryAfterDeletion), M3L.GetString(M3L.string_errorRestoringGame), MessageBoxButton.OK, MessageBoxImage.Error);
                                break;

                            case RestoreResult.ERROR_COULD_NOT_DELETE_GAME_DIRECTORY:
                                Analytics.TrackEvent(@"Restored game", new Dictionary <string, string>()
                                {
                                    { @"Game", Game.ToString() },
                                    { @"Result", @"Failure, Could not delete existing game directory" }
                                });
                                M3L.ShowDialog(window, M3L.GetString(M3L.string_dialogcouldNotFullyDeleteGameDirectory), M3L.GetString(M3L.string_errorRestoringGame), MessageBoxButton.OK, MessageBoxImage.Error);
                                break;

                            case RestoreResult.EXCEPTION_DELETING_GAME_DIRECTORY:
                                Analytics.TrackEvent(@"Restored game", new Dictionary <string, string>()
                                {
                                    { @"Game", Game.ToString() },
                                    { @"Result", @"Failure, Exception deleting existing game directory" }
                                });
                                M3L.ShowDialog(window, M3L.GetString(M3L.string_dialogErrorOccuredDeletingGameDirectory), M3L.GetString(M3L.string_errorRestoringGame), MessageBoxButton.OK, MessageBoxImage.Error);
                                break;

                            case RestoreResult.RESTORE_OK:
                                Analytics.TrackEvent(@"Restored game", new Dictionary <string, string>()
                                {
                                    { @"Game", Game.ToString() },
                                    { @"Result", @"Success" }
                                });
                                break;
                            }
                        }

                        EndRestore();
                        CommandManager.InvalidateRequerySuggested();
                    };
                    var restTarget = RestoreTarget.TargetPath;
                    if (RestoreTarget.IsCustomOption)
                    {
                        CommonOpenFileDialog m = new CommonOpenFileDialog
                        {
                            IsFolderPicker   = true,
                            EnsurePathExists = true,
                            Title            = M3L.GetString(M3L.string_selectNewRestoreDestination)
                        };
                        if (m.ShowDialog() == CommonFileDialogResult.Ok)
                        {
                            //Check empty
                            restTarget = m.FileName;
                            if (Directory.Exists(restTarget))
                            {
                                if (Directory.GetFiles(restTarget).Length > 0 || Directory.GetDirectories(restTarget).Length > 0)
                                {
                                    //Directory not empty
                                    M3L.ShowDialog(window, M3L.GetString(M3L.string_dialogDirectoryIsNotEmptyLocationToRestoreToMustBeEmpty), M3L.GetString(M3L.string_cannotRestoreToThisLocation), MessageBoxButton.OK, MessageBoxImage.Error);
                                    return;
                                }

                                //TODO: PREVENT RESTORING TO DOCUMENTS/BIOWARE
                            }

                            Analytics.TrackEvent(@"Chose to restore game to custom location", new Dictionary <string, string>()
                            {
                                { @"Game", Game.ToString() }
                            });
                        }
                        else
                        {
                            return;
                        }
                    }

                    RefreshTargets = true;
                    TaskbarHelper.SetProgress(0);
                    TaskbarHelper.SetProgressState(TaskbarProgressBarState.Normal);
                    nbw.RunWorkerAsync(restTarget);
                }
            }