summaryrefslogtreecommitdiff
path: root/src/core/hle/service/mii
diff options
context:
space:
mode:
authorGravatar Narr the Reg2022-08-30 00:33:47 -0500
committerGravatar german772022-09-07 01:04:00 -0500
commit19a4e12e6ea6c3d06ee227f3ef1a6cbf93850f6e (patch)
treef96054552ebe182e75fd77eabdcdf205a0dffe46 /src/core/hle/service/mii
parentcore: nfp: Implement amiibo encryption (diff)
downloadyuzu-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.cpp32
-rw-r--r--src/core/hle/service/mii/mii_manager.cpp88
-rw-r--r--src/core/hle/service/mii/mii_manager.h9
-rw-r--r--src/core/hle/service/mii/types.h138
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
45MiiInfo ConvertStoreDataToInfo(const MiiStoreData& data) { 45CharInfo 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
412ResultVal<MiiInfo> MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info, 412ResultVal<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
422MiiInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) { 422CharInfo 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
426MiiInfo MiiManager::BuildDefault(std::size_t index) { 426CharInfo 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
430CharInfo 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
430ResultVal<std::vector<MiiInfoElement>> MiiManager::GetDefault(SourceFlag source_flag) { 506ResultVal<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
444Result MiiManager::GetIndex([[maybe_unused]] const MiiInfo& info, u32& index) { 520Result 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
28private: 29private:
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};
87DECLARE_ENUM_FLAG_OPERATORS(SourceFlag); 87DECLARE_ENUM_FLAG_OPERATORS(SourceFlag);
88 88
89struct MiiInfo { 89// nn::mii::CharInfo
90struct 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};
143static_assert(sizeof(MiiInfo) == 0x58, "MiiInfo has incorrect size."); 144static_assert(sizeof(CharInfo) == 0x58, "CharInfo has incorrect size.");
144static_assert(std::has_unique_object_representations_v<MiiInfo>, 145static_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
149struct MiiInfoElement { 150struct 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};
155static_assert(sizeof(MiiInfoElement) == 0x5c, "MiiInfoElement has incorrect size."); 156static_assert(sizeof(MiiInfoElement) == 0x5c, "MiiInfoElement has incorrect size.");
@@ -243,6 +244,131 @@ static_assert(sizeof(MiiStoreBitFields) == 0x1c, "MiiStoreBitFields has incorrec
243static_assert(std::is_trivially_copyable_v<MiiStoreBitFields>, 244static_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
251struct 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};
370static_assert(sizeof(Ver3StoreData) == 0x60, "Ver3StoreData is an invalid size");
371
246struct MiiStoreData { 372struct MiiStoreData {
247 using Name = std::array<char16_t, 10>; 373 using Name = std::array<char16_t, 10>;
248 374