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;
}