From daf5b8c61b217632193d2777f8e5787d3c14e50a Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Tue, 18 Dec 2018 09:08:44 -0500 Subject: mii: Add MiiManager class to manage Mii database Provides serialization/deserialization to the database in system save files, accessors for database state and proper handling of both major Mii formats (MiiInfo and MiiStoreData) --- src/core/hle/service/mii/mii_manager.h | 253 +++++++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 src/core/hle/service/mii/mii_manager.h (limited to 'src/core/hle/service/mii/mii_manager.h') diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h new file mode 100644 index 000000000..069247cb6 --- /dev/null +++ b/src/core/hle/service/mii/mii_manager.h @@ -0,0 +1,253 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/uuid.h" + +namespace Service::Mii { + +constexpr std::size_t MAX_MIIS = 100; +constexpr u32 INVALID_INDEX = 0xFFFFFFFF; + +struct RandomParameters { + u32 unknown_1; + u32 unknown_2; + u32 unknown_3; +}; +static_assert(sizeof(RandomParameters) == 0xC, "RandomParameters has incorrect size."); + +enum class Source : u32 { + Database = 0, + Default = 1, + Account = 2, + Friend = 3, +}; + +struct MiiInfo { + Common::UUID uuid; + std::array name; + u8 font_region; + u8 favorite_color; + u8 gender; + u8 height; + u8 weight; + u8 mii_type; + u8 mii_region; + u8 face_type; + u8 face_color; + u8 face_wrinkle; + u8 face_makeup; + u8 hair_type; + u8 hair_color; + bool hair_flip; + u8 eye_type; + u8 eye_color; + u8 eye_scale; + u8 eye_aspect_ratio; + u8 eye_rotate; + u8 eye_x; + u8 eye_y; + u8 eyebrow_type; + u8 eyebrow_color; + u8 eyebrow_scale; + u8 eyebrow_aspect_ratio; + u8 eyebrow_rotate; + u8 eyebrow_x; + u8 eyebrow_y; + u8 nose_type; + u8 nose_scale; + u8 nose_y; + u8 mouth_type; + u8 mouth_color; + u8 mouth_scale; + u8 mouth_aspect_ratio; + u8 mouth_y; + u8 facial_hair_color; + u8 beard_type; + u8 mustache_type; + u8 mustache_scale; + u8 mustache_y; + u8 glasses_type; + u8 glasses_color; + u8 glasses_scale; + u8 glasses_y; + u8 mole_type; + u8 mole_scale; + u8 mole_x; + u8 mole_y; + INSERT_PADDING_BYTES(1); + + std::u16string Name() const; +}; +static_assert(sizeof(MiiInfo) == 0x58, "MiiInfo has incorrect size."); + +bool operator==(const MiiInfo& lhs, const MiiInfo& rhs); +bool operator!=(const MiiInfo& lhs, const MiiInfo& rhs); + +#pragma pack(push, 4) +struct MiiInfoElement { + MiiInfo info; + Source source; +}; +static_assert(sizeof(MiiInfoElement) == 0x5C, "MiiInfoElement has incorrect size."); + +struct MiiStoreBitFields { + union { + u32 word_0; + + BitField<24, 8, u32> hair_type; + BitField<23, 1, u32> mole_type; + BitField<16, 7, u32> height; + BitField<15, 1, u32> hair_flip; + BitField<8, 7, u32> weight; + BitField<0, 7, u32> hair_color; + }; + + union { + u32 word_1; + + BitField<31, 1, u32> gender; + BitField<24, 7, u32> eye_color; + BitField<16, 7, u32> eyebrow_color; + BitField<8, 7, u32> mouth_color; + BitField<0, 7, u32> facial_hair_color; + }; + + union { + u32 word_2; + + BitField<31, 1, u32> mii_type; + BitField<24, 7, u32> glasses_color; + BitField<22, 2, u32> font_region; + BitField<16, 6, u32> eye_type; + BitField<14, 2, u32> mii_region; + BitField<8, 6, u32> mouth_type; + BitField<5, 3, u32> glasses_scale; + BitField<0, 5, u32> eye_y; + }; + + union { + u32 word_3; + + BitField<29, 3, u32> mustache_type; + BitField<24, 5, u32> eyebrow_type; + BitField<21, 3, u32> beard_type; + BitField<16, 5, u32> nose_type; + BitField<13, 3, u32> mouth_aspect; + BitField<8, 5, u32> nose_y; + BitField<5, 3, u32> eyebrow_aspect; + BitField<0, 5, u32> mouth_y; + }; + + union { + u32 word_4; + + BitField<29, 3, u32> eye_rotate; + BitField<24, 5, u32> mustache_y; + BitField<21, 3, u32> eye_aspect; + BitField<16, 5, u32> glasses_y; + BitField<13, 3, u32> eye_scale; + BitField<8, 5, u32> mole_x; + BitField<0, 5, u32> mole_y; + }; + + union { + u32 word_5; + + BitField<24, 5, u32> glasses_type; + BitField<20, 4, u32> face_type; + BitField<16, 4, u32> favorite_color; + BitField<12, 4, u32> face_wrinkle; + BitField<8, 4, u32> face_color; + BitField<4, 4, u32> eye_x; + BitField<0, 4, u32> face_makeup; + }; + + union { + u32 word_6; + + BitField<28, 4, u32> eyebrow_rotate; + BitField<24, 4, u32> eyebrow_scale; + BitField<20, 4, u32> eyebrow_y; + BitField<16, 4, u32> eyebrow_x; + BitField<12, 4, u32> mouth_scale; + BitField<8, 4, u32> nose_scale; + BitField<4, 4, u32> mole_scale; + BitField<0, 4, u32> mustache_scale; + }; +}; +static_assert(sizeof(MiiStoreBitFields) == 0x1C, "MiiStoreBitFields has incorrect size."); + +struct MiiStoreData { + // This corresponds to the above structure MiiStoreBitFields. I did it like this because the + // BitField<> type makes this (and any thing that contains it) not trivially copyable, which is + // not suitable for our uses. + std::array data; + static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size."); + + std::array name; + Common::UUID uuid; + u16 crc_1; + u16 crc_2; + + std::u16string Name() const; +}; +static_assert(sizeof(MiiStoreData) == 0x44, "MiiStoreData has incorrect size."); + +struct MiiStoreDataElement { + MiiStoreData data; + Source source; +}; +static_assert(sizeof(MiiStoreDataElement) == 0x48, "MiiStoreDataElement has incorrect size."); + +struct MiiDatabase { + u32 magic; // 'NFDB' + std::array miis; + INSERT_PADDING_BYTES(1); + u8 count; + u16 crc; +}; +static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size."); +#pragma pack(pop) + +// The Mii manager is responsible for loading and storing the Miis to the database in NAND along +// with providing an easy interface for HLE emulation of the mii service. +class MiiManager { +public: + MiiManager(); + ~MiiManager(); + + MiiInfo CreateRandom(RandomParameters params); + MiiInfo CreateDefault(u32 index); + + bool Empty() const; + bool Full() const; + + void Clear(); + + u32 Size() const; + + MiiInfo GetInfo(u32 index) const; + MiiInfoElement GetInfoElement(u32 index) const; + MiiStoreData GetStoreData(u32 index) const; + MiiStoreDataElement GetStoreDataElement(u32 index) const; + + bool Remove(Common::UUID uuid); + u32 IndexOf(Common::UUID uuid) const; + u32 IndexOf(MiiInfo info) const; + + bool Move(Common::UUID uuid, u32 new_index); + bool AddOrReplace(MiiStoreData data); + +private: + void WriteToFile(); + void ReadFromFile(); + + MiiDatabase database; +}; + +}; // namespace Service::Mii -- cgit v1.2.3 From f0db2e3ef36a77f2f3eaf2dca15ddfe8851edecb Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 24 Dec 2018 13:30:07 -0500 Subject: mii_manager: Cleanup and optimization --- src/core/hle/service/mii/mii_manager.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/core/hle/service/mii/mii_manager.h') diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h index 069247cb6..f7e3d2cf9 100644 --- a/src/core/hle/service/mii/mii_manager.h +++ b/src/core/hle/service/mii/mii_manager.h @@ -84,6 +84,8 @@ struct MiiInfo { std::u16string Name() const; }; static_assert(sizeof(MiiInfo) == 0x58, "MiiInfo has incorrect size."); +static_assert(std::has_unique_object_representations_v, + "All bits of MiiInfo must contribute to its value."); bool operator==(const MiiInfo& lhs, const MiiInfo& rhs); bool operator!=(const MiiInfo& lhs, const MiiInfo& rhs); @@ -238,15 +240,19 @@ public: bool Remove(Common::UUID uuid); u32 IndexOf(Common::UUID uuid) const; - u32 IndexOf(MiiInfo info) const; + u32 IndexOf(const MiiInfo& info) const; bool Move(Common::UUID uuid, u32 new_index); - bool AddOrReplace(MiiStoreData data); + bool AddOrReplace(const MiiStoreData& data); private: void WriteToFile(); void ReadFromFile(); + MiiStoreData CreateMiiWithUniqueUUID() const; + + void EnsureDatabasePartition(); + MiiDatabase database; }; -- cgit v1.2.3 From c40cff454d0b4af1c14cafe11ca7372be8ccbd11 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 24 Dec 2018 13:39:07 -0500 Subject: mii: Implement IsUpdated command (IPC 0) --- src/core/hle/service/mii/mii_manager.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/core/hle/service/mii/mii_manager.h') diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h index f7e3d2cf9..bf955930d 100644 --- a/src/core/hle/service/mii/mii_manager.h +++ b/src/core/hle/service/mii/mii_manager.h @@ -226,6 +226,9 @@ public: MiiInfo CreateRandom(RandomParameters params); MiiInfo CreateDefault(u32 index); + bool CheckUpdatedFlag() const; + void ResetUpdatedFlag(); + bool Empty() const; bool Full() const; @@ -254,6 +257,7 @@ private: void EnsureDatabasePartition(); MiiDatabase database; + bool updated_flag = false; }; }; // namespace Service::Mii -- cgit v1.2.3 From 1aa2b99a982e83022c9aae23c6a47eae119d21a4 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 27 Dec 2018 20:54:44 -0500 Subject: mii: Implement Delete and Destroy file --- src/core/hle/service/mii/mii_manager.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/core/hle/service/mii/mii_manager.h') diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h index bf955930d..38ad78a0d 100644 --- a/src/core/hle/service/mii/mii_manager.h +++ b/src/core/hle/service/mii/mii_manager.h @@ -27,6 +27,8 @@ enum class Source : u32 { Friend = 3, }; +std::ostream& operator<<(std::ostream& os, Source source); + struct MiiInfo { Common::UUID uuid; std::array name; @@ -183,6 +185,8 @@ struct MiiStoreBitFields { }; }; static_assert(sizeof(MiiStoreBitFields) == 0x1C, "MiiStoreBitFields has incorrect size."); +static_assert(std::is_trivially_copyable_v, + "MiiStoreBitFields is not trivially copyable."); struct MiiStoreData { // This corresponds to the above structure MiiStoreBitFields. I did it like this because the @@ -229,6 +233,8 @@ public: bool CheckUpdatedFlag() const; void ResetUpdatedFlag(); + bool IsTestModeEnabled() const; + bool Empty() const; bool Full() const; @@ -248,6 +254,9 @@ public: bool Move(Common::UUID uuid, u32 new_index); bool AddOrReplace(const MiiStoreData& data); + bool DestroyFile(); + bool DeleteFile(); + private: void WriteToFile(); void ReadFromFile(); @@ -258,6 +267,7 @@ private: MiiDatabase database; bool updated_flag = false; + bool is_test_mode_enabled = false; }; }; // namespace Service::Mii -- cgit v1.2.3