Beispiel #1
0
        public void RenameFiles(BSA bsa, IDictionary<string, string> renameDict)
        {
            const string opPrefix = "Renaming BSA files";

            var opRename = new InstallStatus(Progress, Token) { CurrentOperation = opPrefix };

            var renameFixes = CreateRenameQuery(bsa, renameDict);
            opRename.ItemsTotal = renameDict.Count;

#if PARALLEL
            Parallel.ForEach(renameFixes, a =>
#else
            foreach (var a in renameFixes)
#endif
            {
                renameDict.Remove(a.Item3);

                opRename.CurrentOperation = opPrefix + ": " + a.Item1 + " -> " + a.Item2;
                opRename.Step();
            }
Beispiel #2
0
        public static void Build(InstallStatus status, string path, string fomod)
        {
            var compressor = new SevenZipCompressor
            {
                ArchiveFormat     = OutArchiveFormat.SevenZip,
                CompressionLevel  = CompressionLevel.Fast,
                CompressionMethod = CompressionMethod.Lzma2,
                CompressionMode   = CompressionMode.Create,
            };

            compressor.CustomParameters.Add("mt", "on"); //enable multithreading

            compressor.FilesFound              += (sender, e) => status.ItemsTotal = e.Value;
            compressor.Compressing             += (sender, e) => e.Cancel = status.Token.IsCancellationRequested;
            compressor.CompressionFinished     += (sender, e) => status.Finish();
            compressor.FileCompressionStarted  += (sender, e) => status.CurrentOperation = "Compressing " + e.FileName;
            compressor.FileCompressionFinished += (sender, e) => status.Step();

            compressor.CompressDirectory(path, fomod, true);
        }
Beispiel #3
0
        private bool PatchMasters(InstallStatus opProg)
        {
            foreach (var esm in Game.CheckedESMs)
            {
                try
                {
                    opProg.CurrentOperation = "Patching " + esm;

                    if (Token.IsCancellationRequested || !PatchMaster(esm))
                    {
                        return(false);
                    }
                }
                finally
                {
                    opProg.Step();
                }
            }

            return(true);
        }
Beispiel #4
0
        public void Install(CancellationToken inToken)
        {
            var LinkedSource = CancellationTokenSource.CreateLinkedTokenSource(inToken);

            Token = LinkedSource.Token;

            Prompts.PromptPaths();

            _bsaDiff = DependencyRegistry.Container
                       //.With("progress").EqualTo(ProgressMinorOperation)
                       //.With("token").EqualTo(Token)
                       .GetInstance <BsaDiff>();
            _nvse = DependencyRegistry.Container
                    .With("FNVPath").EqualTo(Prompts.FalloutNVPath)
                    .GetInstance <NVSE>();

            var opProg = new InstallStatus(ProgressMajorOperation, Token)
            {
                ItemsTotal = 7 + Game.BuildableBSAs.Count + Game.CheckedESMs.Length
            };

            try
            {
                HandleStep <CheckingRequiredFilesStep>(opProg);

                if (!_nvse.Check())
                {
                    string err = null;
                    //true : should download, continue install
                    //false: should not download, continue install
                    //null : should not download, abort install
                    switch (_nvse.Prompt())
                    {
                    case true:
                        if (_nvse.Install(out err))
                        {
                            break;
                        }
                        goto default;

                    case false:
                        break;

                    default:
                        Fail(err);
                        return;
                    }
                }

                try
                {
                    const string curOp = "Creating FOMOD foundation";
                    opProg.CurrentOperation = curOp;

                    Log.File(curOp);

                    string
                        srcFolder = Path.Combine(Paths.AssetsDir, "TTW Data", "TTW Files"),
                        tarFolder = Prompts.TTWSavePath;

                    Util.CopyFolder(srcFolder, tarFolder);
                }
                finally
                {
                    //+1
                    opProg.Step();
                }

                //count BuildableBSAs
                HandleStep <BuildBsasStep>(opProg);

                try
                {
                    opProg.CurrentOperation = "Building SFX";

                    BuildSFX();
                }
                finally
                {
                    //+1
                    opProg.Step();
                }

                try
                {
                    opProg.CurrentOperation = "Building Voices";

                    BuildVoice();
                }
                finally
                {
                    //+1
                    opProg.Step();
                }

                try
                {
                    const string ttwArchive = "TaleOfTwoWastelands.bsa";
                    opProg.CurrentOperation = "Copying " + ttwArchive;

                    if (!File.Exists(Path.Combine(DirTTWMain, ttwArchive)))
                    {
                        File.Copy(Path.Combine(Paths.AssetsDir, "TTW Data", ttwArchive), Path.Combine(DirTTWMain, ttwArchive));
                    }
                }
                finally
                {
                    //+1
                    opProg.Step();
                }

                //count CheckedESMs
                if (!PatchMasters(opProg))
                {
                    return;
                }

                //+2
                {
                    const string prefix = "Copying ";
                    const string opA    = "Fallout3 music files";
                    const string opB    = "Fallout3 video files";

                    opProg.CurrentOperation = prefix + opA;
                    FalloutLineCopy(opA, Path.Combine(Paths.AssetsDir, "TTW Data", "FO3_MusicCopy.txt"));
                    opProg.Step();

                    opProg.CurrentOperation = prefix + opB;
                    FalloutLineCopy(opB, Path.Combine(Paths.AssetsDir, "TTW Data", "FO3_VideoCopy.txt"));
                    opProg.Step();
                }

                HandleStep <BuildFOMODsStep>(opProg);

                opProg.Finish();

                Log.Display("Install completed successfully.");
                MessageBox.Show(string.Format(Localization.InstalledSuccessfully, Localization.TTW));
            }
            catch (OperationCanceledException)
            {
                //intentionally cancelled - swallow exception
                Log.Dual("Install was cancelled.");
            }
            catch (Exception ex)
            {
                Log.File(ex.ToString());
                Fail("An error interrupted the install!");
                MessageBox.Show(string.Format(Localization.ErrorWhileInstalling, ex.Message), Localization.Error);
            }
        }
Beispiel #5
0
        public bool PatchBsa(CompressionOptions bsaOptions, string oldBSA, string newBSA, bool simulate = false)
        {
            var Op = new InstallStatus(Progress, Token) { ItemsTotal = 7 };

            var outBsaFilename = Path.GetFileNameWithoutExtension(newBSA);

            BSA bsa;
            try
            {
                Op.CurrentOperation = "Opening " + Path.GetFileName(oldBSA);

                bsa = new BSA(oldBSA, bsaOptions);
            }
            finally
            {
                Op.Step();
            }

            IDictionary<string, string> renameDict;
            try
            {
                Op.CurrentOperation = "Opening rename database";

#if LEGACY
                var renamePath = Path.Combine(Installer.PatchDir, outBsaFilename, "RenameFiles.dict");
#else
                var renamePath = Path.Combine(Installer.PatchDir, Path.ChangeExtension(outBsaFilename, ".ren"));
#endif
                if (File.Exists(renamePath))
                {
#if LEGACY
                    renameDict = new Dictionary<string, string>(Util.ReadOldDatabase(renamePath));
#else
                    using (var fileStream = File.OpenRead(renamePath))
                    using (var lzmaStream = new LzmaDecodeStream(fileStream))
                    using (var reader = new BinaryReader(lzmaStream))
                    {
                        var numPairs = reader.ReadInt32();
                        renameDict = new Dictionary<string, string>(numPairs);

                        while (numPairs-- > 0)
                            renameDict.Add(reader.ReadString(), reader.ReadString());
                    }
#endif
                }
                else
                    renameDict = new Dictionary<string, string>();
            }
            finally
            {
                Op.Step();
            }

            PatchDict patchDict;
            try
            {
                Op.CurrentOperation = "Opening patch database";

#if LEGACY
                var chkPrefix = Path.Combine(Installer.PatchDir, outBsaFilename);
                var chkPath = Path.Combine(chkPrefix, "CheckSums.dict");
                patchDict = PatchDict.FromOldDatabase(Util.ReadOldDatabase(chkPath), chkPrefix, b => b);
#else
                var patchPath = Path.Combine(Installer.PatchDir, Path.ChangeExtension(outBsaFilename, ".pat"));
                if (File.Exists(patchPath))
                {
                    patchDict = new PatchDict(patchPath);
                }
                else
                {
                    Log.Dual("\tNo patch database is available for: " + oldBSA);
                    return false;
                }
#endif
            }
            finally
            {
                Op.Step();
            }

            using (bsa)
            {
                try
                {
                    RenameFiles(bsa, renameDict);

                    if (renameDict.Count > 0)
                    {
                        foreach (var kvp in renameDict)
                        {
                            Log.Dual("File not found: " + kvp.Value);
                            Log.Dual("\tCannot create: " + kvp.Key);
                        }
                    }
                }
                finally
                {
                    Op.Step();
                }

                var allFiles = bsa.SelectMany(folder => folder).ToList();
                try
                {
                    var opChk = new InstallStatus(Progress, Token) { ItemsTotal = patchDict.Count };

                    var joinedPatches = from patKvp in patchDict
                                        //if the join is not grouped, this will exclude missing files, and we can't find and fail on them
                                        join oldFile in allFiles on patKvp.Key equals oldFile.Filename into foundOld
                                        join bsaFile in allFiles on patKvp.Key equals bsaFile.Filename
                                        select new PatchJoin(bsaFile, foundOld.SingleOrDefault(), patKvp.Value);

#if DEBUG
                    var watch = new Stopwatch();
                    try
                    {
                        watch.Start();
#endif
#if PARALLEL
                        Parallel.ForEach(joinedPatches, join =>
#else
                        foreach (var join in joinedPatches)
#endif
 HandleFile(opChk, join)
#if PARALLEL
)
#endif
;
#if DEBUG
                    }
                    finally
                    {
                        watch.Stop();
                        Debug.WriteLine(outBsaFilename + " HandleFile loop finished in " + watch.Elapsed);
                    }
#endif
                }
                finally
                {
                    Op.Step();
                }

                try
                {
                    Op.CurrentOperation = "Removing unnecessary files";

                    var notIncluded = allFiles.Where(file => !patchDict.ContainsKey(file.Filename));
                    var filesToRemove = new HashSet<BSAFile>(notIncluded);

                    foreach (BSAFolder folder in bsa)
                        folder.RemoveWhere(filesToRemove.Contains);

                    var emptyFolders = bsa.Where(folder => folder.Count == 0).ToList();
                    emptyFolders.ForEach(folder => bsa.Remove(folder));
                }
                finally
                {
                    Op.Step();
                }

                try
                {
                    Op.CurrentOperation = "Saving " + Path.GetFileName(newBSA);

                    if (!simulate)
                        bsa.Save(newBSA.ToLowerInvariant());
                }
                finally
                {
                    Op.Step();
                }
            }

            Op.Finish();

            return true;
        }
Beispiel #6
0
        private void HandleFile(InstallStatus opChk, PatchJoin join)
        {
            try
            {
                var newFile = join.Item1;
                var oldFile = join.Item2;

                var filepath = newFile.Filename;
                var filename = newFile.Name;

                if (oldFile == null)
                {
                    Log.Dual("ERROR: File not found: " + filepath);
                    return;
                }

                var patchTuple = join.Item3;
                var newChk = patchTuple.Item1;
                var patches = patchTuple.Item2;

                if (filepath.StartsWith(Resources.VoicePrefix) && (patches == null || patches.Length == 0))
                {
                    opChk.CurrentOperation = "Skipping " + filename;
                    //Log.File("Skipping voice file: " + filepath);
                    return;
                }

                using (var curChk = FileValidation.FromBSAFile(oldFile, newChk.Type))
                    if (newChk == curChk)
                    {
                        opChk.CurrentOperation = "Compressing " + filename;
                        newFile.Cache();
                    }
                    else
                    {
                        //YOUR HANDY GUIDEBOOK FOR STRANGE CHECKSUM ACRONYMS!
                        //newChk - the checksum for the expected final result (after patching)
                        //oldChk - the checksum for the original file a diff is built against
                        //curChk - the checksum for the current file being compared or patched
                        //tstChk - the checksum for the current file, in the format of oldChk
                        //patChk - the checksum for the current file, after patching or failure
                        foreach (var patchInfo in patches)
                        {
                            var oldChk = patchInfo.Metadata;

                            if (curChk.Type != oldChk.Type)
                            {
                                using (var tstChk = FileValidation.FromBSAFile(oldFile, oldChk.Type))
                                    if (oldChk != tstChk)
                                        //this is a patch for a different original
                                        continue;
                            }
                            else if (oldChk != curChk)
                                //this is a patch for a different original
                                continue;

                            //patch is for this original
                            opChk.CurrentOperation = "Patching " + filename;

                            if (PatchBsaFile(newFile, patchInfo, newChk))
                                return;
                            else
                                Log.Dual("ERROR: Patching " + filepath + " failed");
                        }

                        using (var patChk = FileValidation.FromBSAFile(newFile, newChk.Type))
                            if (newChk != patChk)
                            {
                                //no patch exists for the file
                                Log.Dual("WARNING: File is of an unexpected version: " + newFile.Filename + " - " + patChk);
                                Log.Dual("This file cannot be patched. Errors may occur.");
                            }
                    }
            }
            finally
            {
                opChk.Step();
            }
        }