From e7db7e2aeca5843b716382f3c576d6a7cb0ba109 Mon Sep 17 00:00:00 2001 From: Phillip Smith <35803538+TimeTravelPenguin@users.noreply.github.com> Date: Wed, 23 Oct 2024 20:59:49 +1100 Subject: [PATCH] code cleanup & reformat --- .../Attributes/StringEncodingAttribute.cs | 38 +- MupenSharp/MupenSharp/Enums/AnalogueInput.cs | 18 +- MupenSharp/MupenSharp/Enums/Controller.cs | 34 +- .../MupenSharp/Enums/ControllerInput.cs | 160 +++---- .../MupenSharp/Enums/ControllerProperty.cs | 98 ++--- MupenSharp/MupenSharp/Enums/Encoding.cs | 18 +- .../Exceptions/InvalidFileVersionException.cs | 12 +- .../Exceptions/InvalidFrameCountException.cs | 12 +- .../Exceptions/NoControllerException.cs | 12 +- .../Extensions/BinaryReaderExtensions.cs | 100 ++--- .../MupenSharp/Extensions/EnumExtensions.cs | 8 +- .../MupenSharp/FileParsing/MupenV3Parser.cs | 231 +++++----- .../MupenSharp/FileParsing/StringEncoder.cs | 32 +- .../MupenSharp/Helpers/ReflectionHelper.cs | 19 +- MupenSharp/MupenSharp/Models/IM64.cs | 152 ++++--- MupenSharp/MupenSharp/Models/InputModel.cs | 204 ++++----- MupenSharp/MupenSharp/Models/M64.cs | 416 +++++++++--------- 17 files changed, 753 insertions(+), 811 deletions(-) diff --git a/MupenSharp/MupenSharp/Attributes/StringEncodingAttribute.cs b/MupenSharp/MupenSharp/Attributes/StringEncodingAttribute.cs index 1eed9cf..b39c0f7 100644 --- a/MupenSharp/MupenSharp/Attributes/StringEncodingAttribute.cs +++ b/MupenSharp/MupenSharp/Attributes/StringEncodingAttribute.cs @@ -5,30 +5,30 @@ namespace MupenSharp.Attributes; /// -/// Attribute used to specify a string encoding and byte size. +/// Attribute used to specify a string encoding and byte size. /// [UsedImplicitly] [AttributeUsage(AttributeTargets.Property)] public sealed class StringEncodingAttribute : Attribute { - /// - /// Sets the string encoding type for reading and writing - /// - public Encoding Encoding { get; } + /// + /// Attribute used to specify a string encoding and byte size. + /// + /// The type of encoding of the string. + /// The number of bytes of the string. + public StringEncodingAttribute(Encoding encoding, int byteSize) + { + Encoding = encoding; + ByteSize = byteSize; + } - /// - /// The size of the string in bytes - /// - public int ByteSize { get; } + /// + /// Sets the string encoding type for reading and writing + /// + public Encoding Encoding { get; } - /// - /// Attribute used to specify a string encoding and byte size. - /// - /// The type of encoding of the string. - /// The number of bytes of the string. - public StringEncodingAttribute(Encoding encoding, int byteSize) - { - Encoding = encoding; - ByteSize = byteSize; - } + /// + /// The size of the string in bytes + /// + public int ByteSize { get; } } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/Enums/AnalogueInput.cs b/MupenSharp/MupenSharp/Enums/AnalogueInput.cs index f5f1da6..315a807 100644 --- a/MupenSharp/MupenSharp/Enums/AnalogueInput.cs +++ b/MupenSharp/MupenSharp/Enums/AnalogueInput.cs @@ -1,17 +1,17 @@ namespace MupenSharp.Enums; /// -/// Enum for Analogue Inputs +/// Enum for Analogue Inputs /// public enum AnalogueInput { - /// - /// The horizontal analogue coordinate - /// - X, + /// + /// The horizontal analogue coordinate + /// + X, - /// - /// The vertical analogue coordinate - /// - Y + /// + /// The vertical analogue coordinate + /// + Y } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/Enums/Controller.cs b/MupenSharp/MupenSharp/Enums/Controller.cs index cd30721..a43d5ec 100644 --- a/MupenSharp/MupenSharp/Enums/Controller.cs +++ b/MupenSharp/MupenSharp/Enums/Controller.cs @@ -1,27 +1,27 @@ namespace MupenSharp.Enums; /// -/// Enum to indicate a specific controller selection. +/// Enum to indicate a specific controller selection. /// public enum Controller { - /// - /// Controller in port one. Has offset 0. - /// - ControllerOne = 0, + /// + /// Controller in port one. Has offset 0. + /// + ControllerOne = 0, - /// - /// Controller in port two. Has offset 1. - /// - ControllerTwo = 1, + /// + /// Controller in port two. Has offset 1. + /// + ControllerTwo = 1, - /// - /// Controller in port three. Has offset 2. - /// - ControllerThree = 2, + /// + /// Controller in port three. Has offset 2. + /// + ControllerThree = 2, - /// - /// Controller in port four. Has offset 3. - /// - ControllerFour = 3 + /// + /// Controller in port four. Has offset 3. + /// + ControllerFour = 3 } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/Enums/ControllerInput.cs b/MupenSharp/MupenSharp/Enums/ControllerInput.cs index 44d9cb7..8a66d14 100644 --- a/MupenSharp/MupenSharp/Enums/ControllerInput.cs +++ b/MupenSharp/MupenSharp/Enums/ControllerInput.cs @@ -3,88 +3,88 @@ namespace MupenSharp.Enums; /// -/// Controller button bit flags +/// Controller button bit flags /// [Flags] public enum ControllerInput { - /// - /// The C-Right button - /// - CRight = 0x0001, - - /// - /// The C-Left button - /// - CLeft = 0x0002, - - /// - /// The C-Down button - /// - CDown = 0x0004, - - /// - /// The C-Up button - /// - CUp = 0x0008, - - /// - /// The right shoulder button - /// - R = 0x0010, - - /// - /// The left shoulder button - /// - L = 0x0020, - - /// - /// Reserved input 01 - /// - Reserved1 = 0x0040, - - /// - /// Reserved input 02 - /// - Reserved2 = 0x0080, - - /// - /// Right D-Pad button - /// - DigitalPadRight = 0x0100, - - /// - /// Left D-Pad button - /// - DigitalPadLeft = 0x0200, - - /// - /// Down D-Pad button - /// - DigitalPadDown = 0x0400, - - /// - /// Up D-Pad button - /// - DigitalPadUp = 0x0800, - - /// - /// The Start button - /// - Start = 0x1000, - - /// - /// The Z button - /// - Z = 0x2000, - - /// - /// The B button - /// - B = 0x4000, - - /// - /// The A button - /// - A = 0x8000 + /// + /// The C-Right button + /// + CRight = 0x0001, + + /// + /// The C-Left button + /// + CLeft = 0x0002, + + /// + /// The C-Down button + /// + CDown = 0x0004, + + /// + /// The C-Up button + /// + CUp = 0x0008, + + /// + /// The right shoulder button + /// + R = 0x0010, + + /// + /// The left shoulder button + /// + L = 0x0020, + + /// + /// Reserved input 01 + /// + Reserved1 = 0x0040, + + /// + /// Reserved input 02 + /// + Reserved2 = 0x0080, + + /// + /// Right D-Pad button + /// + DigitalPadRight = 0x0100, + + /// + /// Left D-Pad button + /// + DigitalPadLeft = 0x0200, + + /// + /// Down D-Pad button + /// + DigitalPadDown = 0x0400, + + /// + /// Up D-Pad button + /// + DigitalPadUp = 0x0800, + + /// + /// The Start button + /// + Start = 0x1000, + + /// + /// The Z button + /// + Z = 0x2000, + + /// + /// The B button + /// + B = 0x4000, + + /// + /// The A button + /// + A = 0x8000 } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/Enums/ControllerProperty.cs b/MupenSharp/MupenSharp/Enums/ControllerProperty.cs index 7c49c45..1e05d6d 100644 --- a/MupenSharp/MupenSharp/Enums/ControllerProperty.cs +++ b/MupenSharp/MupenSharp/Enums/ControllerProperty.cs @@ -3,68 +3,68 @@ namespace MupenSharp.Enums; /// -/// Properties to determine controller, controller memory pack, and controller rumble pack presence. +/// Properties to determine controller, controller memory pack, and controller rumble pack presence. /// [Flags] public enum ControllerProperty { - /// - /// Presence flag for controller 1 - /// - ControllerOnePresent = 0x0001, + /// + /// Presence flag for controller 1 + /// + ControllerOnePresent = 0x0001, - /// - /// Presence flag for controller 2 - /// - ControllerTwoPresent = 0x0002, + /// + /// Presence flag for controller 2 + /// + ControllerTwoPresent = 0x0002, - /// - /// Presence flag for controller 3 - /// - ControllerThreePresent = 0x0004, + /// + /// Presence flag for controller 3 + /// + ControllerThreePresent = 0x0004, - /// - /// Presence flag for controller 4 - /// - ControllerFourPresent = 0x0008, + /// + /// Presence flag for controller 4 + /// + ControllerFourPresent = 0x0008, - /// - /// Presence flag for controller 1 memory pack - /// - ControllerOneMemoryPackPresent = 0x0010, + /// + /// Presence flag for controller 1 memory pack + /// + ControllerOneMemoryPackPresent = 0x0010, - /// - /// Presence flag for controller 2 memory pack - /// - ControllerTwoMemoryPackPresent = 0x0020, + /// + /// Presence flag for controller 2 memory pack + /// + ControllerTwoMemoryPackPresent = 0x0020, - /// - /// Presence flag for controller 3 memory pack - /// - ControllerThreeMemoryPackPresent = 0x0040, + /// + /// Presence flag for controller 3 memory pack + /// + ControllerThreeMemoryPackPresent = 0x0040, - /// - /// Presence flag for controller 4 memory pack - /// - ControllerFourMemoryPackPresent = 0x0080, + /// + /// Presence flag for controller 4 memory pack + /// + ControllerFourMemoryPackPresent = 0x0080, - /// - /// Presence flag for controller 1 rumble pack - /// - ControllerOneRumblePackPresent = 0x0100, + /// + /// Presence flag for controller 1 rumble pack + /// + ControllerOneRumblePackPresent = 0x0100, - /// - /// Presence flag for controller 2 rumble pack - /// - ControllerTwoRumblePackPresent = 0x0200, + /// + /// Presence flag for controller 2 rumble pack + /// + ControllerTwoRumblePackPresent = 0x0200, - /// - /// Presence flag for controller 3 rumble pack - /// - ControllerThreeRumblePackPresent = 0x0400, + /// + /// Presence flag for controller 3 rumble pack + /// + ControllerThreeRumblePackPresent = 0x0400, - /// - /// Presence flag for controller 4 rumble pack - /// - ControllerFourRumblePackPresent = 0x0800 + /// + /// Presence flag for controller 4 rumble pack + /// + ControllerFourRumblePackPresent = 0x0800 } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/Enums/Encoding.cs b/MupenSharp/MupenSharp/Enums/Encoding.cs index 105294e..7f97925 100644 --- a/MupenSharp/MupenSharp/Enums/Encoding.cs +++ b/MupenSharp/MupenSharp/Enums/Encoding.cs @@ -1,17 +1,17 @@ namespace MupenSharp.Enums; /// -/// String encoding enums +/// String encoding enums /// public enum Encoding { - /// - /// ASCII encoding - /// - ASCII, + /// + /// ASCII encoding + /// + ASCII, - /// - /// UTF-8 encoding - /// - UTF8 + /// + /// UTF-8 encoding + /// + UTF8 } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/Exceptions/InvalidFileVersionException.cs b/MupenSharp/MupenSharp/Exceptions/InvalidFileVersionException.cs index c3976da..6fc67ae 100644 --- a/MupenSharp/MupenSharp/Exceptions/InvalidFileVersionException.cs +++ b/MupenSharp/MupenSharp/Exceptions/InvalidFileVersionException.cs @@ -4,11 +4,11 @@ namespace MupenSharp.Exceptions; internal class InvalidFileVersionException : Exception { - public InvalidFileVersionException() - { - } + public InvalidFileVersionException() + { + } - public InvalidFileVersionException(string message) : base(message) - { - } + public InvalidFileVersionException(string message) : base(message) + { + } } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/Exceptions/InvalidFrameCountException.cs b/MupenSharp/MupenSharp/Exceptions/InvalidFrameCountException.cs index ae6ebda..85a3502 100644 --- a/MupenSharp/MupenSharp/Exceptions/InvalidFrameCountException.cs +++ b/MupenSharp/MupenSharp/Exceptions/InvalidFrameCountException.cs @@ -4,11 +4,11 @@ namespace MupenSharp.Exceptions; internal class InvalidFrameCountException : Exception { - public InvalidFrameCountException() - { - } + public InvalidFrameCountException() + { + } - public InvalidFrameCountException(string message) : base(message) - { - } + public InvalidFrameCountException(string message) : base(message) + { + } } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/Exceptions/NoControllerException.cs b/MupenSharp/MupenSharp/Exceptions/NoControllerException.cs index c7ce304..72e7914 100644 --- a/MupenSharp/MupenSharp/Exceptions/NoControllerException.cs +++ b/MupenSharp/MupenSharp/Exceptions/NoControllerException.cs @@ -4,11 +4,11 @@ namespace MupenSharp.Exceptions; internal class NoControllerException : Exception { - public NoControllerException() - { - } + public NoControllerException() + { + } - public NoControllerException(string message) : base(message) - { - } + public NoControllerException(string message) : base(message) + { + } } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/Extensions/BinaryReaderExtensions.cs b/MupenSharp/MupenSharp/Extensions/BinaryReaderExtensions.cs index 127f4ec..a0f0cfa 100644 --- a/MupenSharp/MupenSharp/Extensions/BinaryReaderExtensions.cs +++ b/MupenSharp/MupenSharp/Extensions/BinaryReaderExtensions.cs @@ -10,77 +10,65 @@ namespace MupenSharp.Extensions; internal static class BinaryReaderExtensions { - // Read a single byte from a given offset of a binary stream. - public static byte ReadByte([NotNull] this BinaryReader reader, long offset) - { - if (reader is null) + // Read a single byte from a given offset of a binary stream. + public static byte ReadByte([NotNull] this BinaryReader reader, long offset) { - throw new ArgumentNullException(nameof(reader), - string.Format(CultureInfo.InvariantCulture, ExceptionsResource.ArgumentIsNull, reader)); - } + if (reader is null) + throw new ArgumentNullException(nameof(reader), + string.Format(CultureInfo.InvariantCulture, ExceptionsResource.ArgumentIsNull, reader)); - reader.BaseStream.Seek(offset, SeekOrigin.Begin); - return reader.ReadByte(); - } + reader.BaseStream.Seek(offset, SeekOrigin.Begin); + return reader.ReadByte(); + } - // Reads a number of bytes from a given offset of a binary stream. - public static byte[] ReadBytes([NotNull] this BinaryReader reader, long offset, int length) - { - if (reader is null) + // Reads a number of bytes from a given offset of a binary stream. + public static byte[] ReadBytes([NotNull] this BinaryReader reader, long offset, int length) { - throw new ArgumentNullException(nameof(reader), - string.Format(CultureInfo.InvariantCulture, ExceptionsResource.ArgumentIsNull, reader)); - } + if (reader is null) + throw new ArgumentNullException(nameof(reader), + string.Format(CultureInfo.InvariantCulture, ExceptionsResource.ArgumentIsNull, reader)); - reader.BaseStream.Seek(offset, SeekOrigin.Begin); - return reader.ReadBytes(length); - } + reader.BaseStream.Seek(offset, SeekOrigin.Begin); + return reader.ReadBytes(length); + } - // Reads 4 bytes from a given offset of a binary stream and returns it as an . - public static uint ReadUInt32([NotNull] this BinaryReader reader, long offset) - { - if (reader is null) + // Reads 4 bytes from a given offset of a binary stream and returns it as an . + public static uint ReadUInt32([NotNull] this BinaryReader reader, long offset) { - throw new ArgumentNullException(nameof(reader), - string.Format(CultureInfo.InvariantCulture, ExceptionsResource.ArgumentIsNull, reader)); - } + if (reader is null) + throw new ArgumentNullException(nameof(reader), + string.Format(CultureInfo.InvariantCulture, ExceptionsResource.ArgumentIsNull, reader)); - return BitConverter.ToUInt32(reader.ReadBytes(offset, 4), 0); - } + return BitConverter.ToUInt32(reader.ReadBytes(offset, 4), 0); + } - // Reads 4 bytes from a given offset of a binary stream and returns it as an . - public static int ReadInt32([NotNull] this BinaryReader reader, long offset) - { - if (reader is null) + // Reads 4 bytes from a given offset of a binary stream and returns it as an . + public static int ReadInt32([NotNull] this BinaryReader reader, long offset) { - throw new ArgumentNullException(nameof(reader), - string.Format(CultureInfo.InvariantCulture, ExceptionsResource.ArgumentIsNull, reader)); - } + if (reader is null) + throw new ArgumentNullException(nameof(reader), + string.Format(CultureInfo.InvariantCulture, ExceptionsResource.ArgumentIsNull, reader)); - return BitConverter.ToInt32(reader.ReadBytes(offset, 4), 0); - } + return BitConverter.ToInt32(reader.ReadBytes(offset, 4), 0); + } - // Reads 2 bytes from a given offset of a binary stream and returns it as an . - public static ushort ReadUInt16([NotNull] this BinaryReader reader, long offset) - { - if (reader is null) + // Reads 2 bytes from a given offset of a binary stream and returns it as an . + public static ushort ReadUInt16([NotNull] this BinaryReader reader, long offset) { - throw new ArgumentNullException(nameof(reader), - string.Format(CultureInfo.InvariantCulture, ExceptionsResource.ArgumentIsNull, reader)); - } + if (reader is null) + throw new ArgumentNullException(nameof(reader), + string.Format(CultureInfo.InvariantCulture, ExceptionsResource.ArgumentIsNull, reader)); - return BitConverter.ToUInt16(reader.ReadBytes(offset, 2), 0); - } + return BitConverter.ToUInt16(reader.ReadBytes(offset, 2), 0); + } - // Reads a number of bytes from a given offset of a binary stream and returns it as a string with a specific encoding. - public static string ReadString([NotNull] this BinaryReader reader, long offset, int length, Encoding encoding) - { - if (reader is null) + // Reads a number of bytes from a given offset of a binary stream and returns it as a string with a specific encoding. + public static string ReadString([NotNull] this BinaryReader reader, long offset, int length, Encoding encoding) { - throw new ArgumentNullException(nameof(reader), - string.Format(CultureInfo.InvariantCulture, ExceptionsResource.ArgumentIsNull, reader)); - } + if (reader is null) + throw new ArgumentNullException(nameof(reader), + string.Format(CultureInfo.InvariantCulture, ExceptionsResource.ArgumentIsNull, reader)); - return reader.ReadBytes(offset, length).Encode(encoding); - } + return reader.ReadBytes(offset, length).Encode(encoding); + } } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/Extensions/EnumExtensions.cs b/MupenSharp/MupenSharp/Extensions/EnumExtensions.cs index cd6d33b..bb88af7 100644 --- a/MupenSharp/MupenSharp/Extensions/EnumExtensions.cs +++ b/MupenSharp/MupenSharp/Extensions/EnumExtensions.cs @@ -6,8 +6,8 @@ namespace MupenSharp.Extensions; internal static class EnumExtensions { - public static IEnumerable EnumToArray() where T : Enum - { - return Enum.GetValues(typeof(T)).Cast(); - } + public static IEnumerable EnumToArray() where T : Enum + { + return Enum.GetValues(typeof(T)).Cast(); + } } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/FileParsing/MupenV3Parser.cs b/MupenSharp/MupenSharp/FileParsing/MupenV3Parser.cs index 8fd4d7e..ae227c7 100644 --- a/MupenSharp/MupenSharp/FileParsing/MupenV3Parser.cs +++ b/MupenSharp/MupenSharp/FileParsing/MupenV3Parser.cs @@ -14,141 +14,130 @@ namespace MupenSharp.FileParsing; /// -/// A parser for .m64 version 3 files +/// A parser for .m64 version 3 files /// public class MupenV3Parser { - /// - /// Validates that all reserved offsets have a value of zero. - /// - /// The file to process - /// - /// - /// - public static bool ValidateReservedOffsets(FileInfo m64File) - { - if (m64File.WhenNotNull(nameof(m64File)).Exists) + /// + /// Validates that all reserved offsets have a value of zero. + /// + /// The file to process + /// + /// + /// + public static bool ValidateReservedOffsets(FileInfo m64File) { - throw new FileNotFoundException(ExceptionsResource.InvalidFilePath, nameof(m64File)); - } - - using var reader = new BinaryReader(m64File.Open(FileMode.Open, FileAccess.Read)); - - return reader.ReadBytes(0x16, 2).All(x => x == 0) - && reader.ReadBytes(0x1E, 2).All(x => x == 0) - && reader.ReadBytes(0x24, 160).All(x => x == 0) - && reader.ReadBytes(0xEA, 56).All(x => x == 0); - } + if (m64File.WhenNotNull(nameof(m64File)).Exists) + throw new FileNotFoundException(ExceptionsResource.InvalidFilePath, nameof(m64File)); - /// - /// Parses the file . - /// - /// The path of the .m64 file - /// Returns object with data of parsed file - public static M64 Parse(string path) - { - var m64 = new FileInfo(path); + using var reader = new BinaryReader(m64File.Open(FileMode.Open, FileAccess.Read)); - using (var reader = new BinaryReader(m64.Open(FileMode.Open, FileAccess.Read))) - { - // Validate file is a mupen file - var signature = reader.ReadBytes(4); - var validSig = signature.SequenceEqual(Constants.ValidM64Signature); - - if (!validSig) - { - throw new InvalidOperationException(ExceptionsResource.NotM64); - } + return reader.ReadBytes(0x16, 2).All(x => x == 0) + && reader.ReadBytes(0x1E, 2).All(x => x == 0) + && reader.ReadBytes(0x24, 160).All(x => x == 0) + && reader.ReadBytes(0xEA, 56).All(x => x == 0); } - return ParseFile(m64); - } - - private static M64 ParseFile([NotNull] FileInfo m64File) - { - if (!ValidateReservedOffsets(m64File)) + /// + /// Parses the file . + /// + /// The path of the .m64 file + /// Returns object with data of parsed file + public static M64 Parse(string path) { - throw new InvalidOperationException(ExceptionsResource.ReservedOffsetValueInvalid); - } + var m64 = new FileInfo(path); - using var reader = new BinaryReader(m64File.Open(FileMode.Open, FileAccess.Read)); + using (var reader = new BinaryReader(m64.Open(FileMode.Open, FileAccess.Read))) + { + // Validate file is a mupen file + var signature = reader.ReadBytes(4); + var validSig = signature.SequenceEqual(Constants.ValidM64Signature); - var stringAttributes = - typeof(M64).GetPropertyAttributeDictionaryOfType(); + if (!validSig) throw new InvalidOperationException(ExceptionsResource.NotM64); + } - var m64 = new M64 - { - Version = reader.ReadUInt32(0x4), - MovieUid = reader.ReadInt32(0x8), - ViCount = reader.ReadUInt32(0xC), - RerecordCount = reader.ReadUInt32(0x10), - ViPerSecond = reader.ReadByte(0x14), - ControllerCount = reader.ReadByte(0x15), - InputCount = reader.ReadUInt32(0x18), - MovieStartType = reader.ReadUInt16(0x1C), - ControllerFlags = reader.ReadUInt32(0x20), - Crc32 = reader.ReadUInt32(0xE4), - RegionCode = reader.ReadUInt16(0xE8), - - RomName = - reader.ReadString(0xC4, stringAttributes[nameof(M64.RomName)].ByteSize, - stringAttributes[nameof(M64.RomName)].Encoding), - - VideoPluginName = - reader.ReadString(0x122, stringAttributes[nameof(M64.VideoPluginName)].ByteSize, - stringAttributes[nameof(M64.VideoPluginName)].Encoding), - - AudioPluginName = - reader.ReadString(0x162, stringAttributes[nameof(M64.AudioPluginName)].ByteSize, - stringAttributes[nameof(M64.AudioPluginName)].Encoding), - - InputPluginName = - reader.ReadString(0x1A2, stringAttributes[nameof(M64.InputPluginName)].ByteSize, - stringAttributes[nameof(M64.InputPluginName)].Encoding), - - RspPluginName = - reader.ReadString(0x1E2, stringAttributes[nameof(M64.RspPluginName)].ByteSize, - stringAttributes[nameof(M64.RspPluginName)].Encoding), - - Author = - reader.ReadString(0x222, stringAttributes[nameof(M64.Author)].ByteSize, - stringAttributes[nameof(M64.Author)].Encoding), - - MovieDescription = - reader.ReadString(0x300, stringAttributes[nameof(M64.MovieDescription)].ByteSize, - stringAttributes[nameof(M64.MovieDescription)].Encoding) - }; - - var numControllers = - (m64.ControllerFlags & (uint)ControllerProperty.ControllerOnePresent) - + ((m64.ControllerFlags & (uint)ControllerProperty.ControllerTwoPresent) >> 1) - + ((m64.ControllerFlags & (uint)ControllerProperty.ControllerThreePresent) >> 2) - + ((m64.ControllerFlags & (uint)ControllerProperty.ControllerFourPresent) >> 3); - - /* - Mupen does not delete old inputs when writing to an m64 file. - E.g. if someone loads a save-state and works over the top of the work. - Because of this, it is possible for the header to have an InputCount - that is smaller than the list of inputs. This is because Mupen64 plays the file - up until the header length. Any other data after is ignored. - */ - - // Check the file size (minus the header) is not shorter to the header expected value - var inputsBitLength = reader.BaseStream.Length - 0x400; - var headerExpectedLength = m64.InputCount * numControllers; - - if (inputsBitLength < headerExpectedLength) - { - throw new InvalidFrameCountException( - $"File size is too small. The header expects a minimum of {m64.InputCount * numControllers} bytes of input frame data, but got {reader.BaseStream.Length - 0x400}"); + return ParseFile(m64); } - reader.BaseStream.Seek(0x400, SeekOrigin.Begin); - while (reader.BaseStream.Position != reader.BaseStream.Length) + private static M64 ParseFile([NotNull] FileInfo m64File) { - m64.ControllerInputs.Add((InputModel)reader.ReadBytes(4)); + if (!ValidateReservedOffsets(m64File)) + throw new InvalidOperationException(ExceptionsResource.ReservedOffsetValueInvalid); + + using var reader = new BinaryReader(m64File.Open(FileMode.Open, FileAccess.Read)); + + var stringAttributes = + typeof(M64).GetPropertyAttributeDictionaryOfType(); + + var m64 = new M64 + { + Version = reader.ReadUInt32(0x4), + MovieUid = reader.ReadInt32(0x8), + ViCount = reader.ReadUInt32(0xC), + RerecordCount = reader.ReadUInt32(0x10), + ViPerSecond = reader.ReadByte(0x14), + ControllerCount = reader.ReadByte(0x15), + InputCount = reader.ReadUInt32(0x18), + MovieStartType = reader.ReadUInt16(0x1C), + ControllerFlags = reader.ReadUInt32(0x20), + Crc32 = reader.ReadUInt32(0xE4), + RegionCode = reader.ReadUInt16(0xE8), + + RomName = + reader.ReadString(0xC4, stringAttributes[nameof(M64.RomName)].ByteSize, + stringAttributes[nameof(M64.RomName)].Encoding), + + VideoPluginName = + reader.ReadString(0x122, stringAttributes[nameof(M64.VideoPluginName)].ByteSize, + stringAttributes[nameof(M64.VideoPluginName)].Encoding), + + AudioPluginName = + reader.ReadString(0x162, stringAttributes[nameof(M64.AudioPluginName)].ByteSize, + stringAttributes[nameof(M64.AudioPluginName)].Encoding), + + InputPluginName = + reader.ReadString(0x1A2, stringAttributes[nameof(M64.InputPluginName)].ByteSize, + stringAttributes[nameof(M64.InputPluginName)].Encoding), + + RspPluginName = + reader.ReadString(0x1E2, stringAttributes[nameof(M64.RspPluginName)].ByteSize, + stringAttributes[nameof(M64.RspPluginName)].Encoding), + + Author = + reader.ReadString(0x222, stringAttributes[nameof(M64.Author)].ByteSize, + stringAttributes[nameof(M64.Author)].Encoding), + + MovieDescription = + reader.ReadString(0x300, stringAttributes[nameof(M64.MovieDescription)].ByteSize, + stringAttributes[nameof(M64.MovieDescription)].Encoding) + }; + + var numControllers = + (m64.ControllerFlags & (uint)ControllerProperty.ControllerOnePresent) + + ((m64.ControllerFlags & (uint)ControllerProperty.ControllerTwoPresent) >> 1) + + ((m64.ControllerFlags & (uint)ControllerProperty.ControllerThreePresent) >> 2) + + ((m64.ControllerFlags & (uint)ControllerProperty.ControllerFourPresent) >> 3); + + /* + Mupen does not delete old inputs when writing to an m64 file. + E.g. if someone loads a save-state and works over the top of the work. + Because of this, it is possible for the header to have an InputCount + that is smaller than the list of inputs. This is because Mupen64 plays the file + up until the header length. Any other data after is ignored. + */ + + // Check the file size (minus the header) is not shorter to the header expected value + var inputsBitLength = reader.BaseStream.Length - 0x400; + var headerExpectedLength = m64.InputCount * numControllers; + + if (inputsBitLength < headerExpectedLength) + throw new InvalidFrameCountException( + $"File size is too small. The header expects a minimum of {m64.InputCount * numControllers} bytes of input frame data, but got {reader.BaseStream.Length - 0x400}"); + + reader.BaseStream.Seek(0x400, SeekOrigin.Begin); + while (reader.BaseStream.Position != reader.BaseStream.Length) + m64.ControllerInputs.Add((InputModel)reader.ReadBytes(4)); + + return m64; } - - return m64; - } } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/FileParsing/StringEncoder.cs b/MupenSharp/MupenSharp/FileParsing/StringEncoder.cs index 09431ba..d14bcb6 100644 --- a/MupenSharp/MupenSharp/FileParsing/StringEncoder.cs +++ b/MupenSharp/MupenSharp/FileParsing/StringEncoder.cs @@ -22,37 +22,37 @@ #endregion -namespace MupenSharp.FileParsing +namespace MupenSharp.FileParsing; + +/// +/// Static class string encoder helper +/// +internal static class StringEncoder { - /// - /// Static class string encoder helper - /// - internal static class StringEncoder - { /// - /// Encode a byte array with a particular . + /// Encode a byte array with a particular . /// /// Byte array to be encoded /// The encoding type. /// Encoded string public static string Encode(this byte[] bytes, Encoding encoding) { - return encoding switch - { - Encoding.ASCII => bytes.EncodeAscii(), - Encoding.UTF8 => bytes.EncodeUtf8(), - _ => throw new ArgumentOutOfRangeException(nameof(encoding), encoding, ExceptionsResource.InvalidEncodingType) - }; + return encoding switch + { + Encoding.ASCII => bytes.EncodeAscii(), + Encoding.UTF8 => bytes.EncodeUtf8(), + _ => throw new ArgumentOutOfRangeException(nameof(encoding), encoding, + ExceptionsResource.InvalidEncodingType) + }; } private static string EncodeAscii(this byte[] bytes) { - return System.Text.Encoding.ASCII.GetString(bytes); + return System.Text.Encoding.ASCII.GetString(bytes); } private static string EncodeUtf8(this byte[] bytes) { - return System.Text.Encoding.UTF8.GetString(bytes); + return System.Text.Encoding.UTF8.GetString(bytes); } - } } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/Helpers/ReflectionHelper.cs b/MupenSharp/MupenSharp/Helpers/ReflectionHelper.cs index c07e1b5..fb6aacb 100644 --- a/MupenSharp/MupenSharp/Helpers/ReflectionHelper.cs +++ b/MupenSharp/MupenSharp/Helpers/ReflectionHelper.cs @@ -23,19 +23,18 @@ #endregion -namespace MupenSharp.Helpers +namespace MupenSharp.Helpers; + +internal static class ReflectionHelper { - internal static class ReflectionHelper - { public static Dictionary GetPropertyAttributeDictionaryOfType(this Type type) - where TAttribute : Attribute + where TAttribute : Attribute { - var attr = (from prop in type.GetProperties() - from attribs in prop.GetCustomAttributes(typeof(TAttribute)).Cast() - select new KeyValuePair(prop.Name, attribs)) - .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + var attr = (from prop in type.GetProperties() + from attribs in prop.GetCustomAttributes(typeof(TAttribute)).Cast() + select new KeyValuePair(prop.Name, attribs)) + .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); - return attr; + return attr; } - } } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/Models/IM64.cs b/MupenSharp/MupenSharp/Models/IM64.cs index fdbd67d..c949064 100644 --- a/MupenSharp/MupenSharp/Models/IM64.cs +++ b/MupenSharp/MupenSharp/Models/IM64.cs @@ -17,156 +17,154 @@ #region usings using System.Collections.Generic; -using System.Collections.ObjectModel; #endregion -namespace MupenSharp.Models +namespace MupenSharp.Models; + +/// +/// M64 file interface +/// +public interface IM64 { - /// - /// M64 file interface - /// - public interface IM64 - { /// - /// Version number. Should be 3. + /// Version number. Should be 3. /// uint Version { get; set; } /// - /// The number of frames (vertical interrupts). + /// The number of frames (vertical interrupts). /// uint ViCount { get; set; } /// - /// The number of file rerecords. + /// The number of file rerecords. /// uint RerecordCount { get; set; } /// - /// Frames (vertical interrupts) per second. + /// Frames (vertical interrupts) per second. /// uint ViPerSecond { get; set; } /// - /// The number of controllers enabled for the file. + /// The number of controllers enabled for the file. /// uint ControllerCount { get; set; } /// - /// The movie start type. - /// - /// - /// - /// Value - /// - /// - /// Description - /// - /// - /// - /// 1 - /// - /// movie begins from snapshot (the snapshot will be loaded from an external file with the movie filename. - /// and a .st extension) - /// - /// - /// - /// 2 - /// - /// movie begins from power-on - /// - /// - /// - /// other values - /// - /// invalid movie - /// - /// - /// + /// The movie start type. + /// + /// + /// + /// Value + /// + /// + /// Description + /// + /// + /// + /// 1 + /// + /// movie begins from snapshot (the snapshot will be loaded from an external file with the movie filename. + /// and a .st extension) + /// + /// + /// + /// 2 + /// + /// movie begins from power-on + /// + /// + /// + /// other values + /// + /// invalid movie + /// + /// + /// /// ushort MovieStartType { get; set; } /// - /// Flags set for each controller. - /// - /// - /// bit 0 - /// - /// Controller 1 present - /// - /// - /// - /// bit 4 - /// - /// Controller 1 has mempak - /// - /// - /// - /// bit 8 - /// - /// Controller 1 has rumblepak - /// - /// - /// - /// +1..3 for controllers 2..4. + /// Flags set for each controller. + /// + /// + /// bit 0 + /// + /// Controller 1 present + /// + /// + /// + /// bit 4 + /// + /// Controller 1 has mempak + /// + /// + /// + /// bit 8 + /// + /// Controller 1 has rumblepak + /// + /// + /// + /// +1..3 for controllers 2..4. /// uint ControllerFlags { get; set; } /// - /// The internal name of ROM used when recording, directly from ROM. + /// The internal name of ROM used when recording, directly from ROM. /// string RomName { get; set; } /// - /// The name of video plugin used when recording, directly from plugin + /// The name of video plugin used when recording, directly from plugin /// string VideoPluginName { get; set; } /// - /// The name of audio plugin used when recording, directly from plugin + /// The name of audio plugin used when recording, directly from plugin /// string AudioPluginName { get; set; } /// - /// The name of input plugin used when recording, directly from plugin + /// The name of input plugin used when recording, directly from plugin /// string InputPluginName { get; set; } /// - /// The name of rsp plugin used when recording, directly from plugin + /// The name of rsp plugin used when recording, directly from plugin /// string RspPluginName { get; set; } /// - /// CRC32 of ROM used when recording, directly from ROM. + /// CRC32 of ROM used when recording, directly from ROM. /// uint Crc32 { get; set; } /// - /// The country code of ROM used when recording, directly from ROM. + /// The country code of ROM used when recording, directly from ROM. /// ushort RegionCode { get; set; } /// - /// The movie description info. + /// The movie description info. /// string MovieDescription { get; set; } /// - /// The collection of controller inputs every input frame and controller, - /// containing analogue x, y positions and buttons pressed. + /// The collection of controller inputs every input frame and controller, + /// containing analogue x, y positions and buttons pressed. /// IList ControllerInputs { get; } /// - /// The number of input samples from the controllers. + /// The number of input samples from the controllers. /// uint InputCount { get; set; } /// - /// The Author info of the movie. + /// The Author info of the movie. /// string Author { get; set; } - } } \ No newline at end of file diff --git a/MupenSharp/MupenSharp/Models/InputModel.cs b/MupenSharp/MupenSharp/Models/InputModel.cs index 8e27cdf..4e3cf33 100644 --- a/MupenSharp/MupenSharp/Models/InputModel.cs +++ b/MupenSharp/MupenSharp/Models/InputModel.cs @@ -30,179 +30,161 @@ /* TODO: Implement: Mupen64 will trigger a power off/on reset when the value for the controller info is specifically set to Reserved1 = 0x01, and Reserved2 = 0x01. */ -namespace MupenSharp.Models +namespace MupenSharp.Models; + +/// +/// A wrapper for controller input for a particular frame +/// +public class InputModel { - /// - /// A wrapper for controller input for a particular frame - /// - public class InputModel - { private sbyte _x; private sbyte _y; /// - /// The analogue x coordinate + /// InputModel representing data contained within an .m64 file. /// - public int X + /// + /// A 4-byte value containing X and Y analogue positions, and the XOR of buttons pressed. + /// The first two bytes are the XOR of the buttons, followed by the X and Y inputs + /// represented by 1-byte each. + /// + /// + /// Given the input 0xC0182541, this can be seen as: + /// + /// + /// Button Flags + /// 2-bytes = C0 18 + /// + /// + /// X Analogue + /// 1-byte = 25 + /// + /// + /// Y Analogue + /// 1-byte = 41 + /// + /// + /// + /// + /// When reading from an .m64 file from offset 0x400, 4-bytes at a time, the following code works if the + /// hex input is NOT REVERSED. + /// + /// + public InputModel([NotNull] byte[] input) { - get => Convert.ToInt32(_x); - set => _x = Convert.ToSByte(value); + // input = byte[4] { AA, BB, CC, DD } + + if (input is null) throw new ArgumentNullException(nameof(input)); + + if (input.Length != 4) + throw new InvalidOperationException($"{nameof(input)} should be 4 bytes, not {input.Length}"); + + // X = CC + X = unchecked((sbyte)input[2]); + + // Y = DD + Y = unchecked((sbyte)input[3]); + + // Buttons = AA BB + Buttons = BitConverter.ToUInt16(input + .Take(2) + .Reverse() // Reverse because BitConverter reverses order due to being low-endien + .ToArray(), 0); } /// - /// The analogue y coordinate + /// The analogue x coordinate /// - public int Y + public int X { - get => Convert.ToInt32(_y); - set => _y = Convert.ToSByte(value); + get => Convert.ToInt32(_x); + set => _x = Convert.ToSByte(value); } /// - /// The array of bytes representing the combination of buttons pressed + /// The analogue y coordinate /// - public ushort Buttons { get; set; } + public int Y + { + get => Convert.ToInt32(_y); + set => _y = Convert.ToSByte(value); + } /// - /// InputModel representing data contained within an .m64 file. + /// The array of bytes representing the combination of buttons pressed /// - /// - /// A 4-byte value containing X and Y analogue positions, and the XOR of buttons pressed. - /// The first two bytes are the XOR of the buttons, followed by the X and Y inputs - /// represented by 1-byte each. - /// - /// - /// Given the input 0xC0182541, this can be seen as: - /// - /// - /// Button Flags - /// 2-bytes = C0 18 - /// - /// - /// X Analogue - /// 1-byte = 25 - /// - /// - /// Y Analogue - /// 1-byte = 41 - /// - /// - /// - /// - /// When reading from an .m64 file from offset 0x400, 4-bytes at a time, the following code works if the - /// hex input is NOT REVERSED. - /// - /// - public InputModel([NotNull] byte[] input) - { - // input = byte[4] { AA, BB, CC, DD } - - if (input is null) - { - throw new ArgumentNullException(nameof(input)); - } - - if (input.Length != 4) - { - throw new InvalidOperationException($"{nameof(input)} should be 4 bytes, not {input.Length}"); - } - - // X = CC - X = unchecked((sbyte) input[2]); - - // Y = DD - Y = unchecked((sbyte) input[3]); - - // Buttons = AA BB - Buttons = BitConverter.ToUInt16(input - .Take(2) - .Reverse() // Reverse because BitConverter reverses order due to being low-endien - .ToArray(), 0); - } + public ushort Buttons { get; set; } /// - /// Sets a controller input to be either pressed or unpressed + /// Sets a controller input to be either pressed or unpressed /// /// The button type to set /// The state the button is to be set public void SetControllerInput(ControllerInput input, bool isPressed) { - if (isPressed) - { - Buttons |= (ushort) input; - } - else - { - Buttons &= (ushort) ~input; - } + if (isPressed) + Buttons |= (ushort)input; + else + Buttons &= (ushort)~input; } /// - /// Returns the state of a particular button + /// Returns the state of a particular button /// /// /// True is button is pressed public bool GetButtonState(ControllerInput input) { - return ((ushort) input & Buttons) != 0; + return ((ushort)input & Buttons) != 0; } /// - /// Override to return string of analogue inputs and buttons pressed + /// Override to return string of analogue inputs and buttons pressed /// /// public override string ToString() { - return $"{(X, Y)} {string.Join(", ", GetButtons())}"; + return $"{(X, Y)} {string.Join(", ", GetButtons())}"; } /// - /// Returns a string of pressed button inputs + /// Returns a string of pressed button inputs /// /// public IEnumerable GetButtons() { - return EnumExtensions.EnumToArray() - .Where(input => ((ControllerInput) Buttons).HasFlag(input)); + return EnumExtensions.EnumToArray() + .Where(input => ((ControllerInput)Buttons).HasFlag(input)); } /// - /// Implicitly converts a array into an . + /// Implicitly converts a array into an . /// /// public static explicit operator InputModel(byte[] input) { - if (input is null) - { - throw new ArgumentNullException(nameof(input), - string.Format(CultureInfo.InvariantCulture, ExceptionsResource.ArgumentIsNull, nameof(input))); - } - - if (input.Length != 4) - { - throw new ArgumentException(ExceptionsResource.InputArrayInvalidLength, nameof(input)); - } - - return new InputModel(input); + if (input is null) + throw new ArgumentNullException(nameof(input), + string.Format(CultureInfo.InvariantCulture, ExceptionsResource.ArgumentIsNull, nameof(input))); + + if (input.Length != 4) throw new ArgumentException(ExceptionsResource.InputArrayInvalidLength, nameof(input)); + + return new InputModel(input); } /// - /// Explicitly converts an array into a . + /// Explicitly converts an array into a . /// /// public static explicit operator byte[]([NotNull] InputModel input) { - if (input is null) - { - throw new ArgumentNullException(nameof(input)); - } + if (input is null) throw new ArgumentNullException(nameof(input)); - var x = unchecked((byte) input.X); - var y = unchecked((byte) input.Y); - var buttons = BitConverter.GetBytes(input.Buttons); + var x = unchecked((byte)input.X); + var y = unchecked((byte)input.Y); + var buttons = BitConverter.GetBytes(input.Buttons); - // Buttons are reversed because BitConverter reverses order due to being low-endien - return new[] {buttons[1], buttons[0], x, y}; + // Buttons are reversed because BitConverter reverses order due to being little-endien + return [buttons[1], buttons[0], x, y]; } - } -} +} \ No newline at end of file diff --git a/MupenSharp/MupenSharp/Models/M64.cs b/MupenSharp/MupenSharp/Models/M64.cs index 28993e5..3ebb1db 100644 --- a/MupenSharp/MupenSharp/Models/M64.cs +++ b/MupenSharp/MupenSharp/Models/M64.cs @@ -6,232 +6,218 @@ namespace MupenSharp.Models; /// -/// Stores data of a .m64 file. -/// Refer to the header documentation for more -/// information. +/// Stores data of a .m64 file. +/// Refer to the header documentation for more +/// information. /// public class M64 : IM64 { - /// - /// The UID of the movie. - /// - public int MovieUid { get; set; } - - /// - /// The internal name of ROM used when recording, directly from ROM. - /// - [StringEncoding(Encoding.ASCII, 32)] - public string RomName { get; set; } - - /// - /// The name of video plugin used when recording, directly from plugin - /// - [StringEncoding(Encoding.ASCII, 64)] - public string VideoPluginName { get; set; } - - /// - /// The name of audio plugin used when recording, directly from plugin - /// - [StringEncoding(Encoding.ASCII, 64)] - public string AudioPluginName { get; set; } - - /// - /// The name of input plugin used when recording, directly from plugin - /// - [StringEncoding(Encoding.ASCII, 64)] - public string InputPluginName { get; set; } - - /// - /// The name of rsp plugin used when recording, directly from plugin - /// - [StringEncoding(Encoding.ASCII, 64)] - public string RspPluginName { get; set; } - - /// - /// The collection of controller inputs every input frame and controller, - /// containing analogue x, y positions and buttons pressed. - /// - // TODO: Implement multiple controller support - public IList ControllerInputs { get; set; } - - /// - /// Version number. Should be 3. - /// - public uint Version { get; set; } - - /// - /// The number of frames (vertical interrupts). - /// - public uint ViCount { get; set; } - - /// - /// The number of file rerecords. - /// - public uint RerecordCount { get; set; } - - /// - /// Frames (vertical interrupts) per second. - /// - public uint ViPerSecond { get; set; } - - /// - /// The number of controllers enabled for the file. - /// - public uint ControllerCount { get; set; } - - /// - /// The movie start type. - /// - /// - /// - /// Value - /// - /// - /// Description - /// - /// - /// - /// 1 - /// - /// movie begins from snapshot (the snapshot will be loaded from an external file with the movie filename. - /// and a .st extension) - /// - /// - /// - /// 2 - /// - /// movie begins from power-on - /// - /// - /// - /// other values - /// - /// invalid movie - /// - /// - /// - /// - public ushort MovieStartType { get; set; } - - /// - /// Flags set for each controller. - /// - /// - /// bit 0 - /// - /// Controller 1 present - /// - /// - /// - /// bit 4 - /// - /// Controller 1 has mempak - /// - /// - /// - /// bit 8 - /// - /// Controller 1 has rumblepak - /// - /// - /// - /// +1..3 for controllers 2..4. - /// - public uint ControllerFlags { get; set; } - - /// - /// CRC32 of ROM used when recording, directly from ROM. - /// - public uint Crc32 { get; set; } - - /// - /// The country code of ROM used when recording, directly from ROM. - /// - public ushort RegionCode { get; set; } - - /// - /// The movie description info. - /// - [StringEncoding(Encoding.UTF8, 256)] - public string MovieDescription { get; set; } - - /// - /// The number of input samples from the controllers (for one controller). - /// - public uint InputCount { get; set; } - - /// - /// The Author info of the movie. - /// - [StringEncoding(Encoding.UTF8, 222)] - public string Author { get; set; } - - /// - /// Returns if the current controller is present in the given file. - /// - /// The controller to check for. - /// A boolean reflecting whether the controller is present. - /// - public bool IsControllerPresent(Controller controller) - { - var controllerProperty = controller switch + /// + /// The UID of the movie. + /// + public int MovieUid { get; set; } + + /// + /// The internal name of ROM used when recording, directly from ROM. + /// + [StringEncoding(Encoding.ASCII, 32)] + public string RomName { get; set; } + + /// + /// The name of video plugin used when recording, directly from plugin + /// + [StringEncoding(Encoding.ASCII, 64)] + public string VideoPluginName { get; set; } + + /// + /// The name of audio plugin used when recording, directly from plugin + /// + [StringEncoding(Encoding.ASCII, 64)] + public string AudioPluginName { get; set; } + + /// + /// The name of input plugin used when recording, directly from plugin + /// + [StringEncoding(Encoding.ASCII, 64)] + public string InputPluginName { get; set; } + + /// + /// The name of rsp plugin used when recording, directly from plugin + /// + [StringEncoding(Encoding.ASCII, 64)] + public string RspPluginName { get; set; } + + /// + /// The collection of controller inputs every input frame and controller, + /// containing analogue x, y positions and buttons pressed. + /// + // TODO: Implement multiple controller support + public IList ControllerInputs { get; set; } + + /// + /// Version number. Should be 3. + /// + public uint Version { get; set; } + + /// + /// The number of frames (vertical interrupts). + /// + public uint ViCount { get; set; } + + /// + /// The number of file rerecords. + /// + public uint RerecordCount { get; set; } + + /// + /// Frames (vertical interrupts) per second. + /// + public uint ViPerSecond { get; set; } + + /// + /// The number of controllers enabled for the file. + /// + public uint ControllerCount { get; set; } + + /// + /// The movie start type. + /// + /// + /// + /// Value + /// + /// + /// Description + /// + /// + /// + /// 1 + /// + /// movie begins from snapshot (the snapshot will be loaded from an external file with the movie filename. + /// and a .st extension) + /// + /// + /// + /// 2 + /// + /// movie begins from power-on + /// + /// + /// + /// other values + /// + /// invalid movie + /// + /// + /// + /// + public ushort MovieStartType { get; set; } + + /// + /// Flags set for each controller. + /// + /// + /// bit 0 + /// + /// Controller 1 present + /// + /// + /// + /// bit 4 + /// + /// Controller 1 has mempak + /// + /// + /// + /// bit 8 + /// + /// Controller 1 has rumblepak + /// + /// + /// + /// +1..3 for controllers 2..4. + /// + public uint ControllerFlags { get; set; } + + /// + /// CRC32 of ROM used when recording, directly from ROM. + /// + public uint Crc32 { get; set; } + + /// + /// The country code of ROM used when recording, directly from ROM. + /// + public ushort RegionCode { get; set; } + + /// + /// The movie description info. + /// + [StringEncoding(Encoding.UTF8, 256)] + public string MovieDescription { get; set; } + + /// + /// The number of input samples from the controllers (for one controller). + /// + public uint InputCount { get; set; } + + /// + /// The Author info of the movie. + /// + [StringEncoding(Encoding.UTF8, 222)] + public string Author { get; set; } + + /// + /// Returns if the current controller is present in the given file. + /// + /// The controller to check for. + /// A boolean reflecting whether the controller is present. + /// + public bool IsControllerPresent(Controller controller) { - Controller.ControllerOne => ControllerProperty.ControllerOnePresent, - Controller.ControllerTwo => ControllerProperty.ControllerTwoPresent, - Controller.ControllerThree => ControllerProperty.ControllerThreePresent, - Controller.ControllerFour => ControllerProperty.ControllerFourPresent, - _ => throw new ArgumentOutOfRangeException(nameof(controller), controller, null) - }; - - return ((ControllerProperty)ControllerFlags).HasFlag(controllerProperty); - } - - /// - /// Get the input of a particular controller. - /// - /// The controller to get the input of. - /// The input frame of interest. - /// Returns the input of the controller for that input frame. - public InputModel GetControllerInput(Controller controller, int input) - { - if (!IsControllerPresent(controller)) - { - throw new Exception($"Controller '{controller}' is not present."); + var controllerProperty = controller switch + { + Controller.ControllerOne => ControllerProperty.ControllerOnePresent, + Controller.ControllerTwo => ControllerProperty.ControllerTwoPresent, + Controller.ControllerThree => ControllerProperty.ControllerThreePresent, + Controller.ControllerFour => ControllerProperty.ControllerFourPresent, + _ => throw new ArgumentOutOfRangeException(nameof(controller), controller, null) + }; + + return ((ControllerProperty)ControllerFlags).HasFlag(controllerProperty); } - var offset = (int)controller; - if (ControllerInputs.Count * ControllerCount > input + offset) + /// + /// Get the input of a particular controller. + /// + /// The controller to get the input of. + /// The input frame of interest. + /// Returns the input of the controller for that input frame. + public InputModel GetControllerInput(Controller controller, int input) { - throw new IndexOutOfRangeException($"The input '{input}' falls out of range."); - } + if (!IsControllerPresent(controller)) throw new Exception($"Controller '{controller}' is not present."); - return ControllerInputs[input + offset]; - } - - /// - /// Get all inputs for a given controller. - /// - /// The controller to get the inputs. - /// Returns the inputs of the given controller. - public IEnumerable GetControllerInputs(Controller controller) - { - if (!IsControllerPresent(controller)) - { - throw new Exception($"Controller '{controller}' is not present."); - } + var offset = (int)controller; + if (ControllerInputs.Count * ControllerCount > input + offset) + throw new IndexOutOfRangeException($"The input '{input}' falls out of range."); - var inputs = new List(ControllerInputs.Count); - if (ControllerInputs.Count == 0) - { - return inputs; + return ControllerInputs[input + offset]; } - var offset = (int)controller; - for (var i = 0; i < ControllerInputs.Count; i += (int)ControllerCount) + /// + /// Get all inputs for a given controller. + /// + /// The controller to get the inputs. + /// Returns the inputs of the given controller. + public IEnumerable GetControllerInputs(Controller controller) { - inputs.Add(ControllerInputs[i + offset]); - } + if (!IsControllerPresent(controller)) throw new Exception($"Controller '{controller}' is not present."); + + var inputs = new List(ControllerInputs.Count); + if (ControllerInputs.Count == 0) return inputs; - return inputs; - } + var offset = (int)controller; + for (var i = 0; i < ControllerInputs.Count; i += (int)ControllerCount) inputs.Add(ControllerInputs[i + offset]); + + return inputs; + } } \ No newline at end of file