From 19a4e12e6ea6c3d06ee227f3ef1a6cbf93850f6e Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Tue, 30 Aug 2022 00:33:47 -0500 Subject: core: nfp: Implement Convert and RecreateApplicationArea, accuracy fixes --- src/core/hle/service/mii/mii_manager.cpp | 88 +++++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 6 deletions(-) (limited to 'src/core/hle/service/mii/mii_manager.cpp') 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 ResizeArray(const std::array& i return out; } -MiiInfo ConvertStoreDataToInfo(const MiiStoreData& data) { +CharInfo ConvertStoreDataToInfo(const MiiStoreData& data) { MiiStoreBitFields bf; std::memcpy(&bf, data.data.data.data(), sizeof(MiiStoreBitFields)); @@ -409,8 +409,8 @@ u32 MiiManager::GetCount(SourceFlag source_flag) const { return static_cast(count); } -ResultVal MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info, - SourceFlag source_flag) { +ResultVal MiiManager::UpdateLatest([[maybe_unused]] const CharInfo& info, + SourceFlag source_flag) { if ((source_flag & SourceFlag::Database) == SourceFlag::None) { return ERROR_CANNOT_FIND_ENTRY; } @@ -419,14 +419,90 @@ ResultVal MiiManager::UpdateLatest([[maybe_unused]] const MiiInfo& info return ERROR_CANNOT_FIND_ENTRY; } -MiiInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) { +CharInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) { return ConvertStoreDataToInfo(BuildRandomStoreData(age, gender, race, user_id)); } -MiiInfo MiiManager::BuildDefault(std::size_t index) { +CharInfo MiiManager::BuildDefault(std::size_t index) { return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::DefaultMii.at(index), user_id)); } +CharInfo MiiManager::ConvertV3ToCharInfo(Ver3StoreData mii_v3) const { + Service::Mii::MiiManager manager; + auto mii = manager.BuildDefault(0); + + // Check if mii data exist + if (mii_v3.mii_name[0] == 0) { + return mii; + } + + // TODO: We are ignoring a bunch of data from the mii_v3 + + mii.gender = static_cast(mii_v3.mii_information.gender); + mii.favorite_color = static_cast(mii_v3.mii_information.favorite_color); + mii.height = mii_v3.height; + mii.build = mii_v3.build; + + mii.font_region = mii_v3.region_information.character_set; + memcpy(mii.name.data(), mii_v3.mii_name.data(), 10); + + mii.faceline_type = mii_v3.appearance_bits1.face_shape; + mii.faceline_color = mii_v3.appearance_bits1.skin_color; + mii.faceline_wrinkle = mii_v3.appearance_bits2.wrinkles; + mii.faceline_make = mii_v3.appearance_bits2.makeup; + + mii.hair_type = mii_v3.hair_style; + mii.hair_color = mii_v3.appearance_bits3.hair_color; + mii.hair_flip = mii_v3.appearance_bits3.flip_hair; + + mii.eye_type = static_cast(mii_v3.appearance_bits4.eye_type); + mii.eye_color = static_cast(mii_v3.appearance_bits4.eye_color); + mii.eye_scale = static_cast(mii_v3.appearance_bits4.eye_scale); + mii.eye_aspect = static_cast(mii_v3.appearance_bits4.eye_vertical_stretch); + mii.eye_rotate = static_cast(mii_v3.appearance_bits4.eye_rotation); + mii.eye_x = static_cast(mii_v3.appearance_bits4.eye_spacing); + mii.eye_y = static_cast(mii_v3.appearance_bits4.eye_y_position); + + mii.eyebrow_type = static_cast(mii_v3.appearance_bits5.eyebrow_style); + mii.eyebrow_color = static_cast(mii_v3.appearance_bits5.eyebrow_color); + mii.eyebrow_scale = static_cast(mii_v3.appearance_bits5.eyebrow_scale); + mii.eyebrow_aspect = static_cast(mii_v3.appearance_bits5.eyebrow_yscale); + mii.eyebrow_rotate = static_cast(mii_v3.appearance_bits5.eyebrow_rotation); + mii.eyebrow_x = static_cast(mii_v3.appearance_bits5.eyebrow_spacing); + mii.eyebrow_y = static_cast(mii_v3.appearance_bits5.eyebrow_y_position); + + mii.nose_type = static_cast(mii_v3.appearance_bits6.nose_type); + mii.nose_scale = static_cast(mii_v3.appearance_bits6.nose_scale); + mii.nose_y = static_cast(mii_v3.appearance_bits6.nose_y_position); + + mii.mouth_type = static_cast(mii_v3.appearance_bits7.mouth_type); + mii.mouth_color = static_cast(mii_v3.appearance_bits7.mouth_color); + mii.mouth_scale = static_cast(mii_v3.appearance_bits7.mouth_scale); + mii.mouth_aspect = static_cast(mii_v3.appearance_bits7.mouth_horizontal_stretch); + mii.mouth_y = static_cast(mii_v3.appearance_bits8.mouth_y_position); + + mii.mustache_type = static_cast(mii_v3.appearance_bits8.mustache_type); + mii.mustache_scale = static_cast(mii_v3.appearance_bits9.mustache_scale); + mii.mustache_y = static_cast(mii_v3.appearance_bits9.mustache_y_position); + + mii.beard_type = static_cast(mii_v3.appearance_bits9.bear_type); + mii.beard_color = static_cast(mii_v3.appearance_bits9.facial_hair_color); + + mii.glasses_type = static_cast(mii_v3.appearance_bits10.glasses_type); + mii.glasses_color = static_cast(mii_v3.appearance_bits10.glasses_color); + mii.glasses_scale = static_cast(mii_v3.appearance_bits10.glasses_scale); + mii.glasses_y = static_cast(mii_v3.appearance_bits10.glasses_y_position); + + mii.mole_type = static_cast(mii_v3.appearance_bits11.mole_enabled); + mii.mole_scale = static_cast(mii_v3.appearance_bits11.mole_scale); + mii.mole_x = static_cast(mii_v3.appearance_bits11.mole_x_position); + mii.mole_y = static_cast(mii_v3.appearance_bits11.mole_y_position); + + // TODO: Validate mii data + + return mii; +} + ResultVal> MiiManager::GetDefault(SourceFlag source_flag) { std::vector result; @@ -441,7 +517,7 @@ ResultVal> MiiManager::GetDefault(SourceFlag source_ return result; } -Result MiiManager::GetIndex([[maybe_unused]] const MiiInfo& info, u32& index) { +Result MiiManager::GetIndex([[maybe_unused]] const CharInfo& info, u32& index) { constexpr u32 INVALID_INDEX{0xFFFFFFFF}; index = INVALID_INDEX; -- cgit v1.2.3 From caa138b33f6bbc18cde4d403017dad6bd4387e13 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Tue, 30 Aug 2022 19:28:37 -0500 Subject: core: nfp: Correct date and amiibo name --- src/core/hle/service/mii/mii_manager.cpp | 3 ++- src/core/hle/service/nfp/amiibo_types.h | 12 +++++++----- src/core/hle/service/nfp/nfp.cpp | 29 ++++++++++++++++++++--------- src/core/hle/service/nfp/nfp.h | 10 +++++++--- 4 files changed, 36 insertions(+), 18 deletions(-) (limited to 'src/core/hle/service/mii/mii_manager.cpp') diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp index 97d1b948f..c484a9c8d 100644 --- a/src/core/hle/service/mii/mii_manager.cpp +++ b/src/core/hle/service/mii/mii_manager.cpp @@ -443,8 +443,9 @@ CharInfo MiiManager::ConvertV3ToCharInfo(Ver3StoreData mii_v3) const { mii.height = mii_v3.height; mii.build = mii_v3.build; + memset(mii.name.data(), 0, sizeof(mii.name)); + memcpy(mii.name.data(), mii_v3.mii_name.data(), sizeof(mii_v3.mii_name)); mii.font_region = mii_v3.region_information.character_set; - memcpy(mii.name.data(), mii_v3.mii_name.data(), 10); mii.faceline_type = mii_v3.appearance_bits1.face_shape; mii.faceline_color = mii_v3.appearance_bits1.skin_color; diff --git a/src/core/hle/service/nfp/amiibo_types.h b/src/core/hle/service/nfp/amiibo_types.h index bd0424ffd..c9c0932d0 100644 --- a/src/core/hle/service/nfp/amiibo_types.h +++ b/src/core/hle/service/nfp/amiibo_types.h @@ -8,6 +8,8 @@ #include "core/hle/service/mii/types.h" namespace Service::NFP { +static constexpr std::size_t amiibo_name_length = 0xA; + enum class ServiceType : u32 { User, Debug, @@ -76,16 +78,16 @@ using HashData = std::array; using ApplicationArea = std::array; struct AmiiboDate { - u16_be raw_date{}; + u16 raw_date{}; u16 GetYear() const { - return ((raw_date & 0xFE00) >> 9) + 2000; + return static_cast(((raw_date & 0xFE00) >> 9) + 2000); } u8 GetMonth() const { - return ((raw_date & 0x01E0) >> 5) - 1; + return static_cast(((raw_date & 0x01E0) >> 5) - 1); } u8 GetDay() const { - return raw_date & 0x001F; + return static_cast(raw_date & 0x001F); } }; static_assert(sizeof(AmiiboDate) == 2, "AmiiboDate is an invalid size"); @@ -107,7 +109,7 @@ struct AmiiboSettings { AmiiboDate init_date; AmiiboDate write_date; u32_be crc; - std::array amiibo_name; // UTF-16 text + std::array amiibo_name; // UTF-16 text }; static_assert(sizeof(AmiiboSettings) == 0x20, "AmiiboSettings is an invalid size"); diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 20fea87e6..fb89f6911 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -7,6 +7,7 @@ #include "common/fs/file.h" #include "common/fs/path_util.h" #include "common/logging/log.h" +#include "common/string_util.h" #include "core/core.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" @@ -917,20 +918,14 @@ Result Module::Interface::GetRegisterInfo(RegisterInfo& register_info) const { if (is_data_decoded && tag_data.settings.settings.amiibo_initialized != 0) { const auto& settings = tag_data.settings; - // Amiibo name is u16 while the register info is u8. Figure out how to handle this properly - std::array amiibo_name{}; - for (std::size_t i = 0; i < sizeof(amiibo_name) - 1; ++i) { - amiibo_name[i] = static_cast(settings.amiibo_name[i]); - } - // TODO: Validate this data register_info = { .mii_char_info = manager.ConvertV3ToCharInfo(tag_data.owner_mii), .first_write_year = settings.init_date.GetYear(), .first_write_month = settings.init_date.GetMonth(), .first_write_day = settings.init_date.GetDay(), - .amiibo_name = amiibo_name, - .unknown = {}, + .amiibo_name = GetAmiiboName(settings), + .font_region = {}, }; return ResultSuccess; @@ -943,7 +938,7 @@ Result Module::Interface::GetRegisterInfo(RegisterInfo& register_info) const { .first_write_month = 2, .first_write_day = 7, .amiibo_name = {'Y', 'u', 'z', 'u', 'A', 'm', 'i', 'i', 'b', 'o', 0}, - .unknown = {}, + .font_region = {}, }; return ResultSuccess; } @@ -1077,6 +1072,22 @@ Core::HID::NpadIdType Module::Interface::GetNpadId() const { return npad_id; } +AmiiboName Module::Interface::GetAmiiboName(const AmiiboSettings& settings) const { + std::array settings_amiibo_name{}; + AmiiboName amiibo_name{}; + + // Convert from big endian to little endian + for (std::size_t i = 0; i < amiibo_name_length; i++) { + settings_amiibo_name[i] = static_cast(settings.amiibo_name[i]); + } + + // Convert from utf16 to utf8 + const auto amiibo_name_utf8 = Common::UTF16ToUTF8(settings_amiibo_name.data()); + memcpy(amiibo_name.data(), amiibo_name_utf8.data(), amiibo_name_utf8.size()); + + return amiibo_name; +} + void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { auto module = std::make_shared(); std::make_shared(module, system)->InstallAsService(service_manager); diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 6b979daba..0de0b48e7 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h @@ -22,6 +22,8 @@ enum class NpadIdType : u32; } // namespace Core::HID namespace Service::NFP { +using AmiiboName = std::array; + struct TagInfo { TagUuid uuid; u8 uuid_length; @@ -59,9 +61,9 @@ struct RegisterInfo { u16 first_write_year; u8 first_write_month; u8 first_write_day; - std::array amiibo_name; - u8 unknown; - INSERT_PADDING_BYTES(0x98); + AmiiboName amiibo_name; + u8 font_region; + INSERT_PADDING_BYTES(0x7A); }; static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); @@ -109,6 +111,8 @@ public: std::shared_ptr module; private: + AmiiboName GetAmiiboName(const AmiiboSettings& settings) const; + const Core::HID::NpadIdType npad_id; bool is_data_decoded{}; -- cgit v1.2.3