From bd169f417f471f574784fa3b499f57ad42cf1013 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 11 Sep 2023 00:58:46 -0600 Subject: mii: Prepare Interface for new implementation --- .../hle/service/am/applets/applet_mii_edit.cpp | 11 +- src/core/hle/service/mii/mii.cpp | 128 ++++++++-------- src/core/hle/service/mii/mii_manager.cpp | 162 +++++++++++++-------- src/core/hle/service/mii/mii_manager.h | 29 ++-- src/core/hle/service/mii/mii_types.h | 10 ++ src/core/hle/service/nfc/common/device.cpp | 8 +- 6 files changed, 210 insertions(+), 138 deletions(-) diff --git a/src/core/hle/service/am/applets/applet_mii_edit.cpp b/src/core/hle/service/am/applets/applet_mii_edit.cpp index f8e2bac32..350a90818 100644 --- a/src/core/hle/service/am/applets/applet_mii_edit.cpp +++ b/src/core/hle/service/am/applets/applet_mii_edit.cpp @@ -85,15 +85,18 @@ void MiiEdit::Execute() { break; case MiiEditAppletMode::CreateMii: case MiiEditAppletMode::EditMii: { - Service::Mii::MiiManager mii_manager; + Mii::CharInfo char_info{}; + Mii::StoreData store_data{}; + store_data.BuildBase(Mii::Gender::Male); + char_info.SetFromStoreData(store_data); - const MiiEditCharInfo char_info{ + const MiiEditCharInfo edit_char_info{ .mii_info{applet_input_common.applet_mode == MiiEditAppletMode::EditMii ? applet_input_v4.char_info.mii_info - : mii_manager.BuildBase(Mii::Gender::Male)}, + : char_info}, }; - MiiEditOutputForCharInfoEditing(MiiEditResult::Success, char_info); + MiiEditOutputForCharInfoEditing(MiiEditResult::Success, edit_char_info); break; } default: diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp index 680f06beb..653c36740 100644 --- a/src/core/hle/service/mii/mii.cpp +++ b/src/core/hle/service/mii/mii.cpp @@ -15,8 +15,8 @@ namespace Service::Mii { class IDatabaseService final : public ServiceFramework { public: - explicit IDatabaseService(Core::System& system_) - : ServiceFramework{system_, "IDatabaseService"} { + explicit IDatabaseService(Core::System& system_, bool is_system_) + : ServiceFramework{system_, "IDatabaseService"}, is_system{is_system_} { // clang-format off static const FunctionInfo functions[] = { {0, &IDatabaseService::IsUpdated, "IsUpdated"}, @@ -53,34 +53,27 @@ public: } private: - template - std::vector SerializeArray(const std::vector& values) { - std::vector out(values.size() * sizeof(T)); - std::size_t offset{}; - for (const auto& value : values) { - std::memcpy(out.data() + offset, &value, sizeof(T)); - offset += sizeof(T); - } - return out; - } - void IsUpdated(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto source_flag{rp.PopRaw()}; LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); + const bool is_updated = manager.IsUpdated(metadata, source_flag); + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(manager.CheckAndResetUpdateCounter(source_flag, current_update_counter)); + rb.Push(is_updated); } void IsFullDatabase(HLERequestContext& ctx) { LOG_DEBUG(Service_Mii, "called"); + const bool is_full_database = manager.IsFullDatabase(); + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(manager.IsFullDatabase()); + rb.Push(is_full_database); } void GetCount(HLERequestContext& ctx) { @@ -89,57 +82,63 @@ private: LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); + const u32 mii_count = manager.GetCount(metadata, source_flag); + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(manager.GetCount(source_flag)); + rb.Push(mii_count); } void Get(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto source_flag{rp.PopRaw()}; + const auto output_size{ctx.GetWriteBufferNumElements()}; - LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); + LOG_DEBUG(Service_Mii, "called with source_flag={}, out_size={}", source_flag, output_size); + + u32 mii_count{}; + std::vector char_info_elements(output_size); + Result result = manager.Get(metadata, char_info_elements, mii_count, source_flag); - const auto default_miis{manager.GetDefault(source_flag)}; - if (default_miis.size() > 0) { - ctx.WriteBuffer(SerializeArray(default_miis)); + if (mii_count != 0) { + ctx.WriteBuffer(char_info_elements); } IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast(default_miis.size())); + rb.Push(result); + rb.Push(mii_count); } void Get1(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto source_flag{rp.PopRaw()}; + const auto output_size{ctx.GetWriteBufferNumElements()}; - LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); + LOG_DEBUG(Service_Mii, "called with source_flag={}, out_size={}", source_flag, output_size); - const auto default_miis{manager.GetDefault(source_flag)}; + u32 mii_count{}; + std::vector char_info(output_size); + Result result = manager.Get(metadata, char_info, mii_count, source_flag); - std::vector values; - for (const auto& element : default_miis) { - values.emplace_back(element.char_info); + if (mii_count != 0) { + ctx.WriteBuffer(char_info); } - ctx.WriteBuffer(SerializeArray(values)); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push(static_cast(default_miis.size())); + rb.Push(result); + rb.Push(mii_count); } void UpdateLatest(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto info{rp.PopRaw()}; + const auto char_info{rp.PopRaw()}; const auto source_flag{rp.PopRaw()}; LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); CharInfo new_char_info{}; - const auto result{manager.UpdateLatest(&new_char_info, info, source_flag)}; - if (result != ResultSuccess) { + const auto result = manager.UpdateLatest(metadata, new_char_info, char_info, source_flag); + if (result.IsFailure()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); return; @@ -152,7 +151,6 @@ private: void BuildRandom(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto age{rp.PopRaw()}; const auto gender{rp.PopRaw()}; const auto race{rp.PopRaw()}; @@ -162,46 +160,47 @@ private: if (age > Age::All) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultInvalidArgument); - LOG_ERROR(Service_Mii, "invalid age={}", age); return; } if (gender > Gender::All) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultInvalidArgument); - LOG_ERROR(Service_Mii, "invalid gender={}", gender); return; } if (race > Race::All) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultInvalidArgument); - LOG_ERROR(Service_Mii, "invalid race={}", race); return; } + CharInfo char_info{}; + manager.BuildRandom(char_info, age, gender, race); + IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; rb.Push(ResultSuccess); - rb.PushRaw(manager.BuildRandom(age, gender, race)); + rb.PushRaw(char_info); } void BuildDefault(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto index{rp.Pop()}; - LOG_DEBUG(Service_Mii, "called with index={}", index); + LOG_INFO(Service_Mii, "called with index={}", index); if (index > 5) { - LOG_ERROR(Service_Mii, "invalid argument, index cannot be greater than 5 but is {:08X}", - index); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultInvalidArgument); return; } + CharInfo char_info{}; + manager.BuildDefault(char_info, index); + IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; rb.Push(ResultSuccess); - rb.PushRaw(manager.BuildDefault(index)); + rb.PushRaw(char_info); } void GetIndex(HLERequestContext& ctx) { @@ -210,19 +209,21 @@ private: LOG_DEBUG(Service_Mii, "called"); - u32 index{}; + s32 index{}; + const Result result = manager.GetIndex(metadata, info, index); + IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(manager.GetIndex(info, index)); + rb.Push(result); rb.Push(index); } void SetInterfaceVersion(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - current_interface_version = rp.PopRaw(); + const auto interface_version{rp.PopRaw()}; - LOG_DEBUG(Service_Mii, "called, interface_version={:08X}", current_interface_version); + LOG_INFO(Service_Mii, "called, interface_version={:08X}", interface_version); - UNIMPLEMENTED_IF(current_interface_version != 1); + manager.SetInterfaceVersion(metadata, interface_version); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -230,30 +231,27 @@ private: void Convert(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto mii_v3{rp.PopRaw()}; LOG_INFO(Service_Mii, "called"); + CharInfo char_info{}; + manager.ConvertV3ToCharInfo(char_info, mii_v3); + IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; rb.Push(ResultSuccess); - rb.PushRaw(manager.ConvertV3ToCharInfo(mii_v3)); - } - - constexpr bool IsInterfaceVersionSupported(u32 interface_version) const { - return current_interface_version >= interface_version; + rb.PushRaw(char_info); } - MiiManager manager; - - u32 current_interface_version{}; - u64 current_update_counter{}; + MiiManager manager{}; + DatabaseSessionMetadata metadata{}; + bool is_system{}; }; class MiiDBModule final : public ServiceFramework { public: - explicit MiiDBModule(Core::System& system_, const char* name_) - : ServiceFramework{system_, name_} { + explicit MiiDBModule(Core::System& system_, const char* name_, bool is_system_) + : ServiceFramework{system_, name_}, is_system{is_system_} { // clang-format off static const FunctionInfo functions[] = { {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"}, @@ -267,10 +265,12 @@ private: void GetDatabaseService(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface(system); + rb.PushIpcInterface(system, is_system); LOG_DEBUG(Service_Mii, "called"); } + + bool is_system{}; }; class MiiImg final : public ServiceFramework { @@ -302,8 +302,10 @@ public: void LoopProcess(Core::System& system) { auto server_manager = std::make_unique(system); - server_manager->RegisterNamedService("mii:e", std::make_shared(system, "mii:e")); - server_manager->RegisterNamedService("mii:u", std::make_shared(system, "mii:u")); + server_manager->RegisterNamedService("mii:e", + std::make_shared(system, "mii:e", true)); + server_manager->RegisterNamedService("mii:u", + std::make_shared(system, "mii:u", false)); server_manager->RegisterNamedService("miiimg", std::make_shared(system)); ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp index 3951e0b9c..153a484c0 100644 --- a/src/core/hle/service/mii/mii_manager.cpp +++ b/src/core/hle/service/mii/mii_manager.cpp @@ -16,45 +16,18 @@ #include "core/hle/service/mii/types/raw_data.h" namespace Service::Mii { - -namespace { - constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()}; -CharInfo ConvertStoreDataToInfo(const StoreData& data) { - CharInfo char_info{}; - char_info.SetFromStoreData(data); - return char_info; -} - -StoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Common::UUID& user_id) { - StoreData store_data{}; - store_data.BuildRandom(age, gender, race); - - return store_data; -} +MiiManager::MiiManager() {} -StoreData BuildDefaultStoreData(const DefaultMii& info, const Common::UUID& user_id) { - StoreData store_data{}; - store_data.BuildDefault(0); - - return store_data; -} - -} // namespace - -MiiManager::MiiManager() : user_id{Service::Account::ProfileManager().GetLastOpenedUser()} {} - -bool MiiManager::CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter) { +bool MiiManager::IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const { if ((source_flag & SourceFlag::Database) == SourceFlag::None) { return false; } - const bool result{current_update_counter != update_counter}; - - current_update_counter = update_counter; - - return result; + const auto metadata_update_counter = metadata.update_counter; + metadata.update_counter = update_counter; + return metadata_update_counter != update_counter; } bool MiiManager::IsFullDatabase() const { @@ -62,19 +35,19 @@ bool MiiManager::IsFullDatabase() const { 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; +u32 MiiManager::GetCount(const DatabaseSessionMetadata& metadata, SourceFlag source_flag) const { + u32 mii_count{}; + if ((source_flag & SourceFlag::Default) == SourceFlag::None) { + mii_count += DefaultMiiCount; } - if ((source_flag & SourceFlag::Default) != SourceFlag::None) { - count += DefaultMiiCount; + if ((source_flag & SourceFlag::Database) == SourceFlag::None) { + // TODO(bunnei): We don't implement the Mii database, but when we do, update this } - return static_cast(count); + return mii_count; } -Result MiiManager::UpdateLatest(CharInfo* out_info, const CharInfo& info, SourceFlag source_flag) { +Result MiiManager::UpdateLatest(DatabaseSessionMetadata& metadata, CharInfo& out_char_info, + const CharInfo& char_info, SourceFlag source_flag) { if ((source_flag & SourceFlag::Database) == SourceFlag::None) { return ResultNotFound; } @@ -83,48 +56,117 @@ Result MiiManager::UpdateLatest(CharInfo* out_info, const CharInfo& info, Source return ResultNotFound; } -CharInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) { - return ConvertStoreDataToInfo(BuildRandomStoreData(age, gender, race, user_id)); +void MiiManager::BuildDefault(CharInfo& out_char_info, u32 index) const { + StoreData store_data{}; + store_data.BuildDefault(index); + out_char_info.SetFromStoreData(store_data); } -CharInfo MiiManager::BuildBase(Gender gender) { - const std::size_t index = gender == Gender::Female ? 1 : 0; - return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::BaseMii.at(index), user_id)); +void MiiManager::BuildBase(CharInfo& out_char_info, Gender gender) const { + StoreData store_data{}; + store_data.BuildBase(gender); + out_char_info.SetFromStoreData(store_data); } -CharInfo MiiManager::BuildDefault(std::size_t index) { - return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::DefaultMii.at(index), user_id)); +void MiiManager::BuildRandom(CharInfo& out_char_info, Age age, Gender gender, Race race) const { + StoreData store_data{}; + store_data.BuildRandom(age, gender, race); + out_char_info.SetFromStoreData(store_data); } -CharInfo MiiManager::ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const { - CharInfo char_info{}; +void MiiManager::ConvertV3ToCharInfo(CharInfo& out_char_info, const Ver3StoreData& mii_v3) const { StoreData store_data{}; mii_v3.BuildToStoreData(store_data); - char_info.SetFromStoreData(store_data); - return char_info; + out_char_info.SetFromStoreData(store_data); } -std::vector MiiManager::GetDefault(SourceFlag source_flag) { - std::vector result; +Result MiiManager::Get(const DatabaseSessionMetadata& metadata, + std::span out_elements, u32& out_count, + SourceFlag source_flag) { + if ((source_flag & SourceFlag::Database) == SourceFlag::None) { + return BuildDefault(out_elements, out_count, source_flag); + } + // TODO(bunnei): We don't implement the Mii database, so we can't have an entry + + // Include default Mii at the end of the list + return BuildDefault(out_elements, out_count, source_flag); +} + +Result MiiManager::Get(const DatabaseSessionMetadata& metadata, std::span out_char_info, + u32& out_count, SourceFlag source_flag) { + if ((source_flag & SourceFlag::Database) == SourceFlag::None) { + return BuildDefault(out_char_info, out_count, source_flag); + } + + // TODO(bunnei): We don't implement the Mii database, so we can't have an entry + + // Include default Mii at the end of the list + return BuildDefault(out_char_info, out_count, source_flag); +} + +Result MiiManager::BuildDefault(std::span out_elements, u32& out_count, + SourceFlag source_flag) { + if ((source_flag & SourceFlag::Default) == SourceFlag::None) { + return ResultSuccess; + } + + StoreData store_data{}; + + for (std::size_t index = 0; index < DefaultMiiCount; ++index) { + if (out_elements.size() <= static_cast(out_count)) { + return ResultInvalidArgumentSize; + } + + store_data.BuildDefault(static_cast(index)); + + out_elements[out_count].source = Source::Default; + out_elements[out_count].char_info.SetFromStoreData(store_data); + out_count++; + } + + return ResultSuccess; +} + +Result MiiManager::BuildDefault(std::span out_char_info, u32& out_count, + SourceFlag source_flag) { if ((source_flag & SourceFlag::Default) == SourceFlag::None) { - return result; + return ResultSuccess; } - for (std::size_t index = 0; index < DefaultMiiCount; index++) { - result.emplace_back(BuildDefault(index), Source::Default); + StoreData store_data{}; + + for (std::size_t index = 0; index < DefaultMiiCount; ++index) { + if (out_char_info.size() <= static_cast(out_count)) { + return ResultInvalidArgumentSize; + } + + store_data.BuildDefault(static_cast(index)); + + out_char_info[out_count].SetFromStoreData(store_data); + out_count++; } - return result; + return ResultSuccess; } -Result MiiManager::GetIndex([[maybe_unused]] const CharInfo& info, u32& index) { +Result MiiManager::GetIndex(const DatabaseSessionMetadata& metadata, const CharInfo& char_info, + s32& out_index) { + + if (char_info.Verify() != 0) { + return ResultInvalidCharInfo; + } + constexpr u32 INVALID_INDEX{0xFFFFFFFF}; - index = INVALID_INDEX; + out_index = INVALID_INDEX; // TODO(bunnei): We don't implement the Mii database, so we can't have an index return ResultNotFound; } +void MiiManager::SetInterfaceVersion(DatabaseSessionMetadata& metadata, u32 version) { + metadata.interface_version = version; +} + } // namespace Service::Mii diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h index 6098474e9..4f8be06c3 100644 --- a/src/core/hle/service/mii/mii_manager.h +++ b/src/core/hle/service/mii/mii_manager.h @@ -19,16 +19,24 @@ class MiiManager { public: MiiManager(); - bool CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter); + bool IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const; + bool IsFullDatabase() const; - u32 GetCount(SourceFlag source_flag) const; - Result UpdateLatest(CharInfo* out_info, const CharInfo& info, SourceFlag source_flag); - CharInfo BuildRandom(Age age, Gender gender, Race race); - CharInfo BuildBase(Gender gender); - CharInfo BuildDefault(std::size_t index); - CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const; + u32 GetCount(const DatabaseSessionMetadata& metadata, SourceFlag source_flag) const; + Result UpdateLatest(DatabaseSessionMetadata& metadata, CharInfo& out_char_info, + const CharInfo& char_info, SourceFlag source_flag); + Result Get(const DatabaseSessionMetadata& metadata, std::span out_elements, + u32& out_count, SourceFlag source_flag); + Result Get(const DatabaseSessionMetadata& metadata, std::span out_char_info, + u32& out_count, SourceFlag source_flag); + void BuildDefault(CharInfo& out_char_info, u32 index) const; + void BuildBase(CharInfo& out_char_info, Gender gender) const; + void BuildRandom(CharInfo& out_char_info, Age age, Gender gender, Race race) const; + void ConvertV3ToCharInfo(CharInfo& out_char_info, const Ver3StoreData& mii_v3) const; std::vector GetDefault(SourceFlag source_flag); - Result GetIndex(const CharInfo& info, u32& index); + Result GetIndex(const DatabaseSessionMetadata& metadata, const CharInfo& char_info, + s32& out_index); + void SetInterfaceVersion(DatabaseSessionMetadata& metadata, u32 version); struct MiiDatabase { u32 magic{}; // 'NFDB' @@ -40,7 +48,10 @@ public: static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size."); private: - const Common::UUID user_id{}; + Result BuildDefault(std::span out_elements, u32& out_count, + SourceFlag source_flag); + Result BuildDefault(std::span out_char_info, u32& out_count, SourceFlag source_flag); + u64 update_counter{}; }; diff --git a/src/core/hle/service/mii/mii_types.h b/src/core/hle/service/mii/mii_types.h index d62005f61..b23ce477d 100644 --- a/src/core/hle/service/mii/mii_types.h +++ b/src/core/hle/service/mii/mii_types.h @@ -165,4 +165,14 @@ struct DefaultMii { }; static_assert(sizeof(DefaultMii) == 0xd8, "MiiStoreData has incorrect size."); +struct DatabaseSessionMetadata { + u32 interface_version; + u32 magic; + u64 update_counter; + + bool IsInterfaceVersionSupported(u32 version) const { + return version <= interface_version; + } +}; + } // namespace Service::Mii diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp index eb7706015..5dda12343 100644 --- a/src/core/hle/service/nfc/common/device.cpp +++ b/src/core/hle/service/nfc/common/device.cpp @@ -680,12 +680,16 @@ Result NfcDevice::GetRegisterInfo(NFP::RegisterInfo& register_info) const { return ResultRegistrationIsNotInitialized; } - Service::Mii::MiiManager manager; + Mii::CharInfo char_info{}; + Mii::StoreData store_data{}; + tag_data.owner_mii.BuildToStoreData(store_data); + char_info.SetFromStoreData(store_data); + const auto& settings = tag_data.settings; // TODO: Validate this data register_info = { - .mii_char_info = manager.ConvertV3ToCharInfo(tag_data.owner_mii), + .mii_char_info = char_info, .creation_date = settings.init_date.GetWriteDate(), .amiibo_name = GetAmiiboName(settings), .font_region = settings.settings.font_region, -- cgit v1.2.3