Add Game diffing

This commit is contained in:
Matt Nadareski
2020-08-01 14:15:04 -07:00
parent b321c38be9
commit b6c1e9f5c7
5 changed files with 118 additions and 3 deletions

View File

@@ -326,6 +326,14 @@ namespace SabreTools.Library.DatFiles
DiffAgainst(inputFileNames, outDir, inplace); DiffAgainst(inputFileNames, outDir, inplace);
} }
// If we are in game diffing mode
else if (updateMode.HasFlag(UpdateMode.DiffGame))
{
// Populate the combined data
PopulateUserData(baseFileNames, filter);
DiffGame(inputFileNames, outDir, inplace, filter);
}
// If we have one of the base replacement modes // If we have one of the base replacement modes
else if (updateMode.HasFlag(UpdateMode.BaseReplace) else if (updateMode.HasFlag(UpdateMode.BaseReplace)
|| updateMode.HasFlag(UpdateMode.ReverseBaseReplace)) || updateMode.HasFlag(UpdateMode.ReverseBaseReplace))
@@ -406,6 +414,19 @@ namespace SabreTools.Library.DatFiles
DiffNoCascade(paths, outDir, diff); DiffNoCascade(paths, outDir, diff);
} }
/// <summary>
/// Output games that contain different items (by name)
/// </summary>
/// <param name="inputs">Names of the input files</param>
/// <param name="outDir">Optional param for output directory</param>
/// <param name="inplace">True if the output files should overwrite their inputs, false otherwise</param>
/// <param name="filter">Filter object to be passed to the DatItem level</param>
public void DiffGame(List<string> inputs, string outDir, bool inplace, Filter filter)
{
List<ParentablePath> paths = inputs.Select(i => new ParentablePath(i)).ToList();
DiffGame(paths, outDir, inplace, filter);
}
/// <summary> /// <summary>
/// Output user defined merge /// Output user defined merge
/// </summary> /// </summary>
@@ -1226,6 +1247,70 @@ namespace SabreTools.Library.DatFiles
watch.Stop(); watch.Stop();
} }
/// <summary>
/// Replace item values from the base set represented by the current DAT
/// </summary>
/// <param name="inputs">Names of the input files</param>
/// <param name="outDir">Optional param for output directory</param>
/// <param name="inplace">True if the output files should overwrite their inputs, false otherwise</param>
/// <param name="filter">Filter object to be passed to the DatItem level</param>
/// <remarks>TODO: Can this be wrapped into DiffAgainst?</remarks>
internal void DiffGame(List<ParentablePath> inputs, string outDir, bool inplace, Filter filter)
{
// Order the current DAT by game first
Items.BucketBy(BucketedBy.Game, DedupeType.None);
// We want to try to replace each item in each input DAT from the base
foreach (ParentablePath path in inputs)
{
Globals.Logger.User($"Comparing items in '{path.CurrentPath}' to the base DAT");
// First we parse in the DAT internally
DatFile intDat = Create(Header.CloneFiltering());
intDat.Parse(path, 1, keep: true);
filter.FilterDatFile(intDat, false /* useTags */);
intDat.Items.BucketBy(BucketedBy.Game, DedupeType.None);
// TODO: Do we need to include items in base NOT in compare?
List<string> games = intDat.Items.Keys.ToList();
foreach (string game in games)
{
// If the base DAT doesn't contain the key, keep it
if (!Items.ContainsKey(game))
continue;
// If the number of items is different, then keep it
if (Items[game].Count != intDat.Items[game].Count)
continue;
// Otherwise, compare by name and hash the remaining files
bool exactMatch = true;
foreach (DatItem item in intDat.Items[game])
{
// TODO: Make this granular to name as well
if (!Items[game].Contains(item))
{
exactMatch = false;
break;
}
}
// If we have an exact match, remove the game
if (exactMatch)
intDat.Items.Remove(game);
}
// Determine the output path for the DAT
string interOutDir = path.GetOutputPath(outDir, inplace);
// Once we're done, try writing out
intDat.Write(interOutDir, overwrite: inplace);
// Due to possible memory requirements, we force a garbage collection
GC.Collect();
}
}
/// <summary> /// <summary>
/// Output user defined merge /// Output user defined merge
/// </summary> /// </summary>

