diff --git a/SabreTools.DatFiles/ItemDictionaryDB.cs b/SabreTools.DatFiles/ItemDictionaryDB.cs index 6080cebd..9b92b4a2 100644 --- a/SabreTools.DatFiles/ItemDictionaryDB.cs +++ b/SabreTools.DatFiles/ItemDictionaryDB.cs @@ -316,6 +316,19 @@ namespace SabreTools.DatFiles return _machines[index]; } + /// + /// Get a machine based on the name + /// + /// This assume that all machines have unique names + public (long, Machine?) GetMachine(string? name) + { + if (string.IsNullOrEmpty(name)) + return (-1, null); + + var machine = _machines.FirstOrDefault(m => m.Value.GetStringFieldValue(Models.Metadata.Machine.NameKey) == name); + return (machine.Key, machine.Value); + } + /// /// Get the index and machine associated with an item index /// @@ -1172,6 +1185,134 @@ namespace SabreTools.DatFiles #region Splitting + /// + /// Use cloneof tags to add roms to the parents, removing the child sets in the process + /// + /// True to add DatItems to subfolder of parent (not including Disk), false otherwise + /// True to skip checking for duplicate ROMs in parent, false otherwise + public void AddRomsFromChildren(bool subfolder, bool skipDedup) + { + List games = [.. SortedKeys]; + foreach (string game in games) + { + // If the game has no items in it, we want to continue + var items = GetDatItemsForBucket(game); + if (items == null || items.Length == 0) + continue; + + // Get the machine for the first item + var machine = GetMachineForItem(items[0].Item1); + if (machine.Item2 == null) + continue; + + // Determine if the game has a parent or not + (long, string?) parent = (-1, null); + if (!string.IsNullOrEmpty(machine.Item2.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey))) + { + string? cloneOf = machine.Item2.GetStringFieldValue(Models.Metadata.Machine.CloneOfKey); + var cloneOfMachine = GetMachine(cloneOf); + parent = (cloneOfMachine.Item1, cloneOf); + } + + // If there is no parent, then we continue + if (string.IsNullOrEmpty(parent.Item2)) + continue; + + items = GetDatItemsForBucket(game); + foreach ((long, DatItem) item in items!) + { + // Get the parent items and current machine name + var parentItems = GetDatItemsForBucket(parent.Item2!); + string? machineName = GetMachineForItem(item.Item1).Item2?.GetStringFieldValue(Models.Metadata.Machine.NameKey); + + // Special disk handling + if (item.Item2 is Disk disk) + { + string? mergeTag = disk.GetStringFieldValue(Models.Metadata.Disk.MergeKey); + + // If the merge tag exists and the parent already contains it, skip + if (mergeTag != null && parentItems! + .Where(i => i.Item2 is Disk) + .Select(i => (i.Item2 as Disk)!.GetName()) + .Contains(mergeTag)) + { + continue; + } + + // If the merge tag exists but the parent doesn't contain it, add to parent + else if (mergeTag != null && !parentItems! + .Where(i => i.Item2 is Disk) + .Select(i => (i.Item2 as Disk)!.GetName()) + .Contains(mergeTag)) + { + _itemToMachineMapping[item.Item1] = parent.Item1; + _buckets[parent.Item2!].Add(disk); + } + + // If there is no merge tag, add to parent + else if (mergeTag == null) + { + _itemToMachineMapping[item.Item1] = parent.Item1; + _buckets[parent.Item2!].Add(disk); + } + } + + // Special rom handling + else if (item.Item2 is Rom rom) + { + // If the merge tag exists and the parent already contains it, skip + if (rom.GetStringFieldValue(Models.Metadata.Rom.MergeKey) != null && parentItems! + .Where(i => i.Item2 is Rom) + .Select(i => (i.Item2 as Rom)!.GetName()) + .Contains(rom.GetStringFieldValue(Models.Metadata.Rom.MergeKey))) + { + continue; + } + + // If the merge tag exists but the parent doesn't contain it, add to subfolder of parent + else if (rom.GetStringFieldValue(Models.Metadata.Rom.MergeKey) != null && !parentItems! + .Where(i => i.Item2 is Rom) + .Select(i => (i.Item2 as Rom)!.GetName()) + .Contains(rom.GetStringFieldValue(Models.Metadata.Rom.MergeKey))) + { + if (subfolder) + rom.SetName($"{machineName}\\{rom.GetName()}"); + + _itemToMachineMapping[item.Item1] = parent.Item1; + _buckets[parent.Item2!].Add(rom); + } + + // If the parent doesn't already contain this item, add to subfolder of parent + else if (!parentItems!.Contains(item) || skipDedup) + { + if (subfolder) + rom.SetName($"{machineName}\\{rom.GetName()}"); + + _itemToMachineMapping[item.Item1] = parent.Item1; + _buckets[parent.Item2!].Add(rom); + } + } + + // All other that would be missing to subfolder of parent + else if (!parentItems!.Contains(item)) + { + if (subfolder) + item.Item2.SetName($"{machineName}\\{item.Item2.GetName()}"); + + _itemToMachineMapping[item.Item1] = parent.Item1; + _buckets[parent.Item2!].Add(item); + } + } + + // Then, remove the old game so it's not picked up by the writer +#if NET40_OR_GREATER || NETCOREAPP + _buckets.TryRemove(game, out _); +#else + _buckets.Remove(game); +#endif + } + } + /// /// Remove all BIOS and device sets ///