diff --git a/SabreTools.DatFiles/ItemDictionaryDB.cs b/SabreTools.DatFiles/ItemDictionaryDB.cs index e58505b1..e996ba7c 100644 --- a/SabreTools.DatFiles/ItemDictionaryDB.cs +++ b/SabreTools.DatFiles/ItemDictionaryDB.cs @@ -1206,6 +1206,171 @@ namespace SabreTools.DatFiles #region Splitting + /// + /// Use device_ref and optionally slotoption tags to add roms to the children + /// + /// True if only child device sets are touched, false for non-device sets + /// True if slotoptions tags are used as well, false otherwise + public bool AddRomsFromDevices(bool dev, bool useSlotOptions) + { + bool foundnew = false; + List games = [.. SortedKeys]; + foreach (string game in games) + { + // Get the items for this game + var items = GetDatItemsForBucket(game); + + // If the machine doesn't have items, we continue + 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; + + // If the machine (is/is not) a device, we want to continue + if (dev ^ (machine.Item2.GetBoolFieldValue(Models.Metadata.Machine.IsDeviceKey) == true)) + continue; + + // Get all device reference names from the current machine + List deviceReferences = items + .Where(i => i.Item2 is DeviceRef) + .Select(i => i.Item2 as DeviceRef) + .Select(dr => dr!.GetName()) + .Distinct() + .ToList(); + + // Get all slot option names from the current machine + List slotOptions = items + .Where(i => i.Item2 is Slot) + .Select(i => i.Item2 as Slot) + .Where(s => s!.SlotOptionsSpecified) + .SelectMany(s => s!.GetFieldValue(Models.Metadata.Slot.SlotOptionKey)!) + .Select(so => so.GetStringFieldValue(Models.Metadata.SlotOption.DevNameKey)) + .Distinct() + .ToList(); + + // If we're checking device references + if (deviceReferences.Any()) + { + // Loop through all names and check the corresponding machines + List newDeviceReferences = []; + foreach (string? deviceReference in deviceReferences) + { + // If the device reference is invalid + if (deviceReference == null) + continue; + + // If the machine doesn't exist then we continue + var devItems = GetDatItemsForBucket(deviceReference); + if (devItems == null || devItems.Length == 0) + continue; + + // Add to the list of new device reference names + newDeviceReferences.AddRange(devItems + .Where(i => i.Item2 is DeviceRef) + .Select(i => (i.Item2 as DeviceRef)!.GetName()!)); + + // Set new machine information and add to the current machine + var copyFrom = GetMachineForItem(GetDatItemsForBucket(game)![0].Item1); + if (copyFrom.Item2 == null) + continue; + + foreach ((long, DatItem) item in devItems) + { + // If the parent machine doesn't already contain this item, add it + if (!GetDatItemsForBucket(game)! + .Any(i => i.Item2.GetStringFieldValue(Models.Metadata.DatItem.TypeKey) == item.Item2.GetStringFieldValue(Models.Metadata.DatItem.TypeKey) + && i.Item2.GetName() == item.Item2.GetName())) + { + // Set that we found new items + foundnew = true; + + // Clone the item and then add it + DatItem datItem = (item.Item2.Clone() as DatItem)!; + AddItem(datItem, machine.Item1); + } + } + } + + // Now that every device reference is accounted for, add the new list of device references, if they don't already exist + foreach (string deviceReference in newDeviceReferences.Distinct()) + { + if (!deviceReferences.Contains(deviceReference)) + { + var deviceRef = new DeviceRef(); + deviceRef.SetName(deviceReference); + AddItem(deviceRef, machine.Item1); + } + } + } + + // If we're checking slotoptions + if (useSlotOptions && slotOptions.Any()) + { + // Loop through all names and check the corresponding machines + List newSlotOptions = []; + foreach (string? slotOption in slotOptions) + { + // If the slot option is invalid + if (slotOption == null) + continue; + + // If the machine doesn't exist then we continue + var slotItems = GetDatItemsForBucket(slotOption); + if (slotItems == null || slotItems.Length == 0) + continue; + + // Add to the list of new slot option names + newSlotOptions.AddRange(slotItems + .Where(i => i.Item2 is Slot) + .Where(s => (s.Item2 as Slot)!.SlotOptionsSpecified) + .SelectMany(s => (s.Item2 as Slot)!.GetFieldValue(Models.Metadata.Slot.SlotOptionKey)!) + .Select(o => o.GetStringFieldValue(Models.Metadata.SlotOption.DevNameKey)!)); + + // Set new machine information and add to the current machine + var copyFrom = GetMachineForItem(GetDatItemsForBucket(game)![0].Item1); + if (copyFrom.Item2 == null) + continue; + + foreach ((long, DatItem) item in slotItems) + { + // If the parent machine doesn't already contain this item, add it + if (!GetDatItemsForBucket(game)! + .Any(i => i.Item2.GetStringFieldValue(Models.Metadata.DatItem.TypeKey) == item.Item2.GetStringFieldValue(Models.Metadata.DatItem.TypeKey) + && i.Item2.GetName() == item.Item2.GetName())) + { + // Set that we found new items + foundnew = true; + + // Clone the item and then add it + DatItem datItem = (item.Item2.Clone() as DatItem)!; + AddItem(datItem, machine.Item1); + } + } + } + + // Now that every device is accounted for, add the new list of slot options, if they don't already exist + foreach (string slotOption in newSlotOptions.Distinct()) + { + if (!slotOptions.Contains(slotOption)) + { + var slotOptionItem = new SlotOption(); + slotOptionItem.SetFieldValue(Models.Metadata.SlotOption.DevNameKey, slotOption); + + var slotItem = new Slot(); + slotItem.SetFieldValue(Models.Metadata.Slot.SlotOptionKey, [slotOptionItem]); + + AddItem(slotItem, machine.Item1); + } + } + } + } + + return foundnew; + } + /// /// Use cloneof tags to add roms to the children, setting the new romof tag in the process /// diff --git a/SabreTools.Filtering/Splitter.cs b/SabreTools.Filtering/Splitter.cs index f0d35b3a..fac4efed 100644 --- a/SabreTools.Filtering/Splitter.cs +++ b/SabreTools.Filtering/Splitter.cs @@ -109,7 +109,9 @@ namespace SabreTools.Filtering // Now we want to loop through all of the games and set the correct information while (AddRomsFromDevices(datFile, false, false)) ; + while (datFile.ItemsDB.AddRomsFromDevices(false, false)) ; while (AddRomsFromDevices(datFile, true, false)) ; + while (datFile.ItemsDB.AddRomsFromDevices(true, false)) ; // Then, remove the romof and cloneof tags so it's not picked up by the manager RemoveTagsFromChild(datFile); @@ -154,7 +156,9 @@ namespace SabreTools.Filtering // Now we want to loop through all of the games and set the correct information while (AddRomsFromDevices(datFile, true, true)) ; + while (datFile.ItemsDB.AddRomsFromDevices(true, true)) ; AddRomsFromDevices(datFile, false, true); + datFile.ItemsDB.AddRomsFromDevices(false, true); AddRomsFromParent(datFile); datFile.ItemsDB.AddRomsFromParent(); @@ -439,8 +443,6 @@ namespace SabreTools.Filtering return foundnew; } - // TODO: Add AddRomsFromDevicesDB - /// /// Use cloneof tags to add roms to the children, setting the new romof tag in the process ///