Browse Source
Merge pull request #11526 from german77/mii_service_v2
Merge pull request #11526 from german77/mii_service_v2
service: mii: Update implementation Part2 - Mii database supportnce_cpp
committed by
GitHub
19 changed files with 1861 additions and 244 deletions
-
4src/core/CMakeLists.txt
-
357src/core/hle/service/mii/mii.cpp
-
142src/core/hle/service/mii/mii_database.cpp
-
66src/core/hle/service/mii/mii_database.h
-
420src/core/hle/service/mii/mii_database_manager.cpp
-
58src/core/hle/service/mii/mii_database_manager.h
-
410src/core/hle/service/mii/mii_manager.cpp
-
82src/core/hle/service/mii/mii_manager.h
-
9src/core/hle/service/mii/mii_result.h
-
11src/core/hle/service/mii/mii_types.h
-
26src/core/hle/service/mii/mii_util.h
-
6src/core/hle/service/mii/types/char_info.cpp
-
106src/core/hle/service/mii/types/char_info.h
-
213src/core/hle/service/mii/types/core_data.cpp
-
7src/core/hle/service/mii/types/core_data.h
-
83src/core/hle/service/mii/types/store_data.cpp
-
19src/core/hle/service/mii/types/store_data.h
-
78src/core/hle/service/mii/types/ver3_store_data.cpp
-
8src/core/hle/service/nfc/common/device.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 dumps 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
|
|||
const 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() { |
|||
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
|
|||
@ -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 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. |
|||
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 |
|||
@ -0,0 +1,420 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "common/assert.h"
|
|||
#include "common/fs/file.h"
|
|||
#include "common/fs/fs.h"
|
|||
#include "common/fs/path_util.h"
|
|||
#include "common/logging/log.h"
|
|||
#include "common/string_util.h"
|
|||
|
|||
#include "core/hle/service/mii/mii_database_manager.h"
|
|||
#include "core/hle/service/mii/mii_result.h"
|
|||
#include "core/hle/service/mii/mii_util.h"
|
|||
#include "core/hle/service/mii/types/char_info.h"
|
|||
#include "core/hle/service/mii/types/store_data.h"
|
|||
|
|||
namespace Service::Mii { |
|||
const char* DbFileName = "MiiDatabase.dat"; |
|||
|
|||
DatabaseManager::DatabaseManager() {} |
|||
|
|||
Result DatabaseManager::MountSaveData() { |
|||
if (!is_save_data_mounted) { |
|||
system_save_dir = |
|||
Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000030"; |
|||
if (is_test_db) { |
|||
system_save_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / |
|||
"system/save/8000000000000031"; |
|||
} |
|||
|
|||
// mount point should be "mii:"
|
|||
|
|||
if (!Common::FS::CreateDirs(system_save_dir)) { |
|||
return ResultUnknown; |
|||
} |
|||
} |
|||
|
|||
is_save_data_mounted = true; |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result DatabaseManager::Initialize(DatabaseSessionMetadata& metadata, bool& is_database_broken) { |
|||
is_database_broken = false; |
|||
if (!is_save_data_mounted) { |
|||
return ResultInvalidArgument; |
|||
} |
|||
|
|||
database.CleanDatabase(); |
|||
update_counter++; |
|||
metadata.update_counter = update_counter; |
|||
|
|||
const Common::FS::IOFile db_file{system_save_dir / DbFileName, Common::FS::FileAccessMode::Read, |
|||
Common::FS::FileType::BinaryFile}; |
|||
|
|||
if (!db_file.IsOpen()) { |
|||
return SaveDatabase(); |
|||
} |
|||
|
|||
if (Common::FS::GetSize(system_save_dir / DbFileName) != sizeof(NintendoFigurineDatabase)) { |
|||
is_database_broken = true; |
|||
} |
|||
|
|||
if (db_file.Read(database) != 1) { |
|||
is_database_broken = true; |
|||
} |
|||
|
|||
if (is_database_broken) { |
|||
// Dragons happen here for simplicity just clean the database
|
|||
LOG_ERROR(Service_Mii, "Mii database is corrupted"); |
|||
database.CleanDatabase(); |
|||
return ResultUnknown; |
|||
} |
|||
|
|||
const auto result = database.CheckIntegrity(); |
|||
|
|||
if (result.IsError()) { |
|||
LOG_ERROR(Service_Mii, "Mii database is corrupted 0x{:0x}", result.raw); |
|||
database.CleanDatabase(); |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
LOG_INFO(Service_Mii, "Successfully loaded mii database. size={}", |
|||
database.GetDatabaseLength()); |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
bool DatabaseManager::IsFullDatabase() const { |
|||
return database.GetDatabaseLength() == MaxDatabaseLength; |
|||
} |
|||
|
|||
bool DatabaseManager::IsModified() const { |
|||
return is_moddified; |
|||
} |
|||
|
|||
u64 DatabaseManager::GetUpdateCounter() const { |
|||
return update_counter; |
|||
} |
|||
|
|||
u32 DatabaseManager::GetCount(const DatabaseSessionMetadata& metadata) const { |
|||
const u32 database_size = database.GetDatabaseLength(); |
|||
if (metadata.magic == MiiMagic) { |
|||
return database_size; |
|||
} |
|||
|
|||
// Special mii can't be used. Skip those.
|
|||
|
|||
u32 mii_count{}; |
|||
for (std::size_t index = 0; index < database_size; ++index) { |
|||
const auto& store_data = database.Get(index); |
|||
if (store_data.IsSpecial()) { |
|||
continue; |
|||
} |
|||
mii_count++; |
|||
} |
|||
|
|||
return mii_count; |
|||
} |
|||
|
|||
void DatabaseManager::Get(StoreData& out_store_data, std::size_t index, |
|||
const DatabaseSessionMetadata& metadata) const { |
|||
if (metadata.magic == MiiMagic) { |
|||
out_store_data = database.Get(index); |
|||
return; |
|||
} |
|||
|
|||
// The index refeers to the mii index without special mii.
|
|||
// Search on the database until we find it
|
|||
|
|||
u32 virtual_index = 0; |
|||
const u32 database_size = database.GetDatabaseLength(); |
|||
for (std::size_t i = 0; i < database_size; ++i) { |
|||
const auto& store_data = database.Get(i); |
|||
if (store_data.IsSpecial()) { |
|||
continue; |
|||
} |
|||
if (virtual_index == index) { |
|||
out_store_data = store_data; |
|||
return; |
|||
} |
|||
virtual_index++; |
|||
} |
|||
|
|||
// This function doesn't fail. It returns the first mii instead
|
|||
out_store_data = database.Get(0); |
|||
} |
|||
|
|||
Result DatabaseManager::FindIndex(s32& out_index, const Common::UUID& create_id, |
|||
bool is_special) const { |
|||
u32 index{}; |
|||
const bool is_found = database.GetIndexByCreatorId(index, create_id); |
|||
|
|||
if (!is_found) { |
|||
return ResultNotFound; |
|||
} |
|||
|
|||
if (is_special) { |
|||
out_index = index; |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
if (database.Get(index).IsSpecial()) { |
|||
return ResultNotFound; |
|||
} |
|||
|
|||
out_index = 0; |
|||
|
|||
if (index < 1) { |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
for (std::size_t i = 0; i <= index; ++i) { |
|||
if (database.Get(i).IsSpecial()) { |
|||
continue; |
|||
} |
|||
out_index++; |
|||
} |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result DatabaseManager::FindIndex(const DatabaseSessionMetadata& metadata, u32& out_index, |
|||
const Common::UUID& create_id) const { |
|||
u32 index{}; |
|||
const bool is_found = database.GetIndexByCreatorId(index, create_id); |
|||
|
|||
if (!is_found) { |
|||
return ResultNotFound; |
|||
} |
|||
|
|||
if (metadata.magic == MiiMagic) { |
|||
out_index = index; |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
if (database.Get(index).IsSpecial()) { |
|||
return ResultNotFound; |
|||
} |
|||
|
|||
out_index = 0; |
|||
|
|||
if (index < 1) { |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
// The index refeers to the mii index without special mii.
|
|||
// Search on the database until we find it
|
|||
|
|||
for (std::size_t i = 0; i <= index; ++i) { |
|||
const auto& store_data = database.Get(i); |
|||
if (store_data.IsSpecial()) { |
|||
continue; |
|||
} |
|||
out_index++; |
|||
} |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result DatabaseManager::FindMoveIndex(u32& out_index, u32 new_index, |
|||
const Common::UUID& create_id) const { |
|||
const auto database_size = database.GetDatabaseLength(); |
|||
|
|||
if (database_size >= 1) { |
|||
u32 virtual_index{}; |
|||
for (std::size_t i = 0; i < database_size; ++i) { |
|||
const StoreData& store_data = database.Get(i); |
|||
if (store_data.IsSpecial()) { |
|||
continue; |
|||
} |
|||
if (virtual_index == new_index) { |
|||
const bool is_found = database.GetIndexByCreatorId(out_index, create_id); |
|||
if (!is_found) { |
|||
return ResultNotFound; |
|||
} |
|||
if (store_data.IsSpecial()) { |
|||
return ResultInvalidOperation; |
|||
} |
|||
return ResultSuccess; |
|||
} |
|||
virtual_index++; |
|||
} |
|||
} |
|||
|
|||
const bool is_found = database.GetIndexByCreatorId(out_index, create_id); |
|||
if (!is_found) { |
|||
return ResultNotFound; |
|||
} |
|||
const StoreData& store_data = database.Get(out_index); |
|||
if (store_data.IsSpecial()) { |
|||
return ResultInvalidOperation; |
|||
} |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result DatabaseManager::Move(DatabaseSessionMetadata& metadata, u32 new_index, |
|||
const Common::UUID& create_id) { |
|||
u32 current_index{}; |
|||
if (metadata.magic == MiiMagic) { |
|||
const bool is_found = database.GetIndexByCreatorId(current_index, create_id); |
|||
if (!is_found) { |
|||
return ResultNotFound; |
|||
} |
|||
} else { |
|||
const auto result = FindMoveIndex(current_index, new_index, create_id); |
|||
if (result.IsError()) { |
|||
return result; |
|||
} |
|||
} |
|||
|
|||
const auto result = database.Move(current_index, new_index); |
|||
if (result.IsFailure()) { |
|||
return result; |
|||
} |
|||
|
|||
is_moddified = true; |
|||
update_counter++; |
|||
metadata.update_counter = update_counter; |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result DatabaseManager::AddOrReplace(DatabaseSessionMetadata& metadata, |
|||
const StoreData& store_data) { |
|||
if (store_data.IsValid() != ValidationResult::NoErrors) { |
|||
return ResultInvalidStoreData; |
|||
} |
|||
if (metadata.magic != MiiMagic && store_data.IsSpecial()) { |
|||
return ResultInvalidOperation; |
|||
} |
|||
|
|||
u32 index{}; |
|||
const bool is_found = database.GetIndexByCreatorId(index, store_data.GetCreateId()); |
|||
if (is_found) { |
|||
const StoreData& old_store_data = database.Get(index); |
|||
|
|||
if (store_data.IsSpecial() != old_store_data.IsSpecial()) { |
|||
return ResultInvalidOperation; |
|||
} |
|||
|
|||
database.Replace(index, store_data); |
|||
} else { |
|||
if (database.IsFull()) { |
|||
return ResultDatabaseFull; |
|||
} |
|||
|
|||
database.Add(store_data); |
|||
} |
|||
|
|||
is_moddified = true; |
|||
update_counter++; |
|||
metadata.update_counter = update_counter; |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result DatabaseManager::Delete(DatabaseSessionMetadata& metadata, const Common::UUID& create_id) { |
|||
u32 index{}; |
|||
const bool is_found = database.GetIndexByCreatorId(index, create_id); |
|||
if (!is_found) { |
|||
return ResultNotFound; |
|||
} |
|||
|
|||
if (metadata.magic != MiiMagic) { |
|||
const auto& store_data = database.Get(index); |
|||
if (store_data.IsSpecial()) { |
|||
return ResultInvalidOperation; |
|||
} |
|||
} |
|||
|
|||
database.Delete(index); |
|||
|
|||
is_moddified = true; |
|||
update_counter++; |
|||
metadata.update_counter = update_counter; |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
Result DatabaseManager::Append(DatabaseSessionMetadata& metadata, const CharInfo& char_info) { |
|||
if (char_info.Verify() != ValidationResult::NoErrors) { |
|||
return ResultInvalidCharInfo2; |
|||
} |
|||
if (char_info.GetType() == 1) { |
|||
return ResultInvalidCharInfoType; |
|||
} |
|||
|
|||
u32 index{}; |
|||
StoreData store_data{}; |
|||
|
|||
// Loop until the mii we created is not on the database
|
|||
do { |
|||
store_data.BuildWithCharInfo(char_info); |
|||
} while (database.GetIndexByCreatorId(index, store_data.GetCreateId())); |
|||
|
|||
const Result result = store_data.Restore(); |
|||
|
|||
if (result.IsSuccess() || result == ResultNotUpdated) { |
|||
return AddOrReplace(metadata, store_data); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DatabaseManager::DestroyFile(DatabaseSessionMetadata& metadata) { |
|||
database.CorruptCrc(); |
|||
|
|||
is_moddified = true; |
|||
update_counter++; |
|||
metadata.update_counter = update_counter; |
|||
|
|||
const auto result = SaveDatabase(); |
|||
database.CleanDatabase(); |
|||
|
|||
return result; |
|||
} |
|||
|
|||
Result DatabaseManager::DeleteFile() { |
|||
const bool result = Common::FS::RemoveFile(system_save_dir / DbFileName); |
|||
// TODO: Return proper FS error here
|
|||
return result ? ResultSuccess : ResultUnknown; |
|||
} |
|||
|
|||
void DatabaseManager::Format(DatabaseSessionMetadata& metadata) { |
|||
database.CleanDatabase(); |
|||
is_moddified = true; |
|||
update_counter++; |
|||
metadata.update_counter = update_counter; |
|||
} |
|||
|
|||
Result DatabaseManager::SaveDatabase() { |
|||
// TODO: Replace unknown error codes with proper FS error codes when available
|
|||
|
|||
if (!Common::FS::Exists(system_save_dir / DbFileName)) { |
|||
if (!Common::FS::NewFile(system_save_dir / DbFileName)) { |
|||
LOG_ERROR(Service_Mii, "Failed to create mii database"); |
|||
return ResultUnknown; |
|||
} |
|||
} |
|||
|
|||
const auto file_size = Common::FS::GetSize(system_save_dir / DbFileName); |
|||
if (file_size != 0 && file_size != sizeof(NintendoFigurineDatabase)) { |
|||
if (!Common::FS::RemoveFile(system_save_dir / DbFileName)) { |
|||
LOG_ERROR(Service_Mii, "Failed to delete mii database"); |
|||
return ResultUnknown; |
|||
} |
|||
if (!Common::FS::NewFile(system_save_dir / DbFileName)) { |
|||
LOG_ERROR(Service_Mii, "Failed to create mii database"); |
|||
return ResultUnknown; |
|||
} |
|||
} |
|||
|
|||
const Common::FS::IOFile db_file{system_save_dir / DbFileName, |
|||
Common::FS::FileAccessMode::ReadWrite, |
|||
Common::FS::FileType::BinaryFile}; |
|||
|
|||
if (db_file.Write(database) != 1) { |
|||
LOG_ERROR(Service_Mii, "Failed to save mii database"); |
|||
return ResultUnknown; |
|||
} |
|||
|
|||
is_moddified = false; |
|||
return ResultSuccess; |
|||
} |
|||
|
|||
} // namespace Service::Mii
|
|||
@ -0,0 +1,58 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/fs/fs.h" |
|||
#include "core/hle/result.h" |
|||
#include "core/hle/service/mii/mii_database.h" |
|||
|
|||
namespace Service::Mii { |
|||
class CharInfo; |
|||
class StoreData; |
|||
|
|||
class DatabaseManager { |
|||
public: |
|||
DatabaseManager(); |
|||
Result MountSaveData(); |
|||
Result Initialize(DatabaseSessionMetadata& metadata, bool& is_database_broken); |
|||
|
|||
bool IsFullDatabase() const; |
|||
bool IsModified() const; |
|||
u64 GetUpdateCounter() const; |
|||
|
|||
void Get(StoreData& out_store_data, std::size_t index, |
|||
const DatabaseSessionMetadata& metadata) const; |
|||
u32 GetCount(const DatabaseSessionMetadata& metadata) const; |
|||
|
|||
Result FindIndex(s32& out_index, const Common::UUID& create_id, bool is_special) const; |
|||
Result FindIndex(const DatabaseSessionMetadata& metadata, u32& out_index, |
|||
const Common::UUID& create_id) const; |
|||
Result FindMoveIndex(u32& out_index, u32 new_index, const Common::UUID& create_id) const; |
|||
|
|||
Result Move(DatabaseSessionMetadata& metadata, u32 current_index, |
|||
const Common::UUID& create_id); |
|||
Result AddOrReplace(DatabaseSessionMetadata& metadata, const StoreData& out_store_data); |
|||
Result Delete(DatabaseSessionMetadata& metadata, const Common::UUID& create_id); |
|||
Result Append(DatabaseSessionMetadata& metadata, const CharInfo& char_info); |
|||
|
|||
Result DestroyFile(DatabaseSessionMetadata& metadata); |
|||
Result DeleteFile(); |
|||
void Format(DatabaseSessionMetadata& metadata); |
|||
|
|||
Result SaveDatabase(); |
|||
|
|||
private: |
|||
// This is the global value of |
|||
// nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled"); |
|||
bool is_test_db{}; |
|||
|
|||
bool is_moddified{}; |
|||
bool is_save_data_mounted{}; |
|||
u64 update_counter{}; |
|||
NintendoFigurineDatabase database{}; |
|||
|
|||
std::filesystem::path system_save_dir{}; |
|||
}; |
|||
|
|||
}; // namespace Service::Mii |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue