From 086564c3c88d8006670199b3aba5977c07f16261 Mon Sep 17 00:00:00 2001 From: riperiperi Date: Fri, 6 Oct 2023 23:23:39 +0100 Subject: [PATCH] HLE: Fix Mii crc generation and minor issues (#5766) * HLE: Fix Mii crc generation Validating CRCs for data and device involves calculating the crc of all data including the crc being checked, which should then be 0. The crc should be _generated_ on all data _before_ the crc in the struct. It shouldn't include the crcs themselves. This fixes all generated miis (eg. default) having invalid crcs. This does not affect mii maker, as that generates its own charinfo. Does not fix MK8D crash. * Fix other mii issues * Fully define all fields for Nickname and Ver3StoreData Fixes an issue where the nickname for a mii would only have the first character on some method calls. * Add Array96 type --- src/Ryujinx.Common/Memory/StructArrayHelpers.cs | 12 ++++++++++++ src/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs | 2 +- src/Ryujinx.HLE/HOS/Services/Mii/Types/CoreData.cs | 7 ++++--- src/Ryujinx.HLE/HOS/Services/Mii/Types/Nickname.cs | 7 ++++--- src/Ryujinx.HLE/HOS/Services/Mii/Types/StoreData.cs | 9 +++++++-- .../HOS/Services/Mii/Types/Ver3StoreData.cs | 8 +++++--- 6 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/Ryujinx.Common/Memory/StructArrayHelpers.cs b/src/Ryujinx.Common/Memory/StructArrayHelpers.cs index 65956ed326..807bd69c34 100644 --- a/src/Ryujinx.Common/Memory/StructArrayHelpers.cs +++ b/src/Ryujinx.Common/Memory/StructArrayHelpers.cs @@ -756,6 +756,18 @@ namespace Ryujinx.Common.Memory public Span AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length); } + public struct Array96 : IArray where T : unmanaged + { + T _e0; + Array64 _other; + Array31 _other2; + public readonly int Length => 96; + public ref T this[int index] => ref AsSpan()[index]; + + [Pure] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length); + } + public struct Array127 : IArray where T : unmanaged { T _e0; diff --git a/src/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs b/src/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs index d9bcecee1c..5041dc8825 100644 --- a/src/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs +++ b/src/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs @@ -290,7 +290,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii { coreData = new CoreData(); - if (charInfo.IsValid()) + if (!charInfo.IsValid()) { return ResultCode.InvalidCharInfo; } diff --git a/src/Ryujinx.HLE/HOS/Services/Mii/Types/CoreData.cs b/src/Ryujinx.HLE/HOS/Services/Mii/Types/CoreData.cs index 00e49ecb99..4f6e289e2e 100644 --- a/src/Ryujinx.HLE/HOS/Services/Mii/Types/CoreData.cs +++ b/src/Ryujinx.HLE/HOS/Services/Mii/Types/CoreData.cs @@ -1,4 +1,5 @@ -using System; +using Ryujinx.Common.Memory; +using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using static Ryujinx.HLE.HOS.Services.Mii.Types.RandomMiiConstants; @@ -10,9 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types { public const int Size = 0x30; - private byte _storage; + private Array48 _storage; - public Span Storage => MemoryMarshal.CreateSpan(ref _storage, Size); + public Span Storage => _storage.AsSpan(); [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0x18)] public struct ElementInfo diff --git a/src/Ryujinx.HLE/HOS/Services/Mii/Types/Nickname.cs b/src/Ryujinx.HLE/HOS/Services/Mii/Types/Nickname.cs index dc21d8e567..6665ca6d41 100644 --- a/src/Ryujinx.HLE/HOS/Services/Mii/Types/Nickname.cs +++ b/src/Ryujinx.HLE/HOS/Services/Mii/Types/Nickname.cs @@ -1,4 +1,5 @@ -using System; +using Ryujinx.Common.Memory; +using System; using System.Runtime.InteropServices; using System.Text; @@ -10,12 +11,12 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types public const int CharCount = 10; private const int SizeConst = (CharCount + 1) * 2; - private byte _storage; + private Array22 _storage; public static Nickname Default => FromString("no name"); public static Nickname Question => FromString("???"); - public Span Raw => MemoryMarshal.CreateSpan(ref _storage, SizeConst); + public Span Raw => _storage.AsSpan(); private ReadOnlySpan Characters => MemoryMarshal.Cast(Raw); diff --git a/src/Ryujinx.HLE/HOS/Services/Mii/Types/StoreData.cs b/src/Ryujinx.HLE/HOS/Services/Mii/Types/StoreData.cs index 994f6b7ce1..178b483187 100644 --- a/src/Ryujinx.HLE/HOS/Services/Mii/Types/StoreData.cs +++ b/src/Ryujinx.HLE/HOS/Services/Mii/Types/StoreData.cs @@ -62,7 +62,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types private ushort CalculateDataCrc() { - return Helper.CalculateCrc16(AsSpanWithoutDeviceCrc(), 0, true); + return Helper.CalculateCrc16(AsSpanWithoutCrcs(), 0, true); } private ushort CalculateDeviceCrc() @@ -71,7 +71,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types ushort deviceIdCrc16 = Helper.CalculateCrc16(SpanHelpers.AsByteSpan(ref deviceId), 0, false); - return Helper.CalculateCrc16(AsSpan(), deviceIdCrc16, true); + return Helper.CalculateCrc16(AsSpanWithoutDeviceCrc(), deviceIdCrc16, true); } private ReadOnlySpan AsSpan() @@ -84,6 +84,11 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types return AsSpan()[..(Size - 2)]; } + private ReadOnlySpan AsSpanWithoutCrcs() + { + return AsSpan()[..(Size - 4)]; + } + public static StoreData BuildDefault(UtilityImpl utilImpl, uint index) { StoreData result = new() diff --git a/src/Ryujinx.HLE/HOS/Services/Mii/Types/Ver3StoreData.cs b/src/Ryujinx.HLE/HOS/Services/Mii/Types/Ver3StoreData.cs index 70bb348b57..1c7db8e66b 100644 --- a/src/Ryujinx.HLE/HOS/Services/Mii/Types/Ver3StoreData.cs +++ b/src/Ryujinx.HLE/HOS/Services/Mii/Types/Ver3StoreData.cs @@ -1,4 +1,6 @@ -using System; +using Ryujinx.Common.Memory; +using Ryujinx.Common.Utilities; +using System; using System.Runtime.InteropServices; namespace Ryujinx.HLE.HOS.Services.Mii.Types @@ -8,9 +10,9 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types { public const int Size = 0x60; - private byte _storage; + private Array96 _storage; - public Span Storage => MemoryMarshal.CreateSpan(ref _storage, Size); + public Span Storage => _storage.AsSpan(); // TODO: define all getters/setters }