View File

@@ -257,11 +257,12 @@ namespace SabreTools.Library.Data
// Base diffs // Base diffs
DiffAgainst = 1 << 5, DiffAgainst = 1 << 5,
DiffGame = 1 << 6,
// Special update modes // Special update modes
Merge = 1 << 6, Merge = 1 << 7,
BaseReplace = 1 << 7, BaseReplace = 1 << 8,
ReverseBaseReplace = 1 << 8, ReverseBaseReplace = 1 << 9,
// Combinations // Combinations
AllDiffs = DiffDupesOnly | DiffNoDupesOnly | DiffIndividualsOnly, AllDiffs = DiffDupesOnly | DiffNoDupesOnly | DiffIndividualsOnly,

View File

@@ -1205,6 +1205,16 @@ Options:
Add a DAT or folder of DATs to the base set to be used for all Add a DAT or folder of DATs to the base set to be used for all
operations. Multiple instances of this flag are allowed. operations. Multiple instances of this flag are allowed.
-dga, --diff-game Diff all inputs by game against a set of base DATs
This flag will enable a special type of diffing in which a set of base
DATs are used as a comparison point for each of the input DATs by game.
This allows users to get a slightly different output to cascaded
diffing, which may be more useful in some cases.
-bd=, --base-dat= Add a base DAT for processing
Add a DAT or folder of DATs to the base set to be used for all
operations. Multiple instances of this flag are allowed.
-br, --base-replace Replace from base DATs in order -br, --base-replace Replace from base DATs in order
By default, no item names are changed except when there is a merge By default, no item names are changed except when there is a merge
occurring. This flag enables users to define a DAT or set of base occurring. This flag enables users to define a DAT or set of base

View File

@@ -336,6 +336,20 @@ namespace SabreTools.Features
} }
} }
internal const string DiffGameValue = "diff-game";
internal static Feature DiffGameFlag
{
get
{
return new Feature(
DiffAgainstValue,
new List<string>() { "-dga", "--diff-game" },
"Diff all inputs by game against a set of base DATs",
FeatureType.Flag,
"This flag will enable a special type of diffing in which a set of base DATs are used as a comparison point for each of the input DATs by game. This allows users to get a slightly different output to cascaded diffing, which may be more useful in some cases.");
}
}
internal const string DiffIndividualsValue = "diff-individuals"; internal const string DiffIndividualsValue = "diff-individuals";
internal static Feature DiffIndividualsFlag internal static Feature DiffIndividualsFlag
{ {
@@ -2489,6 +2503,9 @@ Some special strings that can be used:
if (GetBoolean(features, DiffDuplicatesValue)) if (GetBoolean(features, DiffDuplicatesValue))
updateMode |= UpdateMode.DiffDupesOnly; updateMode |= UpdateMode.DiffDupesOnly;
if (GetBoolean(features, DiffGameValue))
updateMode |= UpdateMode.DiffGame;
if (GetBoolean(features, DiffIndividualsValue)) if (GetBoolean(features, DiffIndividualsValue))
updateMode |= UpdateMode.DiffIndividualsOnly; updateMode |= UpdateMode.DiffIndividualsOnly;

View File

@@ -56,6 +56,8 @@ namespace SabreTools.Features
this[DiffNoDuplicatesFlag].AddFeature(NoAutomaticDateFlag); this[DiffNoDuplicatesFlag].AddFeature(NoAutomaticDateFlag);
AddFeature(DiffAgainstFlag); AddFeature(DiffAgainstFlag);
this[DiffAgainstFlag].AddFeature(BaseDatListInput); this[DiffAgainstFlag].AddFeature(BaseDatListInput);
AddFeature(DiffGameFlag);
this[DiffGameFlag].AddFeature(BaseDatListInput);
AddFeature(BaseReplaceFlag); AddFeature(BaseReplaceFlag);
this[BaseReplaceFlag].AddFeature(BaseDatListInput); this[BaseReplaceFlag].AddFeature(BaseDatListInput);
this[BaseReplaceFlag].AddFeature(UpdateFieldListInput); this[BaseReplaceFlag].AddFeature(UpdateFieldListInput);