From a50b50f8b4450331fa44f18b7457affa001ab6c9 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 17 Sep 2023 10:47:39 -0600 Subject: service: mii: Implement figurine database --- src/core/hle/service/mii/mii_database.cpp | 142 ++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 src/core/hle/service/mii/mii_database.cpp (limited to 'src/core/hle/service/mii/mii_database.cpp') diff --git a/src/core/hle/service/mii/mii_database.cpp b/src/core/hle/service/mii/mii_database.cpp new file mode 100644 index 000000000..0899f0b45 --- /dev/null +++ b/src/core/hle/service/mii/mii_database.cpp @@ -0,0 +1,142 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/mii/mii_database.h" +#include "core/hle/service/mii/mii_result.h" +#include "core/hle/service/mii/mii_util.h" + +namespace Service::Mii { + +u8 NintendoFigurineDatabase::GetDatabaseLength() const { + return database_length; +} + +bool NintendoFigurineDatabase::IsFull() const { + return database_length >= MaxDatabaseLength; +} + +StoreData NintendoFigurineDatabase::Get(std::size_t index) const { + StoreData store_data = miis.at(index); + + // This hack is to make external database dump compatible + store_data.SetDeviceChecksum(); + + return store_data; +} + +u32 NintendoFigurineDatabase::GetCount(const DatabaseSessionMetadata& metadata) const { + if (magic == MiiMagic) { + return GetDatabaseLength(); + } + + u32 mii_count{}; + for (std::size_t index = 0; index < mii_count; ++index) { + const auto& store_data = Get(index); + if (!store_data.IsSpecial()) { + mii_count++; + } + } + + return mii_count; +} + +bool NintendoFigurineDatabase::GetIndexByCreatorId(u32& out_index, + const Common::UUID& create_id) const { + for (std::size_t index = 0; index < database_length; ++index) { + if (miis[index].GetCreateId() == create_id) { + out_index = static_cast(index); + return true; + } + } + + return false; +} + +Result NintendoFigurineDatabase::Move(u32 current_index, u32 new_index) { + if (current_index == new_index) { + return ResultNotUpdated; + } + + const StoreData store_data = miis[current_index]; + + if (new_index > current_index) { + // shift left + const u32 index_diff = new_index - current_index; + for (std::size_t i = 0; i < index_diff; i++) { + miis[current_index + i] = miis[current_index + i + 1]; + } + } else { + // shift right + const u32 index_diff = current_index - new_index; + for (std::size_t i = 0; i < index_diff; i++) { + miis[current_index - i] = miis[current_index - i - 1]; + } + } + + miis[new_index] = store_data; + crc = GenerateDatabaseCrc(); + return ResultSuccess; +} + +void NintendoFigurineDatabase::Replace(u32 index, const StoreData& store_data) { + miis[index] = store_data; + crc = GenerateDatabaseCrc(); +} + +void NintendoFigurineDatabase::Add(const StoreData& store_data) { + miis[database_length] = store_data; + database_length++; + crc = GenerateDatabaseCrc(); +} + +void NintendoFigurineDatabase::Delete(u32 index) { + // shift left + s32 new_database_size = database_length - 1; + if (static_cast(index) < new_database_size) { + for (std::size_t i = index; i < static_cast(new_database_size); i++) { + miis[i] = miis[i + 1]; + } + } + + database_length = static_cast(new_database_size); + crc = GenerateDatabaseCrc(); +} + +void NintendoFigurineDatabase::CleanDatabase() { + memset(miis.data(), 0, sizeof(miis)); + version = 1; + magic = DatabaseMagic; + database_length = 0; + crc = GenerateDatabaseCrc(); +} + +void NintendoFigurineDatabase::CorruptCrc() { + crc = GenerateDatabaseCrc(); + crc = ~crc; +} + +Result NintendoFigurineDatabase::CheckIntegrity() { + if (magic != DatabaseMagic) { + return ResultInvalidDatabaseSignature; + } + + if (version != 1) { + return ResultInvalidDatabaseVersion; + } + + if (crc != GenerateDatabaseCrc()) { + return ResultInvalidDatabaseChecksum; + } + + if (database_length >= MaxDatabaseLength) { + return ResultInvalidDatabaseLength; + } + + return ResultSuccess; +} + +u16 NintendoFigurineDatabase::GenerateDatabaseCrc() { + return MiiUtil::CalculateCrc16(&magic, sizeof(NintendoFigurineDatabase) - sizeof(crc)); +} + +} // namespace Service::Mii -- cgit v1.2.3 From dca36ebb871d55ca825bb0090949acb59f859f07 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 17 Sep 2023 12:11:31 -0600 Subject: service: mii: Address review comments --- src/core/hle/service/mii/mii.cpp | 19 +++++++++---------- src/core/hle/service/mii/mii_database.cpp | 12 ++++++------ src/core/hle/service/mii/mii_database.h | 4 ++-- src/core/hle/service/mii/mii_database_manager.cpp | 4 ++-- src/core/hle/service/mii/mii_types.h | 4 ++-- src/core/hle/service/mii/types/core_data.h | 1 + src/core/hle/service/mii/types/store_data.h | 2 ++ 7 files changed, 24 insertions(+), 22 deletions(-) (limited to 'src/core/hle/service/mii/mii_database.cpp') diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp index dae95ea68..8de806cfb 100644 --- a/src/core/hle/service/mii/mii.cpp +++ b/src/core/hle/service/mii/mii.cpp @@ -288,7 +288,7 @@ private: LOG_INFO(Service_Mii, "called with create_id={}, is_special={}", create_id.FormattedString(), is_special); - s32 index = manager.FindIndex(create_id, is_special); + const s32 index = manager.FindIndex(create_id, is_special); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); @@ -304,7 +304,6 @@ private: new_index); Result result = ResultSuccess; - if (!is_system) { result = ResultPermissionDenied; } @@ -366,7 +365,7 @@ private: void DestroyFile(HLERequestContext& ctx) { // This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled"); - bool is_db_test_mode_enabled = false; + const bool is_db_test_mode_enabled = false; LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled); @@ -386,7 +385,7 @@ private: void DeleteFile(HLERequestContext& ctx) { // This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled"); - bool is_db_test_mode_enabled = false; + const bool is_db_test_mode_enabled = false; LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled); @@ -406,7 +405,7 @@ private: void Format(HLERequestContext& ctx) { // This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled"); - bool is_db_test_mode_enabled = false; + const bool is_db_test_mode_enabled = false; LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled); @@ -427,7 +426,7 @@ private: void IsBrokenDatabaseWithClearFlag(HLERequestContext& ctx) { LOG_DEBUG(Service_Mii, "called"); - bool is_broken_with_clear_flag{}; + bool is_broken_with_clear_flag = false; Result result = ResultSuccess; if (!is_system) { @@ -547,7 +546,7 @@ private: rb.Push(ResultSuccess); rb.PushIpcInterface(system, is_system); - LOG_CRITICAL(Service_Mii, "called"); + LOG_DEBUG(Service_Mii, "called"); } bool is_system{}; @@ -580,14 +579,14 @@ public: private: void Initialize(HLERequestContext& ctx) { - LOG_CRITICAL(Service_Mii, "called"); + LOG_INFO(Service_Mii, "called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void GetCount(HLERequestContext& ctx) { - LOG_CRITICAL(Service_Mii, "called"); + LOG_DEBUG(Service_Mii, "called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); @@ -606,4 +605,4 @@ void LoopProcess(Core::System& system) { ServerManager::RunServer(std::move(server_manager)); } -} // namespace Service::Mii \ No newline at end of file +} // namespace Service::Mii diff --git a/src/core/hle/service/mii/mii_database.cpp b/src/core/hle/service/mii/mii_database.cpp index 0899f0b45..3803e58e2 100644 --- a/src/core/hle/service/mii/mii_database.cpp +++ b/src/core/hle/service/mii/mii_database.cpp @@ -18,7 +18,7 @@ bool NintendoFigurineDatabase::IsFull() const { StoreData NintendoFigurineDatabase::Get(std::size_t index) const { StoreData store_data = miis.at(index); - // This hack is to make external database dump compatible + // This hack is to make external database dumps compatible store_data.SetDeviceChecksum(); return store_data; @@ -60,13 +60,13 @@ Result NintendoFigurineDatabase::Move(u32 current_index, u32 new_index) { const StoreData store_data = miis[current_index]; if (new_index > current_index) { - // shift left + // Shift left const u32 index_diff = new_index - current_index; for (std::size_t i = 0; i < index_diff; i++) { miis[current_index + i] = miis[current_index + i + 1]; } } else { - // shift right + // Shift right const u32 index_diff = current_index - new_index; for (std::size_t i = 0; i < index_diff; i++) { miis[current_index - i] = miis[current_index - i - 1]; @@ -90,8 +90,8 @@ void NintendoFigurineDatabase::Add(const StoreData& store_data) { } void NintendoFigurineDatabase::Delete(u32 index) { - // shift left - s32 new_database_size = database_length - 1; + // Shift left + const s32 new_database_size = database_length - 1; if (static_cast(index) < new_database_size) { for (std::size_t i = index; i < static_cast(new_database_size); i++) { miis[i] = miis[i + 1]; @@ -103,7 +103,7 @@ void NintendoFigurineDatabase::Delete(u32 index) { } void NintendoFigurineDatabase::CleanDatabase() { - memset(miis.data(), 0, sizeof(miis)); + miis = {}; version = 1; magic = DatabaseMagic; database_length = 0; diff --git a/src/core/hle/service/mii/mii_database.h b/src/core/hle/service/mii/mii_database.h index 01764999f..3bd240f93 100644 --- a/src/core/hle/service/mii/mii_database.h +++ b/src/core/hle/service/mii/mii_database.h @@ -17,13 +17,13 @@ public: /// Returns the total mii count. u8 GetDatabaseLength() const; - /// Returns full if database is full. + /// Returns true if database is full. bool IsFull() const; /// Returns the mii of the specified index. StoreData Get(std::size_t index) const; - /// Returns the total mii count. Ignoring special mii. + /// Returns the total mii count. Ignoring special mii. u32 GetCount(const DatabaseSessionMetadata& metadata) const; /// Returns the index of a mii. If the mii isn't found returns false. diff --git a/src/core/hle/service/mii/mii_database_manager.cpp b/src/core/hle/service/mii/mii_database_manager.cpp index 63c411690..c39898594 100644 --- a/src/core/hle/service/mii/mii_database_manager.cpp +++ b/src/core/hle/service/mii/mii_database_manager.cpp @@ -15,7 +15,7 @@ #include "core/hle/service/mii/types/store_data.h" namespace Service::Mii { -constexpr std::string DbFileName = "MiiDatabase.dat"; +const char* DbFileName = "MiiDatabase.dat"; DatabaseManager::DatabaseManager() {} @@ -371,7 +371,7 @@ Result DatabaseManager::DestroyFile(DatabaseSessionMetadata& metadata) { Result DatabaseManager::DeleteFile() { const bool result = Common::FS::RemoveFile(system_save_dir / DbFileName); - // Return proper FS error here + // TODO: Return proper FS error here return result ? ResultSuccess : ResultUnknown; } diff --git a/src/core/hle/service/mii/mii_types.h b/src/core/hle/service/mii/mii_types.h index 9efe6c915..f43efd83c 100644 --- a/src/core/hle/service/mii/mii_types.h +++ b/src/core/hle/service/mii/mii_types.h @@ -13,6 +13,7 @@ namespace Service::Mii { +constexpr std::size_t MaxNameSize = 10; constexpr u8 MaxHeight = 127; constexpr u8 MaxBuild = 127; constexpr u8 MaxType = 1; @@ -604,8 +605,7 @@ enum class ValidationResult : u32 { }; struct Nickname { - static constexpr std::size_t MaxNameSize = 10; - std::array data; + std::array data{}; // Checks for null or dirty strings bool IsValid() const { diff --git a/src/core/hle/service/mii/types/core_data.h b/src/core/hle/service/mii/types/core_data.h index e6398f68f..8897e4f3b 100644 --- a/src/core/hle/service/mii/types/core_data.h +++ b/src/core/hle/service/mii/types/core_data.h @@ -214,5 +214,6 @@ private: Nickname name{}; }; static_assert(sizeof(CoreData) == 0x30, "CoreData has incorrect size."); +static_assert(std::is_trivially_copyable_v, "CoreData type must be trivially copyable."); }; // namespace Service::Mii diff --git a/src/core/hle/service/mii/types/store_data.h b/src/core/hle/service/mii/types/store_data.h index 38f534d26..ed5dfb949 100644 --- a/src/core/hle/service/mii/types/store_data.h +++ b/src/core/hle/service/mii/types/store_data.h @@ -138,6 +138,8 @@ private: u16 device_crc{}; }; static_assert(sizeof(StoreData) == 0x44, "StoreData has incorrect size."); +static_assert(std::is_trivially_copyable_v, + "StoreData type must be trivially copyable."); struct StoreDataElement { StoreData store_data{}; -- cgit v1.2.3