public MultiBNKEnumerator(BNKFile vanilla, BNKFile[] patches, string vanillaFilePath, string[] patchPaths) { VanillaFile = vanilla; Patches = patches; VanillaPath = vanillaFilePath; PatchPaths = patchPaths; }
/// <summary> /// Patches all bnk files into the vanilla bnk file. /// </summary> public void PatchEverything() { // Set up a list of conflicting WEM files + their corresponding BNK files. List <WEMFile> conflictingWEMs = new List <WEMFile>(); List <string> conflictingPaths = new List <string>(); List <WEMFile> vanillaWEMFiles = VanillaFile.Marshaller.WEMFiles.ToList(); int currentFiles = 0; for (int idx = 0; idx < vanillaWEMFiles.Count; idx++) { // Reset the conflicting lists since we're reviewing a new WEM file. conflictingWEMs.Clear(); conflictingPaths.Clear(); WEMFile vanillaWEM = vanillaWEMFiles[idx]; for (int oidx = 0; oidx < Patches.Length; oidx++) { BNKFile otherBnk = Patches[oidx]; WEMFile other = GetWEMInOtherBNKFromID(vanillaWEM, otherBnk); // conflictingWEMs will contain every wem file that isn't the same as the vanilla one. // This means that if the list only has one element, there are no conflicts to resolve. // Surprisingly, this is far faster than I thought it was going to be. // I had initially anticipated it to take at least a minute to process all of this data, but my implementation proved sturdy. // It can process multiple BNKs in a matter of about a second. // I suppose this is the benefit of my storage method: Spend a lot of time constructing a representation once, Save time indexing the data later. // Given how I overloaded (in)equality in WEMFile, this is alarmingly fast. if (vanillaWEM != other) { conflictingWEMs.Add(other); conflictingPaths.Add(PatchPaths[oidx]); } } int targetReplacement = 0; if (conflictingPaths.Count > 1) { Console.WriteLine(); // Bump it down for the counter. targetReplacement = ResolveFileConflict(vanillaWEM.ID, conflictingPaths.ToArray()); } if (targetReplacement != -1 && conflictingWEMs.Count != 0) { VanillaFile.Marshaller.OverwriteWEMFile(conflictingWEMs[targetReplacement]); } currentFiles++; Console.ForegroundColor = ConsoleColor.DarkGreen; Console.Write("Processed {0} files (of {1})", currentFiles, vanillaWEMFiles.Count); Console.CursorLeft = 0; } Console.WriteLine(); }
/// <summary> /// Gets a WEM in another BNK archive via its ID. /// </summary> /// <param name="template">The template WEM file. This should have the ID you want to get inside of its data.</param> /// <param name="otherArchive">The other archive to search.</param> /// <returns></returns> private WEMFile GetWEMInOtherBNKFromID(WEMFile template, BNKFile otherArchive) { List <WEMFile> otherWemFiles = otherArchive.Marshaller.WEMFiles.ToList(); for (int idx = 0; idx < otherWemFiles.Count; idx++) { WEMFile wemFile = otherWemFiles[idx]; if (wemFile.ID == template.ID) { return(wemFile); } } return(null); }
/// <summary> /// Construct a new BNKPatcher, loading an underlying BNK file to edit. /// </summary> /// <param name="bnkFile">The Stream of the BNK file being patched.</param> public BNKPatcher(Stream bnkFile) { BankFile = new BNKFile(bnkFile); }
static void Main(string[] args) { Console.ForegroundColor = ConsoleColor.Green; string vanillaBnkPath = null; List <string> patchFiles = new List <string>(); // [0] = vanilla file // [1] = custom file 1 // [2] = custom file 2 // [...] = ... if (args.Length < 3) { PopulateDirectoryInfo(out vanillaBnkPath, out patchFiles); } else { vanillaBnkPath = args[0]; if (!File.Exists(vanillaBnkPath)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("ERROR: The file you input does not exist!"); Console.ForegroundColor = ConsoleColor.DarkRed; Console.WriteLine("Failed to find: " + vanillaBnkPath); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Press enter to quit..."); Console.ReadLine(); return; } foreach (string data in args.Skip(1)) { if (!File.Exists(data)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("ERROR: The file you input does not exist!"); Console.ForegroundColor = ConsoleColor.DarkRed; Console.WriteLine("Failed to find: " + data); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Press enter to quit..."); Console.ReadLine(); return; } patchFiles.Add(data); } } Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Loading up all of the BNK files. This might take a bit to complete. Lots of data to go through!"); Console.WriteLine("Opening files..."); FileStream vanillaBnk = File.OpenRead(vanillaBnkPath); FileStream[] otherBnks = new FileStream[patchFiles.Count]; for (int idx = 0; idx < patchFiles.Count; idx++) { otherBnks[idx] = File.OpenRead(patchFiles[idx]); } Console.ForegroundColor = ConsoleColor.DarkGreen; Console.WriteLine("Processing BNK File: {0}", vanillaBnkPath); BNKFile[] otherBnkObjects = new BNKFile[otherBnks.Length]; BNKFile vanillaFile = new BNKFile(vanillaBnk); for (int idx = 0; idx < otherBnkObjects.Length; idx++) { Console.ForegroundColor = ConsoleColor.DarkGreen; Console.WriteLine("Processing BNK File: {0}", patchFiles[idx]); otherBnkObjects[idx] = new BNKFile(otherBnks[idx]); } Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Done populating BNK files! Enumerating... Please be present so that you may resolve any file conflicts."); MultiBNKEnumerator iterator = new MultiBNKEnumerator(vanillaFile, otherBnkObjects, vanillaBnkPath, patchFiles.ToArray()); iterator.PatchEverything(); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Done enumerating BNK files! Saving in the same directory as the EXE..."); string name = "MergedBNK-" + DateTime.Now.ToFileTimeUtc().ToString() + ".BNK"; FileStream save = File.OpenWrite(@".\" + name); iterator.VanillaFile.TranslateToBNKFile(save); save.Flush(); save.Close(); Console.Write("Saved as "); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(name); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Press enter to quit."); Console.ReadLine(); }