private void BuildVoice() { var outBsaPath = Path.Combine(DirTTWOptional, "Fallout3 Player Voice", "TaleOfTwoWastelands - PlayerVoice.bsa"); if (File.Exists(outBsaPath)) { return; } var inBsaPath = Path.Combine(DirFO3Data, "Fallout - Voices.bsa"); using (BSA inBsa = new BSA(inBsaPath), outBsa = new BSA(inBsa.Settings)) { var includedFolders = inBsa .Where(folder => Game.VoicePaths.ContainsKey(folder.Path)) .Select(folder => new BSAFolder(Game.VoicePaths[folder.Path], folder)); foreach (var folder in includedFolders) { outBsa.Add(folder); } outBsa.Save(outBsaPath); } }
/// <summary> /// Opens and return <see cref="Archive"/> of <paramref name="file"/>. /// </summary> /// <param name="file">Archive file to open.</param> /// <param name="owner">Used with <see cref="MessageBox.Show(IWin32Window, string)"/>.</param> public static Archive OpenArchive(string file, IWin32Window owner = null) { Archive archive; try { string extension = Path.GetExtension(file); Encoding encoding = Encoding.GetEncoding(Settings.Default.EncodingCodePage); // ToDo: Read file header to find archive type, not just extension switch (extension.ToLower()) { case ".bsa": case ".dat": if (BSA.IsSupportedVersion(file, encoding) == false) { if (Common.ShowMessageBoxInvoke(owner, "Archive has an unknown version number.\n" + "Attempt to open anyway?", "Warning", MessageBoxButtons.YesNo) != DialogResult.Yes) { return(null); } } archive = new BSA(file, encoding, Settings.Default.RetrieveRealSize) { MatchLastWriteTime = Settings.Default.MatchLastWriteTime }; break; case ".ba2": archive = new BA2(file, encoding, Settings.Default.RetrieveRealSize) { MatchLastWriteTime = Settings.Default.MatchLastWriteTime }; if (archive.Type == ArchiveTypes.BA2_GNMF) { // Check if extensions for GNF textures should be replaced Common.ReplaceGNFExtensions(archive.Files.OfType <BA2GNFEntry>(), Settings.Default.ReplaceGNFExt); } break; default: throw new Exception($"Unrecognized archive file type ({extension})."); } } catch (Exception ex) { Common.ShowMessageBoxInvoke(owner, "An error occured trying to open the archive. Changing the Encoding in Options can help, please try before reporting.\n\n" + ex.ToStringInvariant(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return(null); } return(archive); }
public static IEnumerable<Tuple<string, string, string>> CreateRenameQuery(BSA bsa, IDictionary<string, string> renameDict) { //TODO: use dict union var renameGroup = from folder in bsa from file in folder join kvp in renameDict on file.Filename equals kvp.Value let a = new { folder, file, kvp } //group a by kvp.Value into g select a; var renameCopies = from g in renameGroup let newFilename = g.kvp.Key let newDirectory = Path.GetDirectoryName(newFilename) let a = new { g.folder, g.file, newFilename } group a by newDirectory into outs select outs; var newBsaFolders = renameCopies.ToList(); newBsaFolders.ForEach(g => bsa.Add(new BSAFolder(g.Key))); return from g in newBsaFolders from a in g join folder in bsa on g.Key equals folder.Path let newFile = a.file.DeepCopy(g.Key, Path.GetFileName(a.newFilename)) let addedFile = folder.Add(newFile) select Tuple.Create(a.file.Name, newFile.Name, a.newFilename); }
public static void Clear() { foreach (BSAArchive BSA in LoadedArchives) { BSA.Dispose(); } Meshes.Clear(); Textures.Clear(); AvailableMeshes.Clear(); Loaded = false; }
/// <summary> /// Estimates the dose based on the pharmacy order and calculation factor passed in. /// </summary> /// <param name="context"></param> protected override void DoWork(CodeActivityContext context) { int rxoId = RxoId.Get(context); double bsa = BSA.Get(context); ImpacPersistenceManager pm = ImpacPersistenceManagerFactory.CreatePersistenceManager(); var order = pm.GetEntity <BOM.Entities.PharmOrd>(new PrimaryKey(typeof(BOM.Entities.PharmOrd), rxoId)); if (!order.IsNullEntity) { double calculatedDose; if (DoseCalcUtils.EstimateOrderingDose(order, bsa, out calculatedDose) == DoseCalcUtils.CalcStatus.CalcSucceed) { SuggestedDose.Set(context, calculatedDose); } } }
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(); }
private async void PackBSA(string path, List <Asset> assetList) { string formText = this.Text; this.Text = "Packing..."; this.IsPackingCurrently = true; menuStripMain.Enabled = false; bool compress = bool.Parse(SettingsIni.Data["Archive"]["CompressAssets"]); bool usePS3FileFlags = bool.Parse(SettingsIni.Data["Archive"]["UsePS3FileFlags"]); bool extendDDS = bool.Parse(SettingsIni.Data["DDS"]["ExtendData"]); bool convertNormalMaps = bool.Parse(SettingsIni.Data["DDS"]["ConvertNormalMaps"]); await Task.Run(() => BSA.Write(path, assetList, compress, usePS3FileFlags, extendDDS, convertNormalMaps)); this.IsArchiveSaved = true; this.IsPackingCurrently = false; menuStripMain.Enabled = true; this.Text = formText; MessageBox.Show("Done!", string.Empty, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); }
private static void ProcessBSAs(Recipe recipe, Settings settings) { Console.WriteLine("Processing BSAs ..."); foreach (var filepair in settings.Files.Where(fp => fp.Type == ContentType.BSA)) { Console.Write("{0} => {1} .", filepair.OriginalName, filepair.ResultName); var before = GC.GetTotalMemory(false); var original = BSA.Open(string.Format("{0}\\{1}", settings.Fo3DataPath, filepair.OriginalName)); original.BuildIndex(); var after = GC.GetTotalMemory(false); var referenceFile = string.Format("{0}\\{1}", settings.CurrentDataPath, filepair.ResultName); var referenceDir = new DirectoryInfo(Path.ChangeExtension(referenceFile, null)); Console.Write("."); SortedDictionary <string, Fo3File> reference = new SortedDictionary <string, Fo3File>(); Parallel.ForEach(referenceDir.EnumerateFiles("*.*", SearchOption.AllDirectories).AsParallel(), new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, file => { var assetFile = new Fo3File(file) { Path = file.GetPathRelative(referenceDir.FullName).ToLower() }; lock (reference) { reference.Add(file.GetFullNameRelative(referenceDir.FullName).ToLower(), assetFile); } }); Console.Write(". "); Parallel.ForEach(reference, new ParallelOptions { MaxDegreeOfParallelism = 1 /* Environment.ProcessorCount */ }, record => { Debug.Write(record.Key); if (original.IndexFullPath.ContainsKey(record.Key)) { if (!ByteArrayCompare(record.Value.Checksum, original.IndexFullPath[record.Key].Checksum)) { var originalRecord = original.IndexFullPath[record.Key]; var resultRecord = record.Value; var recordAction = new RecordAction { Path = record.Value.Path, Name = record.Value.Name, Type = ActionType.Copy | ActionType.Patch }; patchQueue.Enqueue(() => CreateAssetPatch(settings, original, originalRecord, resultRecord, recordAction)); filepair.Actions.Add(recordAction); Debug.WriteLine(" patch"); } else { filepair.Actions.Add(new RecordAction { Path = record.Value.Path, Name = record.Value.Name, Type = ActionType.Copy }); Debug.WriteLine(" copy"); } original.IndexFullPath.Remove(record.Key); } else if (original.IndexFileName.ContainsKey(BitConverter.ToString(record.Value.Checksum))) { var originalRecord = original.IndexFileName[BitConverter.ToString(record.Value.Checksum)]; if (original.IndexFullPath.ContainsKey(record.Key)) { original.IndexFullPath.Remove(record.Key); } filepair.Actions.Add(new RecordAction { Path = originalRecord.Path, Name = originalRecord.Name, Type = ActionType.Rename, NewPath = record.Value.Path, NewName = record.Value.Name }); Debug.WriteLine(" rename"); } else { filepair.Actions.Add(new RecordAction { Path = record.Value.Path, Name = record.Value.Name, Type = ActionType.New }); Debug.WriteLine(" new"); } Console.Write("\r{0} => {1} ... {2}/{3}", filepair.OriginalName, filepair.ResultName, filepair.Actions.Count, reference.Count); }); var i = 0; foreach (var newRecord in original.IndexFullPath) { filepair.Actions.Add(new RecordAction { Path = newRecord.Value.Path, Name = newRecord.Value.Name, Type = ActionType.Delete }); Console.Write("\r{0} => {1} ... D{2}/{3} ", filepair.OriginalName, filepair.ResultName, ++i, original.IndexFullPath.Count); Debug.WriteLine(newRecord.Key); } recipe.Files.Add(filepair); Console.Write("\r{0} => {1} ... ", filepair.OriginalName, filepair.ResultName); Console.WriteLine("Done "); #if DEBUG FlushRecipe(settings, recipe); #endif } Console.WriteLine("BSAs completed"); }
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); } }
private void BuildSFX() { var fo3BsaPath = Path.Combine(DirFO3Data, "Fallout - Sound.bsa"); var songsPath = Path.Combine("sound", "songs"); bool skipSongs = false, skipSFX = false; if (Directory.Exists(Path.Combine(DirTTWMain, songsPath))) { skipSongs = ShowSkipDialog("Fallout 3 songs"); } var outBsaPath = Path.Combine(DirTTWOptional, "Fallout3 Sound Effects", "TaleOfTwoWastelands - SFX.bsa"); if (File.Exists(outBsaPath)) { skipSFX = ShowSkipDialog("Fallout 3 sound effects"); } if (skipSongs && skipSFX) { return; } var bsaInstaller = DependencyRegistry.Container.GetInstance <BsaInstaller>(); using (BSA inBsa = new BSA(fo3BsaPath), outBsa = new BSA(inBsa.Settings)) { if (!skipSongs) { Log.Display("Extracting songs"); bsaInstaller.Extract(Token, inBsa.Where(folder => folder.Path.StartsWith(songsPath)), "Fallout - Sound", DirTTWMain, false); } if (skipSFX) { return; } Log.Display("Building optional TaleOfTwoWastelands - SFX.bsa..."); var fxuiPath = Path.Combine("sound", "fx", "ui"); var includedFilenames = new HashSet <string>(File.ReadLines(Path.Combine(Paths.AssetsDir, "TTW Data", "TTW_SFXCopy.txt"))); var includedGroups = from folder in inBsa.Where(folder => folder.Path.StartsWith(fxuiPath)) from file in folder where includedFilenames.Contains(file.Filename) group file by folder; foreach (var group in includedGroups) { //make folder only include files that matched includedFilenames @group.Key.IntersectWith(@group); //add folders back into output BSA outBsa.Add(@group.Key); } Log.File("Building TaleOfTwoWastelands - SFX.bsa."); outBsa.Save(outBsaPath); Log.Display("\tDone"); } }
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; }
static void Main(string[] args) { // If there are no arguments passed then it acts as if help command is ran if (args.Count() == 0) { Program.ShowHelpText(); return; } switch (args[0].ToLower()) { default: { if (args.Count() == 1 && Directory.Exists(args[0])) { // If a single existing folder is inputted, the tool will autopack that // The following codes sets up that process string inputDir = args[0]; args = new string[6]; args[0] = string.Empty; // Can equal blank string value args[1] = "-useps3settings"; args[2] = "-i"; args[3] = inputDir; args[4] = "-o"; args[5] = Path.GetDirectoryName(inputDir) + "\\output.bsa"; goto case "-p"; } Program.ShowHelpText(true); break; } case "-h": case "-help": { Program.ShowHelpText(); break; } case "-p": case "-pack": { string inputDir = string.Empty; string outputPath = string.Empty; bool compress = false; bool usePS3FileFlags = false; bool extendDDS = false; bool convertNormalMaps = false; for (uint i = 1; i < args.Count(); i++) { string option = args[i].ToLower(); switch (option) { default: { Program.ShowHelpText(true); return; } case "-compress": { compress = true; break; } case "-useps3fileflags": { usePS3FileFlags = true; break; } case "-extenddds": { extendDDS = true; break; } case "-convertnormals": { convertNormalMaps = true; break; } case "-useps3settings": { usePS3FileFlags = true; extendDDS = true; convertNormalMaps = true; break; } case "-i": case "-indir": { i++; inputDir = args[i]; break; } case "-o": case "-out": { i++; outputPath = args[i]; break; } } } if (string.IsNullOrEmpty(inputDir) || string.IsNullOrEmpty(outputPath)) { Program.ShowHelpText(true); return; } Console.WriteLine("Reading and verifying files..."); var assetList = new List <Asset>(); foreach (string file in Directory.GetFiles(inputDir, "*", SearchOption.AllDirectories)) { var assetFile = new Asset(file.Substring(inputDir.Length + 1), file); assetList.Add(assetFile); } Console.WriteLine("Packing..."); BSA.Write(outputPath, assetList, compress, usePS3FileFlags, extendDDS, convertNormalMaps); Console.WriteLine("\nDone!\n"); break; } } }
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(Game.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 static Dictionary <string, FileValidation> FromBSA(BSA bsa) { return(bsa .SelectMany(folder => folder) .ToDictionary(file => file.Filename, file => FromBSAFile(file))); }