private static void BuildBsaPatch(string inBsaName, string outBsaName) { string outBSAFile = Path.ChangeExtension(outBsaName, ".bsa"); string outBSAPath = Path.Combine(_dirTTWMain, outBSAFile); string inBSAFile = Path.ChangeExtension(inBsaName, ".bsa"); string inBSAPath = Path.Combine(_dirFO3Data, inBSAFile); var renameDict = BuildRenameDict(outBsaName); Debug.Assert(renameDict != null); var patPath = Path.Combine(OutDir, Path.ChangeExtension(outBsaName, ".pat")); if (File.Exists(patPath)) { return; } var prefix = Path.Combine(InDir, "TTW Patches", outBsaName); using (var inBSA = new BSA(inBSAPath)) using (var outBSA = new BSA(outBSAPath)) { BsaDiff .CreateRenameQuery(inBSA, renameDict) .ToList(); // execute query var oldFiles = inBSA.SelectMany(folder => folder).ToList(); var newFiles = outBSA.SelectMany(folder => folder).ToList(); var newChkDict = FileValidation.FromBSA(outBSA); var joinedPatches = from patKvp in newChkDict join newBsaFile in newFiles on patKvp.Key equals newBsaFile.Filename select new { newBsaFile, file = patKvp.Key, patch = patKvp.Value }; var allJoinedPatches = joinedPatches.ToList(); var patchDict = new PatchDict(allJoinedPatches.Count); foreach (var join in allJoinedPatches) { var oldBsaFile = oldFiles.SingleOrDefault(file => file.Filename == join.file); Debug.Assert(oldBsaFile != null, "File not found: " + join.file); var oldChk = FileValidation.FromBSAFile(oldBsaFile); var newChk = join.patch; var oldFilename = oldBsaFile.Filename; if (oldFilename.StartsWith(TaleOfTwoWastelands.Properties.Resources.VoicePrefix)) { patchDict.Add(join.file, new Patch(newChk, null)); continue; } var patches = new List <PatchInfo>(); var md5OldStr = Util.GetMD5String(oldBsaFile.GetContents(true)); var md5NewStr = Util.GetMD5String(join.newBsaFile.GetContents(true)); var diffPath = Path.Combine(prefix, oldFilename + "." + md5OldStr + "." + md5NewStr + ".diff"); var usedPath = Path.ChangeExtension(diffPath, ".used"); if (File.Exists(usedPath)) { File.Move(usedPath, diffPath); //fixes moronic things } var altDiffs = Util.FindAlternateVersions(diffPath); if (altDiffs != null) { foreach (var altDiff in altDiffs) { var altDiffBytes = GetDiff(altDiff.Item1, Diff.SIG_LZDIFF41); patches.Add(new PatchInfo { Metadata = new FileValidation(altDiff.Item2, 0, FileValidation.ChecksumType.Md5), Data = altDiffBytes }); } } if (newChk != oldChk) { byte[] diffData = GetDiff(diffPath, Diff.SIG_LZDIFF41); var patchInfo = PatchInfo.FromOldDiff(diffData, oldChk); Debug.Assert(patchInfo.Data != null); patches.Add(patchInfo); } patchDict.Add(join.file, new Patch(newChk, patches.ToArray())); } using (var stream = File.OpenWrite(patPath)) patchDict.WriteAll(stream); } }
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); } }