service: mii: Implement figurine database
This commit is contained in:
parent
bd409c3416
commit
a50b50f8b4
|
@ -596,6 +596,8 @@ add_library(core STATIC
|
||||||
hle/service/mii/types/ver3_store_data.h
|
hle/service/mii/types/ver3_store_data.h
|
||||||
hle/service/mii/mii.cpp
|
hle/service/mii/mii.cpp
|
||||||
hle/service/mii/mii.h
|
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.cpp
|
||||||
hle/service/mii/mii_manager.h
|
hle/service/mii/mii_manager.h
|
||||||
hle/service/mii/mii_result.h
|
hle/service/mii/mii_result.h
|
||||||
|
|
|
@ -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
|
|
@ -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