diff options
| author | 2022-08-30 00:33:47 -0500 | |
|---|---|---|
| committer | 2022-09-07 01:04:00 -0500 | |
| commit | 19a4e12e6ea6c3d06ee227f3ef1a6cbf93850f6e (patch) | |
| tree | f96054552ebe182e75fd77eabdcdf205a0dffe46 /src/core/hle/service/mii | |
| parent | core: nfp: Implement amiibo encryption (diff) | |
| download | yuzu-19a4e12e6ea6c3d06ee227f3ef1a6cbf93850f6e.tar.gz yuzu-19a4e12e6ea6c3d06ee227f3ef1a6cbf93850f6e.tar.xz yuzu-19a4e12e6ea6c3d06ee227f3ef1a6cbf93850f6e.zip | |
core: nfp: Implement Convert and RecreateApplicationArea, accuracy fixes
Diffstat (limited to 'src/core/hle/service/mii')
| -rw-r--r-- | src/core/hle/service/mii/mii.cpp | 32 | ||||
| -rw-r--r-- | src/core/hle/service/mii/mii_manager.cpp | 88 | ||||
| -rw-r--r-- | src/core/hle/service/mii/mii_manager.h | 9 | ||||
| -rw-r--r-- | src/core/hle/service/mii/types.h | 138 |
4 files changed, 241 insertions, 26 deletions
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp index efb569993..390514fdc 100644 --- a/src/core/hle/service/mii/mii.cpp +++ b/src/core/hle/service/mii/mii.cpp | |||
| @@ -43,7 +43,7 @@ public: | |||
| 43 | {20, nullptr, "IsBrokenDatabaseWithClearFlag"}, | 43 | {20, nullptr, "IsBrokenDatabaseWithClearFlag"}, |
| 44 | {21, &IDatabaseService::GetIndex, "GetIndex"}, | 44 | {21, &IDatabaseService::GetIndex, "GetIndex"}, |
| 45 | {22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"}, | 45 | {22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"}, |
| 46 | {23, nullptr, "Convert"}, | 46 | {23, &IDatabaseService::Convert, "Convert"}, |
| 47 | {24, nullptr, "ConvertCoreDataToCharInfo"}, | 47 | {24, nullptr, "ConvertCoreDataToCharInfo"}, |
| 48 | {25, nullptr, "ConvertCharInfoToCoreData"}, | 48 | {25, nullptr, "ConvertCharInfoToCoreData"}, |
| 49 | {26, nullptr, "Append"}, | 49 | {26, nullptr, "Append"}, |
| @@ -130,7 +130,7 @@ private: | |||
| 130 | return; | 130 | return; |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | std::vector<MiiInfo> values; | 133 | std::vector<CharInfo> values; |
| 134 | for (const auto& element : *result) { | 134 | for (const auto& element : *result) { |
| 135 | values.emplace_back(element.info); | 135 | values.emplace_back(element.info); |
| 136 | } | 136 | } |
| @@ -144,7 +144,7 @@ private: | |||
| 144 | 144 | ||
| 145 | void UpdateLatest(Kernel::HLERequestContext& ctx) { | 145 | void UpdateLatest(Kernel::HLERequestContext& ctx) { |
| 146 | IPC::RequestParser rp{ctx}; | 146 | IPC::RequestParser rp{ctx}; |
| 147 | const auto info{rp.PopRaw<MiiInfo>()}; | 147 | const auto info{rp.PopRaw<CharInfo>()}; |
| 148 | const auto source_flag{rp.PopRaw<SourceFlag>()}; | 148 | const auto source_flag{rp.PopRaw<SourceFlag>()}; |
| 149 | 149 | ||
| 150 | LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); | 150 | LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); |
| @@ -156,9 +156,9 @@ private: | |||
| 156 | return; | 156 | return; |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(MiiInfo) / sizeof(u32)}; | 159 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; |
| 160 | rb.Push(ResultSuccess); | 160 | rb.Push(ResultSuccess); |
| 161 | rb.PushRaw<MiiInfo>(*result); | 161 | rb.PushRaw<CharInfo>(*result); |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | void BuildRandom(Kernel::HLERequestContext& ctx) { | 164 | void BuildRandom(Kernel::HLERequestContext& ctx) { |
| @@ -191,9 +191,9 @@ private: | |||
| 191 | return; | 191 | return; |
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(MiiInfo) / sizeof(u32)}; | 194 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; |
| 195 | rb.Push(ResultSuccess); | 195 | rb.Push(ResultSuccess); |
| 196 | rb.PushRaw<MiiInfo>(manager.BuildRandom(age, gender, race)); | 196 | rb.PushRaw<CharInfo>(manager.BuildRandom(age, gender, race)); |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | void BuildDefault(Kernel::HLERequestContext& ctx) { | 199 | void BuildDefault(Kernel::HLERequestContext& ctx) { |
| @@ -210,14 +210,14 @@ private: | |||
| 210 | return; | 210 | return; |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(MiiInfo) / sizeof(u32)}; | 213 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; |
| 214 | rb.Push(ResultSuccess); | 214 | rb.Push(ResultSuccess); |
| 215 | rb.PushRaw<MiiInfo>(manager.BuildDefault(index)); | 215 | rb.PushRaw<CharInfo>(manager.BuildDefault(index)); |
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | void GetIndex(Kernel::HLERequestContext& ctx) { | 218 | void GetIndex(Kernel::HLERequestContext& ctx) { |
| 219 | IPC::RequestParser rp{ctx}; | 219 | IPC::RequestParser rp{ctx}; |
| 220 | const auto info{rp.PopRaw<MiiInfo>()}; | 220 | const auto info{rp.PopRaw<CharInfo>()}; |
| 221 | 221 | ||
| 222 | LOG_DEBUG(Service_Mii, "called"); | 222 | LOG_DEBUG(Service_Mii, "called"); |
| 223 | 223 | ||
| @@ -239,6 +239,18 @@ private: | |||
| 239 | rb.Push(ResultSuccess); | 239 | rb.Push(ResultSuccess); |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | void Convert(Kernel::HLERequestContext& ctx) { | ||
| 243 | IPC::RequestParser rp{ctx}; | ||
| 244 | |||
| 245 | const auto mii_v3{rp.PopRaw<Ver3StoreData>()}; | ||
| 246 | |||
| 247 | LOG_INFO(Service_Mii, "called"); | ||
| 248 | |||
| 249 | IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; | ||
| 250 | rb.Push(ResultSuccess); | ||
| 251 | rb.PushRaw<CharInfo>(manager.ConvertV3ToCharInfo(mii_v3)); | ||
| 252 | } | ||
| 253 | |||
| 242 | constexpr bool IsInterfaceVersionSupported(u32 interface_version) const { | 254 | constexpr bool IsInterfaceVersionSupported(u32 interface_version) const { |
| 243 | return current_interface_version >= interface_version; | 255 | return current_interface_version >= interface_version; |
| 244 | } | 256 | } |
diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp index 544c92a00..97d1b948f 100644 --- a/src/core/hle/service/mii/mii_manager.cpp +++ b/src/core/hle/service/mii/mii_manager.cpp | |||
| @@ -42,7 +42,7 @@ std::array<T, DestArraySize> ResizeArray(const std::array<T, SourceArraySize>& i | |||
| 42 | return out; | 42 | return out; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | MiiInfo ConvertStoreDataToInfo(const MiiStoreData& data) { | 45 | CharInfo ConvertStoreDataToInfo(const MiiStoreData& data) { |
| 46 | MiiStoreBitFields bf; | 46 | MiiStoreBitFields bf; |
| 47 | std::memcpy(&bf, data.data.data.data(), sizeof(MiiStoreBitFields)); | 47 | std::memcpy(&bf, data.data.data.data(), sizeof(MiiStoreBitFields)); |
| 48 | 48 | ||
| @@ -409,8 +409,8 @@ u32 MiiManager::GetCount(SourceFlag source_flag) const { | |||
| 409 | return static_cast<u32>(count); | 409 | return static_cast<u32>(count); |
| 410 | } | 410 | } |
| 411 | 411 | ||
| 412 | ResultVal<MiiInfo> MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info, | 412 | ResultVal<CharInfo> MiiManager::UpdateLatest([[maybe_unused]] const CharInfo& info, |
| 413 | SourceFlag source_flag) { | 413 | SourceFlag source_flag) { |
| 414 | if ((source_flag & SourceFlag::Database) == SourceFlag::None) { | 414 | if ((source_flag & SourceFlag::Database) == SourceFlag::None) { |
| 415 | return ERROR_CANNOT_FIND_ENTRY; | 415 | return ERROR_CANNOT_FIND_ENTRY; |
| 416 | } | 416 | } |
| @@ -419,14 +419,90 @@ ResultVal<MiiInfo> MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info | |||
| 419 | return ERROR_CANNOT_FIND_ENTRY; | 419 | return ERROR_CANNOT_FIND_ENTRY; |
| 420 | } | 420 | } |
| 421 | 421 | ||
| 422 | MiiInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) { | 422 | CharInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) { |
| 423 | return ConvertStoreDataToInfo(BuildRandomStoreData(age, gender, race, user_id)); | 423 | return ConvertStoreDataToInfo(BuildRandomStoreData(age, gender, race, user_id)); |
| 424 | } | 424 | } |
| 425 | 425 | ||
| 426 | MiiInfo MiiManager::BuildDefault(std::size_t index) { | 426 | CharInfo MiiManager::BuildDefault(std::size_t index) { |
| 427 | return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::DefaultMii.at(index), user_id)); | 427 | return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::DefaultMii.at(index), user_id)); |
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | CharInfo MiiManager::ConvertV3ToCharInfo(Ver3StoreData mii_v3) const { | ||
| 431 | Service::Mii::MiiManager manager; | ||
| 432 | auto mii = manager.BuildDefault(0); | ||
| 433 | |||
| 434 | // Check if mii data exist | ||
| 435 | if (mii_v3.mii_name[0] == 0) { | ||
| 436 | return mii; | ||
| 437 | } | ||
| 438 | |||
| 439 | // TODO: We are ignoring a bunch of data from the mii_v3 | ||
| 440 | |||
| 441 | mii.gender = static_cast<u8>(mii_v3.mii_information.gender); | ||
| 442 | mii.favorite_color = static_cast<u8>(mii_v3.mii_information.favorite_color); | ||
| 443 | mii.height = mii_v3.height; | ||
| 444 | mii.build = mii_v3.build; | ||
| 445 | |||
| 446 | mii.font_region = mii_v3.region_information.character_set; | ||
| 447 | memcpy(mii.name.data(), mii_v3.mii_name.data(), 10); | ||
| 448 | |||
| 449 | mii.faceline_type = mii_v3.appearance_bits1.face_shape; | ||
| 450 | mii.faceline_color = mii_v3.appearance_bits1.skin_color; | ||
| 451 | mii.faceline_wrinkle = mii_v3.appearance_bits2.wrinkles; | ||
| 452 | mii.faceline_make = mii_v3.appearance_bits2.makeup; | ||
| 453 | |||
| 454 | mii.hair_type = mii_v3.hair_style; | ||
| 455 | mii.hair_color = mii_v3.appearance_bits3.hair_color; | ||
| 456 | mii.hair_flip = mii_v3.appearance_bits3.flip_hair; | ||
| 457 | |||
| 458 | mii.eye_type = static_cast<u8>(mii_v3.appearance_bits4.eye_type); | ||
| 459 | mii.eye_color = static_cast<u8>(mii_v3.appearance_bits4.eye_color); | ||
| 460 | mii.eye_scale = static_cast<u8>(mii_v3.appearance_bits4.eye_scale); | ||
| 461 | mii.eye_aspect = static_cast<u8>(mii_v3.appearance_bits4.eye_vertical_stretch); | ||
| 462 | mii.eye_rotate = static_cast<u8>(mii_v3.appearance_bits4.eye_rotation); | ||
| 463 | mii.eye_x = static_cast<u8>(mii_v3.appearance_bits4.eye_spacing); | ||
| 464 | mii.eye_y = static_cast<u8>(mii_v3.appearance_bits4.eye_y_position); | ||
| 465 | |||
| 466 | mii.eyebrow_type = static_cast<u8>(mii_v3.appearance_bits5.eyebrow_style); | ||
| 467 | mii.eyebrow_color = static_cast<u8>(mii_v3.appearance_bits5.eyebrow_color); | ||
| 468 | mii.eyebrow_scale = static_cast<u8>(mii_v3.appearance_bits5.eyebrow_scale); | ||
| 469 | mii.eyebrow_aspect = static_cast<u8>(mii_v3.appearance_bits5.eyebrow_yscale); | ||
| 470 | mii.eyebrow_rotate = static_cast<u8>(mii_v3.appearance_bits5.eyebrow_rotation); | ||
| 471 | mii.eyebrow_x = static_cast<u8>(mii_v3.appearance_bits5.eyebrow_spacing); | ||
| 472 | mii.eyebrow_y = static_cast<u8>(mii_v3.appearance_bits5.eyebrow_y_position); | ||
| 473 | |||
| 474 | mii.nose_type = static_cast<u8>(mii_v3.appearance_bits6.nose_type); | ||
| 475 | mii.nose_scale = static_cast<u8>(mii_v3.appearance_bits6.nose_scale); | ||
| 476 | mii.nose_y = static_cast<u8>(mii_v3.appearance_bits6.nose_y_position); | ||
| 477 | |||
| 478 | mii.mouth_type = static_cast<u8>(mii_v3.appearance_bits7.mouth_type); | ||
| 479 | mii.mouth_color = static_cast<u8>(mii_v3.appearance_bits7.mouth_color); | ||
| 480 | mii.mouth_scale = static_cast<u8>(mii_v3.appearance_bits7.mouth_scale); | ||
| 481 | mii.mouth_aspect = static_cast<u8>(mii_v3.appearance_bits7.mouth_horizontal_stretch); | ||
| 482 | mii.mouth_y = static_cast<u8>(mii_v3.appearance_bits8.mouth_y_position); | ||
| 483 | |||
| 484 | mii.mustache_type = static_cast<u8>(mii_v3.appearance_bits8.mustache_type); | ||
| 485 | mii.mustache_scale = static_cast<u8>(mii_v3.appearance_bits9.mustache_scale); | ||
| 486 | mii.mustache_y = static_cast<u8>(mii_v3.appearance_bits9.mustache_y_position); | ||
| 487 | |||
| 488 | mii.beard_type = static_cast<u8>(mii_v3.appearance_bits9.bear_type); | ||
| 489 | mii.beard_color = static_cast<u8>(mii_v3.appearance_bits9.facial_hair_color); | ||
| 490 | |||
| 491 | mii.glasses_type = static_cast<u8>(mii_v3.appearance_bits10.glasses_type); | ||
| 492 | mii.glasses_color = static_cast<u8>(mii_v3.appearance_bits10.glasses_color); | ||
| 493 | mii.glasses_scale = static_cast<u8>(mii_v3.appearance_bits10.glasses_scale); | ||
| 494 | mii.glasses_y = static_cast<u8>(mii_v3.appearance_bits10.glasses_y_position); | ||
| 495 | |||
| 496 | mii.mole_type = static_cast<u8>(mii_v3.appearance_bits11.mole_enabled); | ||
| 497 | mii.mole_scale = static_cast<u8>(mii_v3.appearance_bits11.mole_scale); | ||
| 498 | mii.mole_x = static_cast<u8>(mii_v3.appearance_bits11.mole_x_position); | ||
| 499 | mii.mole_y = static_cast<u8>(mii_v3.appearance_bits11.mole_y_position); | ||
| 500 | |||
| 501 | // TODO: Validate mii data | ||
| 502 | |||
| 503 | return mii; | ||
| 504 | } | ||
| 505 | |||
| 430 | ResultVal<std::vector<MiiInfoElement>> MiiManager::GetDefault(SourceFlag source_flag) { | 506 | ResultVal<std::vector<MiiInfoElement>> MiiManager::GetDefault(SourceFlag source_flag) { |
| 431 | std::vector<MiiInfoElement> result; | 507 | std::vector<MiiInfoElement> result; |
| 432 | 508 | ||
| @@ -441,7 +517,7 @@ ResultVal<std::vector<MiiInfoElement>> MiiManager::GetDefault(SourceFlag source_ | |||
| 441 | return result; | 517 | return result; |
| 442 | } | 518 | } |
| 443 | 519 | ||
| 444 | Result MiiManager::GetIndex([[maybe_unused]] const MiiInfo& info, u32& index) { | 520 | Result MiiManager::GetIndex([[maybe_unused]] const CharInfo& info, u32& index) { |
| 445 | constexpr u32 INVALID_INDEX{0xFFFFFFFF}; | 521 | constexpr u32 INVALID_INDEX{0xFFFFFFFF}; |
| 446 | 522 | ||
| 447 | index = INVALID_INDEX; | 523 | index = INVALID_INDEX; |
diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h index 6a286bd96..d847de0bd 100644 --- a/src/core/hle/service/mii/mii_manager.h +++ b/src/core/hle/service/mii/mii_manager.h | |||
| @@ -19,11 +19,12 @@ public: | |||
| 19 | bool CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter); | 19 | bool CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter); |
| 20 | bool IsFullDatabase() const; | 20 | bool IsFullDatabase() const; |
| 21 | u32 GetCount(SourceFlag source_flag) const; | 21 | u32 GetCount(SourceFlag source_flag) const; |
| 22 | ResultVal<MiiInfo> UpdateLatest(const MiiInfo& info, SourceFlag source_flag); | 22 | ResultVal<CharInfo> UpdateLatest(const CharInfo& info, SourceFlag source_flag); |
| 23 | MiiInfo BuildRandom(Age age, Gender gender, Race race); | 23 | CharInfo BuildRandom(Age age, Gender gender, Race race); |
| 24 | MiiInfo BuildDefault(std::size_t index); | 24 | CharInfo BuildDefault(std::size_t index); |
| 25 | CharInfo ConvertV3ToCharInfo(Ver3StoreData mii_v3) const; | ||
| 25 | ResultVal<std::vector<MiiInfoElement>> GetDefault(SourceFlag source_flag); | 26 | ResultVal<std::vector<MiiInfoElement>> GetDefault(SourceFlag source_flag); |
| 26 | Result GetIndex(const MiiInfo& info, u32& index); | 27 | Result GetIndex(const CharInfo& info, u32& index); |
| 27 | 28 | ||
| 28 | private: | 29 | private: |
| 29 | const Common::UUID user_id{}; | 30 | const Common::UUID user_id{}; |
diff --git a/src/core/hle/service/mii/types.h b/src/core/hle/service/mii/types.h index 45edbfeae..9e3247397 100644 --- a/src/core/hle/service/mii/types.h +++ b/src/core/hle/service/mii/types.h | |||
| @@ -86,7 +86,8 @@ enum class SourceFlag : u32 { | |||
| 86 | }; | 86 | }; |
| 87 | DECLARE_ENUM_FLAG_OPERATORS(SourceFlag); | 87 | DECLARE_ENUM_FLAG_OPERATORS(SourceFlag); |
| 88 | 88 | ||
| 89 | struct MiiInfo { | 89 | // nn::mii::CharInfo |
| 90 | struct CharInfo { | ||
| 90 | Common::UUID uuid; | 91 | Common::UUID uuid; |
| 91 | std::array<char16_t, 11> name; | 92 | std::array<char16_t, 11> name; |
| 92 | u8 font_region; | 93 | u8 font_region; |
| @@ -140,16 +141,16 @@ struct MiiInfo { | |||
| 140 | u8 mole_y; | 141 | u8 mole_y; |
| 141 | u8 padding; | 142 | u8 padding; |
| 142 | }; | 143 | }; |
| 143 | static_assert(sizeof(MiiInfo) == 0x58, "MiiInfo has incorrect size."); | 144 | static_assert(sizeof(CharInfo) == 0x58, "CharInfo has incorrect size."); |
| 144 | static_assert(std::has_unique_object_representations_v<MiiInfo>, | 145 | static_assert(std::has_unique_object_representations_v<CharInfo>, |
| 145 | "All bits of MiiInfo must contribute to its value."); | 146 | "All bits of CharInfo must contribute to its value."); |
| 146 | 147 | ||
| 147 | #pragma pack(push, 4) | 148 | #pragma pack(push, 4) |
| 148 | 149 | ||
| 149 | struct MiiInfoElement { | 150 | struct MiiInfoElement { |
| 150 | MiiInfoElement(const MiiInfo& info_, Source source_) : info{info_}, source{source_} {} | 151 | MiiInfoElement(const CharInfo& info_, Source source_) : info{info_}, source{source_} {} |
| 151 | 152 | ||
| 152 | MiiInfo info{}; | 153 | CharInfo info{}; |
| 153 | Source source{}; | 154 | Source source{}; |
| 154 | }; | 155 | }; |
| 155 | static_assert(sizeof(MiiInfoElement) == 0x5c, "MiiInfoElement has incorrect size."); | 156 | static_assert(sizeof(MiiInfoElement) == 0x5c, "MiiInfoElement has incorrect size."); |
| @@ -243,6 +244,131 @@ static_assert(sizeof(MiiStoreBitFields) == 0x1c, "MiiStoreBitFields has incorrec | |||
| 243 | static_assert(std::is_trivially_copyable_v<MiiStoreBitFields>, | 244 | static_assert(std::is_trivially_copyable_v<MiiStoreBitFields>, |
| 244 | "MiiStoreBitFields is not trivially copyable."); | 245 | "MiiStoreBitFields is not trivially copyable."); |
| 245 | 246 | ||
| 247 | // This is nn::mii::Ver3StoreData | ||
| 248 | // Based on citra HLE::Applets::MiiData and PretendoNetwork. | ||
| 249 | // https://github.com/citra-emu/citra/blob/master/src/core/hle/applets/mii_selector.h#L48 | ||
| 250 | // https://github.com/PretendoNetwork/mii-js/blob/master/mii.js#L299 | ||
| 251 | struct Ver3StoreData { | ||
| 252 | u8 version; | ||
| 253 | union { | ||
| 254 | u8 raw; | ||
| 255 | |||
| 256 | BitField<0, 1, u8> allow_copying; | ||
| 257 | BitField<1, 1, u8> profanity_flag; | ||
| 258 | BitField<2, 2, u8> region_lock; | ||
| 259 | BitField<4, 2, u8> character_set; | ||
| 260 | } region_information; | ||
| 261 | u16_be mii_id; | ||
| 262 | u64_be system_id; | ||
| 263 | u32_be specialness_and_creation_date; | ||
| 264 | std::array<u8, 0x6> creator_mac; | ||
| 265 | u16_be padding; | ||
| 266 | union { | ||
| 267 | u16 raw; | ||
| 268 | |||
| 269 | BitField<0, 1, u16> gender; | ||
| 270 | BitField<1, 4, u16> birth_month; | ||
| 271 | BitField<5, 5, u16> birth_day; | ||
| 272 | BitField<10, 4, u16> favorite_color; | ||
| 273 | BitField<14, 1, u16> favorite; | ||
| 274 | } mii_information; | ||
| 275 | std::array<char16_t, 0xA> mii_name; | ||
| 276 | u8 height; | ||
| 277 | u8 build; | ||
| 278 | union { | ||
| 279 | u8 raw; | ||
| 280 | |||
| 281 | BitField<0, 1, u8> disable_sharing; | ||
| 282 | BitField<1, 4, u8> face_shape; | ||
| 283 | BitField<5, 3, u8> skin_color; | ||
| 284 | } appearance_bits1; | ||
| 285 | union { | ||
| 286 | u8 raw; | ||
| 287 | |||
| 288 | BitField<0, 4, u8> wrinkles; | ||
| 289 | BitField<4, 4, u8> makeup; | ||
| 290 | } appearance_bits2; | ||
| 291 | u8 hair_style; | ||
| 292 | union { | ||
| 293 | u8 raw; | ||
| 294 | |||
| 295 | BitField<0, 3, u8> hair_color; | ||
| 296 | BitField<3, 1, u8> flip_hair; | ||
| 297 | } appearance_bits3; | ||
| 298 | union { | ||
| 299 | u32 raw; | ||
| 300 | |||
| 301 | BitField<0, 6, u32> eye_type; | ||
| 302 | BitField<6, 3, u32> eye_color; | ||
| 303 | BitField<9, 4, u32> eye_scale; | ||
| 304 | BitField<13, 3, u32> eye_vertical_stretch; | ||
| 305 | BitField<16, 5, u32> eye_rotation; | ||
| 306 | BitField<21, 4, u32> eye_spacing; | ||
| 307 | BitField<25, 5, u32> eye_y_position; | ||
| 308 | } appearance_bits4; | ||
| 309 | union { | ||
| 310 | u32 raw; | ||
| 311 | |||
| 312 | BitField<0, 5, u32> eyebrow_style; | ||
| 313 | BitField<5, 3, u32> eyebrow_color; | ||
| 314 | BitField<8, 4, u32> eyebrow_scale; | ||
| 315 | BitField<12, 3, u32> eyebrow_yscale; | ||
| 316 | BitField<16, 4, u32> eyebrow_rotation; | ||
| 317 | BitField<21, 4, u32> eyebrow_spacing; | ||
| 318 | BitField<25, 5, u32> eyebrow_y_position; | ||
| 319 | } appearance_bits5; | ||
| 320 | union { | ||
| 321 | u16 raw; | ||
| 322 | |||
| 323 | BitField<0, 5, u16> nose_type; | ||
| 324 | BitField<5, 4, u16> nose_scale; | ||
| 325 | BitField<9, 5, u16> nose_y_position; | ||
| 326 | } appearance_bits6; | ||
| 327 | union { | ||
| 328 | u16 raw; | ||
| 329 | |||
| 330 | BitField<0, 6, u16> mouth_type; | ||
| 331 | BitField<6, 3, u16> mouth_color; | ||
| 332 | BitField<9, 4, u16> mouth_scale; | ||
| 333 | BitField<13, 3, u16> mouth_horizontal_stretch; | ||
| 334 | } appearance_bits7; | ||
| 335 | union { | ||
| 336 | u8 raw; | ||
| 337 | |||
| 338 | BitField<0, 5, u8> mouth_y_position; | ||
| 339 | BitField<5, 3, u8> mustache_type; | ||
| 340 | } appearance_bits8; | ||
| 341 | u8 allow_copying; | ||
| 342 | union { | ||
| 343 | u16 raw; | ||
| 344 | |||
| 345 | BitField<0, 3, u16> bear_type; | ||
| 346 | BitField<3, 3, u16> facial_hair_color; | ||
| 347 | BitField<6, 4, u16> mustache_scale; | ||
| 348 | BitField<10, 5, u16> mustache_y_position; | ||
| 349 | } appearance_bits9; | ||
| 350 | union { | ||
| 351 | u16 raw; | ||
| 352 | |||
| 353 | BitField<0, 4, u16> glasses_type; | ||
| 354 | BitField<4, 3, u16> glasses_color; | ||
| 355 | BitField<7, 4, u16> glasses_scale; | ||
| 356 | BitField<11, 5, u16> glasses_y_position; | ||
| 357 | } appearance_bits10; | ||
| 358 | union { | ||
| 359 | u16 raw; | ||
| 360 | |||
| 361 | BitField<0, 1, u16> mole_enabled; | ||
| 362 | BitField<1, 4, u16> mole_scale; | ||
| 363 | BitField<5, 5, u16> mole_x_position; | ||
| 364 | BitField<10, 5, u16> mole_y_position; | ||
| 365 | } appearance_bits11; | ||
| 366 | |||
| 367 | std::array<u16_le, 0xA> author_name; | ||
| 368 | INSERT_PADDING_BYTES(0x4); | ||
| 369 | }; | ||
| 370 | static_assert(sizeof(Ver3StoreData) == 0x60, "Ver3StoreData is an invalid size"); | ||
| 371 | |||
| 246 | struct MiiStoreData { | 372 | struct MiiStoreData { |
| 247 | using Name = std::array<char16_t, 10>; | 373 | using Name = std::array<char16_t, 10>; |
| 248 | 374 | ||