Преглед на файлове

service: mii: Move ver3 operations

german77 преди 2 години
родител
ревизия
8d7d62dc24

+ 3 - 232
src/core/hle/service/mii/mii_manager.cpp

@@ -394,173 +394,9 @@ CharInfo MiiManager::BuildDefault(std::size_t index) {
 }
 
 CharInfo MiiManager::ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const {
-    Service::Mii::MiiManager manager;
-    auto mii = manager.BuildBase(Mii::Gender::Male);
-
-    if (!ValidateV3Info(mii_v3)) {
-        return mii;
-    }
-
-    // TODO: We are ignoring a bunch of data from the mii_v3
-
-    mii.gender = static_cast<u8>(mii_v3.mii_information.gender);
-    mii.favorite_color = static_cast<u8>(mii_v3.mii_information.favorite_color);
-    mii.height = mii_v3.height;
-    mii.build = mii_v3.build;
-
-    // Copy name until string terminator
-    mii.name = {};
-    for (std::size_t index = 0; index < mii.name.size() - 1; index++) {
-        mii.name[index] = mii_v3.mii_name[index];
-        if (mii.name[index] == 0) {
-            break;
-        }
-    }
-
-    mii.font_region = mii_v3.region_information.character_set;
-
-    mii.faceline_type = mii_v3.appearance_bits1.face_shape;
-    mii.faceline_color = mii_v3.appearance_bits1.skin_color;
-    mii.faceline_wrinkle = mii_v3.appearance_bits2.wrinkles;
-    mii.faceline_make = mii_v3.appearance_bits2.makeup;
-
-    mii.hair_type = mii_v3.hair_style;
-    mii.hair_color = mii_v3.appearance_bits3.hair_color;
-    mii.hair_flip = mii_v3.appearance_bits3.flip_hair;
-
-    mii.eye_type = static_cast<u8>(mii_v3.appearance_bits4.eye_type);
-    mii.eye_color = static_cast<u8>(mii_v3.appearance_bits4.eye_color);
-    mii.eye_scale = static_cast<u8>(mii_v3.appearance_bits4.eye_scale);
-    mii.eye_aspect = static_cast<u8>(mii_v3.appearance_bits4.eye_vertical_stretch);
-    mii.eye_rotate = static_cast<u8>(mii_v3.appearance_bits4.eye_rotation);
-    mii.eye_x = static_cast<u8>(mii_v3.appearance_bits4.eye_spacing);
-    mii.eye_y = static_cast<u8>(mii_v3.appearance_bits4.eye_y_position);
-
-    mii.eyebrow_type = static_cast<u8>(mii_v3.appearance_bits5.eyebrow_style);
-    mii.eyebrow_color = static_cast<u8>(mii_v3.appearance_bits5.eyebrow_color);
-    mii.eyebrow_scale = static_cast<u8>(mii_v3.appearance_bits5.eyebrow_scale);
-    mii.eyebrow_aspect = static_cast<u8>(mii_v3.appearance_bits5.eyebrow_yscale);
-    mii.eyebrow_rotate = static_cast<u8>(mii_v3.appearance_bits5.eyebrow_rotation);
-    mii.eyebrow_x = static_cast<u8>(mii_v3.appearance_bits5.eyebrow_spacing);
-    mii.eyebrow_y = static_cast<u8>(mii_v3.appearance_bits5.eyebrow_y_position);
-
-    mii.nose_type = static_cast<u8>(mii_v3.appearance_bits6.nose_type);
-    mii.nose_scale = static_cast<u8>(mii_v3.appearance_bits6.nose_scale);
-    mii.nose_y = static_cast<u8>(mii_v3.appearance_bits6.nose_y_position);
-
-    mii.mouth_type = static_cast<u8>(mii_v3.appearance_bits7.mouth_type);
-    mii.mouth_color = static_cast<u8>(mii_v3.appearance_bits7.mouth_color);
-    mii.mouth_scale = static_cast<u8>(mii_v3.appearance_bits7.mouth_scale);
-    mii.mouth_aspect = static_cast<u8>(mii_v3.appearance_bits7.mouth_horizontal_stretch);
-    mii.mouth_y = static_cast<u8>(mii_v3.appearance_bits8.mouth_y_position);
-
-    mii.mustache_type = static_cast<u8>(mii_v3.appearance_bits8.mustache_type);
-    mii.mustache_scale = static_cast<u8>(mii_v3.appearance_bits9.mustache_scale);
-    mii.mustache_y = static_cast<u8>(mii_v3.appearance_bits9.mustache_y_position);
-
-    mii.beard_type = static_cast<u8>(mii_v3.appearance_bits9.bear_type);
-    mii.beard_color = static_cast<u8>(mii_v3.appearance_bits9.facial_hair_color);
-
-    mii.glasses_type = static_cast<u8>(mii_v3.appearance_bits10.glasses_type);
-    mii.glasses_color = static_cast<u8>(mii_v3.appearance_bits10.glasses_color);
-    mii.glasses_scale = static_cast<u8>(mii_v3.appearance_bits10.glasses_scale);
-    mii.glasses_y = static_cast<u8>(mii_v3.appearance_bits10.glasses_y_position);
-
-    mii.mole_type = static_cast<u8>(mii_v3.appearance_bits11.mole_enabled);
-    mii.mole_scale = static_cast<u8>(mii_v3.appearance_bits11.mole_scale);
-    mii.mole_x = static_cast<u8>(mii_v3.appearance_bits11.mole_x_position);
-    mii.mole_y = static_cast<u8>(mii_v3.appearance_bits11.mole_y_position);
-
-    // TODO: Validate mii data
-
-    return mii;
-}
-
-Ver3StoreData MiiManager::BuildFromStoreData(const CharInfo& mii) const {
-    Service::Mii::MiiManager manager;
-    Ver3StoreData mii_v3{};
-
-    // TODO: We are ignoring a bunch of data from the mii_v3
-
-    mii_v3.version = 1;
-    mii_v3.mii_information.gender.Assign(mii.gender);
-    mii_v3.mii_information.favorite_color.Assign(mii.favorite_color);
-    mii_v3.height = mii.height;
-    mii_v3.build = mii.build;
-
-    // Copy name until string terminator
-    mii_v3.mii_name = {};
-    for (std::size_t index = 0; index < mii.name.size() - 1; index++) {
-        mii_v3.mii_name[index] = mii.name[index];
-        if (mii_v3.mii_name[index] == 0) {
-            break;
-        }
-    }
-
-    mii_v3.region_information.character_set.Assign(mii.font_region);
-
-    mii_v3.appearance_bits1.face_shape.Assign(mii.faceline_type);
-    mii_v3.appearance_bits2.wrinkles.Assign(mii.faceline_wrinkle);
-    mii_v3.appearance_bits2.makeup.Assign(mii.faceline_make);
-
-    mii_v3.hair_style = mii.hair_type;
-    mii_v3.appearance_bits3.flip_hair.Assign(mii.hair_flip);
-
-    mii_v3.appearance_bits4.eye_type.Assign(mii.eye_type);
-    mii_v3.appearance_bits4.eye_scale.Assign(mii.eye_scale);
-    mii_v3.appearance_bits4.eye_vertical_stretch.Assign(mii.eye_aspect);
-    mii_v3.appearance_bits4.eye_rotation.Assign(mii.eye_rotate);
-    mii_v3.appearance_bits4.eye_spacing.Assign(mii.eye_x);
-    mii_v3.appearance_bits4.eye_y_position.Assign(mii.eye_y);
-
-    mii_v3.appearance_bits5.eyebrow_style.Assign(mii.eyebrow_type);
-    mii_v3.appearance_bits5.eyebrow_scale.Assign(mii.eyebrow_scale);
-    mii_v3.appearance_bits5.eyebrow_yscale.Assign(mii.eyebrow_aspect);
-    mii_v3.appearance_bits5.eyebrow_rotation.Assign(mii.eyebrow_rotate);
-    mii_v3.appearance_bits5.eyebrow_spacing.Assign(mii.eyebrow_x);
-    mii_v3.appearance_bits5.eyebrow_y_position.Assign(mii.eyebrow_y);
-
-    mii_v3.appearance_bits6.nose_type.Assign(mii.nose_type);
-    mii_v3.appearance_bits6.nose_scale.Assign(mii.nose_scale);
-    mii_v3.appearance_bits6.nose_y_position.Assign(mii.nose_y);
-
-    mii_v3.appearance_bits7.mouth_type.Assign(mii.mouth_type);
-    mii_v3.appearance_bits7.mouth_scale.Assign(mii.mouth_scale);
-    mii_v3.appearance_bits7.mouth_horizontal_stretch.Assign(mii.mouth_aspect);
-    mii_v3.appearance_bits8.mouth_y_position.Assign(mii.mouth_y);
-
-    mii_v3.appearance_bits8.mustache_type.Assign(mii.mustache_type);
-    mii_v3.appearance_bits9.mustache_scale.Assign(mii.mustache_scale);
-    mii_v3.appearance_bits9.mustache_y_position.Assign(mii.mustache_y);
-
-    mii_v3.appearance_bits9.bear_type.Assign(mii.beard_type);
-
-    mii_v3.appearance_bits10.glasses_scale.Assign(mii.glasses_scale);
-    mii_v3.appearance_bits10.glasses_y_position.Assign(mii.glasses_y);
-
-    mii_v3.appearance_bits11.mole_enabled.Assign(mii.mole_type);
-    mii_v3.appearance_bits11.mole_scale.Assign(mii.mole_scale);
-    mii_v3.appearance_bits11.mole_x_position.Assign(mii.mole_x);
-    mii_v3.appearance_bits11.mole_y_position.Assign(mii.mole_y);
-
-    // These types are converted to V3 from a table
-    mii_v3.appearance_bits1.skin_color.Assign(
-        RawData::FromVer3GetFacelineColor(mii.faceline_color));
-    mii_v3.appearance_bits3.hair_color.Assign(RawData::FromVer3GetHairColor(mii.hair_color));
-    mii_v3.appearance_bits4.eye_color.Assign(RawData::FromVer3GetEyeColor(mii.eye_color));
-    mii_v3.appearance_bits5.eyebrow_color.Assign(RawData::FromVer3GetHairColor(mii.eyebrow_color));
-    mii_v3.appearance_bits7.mouth_color.Assign(RawData::FromVer3GetMouthlineColor(mii.mouth_color));
-    mii_v3.appearance_bits9.facial_hair_color.Assign(
-        RawData::FromVer3GetHairColor(mii.beard_color));
-    mii_v3.appearance_bits10.glasses_color.Assign(
-        RawData::FromVer3GetGlassColor(mii.glasses_color));
-    mii_v3.appearance_bits10.glasses_type.Assign(RawData::FromVer3GetGlassType(mii.glasses_type));
-
-    mii_v3.crc = MiiUtil::CalculateCrc16(&mii_v3, sizeof(Ver3StoreData) - sizeof(u16));
-
-    // TODO: Validate mii_v3 data
-
-    return mii_v3;
+    CharInfo char_info{};
+    mii_v3.BuildToStoreData(char_info);
+    return char_info;
 }
 
 NfpStoreDataExtension MiiManager::SetFromStoreData(const CharInfo& mii) const {
@@ -576,71 +412,6 @@ NfpStoreDataExtension MiiManager::SetFromStoreData(const CharInfo& mii) const {
     };
 }
 
