diff --git a/SabreTools.Library/DatFiles/DatFile.cs b/SabreTools.Library/DatFiles/DatFile.cs index f738cd02..4c90a072 100644 --- a/SabreTools.Library/DatFiles/DatFile.cs +++ b/SabreTools.Library/DatFiles/DatFile.cs @@ -295,6 +295,31 @@ namespace SabreTools.Library.DatFiles } } + /// + /// Fill a DatFile with all items with a particular source index ID + /// + /// DatFile to add found items to + /// Source index ID to retrieve items for + /// DatFile containing all items with the source index ID/returns> + public void FillWithSourceIndex(DatFile indexDat, int index) + { + // Loop through and add the items for this index to the output + Parallel.ForEach(Items.Keys, Globals.ParallelOptions, key => + { + List items = DatItem.Merge(Items[key]); + + // If the rom list is empty or null, just skip it + if (items == null || items.Count == 0) + return; + + foreach (DatItem item in items) + { + if (item.Source.Index == index) + indexDat.Items.Add(key, item); + } + }); + } + /// /// Output diffs against a base set represented by the current DAT /// @@ -369,110 +394,33 @@ namespace SabreTools.Library.DatFiles /// /// Output cascading diffs /// - /// List of inputs to write out from /// Dat headers used optionally - /// Output directory to write the DATs to - /// True if cascaded diffs are outputted in-place, false otherwise - /// True if the first cascaded diff file should be skipped on output, false otherwise - public void DiffCascade( - List inputs, - List datHeaders, - string outDir, - bool inplace, - bool skip) - { - List paths = inputs.Select(i => new ParentablePath(i)).ToList(); - DiffCascade(paths, datHeaders, outDir, inplace, skip); - } - - /// - /// Output cascading diffs - /// - /// List of inputs to write out from - /// Dat headers used optionally - /// Output directory to write the DATs to - /// True if cascaded diffs are outputted in-place, false otherwise - /// True if the first cascaded diff file should be skipped on output, false otherwise - public void DiffCascade( - List inputs, - List datHeaders, - string outDir, - bool inplace, - bool skip) + /// List of DatFiles representing the individually indexed items + public List DiffCascade(List datHeaders) { // Create a list of DatData objects representing output files List outDats = new List(); + // Ensure the current DatFile is sorted optimally + Items.BucketBy(Field.DatItem_CRC, DedupeType.None); + // Loop through each of the inputs and get or create a new DatData object - InternalStopwatch watch = new InternalStopwatch("Initializing all output DATs"); + InternalStopwatch watch = new InternalStopwatch("Initializing and filling all output DATs"); - DatFile[] outDatsArray = new DatFile[inputs.Count]; - Parallel.For(0, inputs.Count, Globals.ParallelOptions, j => + // Create the DatFiles from the set of headers + DatFile[] outDatsArray = new DatFile[datHeaders.Count]; + Parallel.For(0, datHeaders.Count, Globals.ParallelOptions, j => { - string innerpost = $" ({j} - {inputs[j].GetNormalizedFileName(true)} Only)"; - DatFile diffData; - - // If we're in inplace mode or the output directory is set, take the appropriate DatData object already stored - if (inplace || outDir != Environment.CurrentDirectory) - { - diffData = Create(datHeaders[j]); - } - else - { - diffData = Create(Header); - diffData.Header.FileName += innerpost; - diffData.Header.Name += innerpost; - diffData.Header.Description += innerpost; - } - + DatFile diffData = Create(datHeaders[j]); diffData.Items = new ItemDictionary(); + FillWithSourceIndex(diffData, j); outDatsArray[j] = diffData; }); outDats = outDatsArray.ToList(); watch.Stop(); - // Then, ensure that the internal dat can be bucketed in the best possible way - Items.BucketBy(Field.DatItem_CRC, DedupeType.None); - - // Now, loop through the dictionary and populate the correct DATs - watch.Start("Populating all output DATs"); - - Parallel.ForEach(Items.Keys, Globals.ParallelOptions, key => - { - List items = DatItem.Merge(Items[key]); - - // If the rom list is empty or null, just skip it - if (items == null || items.Count == 0) - return; - - foreach (DatItem item in items) - { - // There's odd cases where there are items with System ID < 0. Skip them for now - if (item.Source.Index < 0) - { - Globals.Logger.Warning($"Item found with a <0 SystemID: {item.Name}"); - continue; - } - - outDats[item.Source.Index].Items.Add(key, item); - } - }); - - watch.Stop(); - - // Finally, loop through and output each of the DATs - watch.Start("Outputting all created DATs"); - - Parallel.For((skip ? 1 : 0), inputs.Count, Globals.ParallelOptions, j => - { - string path = inputs[j].GetOutputPath(outDir, inplace); - - // Try to output the file - outDats[j].Write(path, overwrite: inplace); - }); - - watch.Stop(); + return outDats; } /// diff --git a/SabreTools/Features/Update.cs b/SabreTools/Features/Update.cs index 37a88a5a..fc0632eb 100644 --- a/SabreTools/Features/Update.cs +++ b/SabreTools/Features/Update.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; using System.IO; - +using System.Threading.Tasks; using SabreTools.Library.Data; using SabreTools.Library.DatFiles; using SabreTools.Library.DatItems; using SabreTools.Library.Help; using SabreTools.Library.IO; +using SabreTools.Library.Tools; namespace SabreTools.Features { @@ -155,7 +156,7 @@ namespace SabreTools.Features if (updateMode == UpdateMode.None) { // Loop through each input and update - foreach (ParentablePath inputPath in inputPaths) + Parallel.ForEach(inputPaths, Globals.ParallelOptions, inputPath => { // Create a new base DatFile DatFile datFile = DatFile.Create(Header); @@ -172,7 +173,7 @@ namespace SabreTools.Features // Try to output the file, overwriting only if it's not in the current directory datFile.Write(realOutDir, overwrite: GetBoolean(features, InplaceValue)); - } + }); return; } @@ -218,19 +219,44 @@ namespace SabreTools.Features // Output cascaded diffs if (updateMode.HasFlag(UpdateMode.DiffCascade)) { - userInputDat.DiffCascade( - inputPaths, - datHeaders, - OutputDir, - GetBoolean(features, InplaceValue), - GetBoolean(features, SkipFirstOutputValue)); + // Preprocess the DatHeaders + Parallel.For(0, datHeaders.Count, Globals.ParallelOptions, j => + { + // If we're outputting to the runtime folder, rename + if (!GetBoolean(features, InplaceValue) && OutputDir == Environment.CurrentDirectory) + { + string innerpost = $" ({j} - {inputPaths[j].GetNormalizedFileName(true)} Only)"; + + datHeaders[j] = userInputDat.Header; + datHeaders[j].FileName += innerpost; + datHeaders[j].Name += innerpost; + datHeaders[j].Description += innerpost; + } + }); + + // Get all of the output DatFiles + List datFiles = userInputDat.DiffCascade(datHeaders); + + // Loop through and output the new DatFiles + InternalStopwatch watch = new InternalStopwatch("Outputting all created DATs"); + + int startIndex = GetBoolean(features, SkipFirstOutputValue) ? 1 : 0; + Parallel.For(startIndex, inputPaths.Count, Globals.ParallelOptions, j => + { + string path = inputPaths[j].GetOutputPath(OutputDir, GetBoolean(features, InplaceValue)); + + // Try to output the file + datFiles[j].Write(path, overwrite: GetBoolean(features, InplaceValue)); + }); + + watch.Stop(); } // Output differences against a base DAT if (updateMode.HasFlag(UpdateMode.DiffAgainst)) { // Loop through each input and diff against the base - foreach (ParentablePath inputPath in inputPaths) + Parallel.ForEach(inputPaths, Globals.ParallelOptions, inputPath => { // Parse, extras, and filter the path to a new DatFile DatFile repDat = DatFile.Create(userInputDat.Header.CloneFiltering()); @@ -244,14 +270,14 @@ namespace SabreTools.Features // Finally output the diffed DatFile string interOutDir = inputPath.GetOutputPath(OutputDir, GetBoolean(features, InplaceValue)); repDat.Write(interOutDir, overwrite: GetBoolean(features, InplaceValue)); - } + }); } // Output DATs after replacing fields from a base DatFile if (updateMode.HasFlag(UpdateMode.BaseReplace)) { // Loop through each input and apply the base DatFile - foreach (ParentablePath inputPath in inputPaths) + Parallel.ForEach(inputPaths, Globals.ParallelOptions, inputPath => { // Parse, extras, and filter the path to a new DatFile DatFile repDat = DatFile.Create(userInputDat.Header.CloneFiltering()); @@ -265,7 +291,7 @@ namespace SabreTools.Features // Finally output the replaced DatFile string interOutDir = inputPath.GetOutputPath(OutputDir, GetBoolean(features, InplaceValue)); repDat.Write(interOutDir, overwrite: GetBoolean(features, InplaceValue)); - } + }); } // Merge all input files and write