diff --git a/SabreTools.Data.Extensions/MetadataExtensions.cs b/SabreTools.Data.Extensions/MetadataExtensions.cs index 4bde6ffd..8bd06c05 100644 --- a/SabreTools.Data.Extensions/MetadataExtensions.cs +++ b/SabreTools.Data.Extensions/MetadataExtensions.cs @@ -186,8 +186,12 @@ namespace SabreTools.Data.Extensions // return feature.Clone() as Feature; else if (self is Info info) return info.Clone() as Info; + else if (self is Input input) + return input.Clone() as Input; else if (self is Instance instance) return instance.Clone() as Instance; + else if (self is Media media) + return media.Clone() as Media; else if (self is Original original) return original.Clone() as Original; else if (self is RamOption ramOption) @@ -272,15 +276,6 @@ namespace SabreTools.Data.Extensions cloneHeader.Url = selfHeader.Url; cloneHeader.Version = selfHeader.Version; } - else if (self is Input selfInput && clone is Input cloneInput) - { - cloneInput.Buttons = selfInput.Buttons; - cloneInput.Coins = selfInput.Coins; - cloneInput.ControlAttr = selfInput.ControlAttr; - cloneInput.Players = selfInput.Players; - cloneInput.Service = selfInput.Service; - cloneInput.Tilt = selfInput.Tilt; - } else if (self is Machine selfMachine && clone is Machine cloneMachine) { cloneMachine.Board = selfMachine.Board; @@ -332,13 +327,6 @@ namespace SabreTools.Data.Extensions cloneMachine.Url = selfMachine.Url; cloneMachine.Year = selfMachine.Year; } - else if (self is Media selfMedia && clone is Media cloneMedia) - { - cloneMedia.MD5 = selfMedia.MD5; - cloneMedia.SHA1 = selfMedia.SHA1; - cloneMedia.SHA256 = selfMedia.SHA256; - cloneMedia.SpamSum = selfMedia.SpamSum; - } else if (self is Part selfPart && clone is Part clonePart) { clonePart.Interface = selfPart.Interface; diff --git a/SabreTools.Data.Models/Metadata/Input.cs b/SabreTools.Data.Models/Metadata/Input.cs index 87072425..2e7368ee 100644 --- a/SabreTools.Data.Models/Metadata/Input.cs +++ b/SabreTools.Data.Models/Metadata/Input.cs @@ -1,10 +1,11 @@ +using System; using System.Xml.Serialization; using Newtonsoft.Json; namespace SabreTools.Data.Models.Metadata { [JsonObject("input"), XmlRoot("input")] - public class Input : DatItem + public class Input : DatItem, ICloneable, IEquatable { #region Properties @@ -12,6 +13,8 @@ namespace SabreTools.Data.Models.Metadata public long? Coins { get; set; } + public Control[]? Control { get; set; } + /// Attribute also named Control public string? ControlAttr { get; set; } @@ -25,13 +28,57 @@ namespace SabreTools.Data.Models.Metadata #endregion - #region Keys - - /// Control[] - public const string ControlKey = "control"; - - #endregion - public Input() => ItemType = ItemType.Input; + + /// + public object Clone() + { + var obj = new Input(); + + obj.Buttons = Buttons; + obj.Coins = Coins; + if (Control is not null) + obj.Control = Array.ConvertAll(Control, i => (Control)i.Clone()); + obj.ControlAttr = ControlAttr; + obj.Players = Players; + obj.Service = Service; + obj.Tilt = Tilt; + + return obj; + } + + /// + public bool Equals(Input? other) + { + // Null never matches + if (other is null) + return false; + + // Properties + if (Buttons != other.Buttons) + return false; + + if (Coins != other.Coins) + return false; + + if ((ControlAttr is null) ^ (other.ControlAttr is null)) + return false; + else if (ControlAttr is not null && !ControlAttr.Equals(other.ControlAttr, StringComparison.OrdinalIgnoreCase)) + return false; + + if (Players != other.Players) + return false; + + if (Service != other.Service) + return false; + + if (Tilt != other.Tilt) + return false; + + // Sub-items + // TODO: Figure out how to properly check arrays + + return true; + } } } diff --git a/SabreTools.Data.Models/Metadata/Media.cs b/SabreTools.Data.Models/Metadata/Media.cs index 3e6f2a86..3bf452c1 100644 --- a/SabreTools.Data.Models/Metadata/Media.cs +++ b/SabreTools.Data.Models/Metadata/Media.cs @@ -1,12 +1,12 @@ +using System; using System.Xml.Serialization; using Newtonsoft.Json; namespace SabreTools.Data.Models.Metadata { - // TODO: ICloneable - // TODO: IEquatable + // TODO: IEquatable [JsonObject("media"), XmlRoot("media")] - public class Media : DatItem + public class Media : DatItem, ICloneable { #region Properties @@ -23,5 +23,19 @@ namespace SabreTools.Data.Models.Metadata #endregion public Media() => ItemType = ItemType.Media; + + /// + public object Clone() + { + var obj = new Media(); + + obj.MD5 = MD5; + obj.Name = Name; + obj.SHA1 = SHA1; + obj.SHA256 = SHA256; + obj.SpamSum = SpamSum; + + return obj; + } } } diff --git a/SabreTools.Metadata.DatFiles.Test/DatFileTests.FromMetadata.cs b/SabreTools.Metadata.DatFiles.Test/DatFileTests.FromMetadata.cs index 7dbb386b..637cd8b9 100644 --- a/SabreTools.Metadata.DatFiles.Test/DatFileTests.FromMetadata.cs +++ b/SabreTools.Metadata.DatFiles.Test/DatFileTests.FromMetadata.cs @@ -662,7 +662,7 @@ namespace SabreTools.Metadata.DatFiles.Test { Buttons = 12345, Coins = 12345, - [Data.Models.Metadata.Input.ControlKey] = new Data.Models.Metadata.Control[] { CreateMetadataControl() }, + Control = [CreateMetadataControl()], ControlAttr = "controlattr", Players = 12345, Service = true, @@ -1393,7 +1393,7 @@ namespace SabreTools.Metadata.DatFiles.Test Assert.True(input.Service); Assert.True(input.Tilt); - Control[]? controls = input.Read(Data.Models.Metadata.Input.ControlKey); + Control[]? controls = input.Control; Assert.NotNull(controls); Control? control = Assert.Single(controls); ValidateControl(control); diff --git a/SabreTools.Metadata.DatFiles.Test/DatFileTests.ToMetadata.cs b/SabreTools.Metadata.DatFiles.Test/DatFileTests.ToMetadata.cs index 32a7b59a..3681e4a5 100644 --- a/SabreTools.Metadata.DatFiles.Test/DatFileTests.ToMetadata.cs +++ b/SabreTools.Metadata.DatFiles.Test/DatFileTests.ToMetadata.cs @@ -930,7 +930,7 @@ namespace SabreTools.Metadata.DatFiles.Test Assert.True(input.Service); Assert.True(input.Tilt); - Data.Models.Metadata.Control[]? controls = input.ReadArray(Data.Models.Metadata.Input.ControlKey); + Data.Models.Metadata.Control[]? controls = input.Control; Assert.NotNull(controls); Data.Models.Metadata.Control? control = Assert.Single(controls); ValidateMetadataControl(control); diff --git a/SabreTools.Metadata.DatFiles.Test/FormatsTests.cs b/SabreTools.Metadata.DatFiles.Test/FormatsTests.cs index 5ea7c211..f2f9174c 100644 --- a/SabreTools.Metadata.DatFiles.Test/FormatsTests.cs +++ b/SabreTools.Metadata.DatFiles.Test/FormatsTests.cs @@ -230,7 +230,7 @@ namespace SabreTools.Metadata.DatFiles.Test Assert.NotNull(actual); Assert.True(actual.SequenceEqual([ nameof(Data.Models.Metadata.Input.Players), - Data.Models.Metadata.Input.ControlKey, + nameof(Data.Models.Metadata.Input.Control), ])); } diff --git a/SabreTools.Metadata.DatFiles/Formats/ClrMamePro.cs b/SabreTools.Metadata.DatFiles/Formats/ClrMamePro.cs index 767cabe8..23fae2da 100644 --- a/SabreTools.Metadata.DatFiles/Formats/ClrMamePro.cs +++ b/SabreTools.Metadata.DatFiles/Formats/ClrMamePro.cs @@ -154,8 +154,8 @@ namespace SabreTools.Metadata.DatFiles.Formats case Input input: if (input.Players is null) missingFields.Add(nameof(Data.Models.Metadata.Input.Players)); - if (!input.ControlsSpecified) - missingFields.Add(Data.Models.Metadata.Input.ControlKey); + if (!input.ControlSpecified) + missingFields.Add(nameof(Data.Models.Metadata.Input.Control)); break; case DipSwitch dipswitch: diff --git a/SabreTools.Metadata.DatItems/Formats/Input.cs b/SabreTools.Metadata.DatItems/Formats/Input.cs index 3ab64efd..5885db4e 100644 --- a/SabreTools.Metadata.DatItems/Formats/Input.cs +++ b/SabreTools.Metadata.DatItems/Formats/Input.cs @@ -25,22 +25,17 @@ namespace SabreTools.Metadata.DatItems.Formats set => (_internal as Data.Models.Metadata.Input)?.Coins = value; } + public Control[]? Control { get; set; } + + [JsonIgnore] + public bool ControlSpecified => Control is not null && Control.Length > 0; + public string? ControlAttr { get => (_internal as Data.Models.Metadata.Input)?.ControlAttr; set => (_internal as Data.Models.Metadata.Input)?.ControlAttr = value; } - [JsonIgnore] - public bool ControlsSpecified - { - get - { - var controls = Read(Data.Models.Metadata.Input.ControlKey); - return controls is not null && controls.Length > 0; - } - } - /// /> public override Data.Models.Metadata.ItemType ItemType => Data.Models.Metadata.ItemType.Input; @@ -72,12 +67,8 @@ namespace SabreTools.Metadata.DatItems.Formats public Input(Data.Models.Metadata.Input item) : base(item) { // Handle subitems - var controls = item.ReadArray(Data.Models.Metadata.Input.ControlKey); - if (controls is not null) - { - Control[] controlItems = Array.ConvertAll(controls, control => new Control(control)); - Write(Data.Models.Metadata.Input.ControlKey, controlItems); - } + if (item.Control is not null) + Control = Array.ConvertAll(item.Control, control => new Control(control)); } public Input(Data.Models.Metadata.Input item, Machine machine, Source source) : this(item) @@ -98,12 +89,8 @@ namespace SabreTools.Metadata.DatItems.Formats { var inputItem = base.GetInternalClone(); - var controls = Read(Data.Models.Metadata.Input.ControlKey); - if (controls is not null) - { - Data.Models.Metadata.Control[] controlItems = Array.ConvertAll(controls, control => control.GetInternalClone()); - inputItem[Data.Models.Metadata.Input.ControlKey] = controlItems; - } + if (Control is not null) + inputItem.Control = Array.ConvertAll(Control, control => control.GetInternalClone()); return inputItem; } diff --git a/SabreTools.Metadata/DictionaryBaseExtensions.cs b/SabreTools.Metadata/DictionaryBaseExtensions.cs index 940a913c..1b586053 100644 --- a/SabreTools.Metadata/DictionaryBaseExtensions.cs +++ b/SabreTools.Metadata/DictionaryBaseExtensions.cs @@ -238,17 +238,7 @@ namespace SabreTools.Metadata } else if (self is Input selfInput && other is Input otherInput) { - if (selfInput.Buttons != otherInput.Buttons) - return false; - if (selfInput.Coins != otherInput.Coins) - return false; - if (selfInput.ControlAttr != otherInput.ControlAttr) - return false; - if (selfInput.Players != otherInput.Players) - return false; - if (selfInput.Service != otherInput.Service) - return false; - if (selfInput.Tilt != otherInput.Tilt) + if (!selfInput.Equals(otherInput)) return false; } else if (self is Instance selfInstance && other is Instance otherInstance) diff --git a/SabreTools.Serialization.CrossModel/Listxml.Deserializer.cs b/SabreTools.Serialization.CrossModel/Listxml.Deserializer.cs index 3ac33a38..b3187d51 100644 --- a/SabreTools.Serialization.CrossModel/Listxml.Deserializer.cs +++ b/SabreTools.Serialization.CrossModel/Listxml.Deserializer.cs @@ -504,7 +504,7 @@ namespace SabreTools.Serialization.CrossModel Coins = item.Coins, }; - var controls = item.Read(Data.Models.Metadata.Input.ControlKey); + var controls = item.Control; if (controls is not null && controls.Length > 0) input.Control = Array.ConvertAll(controls, ConvertFromInternalModel); diff --git a/SabreTools.Serialization.CrossModel/Listxml.Serializer.cs b/SabreTools.Serialization.CrossModel/Listxml.Serializer.cs index 6a5a8a82..b69ce6bb 100644 --- a/SabreTools.Serialization.CrossModel/Listxml.Serializer.cs +++ b/SabreTools.Serialization.CrossModel/Listxml.Serializer.cs @@ -528,10 +528,7 @@ namespace SabreTools.Serialization.CrossModel }; if (item.Control is not null && item.Control.Length > 0) - { - input[Data.Models.Metadata.Input.ControlKey] - = Array.ConvertAll(item.Control, ConvertToInternalModel); - } + input.Control = Array.ConvertAll(item.Control, ConvertToInternalModel); return input; }