From c6d7da88c7ab125279ea4ccad0e3e839632b2f7a Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Wed, 14 Jul 2021 00:52:17 -0400 Subject: service: Append service name prefix to common filenames --- src/core/hle/service/mii/manager.cpp | 465 ------------------------------- src/core/hle/service/mii/manager.h | 333 ---------------------- src/core/hle/service/mii/mii.cpp | 2 +- src/core/hle/service/mii/mii_manager.cpp | 465 +++++++++++++++++++++++++++++++ src/core/hle/service/mii/mii_manager.h | 333 ++++++++++++++++++++++ src/core/hle/service/mii/raw_data.h | 2 +- 6 files changed, 800 insertions(+), 800 deletions(-) delete mode 100644 src/core/hle/service/mii/manager.cpp delete mode 100644 src/core/hle/service/mii/manager.h create mode 100644 src/core/hle/service/mii/mii_manager.cpp create mode 100644 src/core/hle/service/mii/mii_manager.h (limited to 'src/core/hle/service/mii') diff --git a/src/core/hle/service/mii/manager.cpp b/src/core/hle/service/mii/manager.cpp deleted file mode 100644 index 869d2763f..000000000 --- a/src/core/hle/service/mii/manager.cpp +++ /dev/null @@ -1,465 +0,0 @@ -// Copyright 2020 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include - -#include "common/assert.h" -#include "common/logging/log.h" -#include "common/string_util.h" - -#include "core/hle/service/acc/profile_manager.h" -#include "core/hle/service/mii/manager.h" -#include "core/hle/service/mii/raw_data.h" -#include "core/hle/service/mii/types.h" - -namespace Service::Mii { - -namespace { - -constexpr ResultCode ERROR_CANNOT_FIND_ENTRY{ErrorModule::Mii, 4}; - -constexpr std::size_t BaseMiiCount{2}; -constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()}; - -constexpr MiiStoreData::Name DefaultMiiName{u'y', u'u', u'z', u'u'}; -constexpr std::array HairColorLookup{8, 1, 2, 3, 4, 5, 6, 7}; -constexpr std::array EyeColorLookup{8, 9, 10, 11, 12, 13}; -constexpr std::array MouthColorLookup{19, 20, 21, 22, 23}; -constexpr std::array GlassesColorLookup{8, 14, 15, 16, 17, 18, 0}; -constexpr std::array EyeRotateLookup{ - {0x03, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x04, - 0x04, 0x04, 0x03, 0x03, 0x04, 0x03, 0x04, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x03, 0x04, 0x04, - 0x04, 0x03, 0x03, 0x03, 0x04, 0x04, 0x03, 0x03, 0x03, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x03, 0x04, 0x04}}; -constexpr std::array EyebrowRotateLookup{{0x06, 0x06, 0x05, 0x07, 0x06, 0x07, 0x06, 0x07, - 0x04, 0x07, 0x06, 0x08, 0x05, 0x05, 0x06, 0x06, - 0x07, 0x07, 0x06, 0x06, 0x05, 0x06, 0x07, 0x05}}; - -template -std::array ResizeArray(const std::array& in) { - std::array out{}; - std::memcpy(out.data(), in.data(), sizeof(T) * std::min(SourceArraySize, DestArraySize)); - return out; -} - -MiiInfo ConvertStoreDataToInfo(const MiiStoreData& data) { - MiiStoreBitFields bf; - std::memcpy(&bf, data.data.data.data(), sizeof(MiiStoreBitFields)); - - return { - .uuid = data.data.uuid, - .name = ResizeArray(data.data.name), - .font_region = static_cast(bf.font_region.Value()), - .favorite_color = static_cast(bf.favorite_color.Value()), - .gender = static_cast(bf.gender.Value()), - .height = static_cast(bf.height.Value()), - .build = static_cast(bf.build.Value()), - .type = static_cast(bf.type.Value()), - .region_move = static_cast(bf.region_move.Value()), - .faceline_type = static_cast(bf.faceline_type.Value()), - .faceline_color = static_cast(bf.faceline_color.Value()), - .faceline_wrinkle = static_cast(bf.faceline_wrinkle.Value()), - .faceline_make = static_cast(bf.faceline_makeup.Value()), - .hair_type = static_cast(bf.hair_type.Value()), - .hair_color = static_cast(bf.hair_color.Value()), - .hair_flip = static_cast(bf.hair_flip.Value()), - .eye_type = static_cast(bf.eye_type.Value()), - .eye_color = static_cast(bf.eye_color.Value()), - .eye_scale = static_cast(bf.eye_scale.Value()), - .eye_aspect = static_cast(bf.eye_aspect.Value()), - .eye_rotate = static_cast(bf.eye_rotate.Value()), - .eye_x = static_cast(bf.eye_x.Value()), - .eye_y = static_cast(bf.eye_y.Value()), - .eyebrow_type = static_cast(bf.eyebrow_type.Value()), - .eyebrow_color = static_cast(bf.eyebrow_color.Value()), - .eyebrow_scale = static_cast(bf.eyebrow_scale.Value()), - .eyebrow_aspect = static_cast(bf.eyebrow_aspect.Value()), - .eyebrow_rotate = static_cast(bf.eyebrow_rotate.Value()), - .eyebrow_x = static_cast(bf.eyebrow_x.Value()), - .eyebrow_y = static_cast(bf.eyebrow_y.Value() + 3), - .nose_type = static_cast(bf.nose_type.Value()), - .nose_scale = static_cast(bf.nose_scale.Value()), - .nose_y = static_cast(bf.nose_y.Value()), - .mouth_type = static_cast(bf.mouth_type.Value()), - .mouth_color = static_cast(bf.mouth_color.Value()), - .mouth_scale = static_cast(bf.mouth_scale.Value()), - .mouth_aspect = static_cast(bf.mouth_aspect.Value()), - .mouth_y = static_cast(bf.mouth_y.Value()), - .beard_color = static_cast(bf.beard_color.Value()), - .beard_type = static_cast(bf.beard_type.Value()), - .mustache_type = static_cast(bf.mustache_type.Value()), - .mustache_scale = static_cast(bf.mustache_scale.Value()), - .mustache_y = static_cast(bf.mustache_y.Value()), - .glasses_type = static_cast(bf.glasses_type.Value()), - .glasses_color = static_cast(bf.glasses_color.Value()), - .glasses_scale = static_cast(bf.glasses_scale.Value()), - .glasses_y = static_cast(bf.glasses_y.Value()), - .mole_type = static_cast(bf.mole_type.Value()), - .mole_scale = static_cast(bf.mole_scale.Value()), - .mole_x = static_cast(bf.mole_x.Value()), - .mole_y = static_cast(bf.mole_y.Value()), - .padding = 0, - }; -} - -u16 GenerateCrc16(const void* data, std::size_t size) { - s32 crc{}; - for (std::size_t i = 0; i < size; i++) { - crc ^= static_cast(data)[i] << 8; - for (std::size_t j = 0; j < 8; j++) { - crc <<= 1; - if ((crc & 0x10000) != 0) { - crc = (crc ^ 0x1021) & 0xFFFF; - } - } - } - return Common::swap16(static_cast(crc)); -} - -Common::UUID GenerateValidUUID() { - auto uuid{Common::UUID::Generate()}; - - // Bit 7 must be set, and bit 6 unset for the UUID to be valid - uuid.uuid[1] &= 0xFFFFFFFFFFFFFF3FULL; - uuid.uuid[1] |= 0x0000000000000080ULL; - - return uuid; -} - -template -T GetRandomValue(T min, T max) { - std::random_device device; - std::mt19937 gen(device()); - std::uniform_int_distribution distribution(static_cast(min), static_cast(max)); - return static_cast(distribution(gen)); -} - -template -T GetRandomValue(T max) { - return GetRandomValue({}, max); -} - -MiiStoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Common::UUID& user_id) { - MiiStoreBitFields bf{}; - - if (gender == Gender::All) { - gender = GetRandomValue(Gender::Maximum); - } - - bf.gender.Assign(gender); - bf.favorite_color.Assign(GetRandomValue(11)); - bf.region_move.Assign(0); - bf.font_region.Assign(FontRegion::Standard); - bf.type.Assign(0); - bf.height.Assign(64); - bf.build.Assign(64); - - if (age == Age::All) { - const auto temp{GetRandomValue(10)}; - if (temp >= 8) { - age = Age::Old; - } else if (temp >= 4) { - age = Age::Normal; - } else { - age = Age::Young; - } - } - - if (race == Race::All) { - const auto temp{GetRandomValue(10)}; - if (temp >= 8) { - race = Race::Black; - } else if (temp >= 4) { - race = Race::White; - } else { - race = Race::Asian; - } - } - - u32 axis_y{}; - if (gender == Gender::Female && age == Age::Young) { - axis_y = GetRandomValue(3); - } - - const std::size_t index{3 * static_cast(age) + - 9 * static_cast(gender) + static_cast(race)}; - - const auto faceline_type_info{RawData::RandomMiiFaceline.at(index)}; - const auto faceline_color_info{RawData::RandomMiiFacelineColor.at( - 3 * static_cast(gender) + static_cast(race))}; - const auto faceline_wrinkle_info{RawData::RandomMiiFacelineWrinkle.at(index)}; - const auto faceline_makeup_info{RawData::RandomMiiFacelineMakeup.at(index)}; - const auto hair_type_info{RawData::RandomMiiHairType.at(index)}; - const auto hair_color_info{RawData::RandomMiiHairColor.at(3 * static_cast(race) + - static_cast(age))}; - const auto eye_type_info{RawData::RandomMiiEyeType.at(index)}; - const auto eye_color_info{RawData::RandomMiiEyeColor.at(static_cast(race))}; - const auto eyebrow_type_info{RawData::RandomMiiEyebrowType.at(index)}; - const auto nose_type_info{RawData::RandomMiiNoseType.at(index)}; - const auto mouth_type_info{RawData::RandomMiiMouthType.at(index)}; - const auto glasses_type_info{RawData::RandomMiiGlassType.at(static_cast(age))}; - - bf.faceline_type.Assign( - faceline_type_info.values[GetRandomValue(faceline_type_info.values_count)]); - bf.faceline_color.Assign( - faceline_color_info.values[GetRandomValue(faceline_color_info.values_count)]); - bf.faceline_wrinkle.Assign( - faceline_wrinkle_info - .values[GetRandomValue(faceline_wrinkle_info.values_count)]); - bf.faceline_makeup.Assign( - faceline_makeup_info - .values[GetRandomValue(faceline_makeup_info.values_count)]); - - bf.hair_type.Assign( - hair_type_info.values[GetRandomValue(hair_type_info.values_count)]); - bf.hair_color.Assign( - HairColorLookup[hair_color_info - .values[GetRandomValue(hair_color_info.values_count)]]); - bf.hair_flip.Assign(GetRandomValue(HairFlip::Maximum)); - - bf.eye_type.Assign( - eye_type_info.values[GetRandomValue(eye_type_info.values_count)]); - - const auto eye_rotate_1{gender != Gender::Male ? 4 : 2}; - const auto eye_rotate_2{gender != Gender::Male ? 3 : 4}; - const auto eye_rotate_offset{32 - EyeRotateLookup[eye_rotate_1] + eye_rotate_2}; - const auto eye_rotate{32 - EyeRotateLookup[bf.eye_type]}; - - bf.eye_color.Assign( - EyeColorLookup[eye_color_info - .values[GetRandomValue(eye_color_info.values_count)]]); - bf.eye_scale.Assign(4); - bf.eye_aspect.Assign(3); - bf.eye_rotate.Assign(eye_rotate_offset - eye_rotate); - bf.eye_x.Assign(2); - bf.eye_y.Assign(axis_y + 12); - - bf.eyebrow_type.Assign( - eyebrow_type_info.values[GetRandomValue(eyebrow_type_info.values_count)]); - - const auto eyebrow_rotate_1{race == Race::Asian ? 6 : 0}; - const auto eyebrow_y{race == Race::Asian ? 9 : 10}; - const auto eyebrow_rotate_offset{32 - EyebrowRotateLookup[eyebrow_rotate_1] + 6}; - const auto eyebrow_rotate{ - 32 - EyebrowRotateLookup[static_cast(bf.eyebrow_type.Value())]}; - - bf.eyebrow_color.Assign(bf.hair_color); - bf.eyebrow_scale.Assign(4); - bf.eyebrow_aspect.Assign(3); - bf.eyebrow_rotate.Assign(eyebrow_rotate_offset - eyebrow_rotate); - bf.eyebrow_x.Assign(2); - bf.eyebrow_y.Assign(axis_y + eyebrow_y); - - const auto nose_scale{gender == Gender::Female ? 3 : 4}; - - bf.nose_type.Assign( - nose_type_info.values[GetRandomValue(nose_type_info.values_count)]); - bf.nose_scale.Assign(nose_scale); - bf.nose_y.Assign(axis_y + 9); - - const auto mouth_color{gender == Gender::Female ? GetRandomValue(4) : 0}; - - bf.mouth_type.Assign( - mouth_type_info.values[GetRandomValue(mouth_type_info.values_count)]); - bf.mouth_color.Assign(MouthColorLookup[mouth_color]); - bf.mouth_scale.Assign(4); - bf.mouth_aspect.Assign(3); - bf.mouth_y.Assign(axis_y + 13); - - bf.beard_color.Assign(bf.hair_color); - bf.mustache_scale.Assign(4); - - if (gender == Gender::Male && age != Age::Young && GetRandomValue(10) < 2) { - const auto mustache_and_beard_flag{ - GetRandomValue(BeardAndMustacheFlag::All)}; - - auto beard_type{BeardType::None}; - auto mustache_type{MustacheType::None}; - - if ((mustache_and_beard_flag & BeardAndMustacheFlag::Beard) == - BeardAndMustacheFlag::Beard) { - beard_type = GetRandomValue(BeardType::Beard1, BeardType::Beard5); - } - - if ((mustache_and_beard_flag & BeardAndMustacheFlag::Mustache) == - BeardAndMustacheFlag::Mustache) { - mustache_type = - GetRandomValue(MustacheType::Mustache1, MustacheType::Mustache5); - } - - bf.mustache_type.Assign(mustache_type); - bf.beard_type.Assign(beard_type); - bf.mustache_y.Assign(10); - } else { - bf.mustache_type.Assign(MustacheType::None); - bf.beard_type.Assign(BeardType::None); - bf.mustache_y.Assign(axis_y + 10); - } - - const auto glasses_type_start{GetRandomValue(100)}; - u8 glasses_type{}; - while (glasses_type_start < glasses_type_info.values[glasses_type]) { - if (++glasses_type >= glasses_type_info.values_count) { - UNREACHABLE(); - break; - } - } - - bf.glasses_type.Assign(glasses_type); - bf.glasses_color.Assign(GlassesColorLookup[0]); - bf.glasses_scale.Assign(4); - bf.glasses_y.Assign(axis_y + 10); - - bf.mole_type.Assign(0); - bf.mole_scale.Assign(4); - bf.mole_x.Assign(2); - bf.mole_y.Assign(20); - - return {DefaultMiiName, bf, user_id}; -} - -MiiStoreData BuildDefaultStoreData(const DefaultMii& info, const Common::UUID& user_id) { - MiiStoreBitFields bf{}; - - bf.font_region.Assign(info.font_region); - bf.favorite_color.Assign(info.favorite_color); - bf.gender.Assign(info.gender); - bf.height.Assign(info.height); - bf.build.Assign(info.weight); - bf.type.Assign(info.type); - bf.region_move.Assign(info.region); - bf.faceline_type.Assign(info.face_type); - bf.faceline_color.Assign(info.face_color); - bf.faceline_wrinkle.Assign(info.face_wrinkle); - bf.faceline_makeup.Assign(info.face_makeup); - bf.hair_type.Assign(info.hair_type); - bf.hair_color.Assign(HairColorLookup[info.hair_color]); - bf.hair_flip.Assign(static_cast(info.hair_flip)); - bf.eye_type.Assign(info.eye_type); - bf.eye_color.Assign(EyeColorLookup[info.eye_color]); - bf.eye_scale.Assign(info.eye_scale); - bf.eye_aspect.Assign(info.eye_aspect); - bf.eye_rotate.Assign(info.eye_rotate); - bf.eye_x.Assign(info.eye_x); - bf.eye_y.Assign(info.eye_y); - bf.eyebrow_type.Assign(info.eyebrow_type); - bf.eyebrow_color.Assign(HairColorLookup[info.eyebrow_color]); - bf.eyebrow_scale.Assign(info.eyebrow_scale); - bf.eyebrow_aspect.Assign(info.eyebrow_aspect); - bf.eyebrow_rotate.Assign(info.eyebrow_rotate); - bf.eyebrow_x.Assign(info.eyebrow_x); - bf.eyebrow_y.Assign(info.eyebrow_y - 3); - bf.nose_type.Assign(info.nose_type); - bf.nose_scale.Assign(info.nose_scale); - bf.nose_y.Assign(info.nose_y); - bf.mouth_type.Assign(info.mouth_type); - bf.mouth_color.Assign(MouthColorLookup[info.mouth_color]); - bf.mouth_scale.Assign(info.mouth_scale); - bf.mouth_aspect.Assign(info.mouth_aspect); - bf.mouth_y.Assign(info.mouth_y); - bf.beard_color.Assign(HairColorLookup[info.beard_color]); - bf.beard_type.Assign(static_cast(info.beard_type)); - bf.mustache_type.Assign(static_cast(info.mustache_type)); - bf.mustache_scale.Assign(info.mustache_scale); - bf.mustache_y.Assign(info.mustache_y); - bf.glasses_type.Assign(info.glasses_type); - bf.glasses_color.Assign(GlassesColorLookup[info.glasses_color]); - bf.glasses_scale.Assign(info.glasses_scale); - bf.glasses_y.Assign(info.glasses_y); - bf.mole_type.Assign(info.mole_type); - bf.mole_scale.Assign(info.mole_scale); - bf.mole_x.Assign(info.mole_x); - bf.mole_y.Assign(info.mole_y); - - return {DefaultMiiName, bf, user_id}; -} - -} // namespace - -MiiStoreData::MiiStoreData() = default; - -MiiStoreData::MiiStoreData(const MiiStoreData::Name& name, const MiiStoreBitFields& bit_fields, - const Common::UUID& user_id) { - data.name = name; - data.uuid = GenerateValidUUID(); - - std::memcpy(data.data.data(), &bit_fields, sizeof(MiiStoreBitFields)); - data_crc = GenerateCrc16(data.data.data(), sizeof(data)); - device_crc = GenerateCrc16(&user_id, sizeof(Common::UUID)); -} - -MiiManager::MiiManager() : user_id{Service::Account::ProfileManager().GetLastOpenedUser()} {} - -bool MiiManager::CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter) { - if ((source_flag & SourceFlag::Database) == SourceFlag::None) { - return false; - } - - const bool result{current_update_counter != update_counter}; - - current_update_counter = update_counter; - - return result; -} - -bool MiiManager::IsFullDatabase() const { - // TODO(bunnei): We don't implement the Mii database, so it cannot be full - return false; -} - -u32 MiiManager::GetCount(SourceFlag source_flag) const { - std::size_t count{}; - if ((source_flag & SourceFlag::Database) != SourceFlag::None) { - // TODO(bunnei): We don't implement the Mii database, but when we do, update this - count += 0; - } - if ((source_flag & SourceFlag::Default) != SourceFlag::None) { - count += (DefaultMiiCount - BaseMiiCount); - } - return static_cast(count); -} - -ResultVal MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info, - SourceFlag source_flag) { - if ((source_flag & SourceFlag::Database) == SourceFlag::None) { - return ERROR_CANNOT_FIND_ENTRY; - } - - // TODO(bunnei): We don't implement the Mii database, so we can't have an entry - return ERROR_CANNOT_FIND_ENTRY; -} - -MiiInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) { - return ConvertStoreDataToInfo(BuildRandomStoreData(age, gender, race, user_id)); -} - -MiiInfo MiiManager::BuildDefault(std::size_t index) { - return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::DefaultMii.at(index), user_id)); -} - -ResultVal> MiiManager::GetDefault(SourceFlag source_flag) { - std::vector result; - - if ((source_flag & SourceFlag::Default) == SourceFlag::None) { - return MakeResult(std::move(result)); - } - - for (std::size_t index = BaseMiiCount; index < DefaultMiiCount; index++) { - result.emplace_back(BuildDefault(index), Source::Default); - } - - return MakeResult(std::move(result)); -} - -ResultCode MiiManager::GetIndex([[maybe_unused]] const MiiInfo& info, u32& index) { - constexpr u32 INVALID_INDEX{0xFFFFFFFF}; - - index = INVALID_INDEX; - - // TODO(bunnei): We don't implement the Mii database, so we can't have an index - return ERROR_CANNOT_FIND_ENTRY; -} - -} // namespace Service::Mii diff --git a/src/core/hle/service/mii/manager.h b/src/core/hle/service/mii/manager.h deleted file mode 100644 index 8e048fc56..000000000 --- a/src/core/hle/service/mii/manager.h +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright 2020 yuzu emulator team -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include "common/bit_field.h" -#include "common/common_funcs.h" -#include "common/uuid.h" -#include "core/hle/result.h" -#include "core/hle/service/mii/types.h" - -namespace Service::Mii { - -enum class Source : u32 { - Database = 0, - Default = 1, - Account = 2, - Friend = 3, -}; - -enum class SourceFlag : u32 { - None = 0, - Database = 1 << 0, - Default = 1 << 1, -}; -DECLARE_ENUM_FLAG_OPERATORS(SourceFlag); - -struct MiiInfo { - Common::UUID uuid; - std::array name; - u8 font_region; - u8 favorite_color; - u8 gender; - u8 height; - u8 build; - u8 type; - u8 region_move; - u8 faceline_type; - u8 faceline_color; - u8 faceline_wrinkle; - u8 faceline_make; - u8 hair_type; - u8 hair_color; - u8 hair_flip; - u8 eye_type; - u8 eye_color; - u8 eye_scale; - u8 eye_aspect; - u8 eye_rotate; - u8 eye_x; - u8 eye_y; - u8 eyebrow_type; - u8 eyebrow_color; - u8 eyebrow_scale; - u8 eyebrow_aspect; - 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; - u8 mouth_y; - u8 beard_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; - u8 padding; - - 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."); - -#pragma pack(push, 4) - -struct MiiInfoElement { - MiiInfoElement(const MiiInfo& info_, Source source_) : info{info_}, source{source_} {} - - MiiInfo info{}; - Source source{}; -}; -static_assert(sizeof(MiiInfoElement) == 0x5c, "MiiInfoElement has incorrect size."); - -struct MiiStoreBitFields { - union { - u32 word_0{}; - - BitField<0, 8, u32> hair_type; - BitField<8, 7, u32> height; - BitField<15, 1, u32> mole_type; - BitField<16, 7, u32> build; - BitField<23, 1, HairFlip> hair_flip; - BitField<24, 7, u32> hair_color; - BitField<31, 1, u32> type; - }; - - union { - u32 word_1{}; - - BitField<0, 7, u32> eye_color; - BitField<7, 1, Gender> gender; - BitField<8, 7, u32> eyebrow_color; - BitField<16, 7, u32> mouth_color; - BitField<24, 7, u32> beard_color; - }; - - union { - u32 word_2{}; - - BitField<0, 7, u32> glasses_color; - BitField<8, 6, u32> eye_type; - BitField<14, 2, u32> region_move; - BitField<16, 6, u32> mouth_type; - BitField<22, 2, FontRegion> font_region; - BitField<24, 5, u32> eye_y; - BitField<29, 3, u32> glasses_scale; - }; - - union { - u32 word_3{}; - - BitField<0, 5, u32> eyebrow_type; - BitField<5, 3, MustacheType> mustache_type; - BitField<8, 5, u32> nose_type; - BitField<13, 3, BeardType> beard_type; - BitField<16, 5, u32> nose_y; - BitField<21, 3, u32> mouth_aspect; - BitField<24, 5, u32> mouth_y; - BitField<29, 3, u32> eyebrow_aspect; - }; - - union { - u32 word_4{}; - - BitField<0, 5, u32> mustache_y; - BitField<5, 3, u32> eye_rotate; - BitField<8, 5, u32> glasses_y; - BitField<13, 3, u32> eye_aspect; - BitField<16, 5, u32> mole_x; - BitField<21, 3, u32> eye_scale; - BitField<24, 5, u32> mole_y; - }; - - union { - u32 word_5{}; - - BitField<0, 5, u32> glasses_type; - BitField<8, 4, u32> favorite_color; - BitField<12, 4, u32> faceline_type; - BitField<16, 4, u32> faceline_color; - BitField<20, 4, u32> faceline_wrinkle; - BitField<24, 4, u32> faceline_makeup; - BitField<28, 4, u32> eye_x; - }; - - union { - u32 word_6{}; - - BitField<0, 4, u32> eyebrow_scale; - BitField<4, 4, u32> eyebrow_rotate; - BitField<8, 4, u32> eyebrow_x; - BitField<12, 4, u32> eyebrow_y; - BitField<16, 4, u32> nose_scale; - BitField<20, 4, u32> mouth_scale; - BitField<24, 4, u32> mustache_scale; - BitField<28, 4, u32> mole_scale; - }; -}; -static_assert(sizeof(MiiStoreBitFields) == 0x1c, "MiiStoreBitFields has incorrect size."); -static_assert(std::is_trivially_copyable_v, - "MiiStoreBitFields is not trivially copyable."); - -struct MiiStoreData { - using Name = std::array; - - MiiStoreData(); - MiiStoreData(const Name& name, const MiiStoreBitFields& bit_fields, - const Common::UUID& user_id); - - // 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. - struct { - std::array data{}; - static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size."); - - Name name{}; - Common::UUID uuid{Common::INVALID_UUID}; - } data; - - u16 data_crc{}; - u16 device_crc{}; -}; -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."); - -struct RandomMiiValues { - std::array values{}; -}; -static_assert(sizeof(RandomMiiValues) == 0xbc, "RandomMiiValues has incorrect size."); - -struct RandomMiiData4 { - Gender gender{}; - Age age{}; - Race race{}; - u32 values_count{}; - std::array values{}; -}; -static_assert(sizeof(RandomMiiData4) == 0xcc, "RandomMiiData4 has incorrect size."); - -struct RandomMiiData3 { - u32 arg_1; - u32 arg_2; - u32 values_count; - std::array values{}; -}; -static_assert(sizeof(RandomMiiData3) == 0xc8, "RandomMiiData3 has incorrect size."); - -struct RandomMiiData2 { - u32 arg_1; - u32 values_count; - std::array values{}; -}; -static_assert(sizeof(RandomMiiData2) == 0xc4, "RandomMiiData2 has incorrect size."); - -struct DefaultMii { - u32 face_type{}; - u32 face_color{}; - u32 face_wrinkle{}; - u32 face_makeup{}; - u32 hair_type{}; - u32 hair_color{}; - u32 hair_flip{}; - u32 eye_type{}; - u32 eye_color{}; - u32 eye_scale{}; - u32 eye_aspect{}; - u32 eye_rotate{}; - u32 eye_x{}; - u32 eye_y{}; - u32 eyebrow_type{}; - u32 eyebrow_color{}; - u32 eyebrow_scale{}; - u32 eyebrow_aspect{}; - u32 eyebrow_rotate{}; - u32 eyebrow_x{}; - u32 eyebrow_y{}; - u32 nose_type{}; - u32 nose_scale{}; - u32 nose_y{}; - u32 mouth_type{}; - u32 mouth_color{}; - u32 mouth_scale{}; - u32 mouth_aspect{}; - u32 mouth_y{}; - u32 mustache_type{}; - u32 beard_type{}; - u32 beard_color{}; - u32 mustache_scale{}; - u32 mustache_y{}; - u32 glasses_type{}; - u32 glasses_color{}; - u32 glasses_scale{}; - u32 glasses_y{}; - u32 mole_type{}; - u32 mole_scale{}; - u32 mole_x{}; - u32 mole_y{}; - u32 height{}; - u32 weight{}; - Gender gender{}; - u32 favorite_color{}; - u32 region{}; - FontRegion font_region{}; - u32 type{}; - INSERT_PADDING_WORDS(5); -}; -static_assert(sizeof(DefaultMii) == 0xd8, "MiiStoreData 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(); - - bool CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter); - bool IsFullDatabase() const; - u32 GetCount(SourceFlag source_flag) const; - ResultVal UpdateLatest(const MiiInfo& info, SourceFlag source_flag); - MiiInfo BuildRandom(Age age, Gender gender, Race race); - MiiInfo BuildDefault(std::size_t index); - ResultVal> GetDefault(SourceFlag source_flag); - ResultCode GetIndex(const MiiInfo& info, u32& index); - -private: - const Common::UUID user_id{Common::INVALID_UUID}; - u64 update_counter{}; -}; - -}; // namespace Service::Mii diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp index bbd81a88a..9d863486a 100644 --- a/src/core/hle/service/mii/mii.cpp +++ b/src/core/hle/service/mii/mii.cpp @@ -7,8 +7,8 @@ #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" -#include "core/hle/service/mii/manager.h" #include "core/hle/service/mii/mii.h" +#include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/service.h" #include "core/hle/service/sm/sm.h" diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp new file mode 100644 index 000000000..4fef2aea4 --- /dev/null +++ b/src/core/hle/service/mii/mii_manager.cpp @@ -0,0 +1,465 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include + +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/string_util.h" + +#include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/mii/mii_manager.h" +#include "core/hle/service/mii/raw_data.h" +#include "core/hle/service/mii/types.h" + +namespace Service::Mii { + +namespace { + +constexpr ResultCode ERROR_CANNOT_FIND_ENTRY{ErrorModule::Mii, 4}; + +constexpr std::size_t BaseMiiCount{2}; +constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()}; + +constexpr MiiStoreData::Name DefaultMiiName{u'y', u'u', u'z', u'u'}; +constexpr std::array HairColorLookup{8, 1, 2, 3, 4, 5, 6, 7}; +constexpr std::array EyeColorLookup{8, 9, 10, 11, 12, 13}; +constexpr std::array MouthColorLookup{19, 20, 21, 22, 23}; +constexpr std::array GlassesColorLookup{8, 14, 15, 16, 17, 18, 0}; +constexpr std::array EyeRotateLookup{ + {0x03, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x04, + 0x04, 0x04, 0x03, 0x03, 0x04, 0x03, 0x04, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x03, 0x04, 0x04, + 0x04, 0x03, 0x03, 0x03, 0x04, 0x04, 0x03, 0x03, 0x03, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x03, 0x04, 0x04, 0x03, 0x04, 0x04}}; +constexpr std::array EyebrowRotateLookup{{0x06, 0x06, 0x05, 0x07, 0x06, 0x07, 0x06, 0x07, + 0x04, 0x07, 0x06, 0x08, 0x05, 0x05, 0x06, 0x06, + 0x07, 0x07, 0x06, 0x06, 0x05, 0x06, 0x07, 0x05}}; + +template +std::array ResizeArray(const std::array& in) { + std::array out{}; + std::memcpy(out.data(), in.data(), sizeof(T) * std::min(SourceArraySize, DestArraySize)); + return out; +} + +MiiInfo ConvertStoreDataToInfo(const MiiStoreData& data) { + MiiStoreBitFields bf; + std::memcpy(&bf, data.data.data.data(), sizeof(MiiStoreBitFields)); + + return { + .uuid = data.data.uuid, + .name = ResizeArray(data.data.name), + .font_region = static_cast(bf.font_region.Value()), + .favorite_color = static_cast(bf.favorite_color.Value()), + .gender = static_cast(bf.gender.Value()), + .height = static_cast(bf.height.Value()), + .build = static_cast(bf.build.Value()), + .type = static_cast(bf.type.Value()), + .region_move = static_cast(bf.region_move.Value()), + .faceline_type = static_cast(bf.faceline_type.Value()), + .faceline_color = static_cast(bf.faceline_color.Value()), + .faceline_wrinkle = static_cast(bf.faceline_wrinkle.Value()), + .faceline_make = static_cast(bf.faceline_makeup.Value()), + .hair_type = static_cast(bf.hair_type.Value()), + .hair_color = static_cast(bf.hair_color.Value()), + .hair_flip = static_cast(bf.hair_flip.Value()), + .eye_type = static_cast(bf.eye_type.Value()), + .eye_color = static_cast(bf.eye_color.Value()), + .eye_scale = static_cast(bf.eye_scale.Value()), + .eye_aspect = static_cast(bf.eye_aspect.Value()), + .eye_rotate = static_cast(bf.eye_rotate.Value()), + .eye_x = static_cast(bf.eye_x.Value()), + .eye_y = static_cast(bf.eye_y.Value()), + .eyebrow_type = static_cast(bf.eyebrow_type.Value()), + .eyebrow_color = static_cast(bf.eyebrow_color.Value()), + .eyebrow_scale = static_cast(bf.eyebrow_scale.Value()), + .eyebrow_aspect = static_cast(bf.eyebrow_aspect.Value()), + .eyebrow_rotate = static_cast(bf.eyebrow_rotate.Value()), + .eyebrow_x = static_cast(bf.eyebrow_x.Value()), + .eyebrow_y = static_cast(bf.eyebrow_y.Value() + 3), + .nose_type = static_cast(bf.nose_type.Value()), + .nose_scale = static_cast(bf.nose_scale.Value()), + .nose_y = static_cast(bf.nose_y.Value()), + .mouth_type = static_cast(bf.mouth_type.Value()), + .mouth_color = static_cast(bf.mouth_color.Value()), + .mouth_scale = static_cast(bf.mouth_scale.Value()), + .mouth_aspect = static_cast(bf.mouth_aspect.Value()), + .mouth_y = static_cast(bf.mouth_y.Value()), + .beard_color = static_cast(bf.beard_color.Value()), + .beard_type = static_cast(bf.beard_type.Value()), + .mustache_type = static_cast(bf.mustache_type.Value()), + .mustache_scale = static_cast(bf.mustache_scale.Value()), + .mustache_y = static_cast(bf.mustache_y.Value()), + .glasses_type = static_cast(bf.glasses_type.Value()), + .glasses_color = static_cast(bf.glasses_color.Value()), + .glasses_scale = static_cast(bf.glasses_scale.Value()), + .glasses_y = static_cast(bf.glasses_y.Value()), + .mole_type = static_cast(bf.mole_type.Value()), + .mole_scale = static_cast(bf.mole_scale.Value()), + .mole_x = static_cast(bf.mole_x.Value()), + .mole_y = static_cast(bf.mole_y.Value()), + .padding = 0, + }; +} + +u16 GenerateCrc16(const void* data, std::size_t size) { + s32 crc{}; + for (std::size_t i = 0; i < size; i++) { + crc ^= static_cast(data)[i] << 8; + for (std::size_t j = 0; j < 8; j++) { + crc <<= 1; + if ((crc & 0x10000) != 0) { + crc = (crc ^ 0x1021) & 0xFFFF; + } + } + } + return Common::swap16(static_cast(crc)); +} + +Common::UUID GenerateValidUUID() { + auto uuid{Common::UUID::Generate()}; + + // Bit 7 must be set, and bit 6 unset for the UUID to be valid + uuid.uuid[1] &= 0xFFFFFFFFFFFFFF3FULL; + uuid.uuid[1] |= 0x0000000000000080ULL; + + return uuid; +} + +template +T GetRandomValue(T min, T max) { + std::random_device device; + std::mt19937 gen(device()); + std::uniform_int_distribution distribution(static_cast(min), static_cast(max)); + return static_cast(distribution(gen)); +} + +template +T GetRandomValue(T max) { + return GetRandomValue({}, max); +} + +MiiStoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Common::UUID& user_id) { + MiiStoreBitFields bf{}; + + if (gender == Gender::All) { + gender = GetRandomValue(Gender::Maximum); + } + + bf.gender.Assign(gender); + bf.favorite_color.Assign(GetRandomValue(11)); + bf.region_move.Assign(0); + bf.font_region.Assign(FontRegion::Standard); + bf.type.Assign(0); + bf.height.Assign(64); + bf.build.Assign(64); + + if (age == Age::All) { + const auto temp{GetRandomValue(10)}; + if (temp >= 8) { + age = Age::Old; + } else if (temp >= 4) { + age = Age::Normal; + } else { + age = Age::Young; + } + } + + if (race == Race::All) { + const auto temp{GetRandomValue(10)}; + if (temp >= 8) { + race = Race::Black; + } else if (temp >= 4) { + race = Race::White; + } else { + race = Race::Asian; + } + } + + u32 axis_y{}; + if (gender == Gender::Female && age == Age::Young) { + axis_y = GetRandomValue(3); + } + + const std::size_t index{3 * static_cast(age) + + 9 * static_cast(gender) + static_cast(race)}; + + const auto faceline_type_info{RawData::RandomMiiFaceline.at(index)}; + const auto faceline_color_info{RawData::RandomMiiFacelineColor.at( + 3 * static_cast(gender) + static_cast(race))}; + const auto faceline_wrinkle_info{RawData::RandomMiiFacelineWrinkle.at(index)}; + const auto faceline_makeup_info{RawData::RandomMiiFacelineMakeup.at(index)}; + const auto hair_type_info{RawData::RandomMiiHairType.at(index)}; + const auto hair_color_info{RawData::RandomMiiHairColor.at(3 * static_cast(race) + + static_cast(age))}; + const auto eye_type_info{RawData::RandomMiiEyeType.at(index)}; + const auto eye_color_info{RawData::RandomMiiEyeColor.at(static_cast(race))}; + const auto eyebrow_type_info{RawData::RandomMiiEyebrowType.at(index)}; + const auto nose_type_info{RawData::RandomMiiNoseType.at(index)}; + const auto mouth_type_info{RawData::RandomMiiMouthType.at(index)}; + const auto glasses_type_info{RawData::RandomMiiGlassType.at(static_cast(age))}; + + bf.faceline_type.Assign( + faceline_type_info.values[GetRandomValue(faceline_type_info.values_count)]); + bf.faceline_color.Assign( + faceline_color_info.values[GetRandomValue(faceline_color_info.values_count)]); + bf.faceline_wrinkle.Assign( + faceline_wrinkle_info + .values[GetRandomValue(faceline_wrinkle_info.values_count)]); + bf.faceline_makeup.Assign( + faceline_makeup_info + .values[GetRandomValue(faceline_makeup_info.values_count)]); + + bf.hair_type.Assign( + hair_type_info.values[GetRandomValue(hair_type_info.values_count)]); + bf.hair_color.Assign( + HairColorLookup[hair_color_info + .values[GetRandomValue(hair_color_info.values_count)]]); + bf.hair_flip.Assign(GetRandomValue(HairFlip::Maximum)); + + bf.eye_type.Assign( + eye_type_info.values[GetRandomValue(eye_type_info.values_count)]); + + const auto eye_rotate_1{gender != Gender::Male ? 4 : 2}; + const auto eye_rotate_2{gender != Gender::Male ? 3 : 4}; + const auto eye_rotate_offset{32 - EyeRotateLookup[eye_rotate_1] + eye_rotate_2}; + const auto eye_rotate{32 - EyeRotateLookup[bf.eye_type]}; + + bf.eye_color.Assign( + EyeColorLookup[eye_color_info + .values[GetRandomValue(eye_color_info.values_count)]]); + bf.eye_scale.Assign(4); + bf.eye_aspect.Assign(3); + bf.eye_rotate.Assign(eye_rotate_offset - eye_rotate); + bf.eye_x.Assign(2); + bf.eye_y.Assign(axis_y + 12); + + bf.eyebrow_type.Assign( + eyebrow_type_info.values[GetRandomValue(eyebrow_type_info.values_count)]); + + const auto eyebrow_rotate_1{race == Race::Asian ? 6 : 0}; + const auto eyebrow_y{race == Race::Asian ? 9 : 10}; + const auto eyebrow_rotate_offset{32 - EyebrowRotateLookup[eyebrow_rotate_1] + 6}; + const auto eyebrow_rotate{ + 32 - EyebrowRotateLookup[static_cast(bf.eyebrow_type.Value())]}; + + bf.eyebrow_color.Assign(bf.hair_color); + bf.eyebrow_scale.Assign(4); + bf.eyebrow_aspect.Assign(3); + bf.eyebrow_rotate.Assign(eyebrow_rotate_offset - eyebrow_rotate); + bf.eyebrow_x.Assign(2); + bf.eyebrow_y.Assign(axis_y + eyebrow_y); + + const auto nose_scale{gender == Gender::Female ? 3 : 4}; + + bf.nose_type.Assign( + nose_type_info.values[GetRandomValue(nose_type_info.values_count)]); + bf.nose_scale.Assign(nose_scale); + bf.nose_y.Assign(axis_y + 9); + + const auto mouth_color{gender == Gender::Female ? GetRandomValue(4) : 0}; + + bf.mouth_type.Assign( + mouth_type_info.values[GetRandomValue(mouth_type_info.values_count)]); + bf.mouth_color.Assign(MouthColorLookup[mouth_color]); + bf.mouth_scale.Assign(4); + bf.mouth_aspect.Assign(3); + bf.mouth_y.Assign(axis_y + 13); + + bf.beard_color.Assign(bf.hair_color); + bf.mustache_scale.Assign(4); + + if (gender == Gender::Male && age != Age::Young && GetRandomValue(10) < 2) { + const auto mustache_and_beard_flag{ + GetRandomValue(BeardAndMustacheFlag::All)}; + + auto beard_type{BeardType::None}; + auto mustache_type{MustacheType::None}; + + if ((mustache_and_beard_flag & BeardAndMustacheFlag::Beard) == + BeardAndMustacheFlag::Beard) { + beard_type = GetRandomValue(BeardType::Beard1, BeardType::Beard5); + } + + if ((mustache_and_beard_flag & BeardAndMustacheFlag::Mustache) == + BeardAndMustacheFlag::Mustache) { + mustache_type = + GetRandomValue(MustacheType::Mustache1, MustacheType::Mustache5); + } + + bf.mustache_type.Assign(mustache_type); + bf.beard_type.Assign(beard_type); + bf.mustache_y.Assign(10); + } else { + bf.mustache_type.Assign(MustacheType::None); + bf.beard_type.Assign(BeardType::None); + bf.mustache_y.Assign(axis_y + 10); + } + + const auto glasses_type_start{GetRandomValue(100)}; + u8 glasses_type{}; + while (glasses_type_start < glasses_type_info.values[glasses_type]) { + if (++glasses_type >= glasses_type_info.values_count) { + UNREACHABLE(); + break; + } + } + + bf.glasses_type.Assign(glasses_type); + bf.glasses_color.Assign(GlassesColorLookup[0]); + bf.glasses_scale.Assign(4); + bf.glasses_y.Assign(axis_y + 10); + + bf.mole_type.Assign(0); + bf.mole_scale.Assign(4); + bf.mole_x.Assign(2); + bf.mole_y.Assign(20); + + return {DefaultMiiName, bf, user_id}; +} + +MiiStoreData BuildDefaultStoreData(const DefaultMii& info, const Common::UUID& user_id) { + MiiStoreBitFields bf{}; + + bf.font_region.Assign(info.font_region); + bf.favorite_color.Assign(info.favorite_color); + bf.gender.Assign(info.gender); + bf.height.Assign(info.height); + bf.build.Assign(info.weight); + bf.type.Assign(info.type); + bf.region_move.Assign(info.region); + bf.faceline_type.Assign(info.face_type); + bf.faceline_color.Assign(info.face_color); + bf.faceline_wrinkle.Assign(info.face_wrinkle); + bf.faceline_makeup.Assign(info.face_makeup); + bf.hair_type.Assign(info.hair_type); + bf.hair_color.Assign(HairColorLookup[info.hair_color]); + bf.hair_flip.Assign(static_cast(info.hair_flip)); + bf.eye_type.Assign(info.eye_type); + bf.eye_color.Assign(EyeColorLookup[info.eye_color]); + bf.eye_scale.Assign(info.eye_scale); + bf.eye_aspect.Assign(info.eye_aspect); + bf.eye_rotate.Assign(info.eye_rotate); + bf.eye_x.Assign(info.eye_x); + bf.eye_y.Assign(info.eye_y); + bf.eyebrow_type.Assign(info.eyebrow_type); + bf.eyebrow_color.Assign(HairColorLookup[info.eyebrow_color]); + bf.eyebrow_scale.Assign(info.eyebrow_scale); + bf.eyebrow_aspect.Assign(info.eyebrow_aspect); + bf.eyebrow_rotate.Assign(info.eyebrow_rotate); + bf.eyebrow_x.Assign(info.eyebrow_x); + bf.eyebrow_y.Assign(info.eyebrow_y - 3); + bf.nose_type.Assign(info.nose_type); + bf.nose_scale.Assign(info.nose_scale); + bf.nose_y.Assign(info.nose_y); + bf.mouth_type.Assign(info.mouth_type); + bf.mouth_color.Assign(MouthColorLookup[info.mouth_color]); + bf.mouth_scale.Assign(info.mouth_scale); + bf.mouth_aspect.Assign(info.mouth_aspect); + bf.mouth_y.Assign(info.mouth_y); + bf.beard_color.Assign(HairColorLookup[info.beard_color]); + bf.beard_type.Assign(static_cast(info.beard_type)); + bf.mustache_type.Assign(static_cast(info.mustache_type)); + bf.mustache_scale.Assign(info.mustache_scale); + bf.mustache_y.Assign(info.mustache_y); + bf.glasses_type.Assign(info.glasses_type); + bf.glasses_color.Assign(GlassesColorLookup[info.glasses_color]); + bf.glasses_scale.Assign(info.glasses_scale); + bf.glasses_y.Assign(info.glasses_y); + bf.mole_type.Assign(info.mole_type); + bf.mole_scale.Assign(info.mole_scale); + bf.mole_x.Assign(info.mole_x); + bf.mole_y.Assign(info.mole_y); + + return {DefaultMiiName, bf, user_id}; +} + +} // namespace + +MiiStoreData::MiiStoreData() = default; + +MiiStoreData::MiiStoreData(const MiiStoreData::Name& name, const MiiStoreBitFields& bit_fields, + const Common::UUID& user_id) { + data.name = name; + data.uuid = GenerateValidUUID(); + + std::memcpy(data.data.data(), &bit_fields, sizeof(MiiStoreBitFields)); + data_crc = GenerateCrc16(data.data.data(), sizeof(data)); + device_crc = GenerateCrc16(&user_id, sizeof(Common::UUID)); +} + +MiiManager::MiiManager() : user_id{Service::Account::ProfileManager().GetLastOpenedUser()} {} + +bool MiiManager::CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter) { + if ((source_flag & SourceFlag::Database) == SourceFlag::None) { + return false; + } + + const bool result{current_update_counter != update_counter}; + + current_update_counter = update_counter; + + return result; +} + +bool MiiManager::IsFullDatabase() const { + // TODO(bunnei): We don't implement the Mii database, so it cannot be full + return false; +} + +u32 MiiManager::GetCount(SourceFlag source_flag) const { + std::size_t count{}; + if ((source_flag & SourceFlag::Database) != SourceFlag::None) { + // TODO(bunnei): We don't implement the Mii database, but when we do, update this + count += 0; + } + if ((source_flag & SourceFlag::Default) != SourceFlag::None) { + count += (DefaultMiiCount - BaseMiiCount); + } + return static_cast(count); +} + +ResultVal MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info, + SourceFlag source_flag) { + if ((source_flag & SourceFlag::Database) == SourceFlag::None) { + return ERROR_CANNOT_FIND_ENTRY; + } + + // TODO(bunnei): We don't implement the Mii database, so we can't have an entry + return ERROR_CANNOT_FIND_ENTRY; +} + +MiiInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) { + return ConvertStoreDataToInfo(BuildRandomStoreData(age, gender, race, user_id)); +} + +MiiInfo MiiManager::BuildDefault(std::size_t index) { + return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::DefaultMii.at(index), user_id)); +} + +ResultVal> MiiManager::GetDefault(SourceFlag source_flag) { + std::vector result; + + if ((source_flag & SourceFlag::Default) == SourceFlag::None) { + return MakeResult(std::move(result)); + } + + for (std::size_t index = BaseMiiCount; index < DefaultMiiCount; index++) { + result.emplace_back(BuildDefault(index), Source::Default); + } + + return MakeResult(std::move(result)); +} + +ResultCode MiiManager::GetIndex([[maybe_unused]] const MiiInfo& info, u32& index) { + constexpr u32 INVALID_INDEX{0xFFFFFFFF}; + + index = INVALID_INDEX; + + // TODO(bunnei): We don't implement the Mii database, so we can't have an index + return ERROR_CANNOT_FIND_ENTRY; +} + +} // namespace Service::Mii 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..8e048fc56 --- /dev/null +++ b/src/core/hle/service/mii/mii_manager.h @@ -0,0 +1,333 @@ +// Copyright 2020 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/uuid.h" +#include "core/hle/result.h" +#include "core/hle/service/mii/types.h" + +namespace Service::Mii { + +enum class Source : u32 { + Database = 0, + Default = 1, + Account = 2, + Friend = 3, +}; + +enum class SourceFlag : u32 { + None = 0, + Database = 1 << 0, + Default = 1 << 1, +}; +DECLARE_ENUM_FLAG_OPERATORS(SourceFlag); + +struct MiiInfo { + Common::UUID uuid; + std::array name; + u8 font_region; + u8 favorite_color; + u8 gender; + u8 height; + u8 build; + u8 type; + u8 region_move; + u8 faceline_type; + u8 faceline_color; + u8 faceline_wrinkle; + u8 faceline_make; + u8 hair_type; + u8 hair_color; + u8 hair_flip; + u8 eye_type; + u8 eye_color; + u8 eye_scale; + u8 eye_aspect; + u8 eye_rotate; + u8 eye_x; + u8 eye_y; + u8 eyebrow_type; + u8 eyebrow_color; + u8 eyebrow_scale; + u8 eyebrow_aspect; + 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; + u8 mouth_y; + u8 beard_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; + u8 padding; + + 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."); + +#pragma pack(push, 4) + +struct MiiInfoElement { + MiiInfoElement(const MiiInfo& info_, Source source_) : info{info_}, source{source_} {} + + MiiInfo info{}; + Source source{}; +}; +static_assert(sizeof(MiiInfoElement) == 0x5c, "MiiInfoElement has incorrect size."); + +struct MiiStoreBitFields { + union { + u32 word_0{}; + + BitField<0, 8, u32> hair_type; + BitField<8, 7, u32> height; + BitField<15, 1, u32> mole_type; + BitField<16, 7, u32> build; + BitField<23, 1, HairFlip> hair_flip; + BitField<24, 7, u32> hair_color; + BitField<31, 1, u32> type; + }; + + union { + u32 word_1{}; + + BitField<0, 7, u32> eye_color; + BitField<7, 1, Gender> gender; + BitField<8, 7, u32> eyebrow_color; + BitField<16, 7, u32> mouth_color; + BitField<24, 7, u32> beard_color; + }; + + union { + u32 word_2{}; + + BitField<0, 7, u32> glasses_color; + BitField<8, 6, u32> eye_type; + BitField<14, 2, u32> region_move; + BitField<16, 6, u32> mouth_type; + BitField<22, 2, FontRegion> font_region; + BitField<24, 5, u32> eye_y; + BitField<29, 3, u32> glasses_scale; + }; + + union { + u32 word_3{}; + + BitField<0, 5, u32> eyebrow_type; + BitField<5, 3, MustacheType> mustache_type; + BitField<8, 5, u32> nose_type; + BitField<13, 3, BeardType> beard_type; + BitField<16, 5, u32> nose_y; + BitField<21, 3, u32> mouth_aspect; + BitField<24, 5, u32> mouth_y; + BitField<29, 3, u32> eyebrow_aspect; + }; + + union { + u32 word_4{}; + + BitField<0, 5, u32> mustache_y; + BitField<5, 3, u32> eye_rotate; + BitField<8, 5, u32> glasses_y; + BitField<13, 3, u32> eye_aspect; + BitField<16, 5, u32> mole_x; + BitField<21, 3, u32> eye_scale; + BitField<24, 5, u32> mole_y; + }; + + union { + u32 word_5{}; + + BitField<0, 5, u32> glasses_type; + BitField<8, 4, u32> favorite_color; + BitField<12, 4, u32> faceline_type; + BitField<16, 4, u32> faceline_color; + BitField<20, 4, u32> faceline_wrinkle; + BitField<24, 4, u32> faceline_makeup; + BitField<28, 4, u32> eye_x; + }; + + union { + u32 word_6{}; + + BitField<0, 4, u32> eyebrow_scale; + BitField<4, 4, u32> eyebrow_rotate; + BitField<8, 4, u32> eyebrow_x; + BitField<12, 4, u32> eyebrow_y; + BitField<16, 4, u32> nose_scale; + BitField<20, 4, u32> mouth_scale; + BitField<24, 4, u32> mustache_scale; + BitField<28, 4, u32> mole_scale; + }; +}; +static_assert(sizeof(MiiStoreBitFields) == 0x1c, "MiiStoreBitFields has incorrect size."); +static_assert(std::is_trivially_copyable_v, + "MiiStoreBitFields is not trivially copyable."); + +struct MiiStoreData { + using Name = std::array; + + MiiStoreData(); + MiiStoreData(const Name& name, const MiiStoreBitFields& bit_fields, + const Common::UUID& user_id); + + // 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. + struct { + std::array data{}; + static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size."); + + Name name{}; + Common::UUID uuid{Common::INVALID_UUID}; + } data; + + u16 data_crc{}; + u16 device_crc{}; +}; +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."); + +struct RandomMiiValues { + std::array values{}; +}; +static_assert(sizeof(RandomMiiValues) == 0xbc, "RandomMiiValues has incorrect size."); + +struct RandomMiiData4 { + Gender gender{}; + Age age{}; + Race race{}; + u32 values_count{}; + std::array values{}; +}; +static_assert(sizeof(RandomMiiData4) == 0xcc, "RandomMiiData4 has incorrect size."); + +struct RandomMiiData3 { + u32 arg_1; + u32 arg_2; + u32 values_count; + std::array values{}; +}; +static_assert(sizeof(RandomMiiData3) == 0xc8, "RandomMiiData3 has incorrect size."); + +struct RandomMiiData2 { + u32 arg_1; + u32 values_count; + std::array values{}; +}; +static_assert(sizeof(RandomMiiData2) == 0xc4, "RandomMiiData2 has incorrect size."); + +struct DefaultMii { + u32 face_type{}; + u32 face_color{}; + u32 face_wrinkle{}; + u32 face_makeup{}; + u32 hair_type{}; + u32 hair_color{}; + u32 hair_flip{}; + u32 eye_type{}; + u32 eye_color{}; + u32 eye_scale{}; + u32 eye_aspect{}; + u32 eye_rotate{}; + u32 eye_x{}; + u32 eye_y{}; + u32 eyebrow_type{}; + u32 eyebrow_color{}; + u32 eyebrow_scale{}; + u32 eyebrow_aspect{}; + u32 eyebrow_rotate{}; + u32 eyebrow_x{}; + u32 eyebrow_y{}; + u32 nose_type{}; + u32 nose_scale{}; + u32 nose_y{}; + u32 mouth_type{}; + u32 mouth_color{}; + u32 mouth_scale{}; + u32 mouth_aspect{}; + u32 mouth_y{}; + u32 mustache_type{}; + u32 beard_type{}; + u32 beard_color{}; + u32 mustache_scale{}; + u32 mustache_y{}; + u32 glasses_type{}; + u32 glasses_color{}; + u32 glasses_scale{}; + u32 glasses_y{}; + u32 mole_type{}; + u32 mole_scale{}; + u32 mole_x{}; + u32 mole_y{}; + u32 height{}; + u32 weight{}; + Gender gender{}; + u32 favorite_color{}; + u32 region{}; + FontRegion font_region{}; + u32 type{}; + INSERT_PADDING_WORDS(5); +}; +static_assert(sizeof(DefaultMii) == 0xd8, "MiiStoreData 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(); + + bool CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter); + bool IsFullDatabase() const; + u32 GetCount(SourceFlag source_flag) const; + ResultVal UpdateLatest(const MiiInfo& info, SourceFlag source_flag); + MiiInfo BuildRandom(Age age, Gender gender, Race race); + MiiInfo BuildDefault(std::size_t index); + ResultVal> GetDefault(SourceFlag source_flag); + ResultCode GetIndex(const MiiInfo& info, u32& index); + +private: + const Common::UUID user_id{Common::INVALID_UUID}; + u64 update_counter{}; +}; + +}; // namespace Service::Mii diff --git a/src/core/hle/service/mii/raw_data.h b/src/core/hle/service/mii/raw_data.h index 0e35d69d2..a0d2b9d3a 100644 --- a/src/core/hle/service/mii/raw_data.h +++ b/src/core/hle/service/mii/raw_data.h @@ -7,7 +7,7 @@ #include #include "common/common_types.h" -#include "core/hle/service/mii/manager.h" +#include "core/hle/service/mii/mii_manager.h" namespace Service::Mii::RawData { -- cgit v1.2.3