service: mii: Implement figurine database
This commit is contained in:
		| @@ -596,6 +596,8 @@ add_library(core STATIC | ||||
|     hle/service/mii/types/ver3_store_data.h | ||||
|     hle/service/mii/mii.cpp | ||||
|     hle/service/mii/mii.h | ||||
|     hle/service/mii/mii_database.cpp | ||||
|     hle/service/mii/mii_database.h | ||||
|     hle/service/mii/mii_manager.cpp | ||||
|     hle/service/mii/mii_manager.h | ||||
|     hle/service/mii/mii_result.h | ||||
|   | ||||
							
								
								
									
										142
									
								
								src/core/hle/service/mii/mii_database.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								src/core/hle/service/mii/mii_database.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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<u32>(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<s32>(index) < new_database_size) { | ||||
|         for (std::size_t i = index; i < static_cast<std::size_t>(new_database_size); i++) { | ||||
|             miis[i] = miis[i + 1]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     database_length = static_cast<u8>(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 | ||||
							
								
								
									
										66
									
								
								src/core/hle/service/mii/mii_database.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/core/hle/service/mii/mii_database.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "core/hle/result.h" | ||||
| #include "core/hle/service/mii/types/store_data.h" | ||||
|  | ||||
| namespace Service::Mii { | ||||
|  | ||||
| constexpr std::size_t MaxDatabaseLength{100}; | ||||
| constexpr u32 MiiMagic{0xa523b78f}; | ||||
| constexpr u32 DatabaseMagic{0x4244464e}; // NFDB | ||||
|  | ||||
| class NintendoFigurineDatabase { | ||||
| public: | ||||
|     /// Returns the total mii count. | ||||
|     u8 GetDatabaseLength() const; | ||||
|  | ||||
|     /// Returns full 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. | ||||
|     u32 GetCount(const DatabaseSessionMetadata& metadata) const; | ||||
|  | ||||
|     /// Returns the index of a mii. If the mii isn't found returns false. | ||||
|     bool GetIndexByCreatorId(u32& out_index, const Common::UUID& create_id) const; | ||||
|  | ||||
|     /// Moves the location of a specific mii. | ||||
|     Result Move(u32 current_index, u32 new_index); | ||||
|  | ||||
|     /// Replaces mii with new data. | ||||
|     void Replace(u32 index, const StoreData& store_data); | ||||
|  | ||||
|     /// Adds a new mii to the end of the database. | ||||
|     void Add(const StoreData& store_data); | ||||
|  | ||||
|     /// Removes mii from database and shifts left the remainding data. | ||||
|     void Delete(u32 index); | ||||
|  | ||||
|     /// Deletes all contents with a fresh database | ||||
|     void CleanDatabase(); | ||||
|  | ||||
|     /// Intentionally sets a bad checksum | ||||
|     void CorruptCrc(); | ||||
|  | ||||
|     /// Returns success if database is valid otherwise returns the corresponding error code. | ||||
|     Result CheckIntegrity(); | ||||
|  | ||||
| private: | ||||
|     /// Returns the checksum of the database | ||||
|     u16 GenerateDatabaseCrc(); | ||||
|  | ||||
|     u32 magic{}; // 'NFDB' | ||||
|     std::array<StoreData, MaxDatabaseLength> miis{}; | ||||
|     u8 version{}; | ||||
|     u8 database_length{}; | ||||
|     u16 crc{}; | ||||
| }; | ||||
| static_assert(sizeof(NintendoFigurineDatabase) == 0x1A98, | ||||
|               "NintendoFigurineDatabase has incorrect size."); | ||||
|  | ||||
| }; // namespace Service::Mii | ||||
		Reference in New Issue
	
	Block a user