service: mii: Fix ver3 inconsistencies
This commit is contained in:
		@@ -98,23 +98,12 @@ CharInfo MiiManager::BuildDefault(std::size_t index) {
 | 
			
		||||
 | 
			
		||||
CharInfo MiiManager::ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const {
 | 
			
		||||
    CharInfo char_info{};
 | 
			
		||||
    mii_v3.BuildToStoreData(char_info);
 | 
			
		||||
    StoreData store_data{};
 | 
			
		||||
    mii_v3.BuildToStoreData(store_data);
 | 
			
		||||
    char_info.SetFromStoreData(store_data);
 | 
			
		||||
    return char_info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NfpStoreDataExtension MiiManager::SetFromStoreData(const CharInfo& mii) const {
 | 
			
		||||
    return {
 | 
			
		||||
        .faceline_color = static_cast<u8>(mii.GetFacelineColor() & 0xf),
 | 
			
		||||
        .hair_color = static_cast<u8>(mii.GetHairColor() & 0x7f),
 | 
			
		||||
        .eye_color = static_cast<u8>(mii.GetEyeColor() & 0x7f),
 | 
			
		||||
        .eyebrow_color = static_cast<u8>(mii.GetEyebrowColor() & 0x7f),
 | 
			
		||||
        .mouth_color = static_cast<u8>(mii.GetMouthColor() & 0x7f),
 | 
			
		||||
        .beard_color = static_cast<u8>(mii.GetBeardColor() & 0x7f),
 | 
			
		||||
        .glass_color = static_cast<u8>(mii.GetGlassColor() & 0x7f),
 | 
			
		||||
        .glass_type = static_cast<u8>(mii.GetGlassType() & 0x1f),
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<CharInfoElement> MiiManager::GetDefault(SourceFlag source_flag) {
 | 
			
		||||
    std::vector<CharInfoElement> result;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -30,9 +30,6 @@ public:
 | 
			
		||||
    std::vector<CharInfoElement> GetDefault(SourceFlag source_flag);
 | 
			
		||||
    Result GetIndex(const CharInfo& info, u32& index);
 | 
			
		||||
 | 
			
		||||
    // This is nn::mii::detail::NfpStoreDataExtentionRaw::SetFromStoreData
 | 
			
		||||
    NfpStoreDataExtension SetFromStoreData(const CharInfo& mii) const;
 | 
			
		||||
 | 
			
		||||
    struct MiiDatabase {
 | 
			
		||||
        u32 magic{}; // 'NFDB'
 | 
			
		||||
        std::array<StoreData, 0x64> miis{};
 | 
			
		||||
 
 | 
			
		||||
@@ -108,25 +108,9 @@ struct Nickname {
 | 
			
		||||
        }
 | 
			
		||||
        return index == MaxNameSize;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool operator==(const Nickname& name) {
 | 
			
		||||
        return data == name.data;
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(Nickname) == 0x14, "Nickname is an invalid size");
 | 
			
		||||
 | 
			
		||||
struct NfpStoreDataExtension {
 | 
			
		||||
    u8 faceline_color;
 | 
			
		||||
    u8 hair_color;
 | 
			
		||||
    u8 eye_color;
 | 
			
		||||
    u8 eyebrow_color;
 | 
			
		||||
    u8 mouth_color;
 | 
			
		||||
    u8 beard_color;
 | 
			
		||||
    u8 glass_color;
 | 
			
		||||
    u8 glass_type;
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(NfpStoreDataExtension) == 0x8, "NfpStoreDataExtension is an invalid size");
 | 
			
		||||
 | 
			
		||||
struct DefaultMii {
 | 
			
		||||
    u32 face_type{};
 | 
			
		||||
    u32 face_color{};
 | 
			
		||||
 
 | 
			
		||||
@@ -425,7 +425,7 @@ u8 CharInfo::GetMoleY() const {
 | 
			
		||||
 | 
			
		||||
bool CharInfo::operator==(const CharInfo& info) {
 | 
			
		||||
    bool is_identical = info.Verify() == 0;
 | 
			
		||||
    is_identical &= name == info.GetNickname();
 | 
			
		||||
    is_identical &= name.data == info.GetNickname().data;
 | 
			
		||||
    is_identical &= create_id == info.GetCreateId();
 | 
			
		||||
    is_identical &= font_region == info.GetFontRegion();
 | 
			
		||||
    is_identical &= favorite_color == info.GetFavoriteColor();
 | 
			
		||||
 
 | 
			
		||||
@@ -180,6 +180,206 @@ u32 StoreData::IsValid() const {
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetFontRegion(FontRegion value) {
 | 
			
		||||
    core_data.SetFontRegion(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetFavoriteColor(u8 value) {
 | 
			
		||||
    core_data.SetFavoriteColor(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetGender(Gender value) {
 | 
			
		||||
    core_data.SetGender(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetHeight(u8 value) {
 | 
			
		||||
    core_data.SetHeight(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetBuild(u8 value) {
 | 
			
		||||
    core_data.SetBuild(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetType(u8 value) {
 | 
			
		||||
    core_data.SetType(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetRegionMove(u8 value) {
 | 
			
		||||
    core_data.SetRegionMove(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetFacelineType(u8 value) {
 | 
			
		||||
    core_data.SetFacelineType(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetFacelineColor(u8 value) {
 | 
			
		||||
    core_data.SetFacelineColor(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetFacelineWrinkle(u8 value) {
 | 
			
		||||
    core_data.SetFacelineWrinkle(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetFacelineMake(u8 value) {
 | 
			
		||||
    core_data.SetFacelineMake(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetHairType(u8 value) {
 | 
			
		||||
    core_data.SetHairType(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetHairColor(u8 value) {
 | 
			
		||||
    core_data.SetHairColor(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetHairFlip(HairFlip value) {
 | 
			
		||||
    core_data.SetHairFlip(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetEyeType(u8 value) {
 | 
			
		||||
    core_data.SetEyeType(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetEyeColor(u8 value) {
 | 
			
		||||
    core_data.SetEyeColor(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetEyeScale(u8 value) {
 | 
			
		||||
    core_data.SetEyeScale(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetEyeAspect(u8 value) {
 | 
			
		||||
    core_data.SetEyeAspect(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetEyeRotate(u8 value) {
 | 
			
		||||
    core_data.SetEyeRotate(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetEyeX(u8 value) {
 | 
			
		||||
    core_data.SetEyeX(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetEyeY(u8 value) {
 | 
			
		||||
    core_data.SetEyeY(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetEyebrowType(u8 value) {
 | 
			
		||||
    core_data.SetEyebrowType(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetEyebrowColor(u8 value) {
 | 
			
		||||
    core_data.SetEyebrowColor(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetEyebrowScale(u8 value) {
 | 
			
		||||
    core_data.SetEyebrowScale(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetEyebrowAspect(u8 value) {
 | 
			
		||||
    core_data.SetEyebrowAspect(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetEyebrowRotate(u8 value) {
 | 
			
		||||
    core_data.SetEyebrowRotate(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetEyebrowX(u8 value) {
 | 
			
		||||
    core_data.SetEyebrowX(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetEyebrowY(u8 value) {
 | 
			
		||||
    core_data.SetEyebrowY(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetNoseType(u8 value) {
 | 
			
		||||
    core_data.SetNoseType(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetNoseScale(u8 value) {
 | 
			
		||||
    core_data.SetNoseScale(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetNoseY(u8 value) {
 | 
			
		||||
    core_data.SetNoseY(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetMouthType(u8 value) {
 | 
			
		||||
    core_data.SetMouthType(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetMouthColor(u8 value) {
 | 
			
		||||
    core_data.SetMouthColor(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetMouthScale(u8 value) {
 | 
			
		||||
    core_data.SetMouthScale(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetMouthAspect(u8 value) {
 | 
			
		||||
    core_data.SetMouthAspect(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetMouthY(u8 value) {
 | 
			
		||||
    core_data.SetMouthY(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetBeardColor(u8 value) {
 | 
			
		||||
    core_data.SetBeardColor(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetBeardType(BeardType value) {
 | 
			
		||||
    core_data.SetBeardType(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetMustacheType(MustacheType value) {
 | 
			
		||||
    core_data.SetMustacheType(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetMustacheScale(u8 value) {
 | 
			
		||||
    core_data.SetMustacheScale(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetMustacheY(u8 value) {
 | 
			
		||||
    core_data.SetMustacheY(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetGlassType(u8 value) {
 | 
			
		||||
    core_data.SetGlassType(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetGlassColor(u8 value) {
 | 
			
		||||
    core_data.SetGlassColor(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetGlassScale(u8 value) {
 | 
			
		||||
    core_data.SetGlassScale(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetGlassY(u8 value) {
 | 
			
		||||
    core_data.SetGlassY(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetMoleType(u8 value) {
 | 
			
		||||
    core_data.SetMoleType(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetMoleScale(u8 value) {
 | 
			
		||||
    core_data.SetMoleScale(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetMoleX(u8 value) {
 | 
			
		||||
    core_data.SetMoleX(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetMoleY(u8 value) {
 | 
			
		||||
    core_data.SetMoleY(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StoreData::SetNickname(Nickname value) {
 | 
			
		||||
    core_data.SetNickname(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Common::UUID StoreData::GetCreateId() const {
 | 
			
		||||
    return create_id;
 | 
			
		||||
}
 | 
			
		||||
@@ -386,7 +586,7 @@ Nickname StoreData::GetNickname() const {
 | 
			
		||||
 | 
			
		||||
bool StoreData::operator==(const StoreData& data) {
 | 
			
		||||
    bool is_identical = data.core_data.IsValid() == 0;
 | 
			
		||||
    is_identical &= core_data.GetNickname() == data.core_data.GetNickname();
 | 
			
		||||
    is_identical &= core_data.GetNickname().data == data.core_data.GetNickname().data;
 | 
			
		||||
    is_identical &= GetCreateId() == data.GetCreateId();
 | 
			
		||||
    is_identical &= GetFontRegion() == data.GetFontRegion();
 | 
			
		||||
    is_identical &= GetFavoriteColor() == data.GetFavoriteColor();
 | 
			
		||||
 
 | 
			
		||||
@@ -18,12 +18,62 @@ public:
 | 
			
		||||
    // nn::mii::detail::StoreDataRaw::BuildRandom
 | 
			
		||||
    void BuildRandom(Age age, Gender gender, Race race);
 | 
			
		||||
 | 
			
		||||
    void SetInvalidName();
 | 
			
		||||
 | 
			
		||||
    bool IsSpecial() const;
 | 
			
		||||
 | 
			
		||||
    u32 IsValid() const;
 | 
			
		||||
 | 
			
		||||
    void SetFontRegion(FontRegion value);
 | 
			
		||||
    void SetFavoriteColor(u8 value);
 | 
			
		||||
    void SetGender(Gender value);
 | 
			
		||||
    void SetHeight(u8 value);
 | 
			
		||||
    void SetBuild(u8 value);
 | 
			
		||||
    void SetType(u8 value);
 | 
			
		||||
    void SetRegionMove(u8 value);
 | 
			
		||||
    void SetFacelineType(u8 value);
 | 
			
		||||
    void SetFacelineColor(u8 value);
 | 
			
		||||
    void SetFacelineWrinkle(u8 value);
 | 
			
		||||
    void SetFacelineMake(u8 value);
 | 
			
		||||
    void SetHairType(u8 value);
 | 
			
		||||
    void SetHairColor(u8 value);
 | 
			
		||||
    void SetHairFlip(HairFlip value);
 | 
			
		||||
    void SetEyeType(u8 value);
 | 
			
		||||
    void SetEyeColor(u8 value);
 | 
			
		||||
    void SetEyeScale(u8 value);
 | 
			
		||||
    void SetEyeAspect(u8 value);
 | 
			
		||||
    void SetEyeRotate(u8 value);
 | 
			
		||||
    void SetEyeX(u8 value);
 | 
			
		||||
    void SetEyeY(u8 value);
 | 
			
		||||
    void SetEyebrowType(u8 value);
 | 
			
		||||
    void SetEyebrowColor(u8 value);
 | 
			
		||||
    void SetEyebrowScale(u8 value);
 | 
			
		||||
    void SetEyebrowAspect(u8 value);
 | 
			
		||||
    void SetEyebrowRotate(u8 value);
 | 
			
		||||
    void SetEyebrowX(u8 value);
 | 
			
		||||
    void SetEyebrowY(u8 value);
 | 
			
		||||
    void SetNoseType(u8 value);
 | 
			
		||||
    void SetNoseScale(u8 value);
 | 
			
		||||
    void SetNoseY(u8 value);
 | 
			
		||||
    void SetMouthType(u8 value);
 | 
			
		||||
    void SetMouthColor(u8 value);
 | 
			
		||||
    void SetMouthScale(u8 value);
 | 
			
		||||
    void SetMouthAspect(u8 value);
 | 
			
		||||
    void SetMouthY(u8 value);
 | 
			
		||||
    void SetBeardColor(u8 value);
 | 
			
		||||
    void SetBeardType(BeardType value);
 | 
			
		||||
    void SetMustacheType(MustacheType value);
 | 
			
		||||
    void SetMustacheScale(u8 value);
 | 
			
		||||
    void SetMustacheY(u8 value);
 | 
			
		||||
    void SetGlassType(u8 value);
 | 
			
		||||
    void SetGlassColor(u8 value);
 | 
			
		||||
    void SetGlassScale(u8 value);
 | 
			
		||||
    void SetGlassY(u8 value);
 | 
			
		||||
    void SetMoleType(u8 value);
 | 
			
		||||
    void SetMoleScale(u8 value);
 | 
			
		||||
    void SetMoleX(u8 value);
 | 
			
		||||
    void SetMoleY(u8 value);
 | 
			
		||||
    void SetNickname(Nickname nickname);
 | 
			
		||||
    void SetInvalidName();
 | 
			
		||||
 | 
			
		||||
    Common::UUID GetCreateId() const;
 | 
			
		||||
    FontRegion GetFontRegion() const;
 | 
			
		||||
    u8 GetFavoriteColor() const;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,160 +2,180 @@
 | 
			
		||||
// 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 {
 | 
			
		||||
 | 
			
		||||
void Ver3StoreData::BuildToStoreData(CharInfo& out_char_info) const {
 | 
			
		||||
void NfpStoreDataExtension::SetFromStoreData(const StoreData& store_data) {
 | 
			
		||||
    faceline_color = static_cast<u8>(store_data.GetFacelineColor() & 0xf);
 | 
			
		||||
    hair_color = static_cast<u8>(store_data.GetHairColor() & 0x7f);
 | 
			
		||||
    eye_color = static_cast<u8>(store_data.GetEyeColor() & 0x7f);
 | 
			
		||||
    eyebrow_color = static_cast<u8>(store_data.GetEyebrowColor() & 0x7f);
 | 
			
		||||
    mouth_color = static_cast<u8>(store_data.GetMouthColor() & 0x7f);
 | 
			
		||||
    beard_color = static_cast<u8>(store_data.GetBeardColor() & 0x7f);
 | 
			
		||||
    glass_color = static_cast<u8>(store_data.GetGlassColor() & 0x7f);
 | 
			
		||||
    glass_type = static_cast<u8>(store_data.GetGlassType() & 0x1f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Ver3StoreData::BuildToStoreData(StoreData& out_store_data) const {
 | 
			
		||||
    out_store_data.BuildBase(Gender::Male);
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
    out_store_data.SetGender(static_cast<Gender>(static_cast<u8>(mii_information.gender)));
 | 
			
		||||
    out_store_data.SetFavoriteColor(static_cast<u8>(mii_information.favorite_color));
 | 
			
		||||
    out_store_data.SetHeight(height);
 | 
			
		||||
    out_store_data.SetBuild(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) {
 | 
			
		||||
    Nickname name = {};
 | 
			
		||||
    for (std::size_t index = 0; index < name.data.size() - 1; index++) {
 | 
			
		||||
        name.data[index] = mii_name[index];
 | 
			
		||||
        if (name.data[index] == 0) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    out_char_info.font_region = region_information.character_set;
 | 
			
		||||
    out_store_data.SetNickname(name);
 | 
			
		||||
    out_store_data.SetFontRegion(
 | 
			
		||||
        static_cast<FontRegion>(static_cast<u8>(region_information.font_region)));
 | 
			
		||||
 | 
			
		||||
    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_store_data.SetFacelineType(appearance_bits1.faceline_type);
 | 
			
		||||
    out_store_data.SetFacelineColor(appearance_bits1.faceline_color);
 | 
			
		||||
    out_store_data.SetFacelineWrinkle(appearance_bits2.faceline_wrinkle);
 | 
			
		||||
    out_store_data.SetFacelineMake(appearance_bits2.faceline_make);
 | 
			
		||||
 | 
			
		||||
    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_store_data.SetHairType(hair_type);
 | 
			
		||||
    out_store_data.SetHairColor(appearance_bits3.hair_color);
 | 
			
		||||
    out_store_data.SetHairFlip(static_cast<HairFlip>(static_cast<u8>(appearance_bits3.hair_flip)));
 | 
			
		||||
 | 
			
		||||
    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_store_data.SetEyeType(static_cast<u8>(appearance_bits4.eye_type));
 | 
			
		||||
    out_store_data.SetEyeColor(static_cast<u8>(appearance_bits4.eye_color));
 | 
			
		||||
    out_store_data.SetEyeScale(static_cast<u8>(appearance_bits4.eye_scale));
 | 
			
		||||
    out_store_data.SetEyeAspect(static_cast<u8>(appearance_bits4.eye_aspect));
 | 
			
		||||
    out_store_data.SetEyeRotate(static_cast<u8>(appearance_bits4.eye_rotate));
 | 
			
		||||
    out_store_data.SetEyeX(static_cast<u8>(appearance_bits4.eye_x));
 | 
			
		||||
    out_store_data.SetEyeY(static_cast<u8>(appearance_bits4.eye_y));
 | 
			
		||||
 | 
			
		||||
    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_store_data.SetEyebrowType(static_cast<u8>(appearance_bits5.eyebrow_type));
 | 
			
		||||
    out_store_data.SetEyebrowColor(static_cast<u8>(appearance_bits5.eyebrow_color));
 | 
			
		||||
    out_store_data.SetEyebrowScale(static_cast<u8>(appearance_bits5.eyebrow_scale));
 | 
			
		||||
    out_store_data.SetEyebrowAspect(static_cast<u8>(appearance_bits5.eyebrow_aspect));
 | 
			
		||||
    out_store_data.SetEyebrowRotate(static_cast<u8>(appearance_bits5.eyebrow_rotate));
 | 
			
		||||
    out_store_data.SetEyebrowX(static_cast<u8>(appearance_bits5.eyebrow_x));
 | 
			
		||||
    out_store_data.SetEyebrowY(static_cast<u8>(appearance_bits5.eyebrow_y));
 | 
			
		||||
 | 
			
		||||
    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_store_data.SetNoseType(static_cast<u8>(appearance_bits6.nose_type));
 | 
			
		||||
    out_store_data.SetNoseScale(static_cast<u8>(appearance_bits6.nose_scale));
 | 
			
		||||
    out_store_data.SetNoseY(static_cast<u8>(appearance_bits6.nose_y));
 | 
			
		||||
 | 
			
		||||
    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_store_data.SetMouthType(static_cast<u8>(appearance_bits7.mouth_type));
 | 
			
		||||
    out_store_data.SetMouthColor(static_cast<u8>(appearance_bits7.mouth_color));
 | 
			
		||||
    out_store_data.SetMouthScale(static_cast<u8>(appearance_bits7.mouth_scale));
 | 
			
		||||
    out_store_data.SetMouthAspect(static_cast<u8>(appearance_bits7.mouth_aspect));
 | 
			
		||||
    out_store_data.SetMouthY(static_cast<u8>(appearance_bits8.mouth_y));
 | 
			
		||||
 | 
			
		||||
    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_store_data.SetMustacheType(
 | 
			
		||||
        static_cast<MustacheType>(static_cast<u8>(appearance_bits8.mustache_type)));
 | 
			
		||||
    out_store_data.SetMustacheScale(static_cast<u8>(appearance_bits9.mustache_scale));
 | 
			
		||||
    out_store_data.SetMustacheY(static_cast<u8>(appearance_bits9.mustache_y));
 | 
			
		||||
 | 
			
		||||
    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_store_data.SetBeardType(
 | 
			
		||||
        static_cast<BeardType>(static_cast<u8>(appearance_bits9.beard_type)));
 | 
			
		||||
    out_store_data.SetBeardColor(static_cast<u8>(appearance_bits9.beard_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_store_data.SetGlassType(static_cast<u8>(appearance_bits10.glass_type));
 | 
			
		||||
    out_store_data.SetGlassColor(static_cast<u8>(appearance_bits10.glass_color));
 | 
			
		||||
    out_store_data.SetGlassScale(static_cast<u8>(appearance_bits10.glass_scale));
 | 
			
		||||
    out_store_data.SetGlassY(static_cast<u8>(appearance_bits10.glass_y));
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    out_store_data.SetMoleType(static_cast<u8>(appearance_bits11.mole_type));
 | 
			
		||||
    out_store_data.SetMoleScale(static_cast<u8>(appearance_bits11.mole_scale));
 | 
			
		||||
    out_store_data.SetMoleX(static_cast<u8>(appearance_bits11.mole_x));
 | 
			
		||||
    out_store_data.SetMoleY(static_cast<u8>(appearance_bits11.mole_y));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Ver3StoreData::BuildFromStoreData(const CharInfo& char_info) {
 | 
			
		||||
void Ver3StoreData::BuildFromStoreData(const StoreData& store_data) {
 | 
			
		||||
    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;
 | 
			
		||||
    mii_information.gender.Assign(store_data.GetGender());
 | 
			
		||||
    mii_information.favorite_color.Assign(store_data.GetFavoriteColor());
 | 
			
		||||
    height = store_data.GetHeight();
 | 
			
		||||
    build = store_data.GetBuild();
 | 
			
		||||
 | 
			
		||||
    // 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];
 | 
			
		||||
    for (std::size_t index = 0; index < store_data.GetNickname().data.size() - 1; index++) {
 | 
			
		||||
        mii_name[index] = store_data.GetNickname().data[index];
 | 
			
		||||
        if (mii_name[index] == 0) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    region_information.character_set.Assign(char_info.font_region);
 | 
			
		||||
    region_information.font_region.Assign(static_cast<u8>(store_data.GetFontRegion()));
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    appearance_bits1.faceline_type.Assign(store_data.GetFacelineType());
 | 
			
		||||
    appearance_bits2.faceline_wrinkle.Assign(store_data.GetFacelineWrinkle());
 | 
			
		||||
    appearance_bits2.faceline_make.Assign(store_data.GetFacelineMake());
 | 
			
		||||
 | 
			
		||||
    hair_style = char_info.hair_type;
 | 
			
		||||
    appearance_bits3.flip_hair.Assign(char_info.hair_flip);
 | 
			
		||||
    hair_type = store_data.GetHairType();
 | 
			
		||||
    appearance_bits3.hair_flip.Assign(store_data.GetHairFlip());
 | 
			
		||||
 | 
			
		||||
    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_bits4.eye_type.Assign(store_data.GetEyeType());
 | 
			
		||||
    appearance_bits4.eye_scale.Assign(store_data.GetEyeScale());
 | 
			
		||||
    appearance_bits4.eye_aspect.Assign(store_data.GetEyebrowAspect());
 | 
			
		||||
    appearance_bits4.eye_rotate.Assign(store_data.GetEyeRotate());
 | 
			
		||||
    appearance_bits4.eye_x.Assign(store_data.GetEyeX());
 | 
			
		||||
    appearance_bits4.eye_y.Assign(store_data.GetEyeY());
 | 
			
		||||
 | 
			
		||||
    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_bits5.eyebrow_type.Assign(store_data.GetEyebrowType());
 | 
			
		||||
    appearance_bits5.eyebrow_scale.Assign(store_data.GetEyebrowScale());
 | 
			
		||||
    appearance_bits5.eyebrow_aspect.Assign(store_data.GetEyebrowAspect());
 | 
			
		||||
    appearance_bits5.eyebrow_rotate.Assign(store_data.GetEyebrowRotate());
 | 
			
		||||
    appearance_bits5.eyebrow_x.Assign(store_data.GetEyebrowX());
 | 
			
		||||
    appearance_bits5.eyebrow_y.Assign(store_data.GetEyebrowY());
 | 
			
		||||
 | 
			
		||||
    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_bits6.nose_type.Assign(store_data.GetNoseType());
 | 
			
		||||
    appearance_bits6.nose_scale.Assign(store_data.GetNoseScale());
 | 
			
		||||
    appearance_bits6.nose_y.Assign(store_data.GetNoseY());
 | 
			
		||||
 | 
			
		||||
    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_bits7.mouth_type.Assign(store_data.GetMouthType());
 | 
			
		||||
    appearance_bits7.mouth_scale.Assign(store_data.GetMouthScale());
 | 
			
		||||
    appearance_bits7.mouth_aspect.Assign(store_data.GetMouthAspect());
 | 
			
		||||
    appearance_bits8.mouth_y.Assign(store_data.GetMouthY());
 | 
			
		||||
 | 
			
		||||
    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_bits8.mustache_type.Assign(store_data.GetMustacheType());
 | 
			
		||||
    appearance_bits9.mustache_scale.Assign(store_data.GetMustacheScale());
 | 
			
		||||
    appearance_bits9.mustache_y.Assign(store_data.GetMustacheY());
 | 
			
		||||
 | 
			
		||||
    appearance_bits9.bear_type.Assign(char_info.beard_type);
 | 
			
		||||
    appearance_bits9.beard_type.Assign(store_data.GetBeardType());
 | 
			
		||||
 | 
			
		||||
    appearance_bits10.glasses_scale.Assign(char_info.glasses_scale);
 | 
			
		||||
    appearance_bits10.glasses_y_position.Assign(char_info.glasses_y);
 | 
			
		||||
    appearance_bits10.glass_scale.Assign(store_data.GetGlassScale());
 | 
			
		||||
    appearance_bits10.glass_y.Assign(store_data.GetGlassY());
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
    appearance_bits11.mole_type.Assign(store_data.GetMoleType());
 | 
			
		||||
    appearance_bits11.mole_scale.Assign(store_data.GetMoleScale());
 | 
			
		||||
    appearance_bits11.mole_x.Assign(store_data.GetMoleX());
 | 
			
		||||
    appearance_bits11.mole_y.Assign(store_data.GetMoleY());
 | 
			
		||||
 | 
			
		||||
    // 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));
 | 
			
		||||
    appearance_bits1.faceline_color.Assign(
 | 
			
		||||
        RawData::FromVer3GetFacelineColor(store_data.GetFacelineColor()));
 | 
			
		||||
    appearance_bits3.hair_color.Assign(RawData::FromVer3GetHairColor(store_data.GetHairColor()));
 | 
			
		||||
    appearance_bits4.eye_color.Assign(RawData::FromVer3GetEyeColor(store_data.GetEyeColor()));
 | 
			
		||||
    appearance_bits5.eyebrow_color.Assign(
 | 
			
		||||
        RawData::FromVer3GetHairColor(store_data.GetEyebrowColor()));
 | 
			
		||||
    appearance_bits7.mouth_color.Assign(
 | 
			
		||||
        RawData::FromVer3GetMouthlineColor(store_data.GetMouthColor()));
 | 
			
		||||
    appearance_bits9.beard_color.Assign(RawData::FromVer3GetHairColor(store_data.GetBeardColor()));
 | 
			
		||||
    appearance_bits10.glass_color.Assign(
 | 
			
		||||
        RawData::FromVer3GetGlassColor(store_data.GetGlassColor()));
 | 
			
		||||
    appearance_bits10.glass_type.Assign(RawData::FromVer3GetGlassType(store_data.GetGlassType()));
 | 
			
		||||
 | 
			
		||||
    crc = MiiUtil::CalculateCrc16(&version, sizeof(Ver3StoreData) - sizeof(u16));
 | 
			
		||||
}
 | 
			
		||||
@@ -171,56 +191,56 @@ u32 Ver3StoreData::IsValid() const {
 | 
			
		||||
    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 && (appearance_bits1.faceline_type < 12);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits1.faceline_color < 7);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits2.faceline_wrinkle < 12);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits2.faceline_make < 12);
 | 
			
		||||
 | 
			
		||||
    is_valid = is_valid && (hair_style < 132);
 | 
			
		||||
    is_valid = is_valid && (hair_type < 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_bits4.eye_aspect < 7);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits4.eye_rotate < 8);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits4.eye_x < 13);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits4.eye_y < 19);
 | 
			
		||||
 | 
			
		||||
    is_valid = is_valid && (appearance_bits5.eyebrow_style < 25);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits5.eyebrow_type < 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_bits5.eyebrow_aspect < 7);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits5.eyebrow_rotate < 12);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits5.eyebrow_x < 12);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits5.eyebrow_y < 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_bits6.nose_y < 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_bits7.mouth_aspect < 7);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits8.mouth_y < 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.mustache_y < 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_bits9.beard_type < 6);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits9.beard_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_bits10.glass_type < 9);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits10.glass_color < 6);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits10.glass_scale < 8);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits10.glass_y < 21);
 | 
			
		||||
 | 
			
		||||
    is_valid = is_valid && (appearance_bits11.mole_enabled < 2);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits11.mole_type < 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);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits11.mole_x < 17);
 | 
			
		||||
    is_valid = is_valid && (appearance_bits11.mole_y < 31);
 | 
			
		||||
 | 
			
		||||
    return is_valid;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,20 +6,32 @@
 | 
			
		||||
#include "core/hle/service/mii/mii_types.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::Mii {
 | 
			
		||||
class CharInfo;
 | 
			
		||||
class StoreData;
 | 
			
		||||
 | 
			
		||||
// This is nn::mii::Ver3StoreData
 | 
			
		||||
// Based on citra HLE::Applets::MiiData and PretendoNetwork.
 | 
			
		||||
// https://github.com/citra-emu/citra/blob/master/src/core/hle/applets/mii_selector.h#L48
 | 
			
		||||
// https://github.com/PretendoNetwork/mii-js/blob/master/mii.js#L299
 | 
			
		||||
 | 
			
		||||
struct NfpStoreDataExtension {
 | 
			
		||||
    void SetFromStoreData(const StoreData& store_data);
 | 
			
		||||
 | 
			
		||||
    u8 faceline_color;
 | 
			
		||||
    u8 hair_color;
 | 
			
		||||
    u8 eye_color;
 | 
			
		||||
    u8 eyebrow_color;
 | 
			
		||||
    u8 mouth_color;
 | 
			
		||||
    u8 beard_color;
 | 
			
		||||
    u8 glass_color;
 | 
			
		||||
    u8 glass_type;
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(NfpStoreDataExtension) == 0x8, "NfpStoreDataExtension is an invalid size");
 | 
			
		||||
 | 
			
		||||
#pragma pack(push, 4)
 | 
			
		||||
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);
 | 
			
		||||
    void BuildToStoreData(StoreData& out_store_data) const;
 | 
			
		||||
    void BuildFromStoreData(const StoreData& store_data);
 | 
			
		||||
 | 
			
		||||
    u32 IsValid() const;
 | 
			
		||||
 | 
			
		||||
@@ -30,7 +42,7 @@ public:
 | 
			
		||||
        BitField<0, 1, u8> allow_copying;
 | 
			
		||||
        BitField<1, 1, u8> profanity_flag;
 | 
			
		||||
        BitField<2, 2, u8> region_lock;
 | 
			
		||||
        BitField<4, 2, u8> character_set;
 | 
			
		||||
        BitField<4, 2, u8> font_region;
 | 
			
		||||
    } region_information;
 | 
			
		||||
    u16_be mii_id;
 | 
			
		||||
    u64_be system_id;
 | 
			
		||||
@@ -53,21 +65,21 @@ public:
 | 
			
		||||
        u8 raw;
 | 
			
		||||
 | 
			
		||||
        BitField<0, 1, u8> disable_sharing;
 | 
			
		||||
        BitField<1, 4, u8> face_shape;
 | 
			
		||||
        BitField<5, 3, u8> skin_color;
 | 
			
		||||
        BitField<1, 4, u8> faceline_type;
 | 
			
		||||
        BitField<5, 3, u8> faceline_color;
 | 
			
		||||
    } appearance_bits1;
 | 
			
		||||
    union {
 | 
			
		||||
        u8 raw;
 | 
			
		||||
 | 
			
		||||
        BitField<0, 4, u8> wrinkles;
 | 
			
		||||
        BitField<4, 4, u8> makeup;
 | 
			
		||||
        BitField<0, 4, u8> faceline_wrinkle;
 | 
			
		||||
        BitField<4, 4, u8> faceline_make;
 | 
			
		||||
    } appearance_bits2;
 | 
			
		||||
    u8 hair_style;
 | 
			
		||||
    u8 hair_type;
 | 
			
		||||
    union {
 | 
			
		||||
        u8 raw;
 | 
			
		||||
 | 
			
		||||
        BitField<0, 3, u8> hair_color;
 | 
			
		||||
        BitField<3, 1, u8> flip_hair;
 | 
			
		||||
        BitField<3, 1, u8> hair_flip;
 | 
			
		||||
    } appearance_bits3;
 | 
			
		||||
    union {
 | 
			
		||||
        u32 raw;
 | 
			
		||||
@@ -75,28 +87,28 @@ public:
 | 
			
		||||
        BitField<0, 6, u32> eye_type;
 | 
			
		||||
        BitField<6, 3, u32> eye_color;
 | 
			
		||||
        BitField<9, 4, u32> eye_scale;
 | 
			
		||||
        BitField<13, 3, u32> eye_vertical_stretch;
 | 
			
		||||
        BitField<16, 5, u32> eye_rotation;
 | 
			
		||||
        BitField<21, 4, u32> eye_spacing;
 | 
			
		||||
        BitField<25, 5, u32> eye_y_position;
 | 
			
		||||
        BitField<13, 3, u32> eye_aspect;
 | 
			
		||||
        BitField<16, 5, u32> eye_rotate;
 | 
			
		||||
        BitField<21, 4, u32> eye_x;
 | 
			
		||||
        BitField<25, 5, u32> eye_y;
 | 
			
		||||
    } appearance_bits4;
 | 
			
		||||
    union {
 | 
			
		||||
        u32 raw;
 | 
			
		||||
 | 
			
		||||
        BitField<0, 5, u32> eyebrow_style;
 | 
			
		||||
        BitField<0, 5, u32> eyebrow_type;
 | 
			
		||||
        BitField<5, 3, u32> eyebrow_color;
 | 
			
		||||
        BitField<8, 4, u32> eyebrow_scale;
 | 
			
		||||
        BitField<12, 3, u32> eyebrow_yscale;
 | 
			
		||||
        BitField<16, 4, u32> eyebrow_rotation;
 | 
			
		||||
        BitField<21, 4, u32> eyebrow_spacing;
 | 
			
		||||
        BitField<25, 5, u32> eyebrow_y_position;
 | 
			
		||||
        BitField<12, 3, u32> eyebrow_aspect;
 | 
			
		||||
        BitField<16, 4, u32> eyebrow_rotate;
 | 
			
		||||
        BitField<21, 4, u32> eyebrow_x;
 | 
			
		||||
        BitField<25, 5, u32> eyebrow_y;
 | 
			
		||||
    } appearance_bits5;
 | 
			
		||||
    union {
 | 
			
		||||
        u16 raw;
 | 
			
		||||
 | 
			
		||||
        BitField<0, 5, u16> nose_type;
 | 
			
		||||
        BitField<5, 4, u16> nose_scale;
 | 
			
		||||
        BitField<9, 5, u16> nose_y_position;
 | 
			
		||||
        BitField<9, 5, u16> nose_y;
 | 
			
		||||
    } appearance_bits6;
 | 
			
		||||
    union {
 | 
			
		||||
        u16 raw;
 | 
			
		||||
@@ -104,38 +116,38 @@ public:
 | 
			
		||||
        BitField<0, 6, u16> mouth_type;
 | 
			
		||||
        BitField<6, 3, u16> mouth_color;
 | 
			
		||||
        BitField<9, 4, u16> mouth_scale;
 | 
			
		||||
        BitField<13, 3, u16> mouth_horizontal_stretch;
 | 
			
		||||
        BitField<13, 3, u16> mouth_aspect;
 | 
			
		||||
    } appearance_bits7;
 | 
			
		||||
    union {
 | 
			
		||||
        u8 raw;
 | 
			
		||||
 | 
			
		||||
        BitField<0, 5, u8> mouth_y_position;
 | 
			
		||||
        BitField<0, 5, u8> mouth_y;
 | 
			
		||||
        BitField<5, 3, u8> mustache_type;
 | 
			
		||||
    } appearance_bits8;
 | 
			
		||||
    u8 allow_copying;
 | 
			
		||||
    union {
 | 
			
		||||
        u16 raw;
 | 
			
		||||
 | 
			
		||||
        BitField<0, 3, u16> bear_type;
 | 
			
		||||
        BitField<3, 3, u16> facial_hair_color;
 | 
			
		||||
        BitField<0, 3, u16> beard_type;
 | 
			
		||||
        BitField<3, 3, u16> beard_color;
 | 
			
		||||
        BitField<6, 4, u16> mustache_scale;
 | 
			
		||||
        BitField<10, 5, u16> mustache_y_position;
 | 
			
		||||
        BitField<10, 5, u16> mustache_y;
 | 
			
		||||
    } appearance_bits9;
 | 
			
		||||
    union {
 | 
			
		||||
        u16 raw;
 | 
			
		||||
 | 
			
		||||
        BitField<0, 4, u16> glasses_type;
 | 
			
		||||
        BitField<4, 3, u16> glasses_color;
 | 
			
		||||
        BitField<7, 4, u16> glasses_scale;
 | 
			
		||||
        BitField<11, 5, u16> glasses_y_position;
 | 
			
		||||
        BitField<0, 4, u16> glass_type;
 | 
			
		||||
        BitField<4, 3, u16> glass_color;
 | 
			
		||||
        BitField<7, 4, u16> glass_scale;
 | 
			
		||||
        BitField<11, 5, u16> glass_y;
 | 
			
		||||
    } appearance_bits10;
 | 
			
		||||
    union {
 | 
			
		||||
        u16 raw;
 | 
			
		||||
 | 
			
		||||
        BitField<0, 1, u16> mole_enabled;
 | 
			
		||||
        BitField<0, 1, u16> mole_type;
 | 
			
		||||
        BitField<1, 4, u16> mole_scale;
 | 
			
		||||
        BitField<5, 5, u16> mole_x_position;
 | 
			
		||||
        BitField<10, 5, u16> mole_y_position;
 | 
			
		||||
        BitField<5, 5, u16> mole_x;
 | 
			
		||||
        BitField<10, 5, u16> mole_y;
 | 
			
		||||
    } appearance_bits11;
 | 
			
		||||
 | 
			
		||||
    std::array<u16_le, 0xA> author_name;
 | 
			
		||||
 
 | 
			
		||||
@@ -824,8 +824,11 @@ Result NfcDevice::SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& registe
 | 
			
		||||
        return ResultWrongDeviceState;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Service::Mii::MiiManager manager;
 | 
			
		||||
    const auto mii = manager.BuildBase(Mii::Gender::Male);
 | 
			
		||||
    Service::Mii::StoreData store_data{};
 | 
			
		||||
    Service::Mii::NfpStoreDataExtension extension{};
 | 
			
		||||
    store_data.BuildBase(Mii::Gender::Male);
 | 
			
		||||
    extension.SetFromStoreData(store_data);
 | 
			
		||||
 | 
			
		||||
    auto& settings = tag_data.settings;
 | 
			
		||||
 | 
			
		||||
    if (tag_data.settings.settings.amiibo_initialized == 0) {
 | 
			
		||||
@@ -834,8 +837,8 @@ Result NfcDevice::SetRegisterInfoPrivate(const NFP::RegisterInfoPrivate& registe
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SetAmiiboName(settings, register_info.amiibo_name);
 | 
			
		||||
    tag_data.owner_mii.BuildFromStoreData(mii);
 | 
			
		||||
    tag_data.mii_extension = manager.SetFromStoreData(mii);
 | 
			
		||||
    tag_data.owner_mii.BuildFromStoreData(store_data);
 | 
			
		||||
    tag_data.mii_extension = extension;
 | 
			
		||||
    tag_data.unknown = 0;
 | 
			
		||||
    tag_data.unknown2 = {};
 | 
			
		||||
    settings.country_code_id = 0;
 | 
			
		||||
@@ -1452,7 +1455,7 @@ void NfcDevice::UpdateRegisterInfoCrc() {
 | 
			
		||||
 | 
			
		||||
void NfcDevice::BuildAmiiboWithoutKeys(NFP::NTAG215File& stubbed_tag_data,
 | 
			
		||||
                                       const NFP::EncryptedNTAG215File& encrypted_file) const {
 | 
			
		||||
    Service::Mii::MiiManager manager;
 | 
			
		||||
    Service::Mii::StoreData store_data{};
 | 
			
		||||
    auto& settings = stubbed_tag_data.settings;
 | 
			
		||||
 | 
			
		||||
    stubbed_tag_data = NFP::AmiiboCrypto::NfcDataToEncodedData(encrypted_file);
 | 
			
		||||
@@ -1466,7 +1469,8 @@ 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.BuildFromStoreData(manager.BuildBase(Mii::Gender::Male));
 | 
			
		||||
    store_data.BuildBase(Mii::Gender::Male);
 | 
			
		||||
    stubbed_tag_data.owner_mii.BuildFromStoreData(store_data);
 | 
			
		||||
 | 
			
		||||
    // Admin info
 | 
			
		||||
    settings.settings.amiibo_initialized.Assign(1);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user