service: nfp: Convert mii colors to v3

This commit is contained in:
Narr the Reg 2023-03-15 01:39:11 -06:00
parent 026fe2e4f4
commit 5031f5b8b0
6 changed files with 100 additions and 15 deletions

View File

@ -510,7 +510,7 @@ CharInfo MiiManager::ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const {
return mii; return mii;
} }
Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const { Ver3StoreData MiiManager::BuildFromStoreData(const CharInfo& mii) const {
Service::Mii::MiiManager manager; Service::Mii::MiiManager manager;
Ver3StoreData mii_v3{}; Ver3StoreData mii_v3{};
@ -534,16 +534,13 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
mii_v3.region_information.character_set.Assign(mii.font_region); mii_v3.region_information.character_set.Assign(mii.font_region);
mii_v3.appearance_bits1.face_shape.Assign(mii.faceline_type); mii_v3.appearance_bits1.face_shape.Assign(mii.faceline_type);
mii_v3.appearance_bits1.skin_color.Assign(mii.faceline_color);
mii_v3.appearance_bits2.wrinkles.Assign(mii.faceline_wrinkle); mii_v3.appearance_bits2.wrinkles.Assign(mii.faceline_wrinkle);
mii_v3.appearance_bits2.makeup.Assign(mii.faceline_make); mii_v3.appearance_bits2.makeup.Assign(mii.faceline_make);
mii_v3.hair_style = mii.hair_type; mii_v3.hair_style = mii.hair_type;
mii_v3.appearance_bits3.hair_color.Assign(mii.hair_color);
mii_v3.appearance_bits3.flip_hair.Assign(mii.hair_flip); 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_type.Assign(mii.eye_type);
mii_v3.appearance_bits4.eye_color.Assign(mii.eye_color);
mii_v3.appearance_bits4.eye_scale.Assign(mii.eye_scale); 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_vertical_stretch.Assign(mii.eye_aspect);
mii_v3.appearance_bits4.eye_rotation.Assign(mii.eye_rotate); mii_v3.appearance_bits4.eye_rotation.Assign(mii.eye_rotate);
@ -551,7 +548,6 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
mii_v3.appearance_bits4.eye_y_position.Assign(mii.eye_y); 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_style.Assign(mii.eyebrow_type);
mii_v3.appearance_bits5.eyebrow_color.Assign(mii.eyebrow_color);
mii_v3.appearance_bits5.eyebrow_scale.Assign(mii.eyebrow_scale); 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_yscale.Assign(mii.eyebrow_aspect);
mii_v3.appearance_bits5.eyebrow_rotation.Assign(mii.eyebrow_rotate); mii_v3.appearance_bits5.eyebrow_rotation.Assign(mii.eyebrow_rotate);
@ -563,7 +559,6 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
mii_v3.appearance_bits6.nose_y_position.Assign(mii.nose_y); 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_type.Assign(mii.mouth_type);
mii_v3.appearance_bits7.mouth_color.Assign(mii.mouth_color);
mii_v3.appearance_bits7.mouth_scale.Assign(mii.mouth_scale); mii_v3.appearance_bits7.mouth_scale.Assign(mii.mouth_scale);
mii_v3.appearance_bits7.mouth_horizontal_stretch.Assign(mii.mouth_aspect); 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.mouth_y_position.Assign(mii.mouth_y);
@ -573,10 +568,7 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
mii_v3.appearance_bits9.mustache_y_position.Assign(mii.mustache_y); mii_v3.appearance_bits9.mustache_y_position.Assign(mii.mustache_y);
mii_v3.appearance_bits9.bear_type.Assign(mii.beard_type); mii_v3.appearance_bits9.bear_type.Assign(mii.beard_type);
mii_v3.appearance_bits9.facial_hair_color.Assign(mii.beard_color);
mii_v3.appearance_bits10.glasses_type.Assign(mii.glasses_type);
mii_v3.appearance_bits10.glasses_color.Assign(mii.glasses_color);
mii_v3.appearance_bits10.glasses_scale.Assign(mii.glasses_scale); mii_v3.appearance_bits10.glasses_scale.Assign(mii.glasses_scale);
mii_v3.appearance_bits10.glasses_y_position.Assign(mii.glasses_y); mii_v3.appearance_bits10.glasses_y_position.Assign(mii.glasses_y);
@ -585,6 +577,16 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
mii_v3.appearance_bits11.mole_x_position.Assign(mii.mole_x); mii_v3.appearance_bits11.mole_x_position.Assign(mii.mole_x);
mii_v3.appearance_bits11.mole_y_position.Assign(mii.mole_y); 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(Ver3FacelineColorTable[mii.faceline_color]);
mii_v3.appearance_bits3.hair_color.Assign(Ver3HairColorTable[mii.hair_color]);
mii_v3.appearance_bits4.eye_color.Assign(Ver3EyeColorTable[mii.eye_color]);
mii_v3.appearance_bits5.eyebrow_color.Assign(Ver3HairColorTable[mii.eyebrow_color]);
mii_v3.appearance_bits7.mouth_color.Assign(Ver3MouthlineColorTable[mii.mouth_color]);
mii_v3.appearance_bits9.facial_hair_color.Assign(Ver3HairColorTable[mii.beard_color]);
mii_v3.appearance_bits10.glasses_color.Assign(Ver3GlassColorTable[mii.glasses_color]);
mii_v3.appearance_bits10.glasses_type.Assign(Ver3GlassTypeTable[mii.glasses_type]);
mii_v3.crc = GenerateCrc16(&mii_v3, sizeof(Ver3StoreData) - sizeof(u16)); mii_v3.crc = GenerateCrc16(&mii_v3, sizeof(Ver3StoreData) - sizeof(u16));
// TODO: Validate mii_v3 data // TODO: Validate mii_v3 data
@ -592,6 +594,19 @@ Ver3StoreData MiiManager::ConvertCharInfoToV3(const CharInfo& mii) const {
return mii_v3; return mii_v3;
} }
NfpStoreDataExtension MiiManager::SetFromStoreData(const CharInfo& mii) const {
return {
.faceline_color = static_cast<u8>(mii.faceline_color & 0xf),
.hair_color = static_cast<u8>(mii.hair_color & 0x7f),
.eye_color = static_cast<u8>(mii.eyebrow_color & 0x7f),
.eyebrow_color = static_cast<u8>(mii.eyebrow_color & 0x7f),
.mouth_color = static_cast<u8>(mii.mouth_color & 0x7f),
.beard_color = static_cast<u8>(mii.beard_color & 0x7f),
.glass_color = static_cast<u8>(mii.glasses_color & 0x7f),
.glass_type = static_cast<u8>(mii.glasses_type & 0x1f),
};
}
bool MiiManager::ValidateV3Info(const Ver3StoreData& mii_v3) const { bool MiiManager::ValidateV3Info(const Ver3StoreData& mii_v3) const {
bool is_valid = mii_v3.version == 0 || mii_v3.version == 3; bool is_valid = mii_v3.version == 0 || mii_v3.version == 3;

View File

@ -23,11 +23,16 @@ public:
CharInfo BuildRandom(Age age, Gender gender, Race race); CharInfo BuildRandom(Age age, Gender gender, Race race);
CharInfo BuildDefault(std::size_t index); CharInfo BuildDefault(std::size_t index);
CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const; CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const;
Ver3StoreData ConvertCharInfoToV3(const CharInfo& mii) const;
bool ValidateV3Info(const Ver3StoreData& mii_v3) const; bool ValidateV3Info(const Ver3StoreData& mii_v3) const;
ResultVal<std::vector<MiiInfoElement>> GetDefault(SourceFlag source_flag); ResultVal<std::vector<MiiInfoElement>> GetDefault(SourceFlag source_flag);
Result GetIndex(const CharInfo& info, u32& index); 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;
private: private:
const Common::UUID user_id{}; const Common::UUID user_id{};
u64 update_counter{}; u64 update_counter{};

View File

@ -370,6 +370,63 @@ struct Ver3StoreData {
}; };
static_assert(sizeof(Ver3StoreData) == 0x60, "Ver3StoreData is an invalid size"); static_assert(sizeof(Ver3StoreData) == 0x60, "Ver3StoreData 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");
constexpr std::array<u8, 0x10> Ver3FacelineColorTable{
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x0, 0x1, 0x5, 0x5,
};
constexpr std::array<u8, 100> Ver3HairColorTable{
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x0, 0x4, 0x3, 0x5, 0x4, 0x4, 0x6, 0x2, 0x0,
0x6, 0x4, 0x3, 0x2, 0x2, 0x7, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x4,
0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5,
0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x7, 0x5, 0x7, 0x7, 0x7, 0x7, 0x7, 0x6, 0x7,
0x7, 0x7, 0x7, 0x7, 0x3, 0x7, 0x7, 0x7, 0x7, 0x7, 0x0, 0x4, 0x4, 0x4, 0x4,
};
constexpr std::array<u8, 100> Ver3EyeColorTable{
0x0, 0x2, 0x2, 0x2, 0x1, 0x3, 0x2, 0x3, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x2, 0x2, 0x4,
0x2, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x1, 0x0, 0x4, 0x4,
0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5,
0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x2, 0x2,
0x3, 0x3, 0x3, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
};
constexpr std::array<u8, 100> Ver3MouthlineColorTable{
0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x1, 0x4,
0x4, 0x4, 0x0, 0x1, 0x2, 0x3, 0x4, 0x4, 0x2, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x1, 0x4,
0x4, 0x2, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4,
0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x4, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4,
0x4, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3,
0x3, 0x3, 0x3, 0x3, 0x4, 0x0, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, 0x3, 0x3,
};
constexpr std::array<u8, 100> Ver3GlassColorTable{
0x0, 0x1, 0x1, 0x1, 0x5, 0x1, 0x1, 0x4, 0x0, 0x5, 0x1, 0x1, 0x3, 0x5, 0x1, 0x2, 0x3,
0x4, 0x5, 0x4, 0x2, 0x2, 0x4, 0x4, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
0x2, 0x2, 0x2, 0x2, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3,
0x3, 0x3, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x0, 0x5, 0x5,
0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5, 0x1, 0x4,
0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5, 0x5, 0x5, 0x5,
};
constexpr std::array<u8, 20> Ver3GlassTypeTable{
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x1,
0x2, 0x1, 0x3, 0x7, 0x7, 0x6, 0x7, 0x8, 0x7, 0x7,
};
struct MiiStoreData { struct MiiStoreData {
using Name = std::array<char16_t, 10>; using Name = std::array<char16_t, 10>;

View File

@ -88,6 +88,7 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
encoded_data.application_area_id = nfc_data.user_memory.application_area_id; encoded_data.application_area_id = nfc_data.user_memory.application_area_id;
encoded_data.application_id_byte = nfc_data.user_memory.application_id_byte; encoded_data.application_id_byte = nfc_data.user_memory.application_id_byte;
encoded_data.unknown = nfc_data.user_memory.unknown; encoded_data.unknown = nfc_data.user_memory.unknown;
encoded_data.mii_extension = nfc_data.user_memory.mii_extension;
encoded_data.unknown2 = nfc_data.user_memory.unknown2; encoded_data.unknown2 = nfc_data.user_memory.unknown2;
encoded_data.register_info_crc = nfc_data.user_memory.register_info_crc; encoded_data.register_info_crc = nfc_data.user_memory.register_info_crc;
encoded_data.application_area = nfc_data.user_memory.application_area; encoded_data.application_area = nfc_data.user_memory.application_area;
@ -122,6 +123,7 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
nfc_data.user_memory.application_area_id = encoded_data.application_area_id; nfc_data.user_memory.application_area_id = encoded_data.application_area_id;
nfc_data.user_memory.application_id_byte = encoded_data.application_id_byte; nfc_data.user_memory.application_id_byte = encoded_data.application_id_byte;
nfc_data.user_memory.unknown = encoded_data.unknown; nfc_data.user_memory.unknown = encoded_data.unknown;
nfc_data.user_memory.mii_extension = encoded_data.mii_extension;
nfc_data.user_memory.unknown2 = encoded_data.unknown2; nfc_data.user_memory.unknown2 = encoded_data.unknown2;
nfc_data.user_memory.register_info_crc = encoded_data.register_info_crc; nfc_data.user_memory.register_info_crc = encoded_data.register_info_crc;
nfc_data.user_memory.application_area = encoded_data.application_area; nfc_data.user_memory.application_area = encoded_data.application_area;

View File

@ -471,6 +471,7 @@ Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) {
} }
Service::Mii::MiiManager manager; Service::Mii::MiiManager manager;
const auto mii = manager.BuildDefault(0);
auto& settings = tag_data.settings; auto& settings = tag_data.settings;
if (tag_data.settings.settings.amiibo_initialized == 0) { if (tag_data.settings.settings.amiibo_initialized == 0) {
@ -479,9 +480,10 @@ Result NfpDevice::SetRegisterInfoPrivate(const AmiiboName& amiibo_name) {
} }
SetAmiiboName(settings, amiibo_name); SetAmiiboName(settings, amiibo_name);
tag_data.owner_mii = manager.ConvertCharInfoToV3(manager.BuildDefault(0)); tag_data.owner_mii = manager.BuildFromStoreData(mii);
tag_data.mii_extension = manager.SetFromStoreData(mii);
tag_data.unknown = 0; tag_data.unknown = 0;
tag_data.unknown2[6] = 0; tag_data.unknown2 = {};
settings.country_code_id = 0; settings.country_code_id = 0;
settings.settings.font_region.Assign(0); settings.settings.font_region.Assign(0);
settings.settings.amiibo_initialized.Assign(1); settings.settings.amiibo_initialized.Assign(1);
@ -840,7 +842,8 @@ void NfpDevice::UpdateRegisterInfoCrc() {
Mii::Ver3StoreData mii; Mii::Ver3StoreData mii;
u8 application_id_byte; u8 application_id_byte;
u8 unknown; u8 unknown;
std::array<u32, 0x7> unknown2; Mii::NfpStoreDataExtension mii_extension;
std::array<u32, 0x5> unknown2;
}; };
static_assert(sizeof(CrcData) == 0x7e, "CrcData is an invalid size"); static_assert(sizeof(CrcData) == 0x7e, "CrcData is an invalid size");
#pragma pack(pop) #pragma pack(pop)
@ -849,6 +852,7 @@ void NfpDevice::UpdateRegisterInfoCrc() {
.mii = tag_data.owner_mii, .mii = tag_data.owner_mii,
.application_id_byte = tag_data.application_id_byte, .application_id_byte = tag_data.application_id_byte,
.unknown = tag_data.unknown, .unknown = tag_data.unknown,
.mii_extension = tag_data.mii_extension,
.unknown2 = tag_data.unknown2, .unknown2 = tag_data.unknown2,
}; };

View File

@ -259,7 +259,8 @@ struct EncryptedAmiiboFile {
u32_be application_area_id; // Encrypted Game id u32_be application_area_id; // Encrypted Game id
u8 application_id_byte; u8 application_id_byte;
u8 unknown; u8 unknown;
std::array<u32, 0x7> unknown2; Service::Mii::NfpStoreDataExtension mii_extension;
std::array<u32, 0x5> unknown2;
u32_be register_info_crc; u32_be register_info_crc;
ApplicationArea application_area; // Encrypted Game data ApplicationArea application_area; // Encrypted Game data
}; };
@ -280,7 +281,8 @@ struct NTAG215File {
u32_be application_area_id; u32_be application_area_id;
u8 application_id_byte; u8 application_id_byte;
u8 unknown; u8 unknown;
std::array<u32, 0x7> unknown2; Service::Mii::NfpStoreDataExtension mii_extension;
std::array<u32, 0x5> unknown2;
u32_be register_info_crc; u32_be register_info_crc;
ApplicationArea application_area; // Encrypted Game data ApplicationArea application_area; // Encrypted Game data
HashData hmac_tag; // Hash HashData hmac_tag; // Hash