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(); }
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); }
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); }
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); } }
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; }
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(); } }