-bool MiiManager::ValidateV3Info(const Ver3StoreData& mii_v3) const {
-    bool is_valid = mii_v3.version == 0 || mii_v3.version == 3;
-
-    is_valid = is_valid && (mii_v3.mii_name[0] != 0);
-
-    is_valid = is_valid && (mii_v3.mii_information.birth_month < 13);
-    is_valid = is_valid && (mii_v3.mii_information.birth_day < 32);
-    is_valid = is_valid && (mii_v3.mii_information.favorite_color < 12);
-    is_valid = is_valid && (mii_v3.height < 128);
-    is_valid = is_valid && (mii_v3.build < 128);
-
-    is_valid = is_valid && (mii_v3.appearance_bits1.face_shape < 12);
-    is_valid = is_valid && (mii_v3.appearance_bits1.skin_color < 7);
-    is_valid = is_valid && (mii_v3.appearance_bits2.wrinkles < 12);
-    is_valid = is_valid && (mii_v3.appearance_bits2.makeup < 12);
-
-    is_valid = is_valid && (mii_v3.hair_style < 132);
-    is_valid = is_valid && (mii_v3.appearance_bits3.hair_color < 8);
-
-    is_valid = is_valid && (mii_v3.appearance_bits4.eye_type < 60);
-    is_valid = is_valid && (mii_v3.appearance_bits4.eye_color < 6);
-    is_valid = is_valid && (mii_v3.appearance_bits4.eye_scale < 8);
-    is_valid = is_valid && (mii_v3.appearance_bits4.eye_vertical_stretch < 7);
-    is_valid = is_valid && (mii_v3.appearance_bits4.eye_rotation < 8);
-    is_valid = is_valid && (mii_v3.appearance_bits4.eye_spacing < 13);
-    is_valid = is_valid && (mii_v3.appearance_bits4.eye_y_position < 19);
-
-    is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_style < 25);
-    is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_color < 8);
-    is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_scale < 9);
-    is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_yscale < 7);
-    is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_rotation < 12);
-    is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_spacing < 12);
-    is_valid = is_valid && (mii_v3.appearance_bits5.eyebrow_y_position < 19);
-
-    is_valid = is_valid && (mii_v3.appearance_bits6.nose_type < 18);
-    is_valid = is_valid && (mii_v3.appearance_bits6.nose_scale < 9);
-    is_valid = is_valid && (mii_v3.appearance_bits6.nose_y_position < 19);
-
-    is_valid = is_valid && (mii_v3.appearance_bits7.mouth_type < 36);
-    is_valid = is_valid && (mii_v3.appearance_bits7.mouth_color < 5);
-    is_valid = is_valid && (mii_v3.appearance_bits7.mouth_scale < 9);
-    is_valid = is_valid && (mii_v3.appearance_bits7.mouth_horizontal_stretch < 7);
-    is_valid = is_valid && (mii_v3.appearance_bits8.mouth_y_position < 19);
-
-    is_valid = is_valid && (mii_v3.appearance_bits8.mustache_type < 6);
-    is_valid = is_valid && (mii_v3.appearance_bits9.mustache_scale < 7);
-    is_valid = is_valid && (mii_v3.appearance_bits9.mustache_y_position < 17);
-
-    is_valid = is_valid && (mii_v3.appearance_bits9.bear_type < 6);
-    is_valid = is_valid && (mii_v3.appearance_bits9.facial_hair_color < 8);
-
-    is_valid = is_valid && (mii_v3.appearance_bits10.glasses_type < 9);
-    is_valid = is_valid && (mii_v3.appearance_bits10.glasses_color < 6);
-    is_valid = is_valid && (mii_v3.appearance_bits10.glasses_scale < 8);
-    is_valid = is_valid && (mii_v3.appearance_bits10.glasses_y_position < 21);
-
-    is_valid = is_valid && (mii_v3.appearance_bits11.mole_enabled < 2);
-    is_valid = is_valid && (mii_v3.appearance_bits11.mole_scale < 9);
-    is_valid = is_valid && (mii_v3.appearance_bits11.mole_x_position < 17);
-    is_valid = is_valid && (mii_v3.appearance_bits11.mole_y_position < 31);
-
-    return is_valid;
-}
-
 std::vector<CharInfoElement> MiiManager::GetDefault(SourceFlag source_flag) {
     std::vector<CharInfoElement> result;
 

+ 0 - 4
src/core/hle/service/mii/mii_manager.h

@@ -27,13 +27,9 @@ public:
     CharInfo BuildBase(Gender gender);
     CharInfo BuildDefault(std::size_t index);
     CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const;
-    bool ValidateV3Info(const Ver3StoreData& mii_v3) const;
     std::vector<CharInfoElement> GetDefault(SourceFlag source_flag);
     Result GetIndex(const CharInfo& info, u32& index);
 
-    // This is nn::mii::detail::Ver::StoreDataRaw::BuildFromStoreData
-    Ver3StoreData BuildFromStoreData(const CharInfo& mii) const;
-
     // This is nn::mii::detail::NfpStoreDataExtentionRaw::SetFromStoreData
     NfpStoreDataExtension SetFromStoreData(const CharInfo& mii) const;
 

+ 2 - 1
src/core/hle/service/mii/types/char_info.h

@@ -8,7 +8,8 @@
 namespace Service::Mii {
 
 // This is nn::mii::detail::CharInfoRaw
-struct CharInfo {
+class CharInfo {
+public:
     Common::UUID create_id;
     Nickname name;
     u16 null_terminator;

+ 223 - 1
src/core/hle/service/mii/types/ver3_store_data.cpp

@@ -1,6 +1,228 @@
 // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 // SPDX-License-Identifier: GPL-2.0-or-later
 
+#include "core/hle/service/mii/mii_util.h"
+#include "core/hle/service/mii/types/char_info.h"
+#include "core/hle/service/mii/types/raw_data.h"
+#include "core/hle/service/mii/types/store_data.h"
 #include "core/hle/service/mii/types/ver3_store_data.h"
 
-namespace Service::Mii {} // namespace Service::Mii
+namespace Service::Mii {
+
+void Ver3StoreData::BuildToStoreData(CharInfo& out_char_info) const {
+    if (!IsValid()) {
+        return;
+    }
+
+    // TODO: We are ignoring a bunch of data from the mii_v3
+
+    out_char_info.gender = static_cast<u8>(mii_information.gender);
+    out_char_info.favorite_color = static_cast<u8>(mii_information.favorite_color);
+    out_char_info.height = height;
+    out_char_info.build = build;
+
+    // Copy name until string terminator
+    out_char_info.name = {};
+    for (std::size_t index = 0; index < out_char_info.name.size() - 1; index++) {
+        out_char_info.name[index] = mii_name[index];
+        if (out_char_info.name[index] == 0) {
+            break;
+        }
+    }
+
+    out_char_info.font_region = region_information.character_set;
+
+    out_char_info.faceline_type = appearance_bits1.face_shape;
+    out_char_info.faceline_color = appearance_bits1.skin_color;
+    out_char_info.faceline_wrinkle = appearance_bits2.wrinkles;
+    out_char_info.faceline_make = appearance_bits2.makeup;
+
+    out_char_info.hair_type = hair_style;
+    out_char_info.hair_color = appearance_bits3.hair_color;
+    out_char_info.hair_flip = appearance_bits3.flip_hair;
+
+    out_char_info.eye_type = static_cast<u8>(appearance_bits4.eye_type);
+    out_char_info.eye_color = static_cast<u8>(appearance_bits4.eye_color);
+    out_char_info.eye_scale = static_cast<u8>(appearance_bits4.eye_scale);
+    out_char_info.eye_aspect = static_cast<u8>(appearance_bits4.eye_vertical_stretch);
+    out_char_info.eye_rotate = static_cast<u8>(appearance_bits4.eye_rotation);
+    out_char_info.eye_x = static_cast<u8>(appearance_bits4.eye_spacing);
+    out_char_info.eye_y = static_cast<u8>(appearance_bits4.eye_y_position);
+
+    out_char_info.eyebrow_type = static_cast<u8>(appearance_bits5.eyebrow_style);
+    out_char_info.eyebrow_color = static_cast<u8>(appearance_bits5.eyebrow_color);
+    out_char_info.eyebrow_scale = static_cast<u8>(appearance_bits5.eyebrow_scale);
+    out_char_info.eyebrow_aspect = static_cast<u8>(appearance_bits5.eyebrow_yscale);
+    out_char_info.eyebrow_rotate = static_cast<u8>(appearance_bits5.eyebrow_rotation);
+    out_char_info.eyebrow_x = static_cast<u8>(appearance_bits5.eyebrow_spacing);
+    out_char_info.eyebrow_y = static_cast<u8>(appearance_bits5.eyebrow_y_position);
+
+    out_char_info.nose_type = static_cast<u8>(appearance_bits6.nose_type);
+    out_char_info.nose_scale = static_cast<u8>(appearance_bits6.nose_scale);
+    out_char_info.nose_y = static_cast<u8>(appearance_bits6.nose_y_position);
+
+    out_char_info.mouth_type = static_cast<u8>(appearance_bits7.mouth_type);
+    out_char_info.mouth_color = static_cast<u8>(appearance_bits7.mouth_color);
+    out_char_info.mouth_scale = static_cast<u8>(appearance_bits7.mouth_scale);
+    out_char_info.mouth_aspect = static_cast<u8>(appearance_bits7.mouth_horizontal_stretch);
+    out_char_info.mouth_y = static_cast<u8>(appearance_bits8.mouth_y_position);
+
+    out_char_info.mustache_type = static_cast<u8>(appearance_bits8.mustache_type);
+    out_char_info.mustache_scale = static_cast<u8>(appearance_bits9.mustache_scale);
+    out_char_info.mustache_y = static_cast<u8>(appearance_bits9.mustache_y_position);
+
+    out_char_info.beard_type = static_cast<u8>(appearance_bits9.bear_type);
+    out_char_info.beard_color = static_cast<u8>(appearance_bits9.facial_hair_color);
+
+    out_char_info.glasses_type = static_cast<u8>(appearance_bits10.glasses_type);
+    out_char_info.glasses_color = static_cast<u8>(appearance_bits10.glasses_color);
+    out_char_info.glasses_scale = static_cast<u8>(appearance_bits10.glasses_scale);
+    out_char_info.glasses_y = static_cast<u8>(appearance_bits10.glasses_y_position);
+
+    out_char_info.mole_type = static_cast<u8>(appearance_bits11.mole_enabled);
+    out_char_info.mole_scale = static_cast<u8>(appearance_bits11.mole_scale);
+    out_char_info.mole_x = static_cast<u8>(appearance_bits11.mole_x_position);
+    out_char_info.mole_y = static_cast<u8>(appearance_bits11.mole_y_position);
+}
+
+void Ver3StoreData::BuildFromStoreData(const CharInfo& char_info) {
+    version = 1;
+    mii_information.gender.Assign(char_info.gender);
+    mii_information.favorite_color.Assign(char_info.favorite_color);
+    height = char_info.height;
+    build = char_info.build;
+
+    // Copy name until string terminator
+    mii_name = {};
+    for (std::size_t index = 0; index < char_info.name.size() - 1; index++) {
+        mii_name[index] = char_info.name[index];
+        if (mii_name[index] == 0) {
+            break;
+        }
+    }
+
+    region_information.character_set.Assign(char_info.font_region);
+
+    appearance_bits1.face_shape.Assign(char_info.faceline_type);
+    appearance_bits2.wrinkles.Assign(char_info.faceline_wrinkle);
+    appearance_bits2.makeup.Assign(char_info.faceline_make);
+
+    hair_style = char_info.hair_type;
+    appearance_bits3.flip_hair.Assign(char_info.hair_flip);
+
+    appearance_bits4.eye_type.Assign(char_info.eye_type);
+    appearance_bits4.eye_scale.Assign(char_info.eye_scale);
+    appearance_bits4.eye_vertical_stretch.Assign(char_info.eye_aspect);
+    appearance_bits4.eye_rotation.Assign(char_info.eye_rotate);
+    appearance_bits4.eye_spacing.Assign(char_info.eye_x);
+    appearance_bits4.eye_y_position.Assign(char_info.eye_y);
+
+    appearance_bits5.eyebrow_style.Assign(char_info.eyebrow_type);
+    appearance_bits5.eyebrow_scale.Assign(char_info.eyebrow_scale);
+    appearance_bits5.eyebrow_yscale.Assign(char_info.eyebrow_aspect);
+    appearance_bits5.eyebrow_rotation.Assign(char_info.eyebrow_rotate);
+    appearance_bits5.eyebrow_spacing.Assign(char_info.eyebrow_x);
+    appearance_bits5.eyebrow_y_position.Assign(char_info.eyebrow_y);
+
+    appearance_bits6.nose_type.Assign(char_info.nose_type);
+    appearance_bits6.nose_scale.Assign(char_info.nose_scale);
+    appearance_bits6.nose_y_position.Assign(char_info.nose_y);
+
+    appearance_bits7.mouth_type.Assign(char_info.mouth_type);
+    appearance_bits7.mouth_scale.Assign(char_info.mouth_scale);
+    appearance_bits7.mouth_horizontal_stretch.Assign(char_info.mouth_aspect);
+    appearance_bits8.mouth_y_position.Assign(char_info.mouth_y);
+
+    appearance_bits8.mustache_type.Assign(char_info.mustache_type);
+    appearance_bits9.mustache_scale.Assign(char_info.mustache_scale);
+    appearance_bits9.mustache_y_position.Assign(char_info.mustache_y);
+
+    appearance_bits9.bear_type.Assign(char_info.beard_type);
+
+    appearance_bits10.glasses_scale.Assign(char_info.glasses_scale);
+    appearance_bits10.glasses_y_position.Assign(char_info.glasses_y);
+
+    appearance_bits11.mole_enabled.Assign(char_info.mole_type);
+    appearance_bits11.mole_scale.Assign(char_info.mole_scale);
+    appearance_bits11.mole_x_position.Assign(char_info.mole_x);
+    appearance_bits11.mole_y_position.Assign(char_info.mole_y);
+
+    // These types are converted to V3 from a table
+    appearance_bits1.skin_color.Assign(RawData::FromVer3GetFacelineColor(char_info.faceline_color));
+    appearance_bits3.hair_color.Assign(RawData::FromVer3GetHairColor(char_info.hair_color));
+    appearance_bits4.eye_color.Assign(RawData::FromVer3GetEyeColor(char_info.eye_color));
+    appearance_bits5.eyebrow_color.Assign(RawData::FromVer3GetHairColor(char_info.eyebrow_color));
+    appearance_bits7.mouth_color.Assign(RawData::FromVer3GetMouthlineColor(char_info.mouth_color));
+    appearance_bits9.facial_hair_color.Assign(RawData::FromVer3GetHairColor(char_info.beard_color));
+    appearance_bits10.glasses_color.Assign(RawData::FromVer3GetGlassColor(char_info.glasses_color));
+    appearance_bits10.glasses_type.Assign(RawData::FromVer3GetGlassType(char_info.glasses_type));
+
+    crc = MiiUtil::CalculateCrc16(&version, sizeof(Ver3StoreData) - sizeof(u16));
+}
+
+u32 Ver3StoreData::IsValid() const {
+    bool is_valid = version == 0 || version == 3;
+
+    is_valid = is_valid && (mii_name[0] != 0);
+
+    is_valid = is_valid && (mii_information.birth_month < 13);
+    is_valid = is_valid && (mii_information.birth_day < 32);
+    is_valid = is_valid && (mii_information.favorite_color < 12);
+    is_valid = is_valid && (height < 128);
+    is_valid = is_valid && (build < 128);
+
+    is_valid = is_valid && (appearance_bits1.face_shape < 12);
+    is_valid = is_valid && (appearance_bits1.skin_color < 7);
+    is_valid = is_valid && (appearance_bits2.wrinkles < 12);
+    is_valid = is_valid && (appearance_bits2.makeup < 12);
+
+    is_valid = is_valid && (hair_style < 132);
+    is_valid = is_valid && (appearance_bits3.hair_color < 8);
+
+    is_valid = is_valid && (appearance_bits4.eye_type < 60);
+    is_valid = is_valid && (appearance_bits4.eye_color < 6);
+    is_valid = is_valid && (appearance_bits4.eye_scale < 8);
+    is_valid = is_valid && (appearance_bits4.eye_vertical_stretch < 7);
+    is_valid = is_valid && (appearance_bits4.eye_rotation < 8);
+    is_valid = is_valid && (appearance_bits4.eye_spacing < 13);
+    is_valid = is_valid && (appearance_bits4.eye_y_position < 19);
+
+    is_valid = is_valid && (appearance_bits5.eyebrow_style < 25);
+    is_valid = is_valid && (appearance_bits5.eyebrow_color < 8);
+    is_valid = is_valid && (appearance_bits5.eyebrow_scale < 9);
+    is_valid = is_valid && (appearance_bits5.eyebrow_yscale < 7);
+    is_valid = is_valid && (appearance_bits5.eyebrow_rotation < 12);
+    is_valid = is_valid && (appearance_bits5.eyebrow_spacing < 12);
+    is_valid = is_valid && (appearance_bits5.eyebrow_y_position < 19);
+
+    is_valid = is_valid && (appearance_bits6.nose_type < 18);
+    is_valid = is_valid && (appearance_bits6.nose_scale < 9);
+    is_valid = is_valid && (appearance_bits6.nose_y_position < 19);
+
+    is_valid = is_valid && (appearance_bits7.mouth_type < 36);
+    is_valid = is_valid && (appearance_bits7.mouth_color < 5);
+    is_valid = is_valid && (appearance_bits7.mouth_scale < 9);
+    is_valid = is_valid && (appearance_bits7.mouth_horizontal_stretch < 7);
+    is_valid = is_valid && (appearance_bits8.mouth_y_position < 19);
+
+    is_valid = is_valid && (appearance_bits8.mustache_type < 6);
+    is_valid = is_valid && (appearance_bits9.mustache_scale < 7);
+    is_valid = is_valid && (appearance_bits9.mustache_y_position < 17);
+
+    is_valid = is_valid && (appearance_bits9.bear_type < 6);
+    is_valid = is_valid && (appearance_bits9.facial_hair_color < 8);
+
+    is_valid = is_valid && (appearance_bits10.glasses_type < 9);
+    is_valid = is_valid && (appearance_bits10.glasses_color < 6);
+    is_valid = is_valid && (appearance_bits10.glasses_scale < 8);
+    is_valid = is_valid && (appearance_bits10.glasses_y_position < 21);
+
+    is_valid = is_valid && (appearance_bits11.mole_enabled < 2);
+    is_valid = is_valid && (appearance_bits11.mole_scale < 9);
+    is_valid = is_valid && (appearance_bits11.mole_x_position < 17);
+    is_valid = is_valid && (appearance_bits11.mole_y_position < 31);
+
+    return is_valid;
+}
+
+} // namespace Service::Mii

+ 10 - 3
src/core/hle/service/mii/types/ver3_store_data.h

@@ -4,10 +4,9 @@
 #pragma once
 
 #include "core/hle/service/mii/mii_types.h"
-#include "core/hle/service/mii/types/core_data.h"
-#include "core/hle/service/mii/types/store_data.h"
 
 namespace Service::Mii {
+class CharInfo;
 
 // This is nn::mii::Ver3StoreData
 // Based on citra HLE::Applets::MiiData and PretendoNetwork.
@@ -15,7 +14,15 @@ namespace Service::Mii {
 // https://github.com/PretendoNetwork/mii-js/blob/master/mii.js#L299
 
 #pragma pack(push, 4)
-struct Ver3StoreData {
+class Ver3StoreData {
+public:
+    // TODO: This function is wrong. It should use StoreData.
+    void BuildToStoreData(CharInfo& out_char_info) const;
+    // TODO: This function is wrong. It should use StoreData.
+    void BuildFromStoreData(const CharInfo& char_info);
+
+    u32 IsValid() const;
+
     u8 version;
     union {
         u8 raw;

+ 2 - 2
src/core/hle/service/nfc/common/device.cpp

@@ -834,7 +834,7 @@ Result NfcDevice::SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& registe
     }
 
     SetAmiiboName(settings, register_info.amiibo_name);
-    tag_data.owner_mii = manager.BuildFromStoreData(mii);
+    tag_data.owner_mii.BuildFromStoreData(mii);
     tag_data.mii_extension = manager.SetFromStoreData(mii);
     tag_data.unknown = 0;
     tag_data.unknown2 = {};
@@ -1466,7 +1466,7 @@ void NfcDevice::BuildAmiiboWithoutKeys(NFP::NTAG215File& stubbed_tag_data,
     SetAmiiboName(settings, {'y', 'u', 'z', 'u', 'A', 'm', 'i', 'i', 'b', 'o'});
     settings.settings.font_region.Assign(0);
     settings.init_date = GetAmiiboDate(GetCurrentPosixTime());
-    stubbed_tag_data.owner_mii = manager.BuildFromStoreData(manager.BuildBase(Mii::Gender::Male));
+    stubbed_tag_data.owner_mii.BuildFromStoreData(manager.BuildBase(Mii::Gender::Male));
 
     // Admin info
     settings.settings.amiibo_initialized.Assign(1);

+ 1 - 0
src/core/hle/service/nfp/nfp_types.h

@@ -7,6 +7,7 @@
 
 #include "common/swap.h"
 #include "core/hle/service/mii/types/char_info.h"
+#include "core/hle/service/mii/types/store_data.h"
 #include "core/hle/service/mii/types/ver3_store_data.h"
 #include "core/hle/service/nfc/nfc_types.h"