service: mii: Implement the rest of the service
This commit is contained in:
parent
9a878de33f
commit
2fb71aecb0
3 changed files with 763 additions and 115 deletions
|
@ -8,6 +8,9 @@
|
||||||
#include "core/hle/service/mii/mii.h"
|
#include "core/hle/service/mii/mii.h"
|
||||||
#include "core/hle/service/mii/mii_manager.h"
|
#include "core/hle/service/mii/mii_manager.h"
|
||||||
#include "core/hle/service/mii/mii_result.h"
|
#include "core/hle/service/mii/mii_result.h"
|
||||||
|
#include "core/hle/service/mii/types/char_info.h"
|
||||||
|
#include "core/hle/service/mii/types/store_data.h"
|
||||||
|
#include "core/hle/service/mii/types/ver3_store_data.h"
|
||||||
#include "core/hle/service/server_manager.h"
|
#include "core/hle/service/server_manager.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
@ -27,29 +30,31 @@ public:
|
||||||
{5, &IDatabaseService::UpdateLatest, "UpdateLatest"},
|
{5, &IDatabaseService::UpdateLatest, "UpdateLatest"},
|
||||||
{6, &IDatabaseService::BuildRandom, "BuildRandom"},
|
{6, &IDatabaseService::BuildRandom, "BuildRandom"},
|
||||||
{7, &IDatabaseService::BuildDefault, "BuildDefault"},
|
{7, &IDatabaseService::BuildDefault, "BuildDefault"},
|
||||||
{8, nullptr, "Get2"},
|
{8, &IDatabaseService::Get2, "Get2"},
|
||||||
{9, nullptr, "Get3"},
|
{9, &IDatabaseService::Get3, "Get3"},
|
||||||
{10, nullptr, "UpdateLatest1"},
|
{10, &IDatabaseService::UpdateLatest1, "UpdateLatest1"},
|
||||||
{11, nullptr, "FindIndex"},
|
{11, &IDatabaseService::FindIndex, "FindIndex"},
|
||||||
{12, nullptr, "Move"},
|
{12, &IDatabaseService::Move, "Move"},
|
||||||
{13, nullptr, "AddOrReplace"},
|
{13, &IDatabaseService::AddOrReplace, "AddOrReplace"},
|
||||||
{14, nullptr, "Delete"},
|
{14, &IDatabaseService::Delete, "Delete"},
|
||||||
{15, nullptr, "DestroyFile"},
|
{15, &IDatabaseService::DestroyFile, "DestroyFile"},
|
||||||
{16, nullptr, "DeleteFile"},
|
{16, &IDatabaseService::DeleteFile, "DeleteFile"},
|
||||||
{17, nullptr, "Format"},
|
{17, &IDatabaseService::Format, "Format"},
|
||||||
{18, nullptr, "Import"},
|
{18, nullptr, "Import"},
|
||||||
{19, nullptr, "Export"},
|
{19, nullptr, "Export"},
|
||||||
{20, nullptr, "IsBrokenDatabaseWithClearFlag"},
|
{20, &IDatabaseService::IsBrokenDatabaseWithClearFlag, "IsBrokenDatabaseWithClearFlag"},
|
||||||
{21, &IDatabaseService::GetIndex, "GetIndex"},
|
{21, &IDatabaseService::GetIndex, "GetIndex"},
|
||||||
{22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"},
|
{22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"},
|
||||||
{23, &IDatabaseService::Convert, "Convert"},
|
{23, &IDatabaseService::Convert, "Convert"},
|
||||||
{24, nullptr, "ConvertCoreDataToCharInfo"},
|
{24, &IDatabaseService::ConvertCoreDataToCharInfo, "ConvertCoreDataToCharInfo"},
|
||||||
{25, nullptr, "ConvertCharInfoToCoreData"},
|
{25, &IDatabaseService::ConvertCharInfoToCoreData, "ConvertCharInfoToCoreData"},
|
||||||
{26, nullptr, "Append"},
|
{26, &IDatabaseService::Append, "Append"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
|
manager.Initialize(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -80,10 +85,10 @@ private:
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
||||||
|
|
||||||
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
|
|
||||||
|
|
||||||
const u32 mii_count = manager.GetCount(metadata, source_flag);
|
const u32 mii_count = manager.GetCount(metadata, source_flag);
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_Mii, "called with source_flag={}, mii_count={}", source_flag, mii_count);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push(mii_count);
|
rb.Push(mii_count);
|
||||||
|
@ -94,16 +99,17 @@ private:
|
||||||
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
||||||
const auto output_size{ctx.GetWriteBufferNumElements<CharInfoElement>()};
|
const auto output_size{ctx.GetWriteBufferNumElements<CharInfoElement>()};
|
||||||
|
|
||||||
LOG_DEBUG(Service_Mii, "called with source_flag={}, out_size={}", source_flag, output_size);
|
|
||||||
|
|
||||||
u32 mii_count{};
|
u32 mii_count{};
|
||||||
std::vector<CharInfoElement> char_info_elements(output_size);
|
std::vector<CharInfoElement> char_info_elements(output_size);
|
||||||
Result result = manager.Get(metadata, char_info_elements, mii_count, source_flag);
|
const auto result = manager.Get(metadata, char_info_elements, mii_count, source_flag);
|
||||||
|
|
||||||
if (mii_count != 0) {
|
if (mii_count != 0) {
|
||||||
ctx.WriteBuffer(char_info_elements);
|
ctx.WriteBuffer(char_info_elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag,
|
||||||
|
output_size, mii_count);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(result);
|
rb.Push(result);
|
||||||
rb.Push(mii_count);
|
rb.Push(mii_count);
|
||||||
|
@ -114,16 +120,17 @@ private:
|
||||||
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
||||||
const auto output_size{ctx.GetWriteBufferNumElements<CharInfo>()};
|
const auto output_size{ctx.GetWriteBufferNumElements<CharInfo>()};
|
||||||
|
|
||||||
LOG_DEBUG(Service_Mii, "called with source_flag={}, out_size={}", source_flag, output_size);
|
|
||||||
|
|
||||||
u32 mii_count{};
|
u32 mii_count{};
|
||||||
std::vector<CharInfo> char_info(output_size);
|
std::vector<CharInfo> char_info(output_size);
|
||||||
Result result = manager.Get(metadata, char_info, mii_count, source_flag);
|
const auto result = manager.Get(metadata, char_info, mii_count, source_flag);
|
||||||
|
|
||||||
if (mii_count != 0) {
|
if (mii_count != 0) {
|
||||||
ctx.WriteBuffer(char_info);
|
ctx.WriteBuffer(char_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag,
|
||||||
|
output_size, mii_count);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(result);
|
rb.Push(result);
|
||||||
rb.Push(mii_count);
|
rb.Push(mii_count);
|
||||||
|
@ -134,7 +141,7 @@ private:
|
||||||
const auto char_info{rp.PopRaw<CharInfo>()};
|
const auto char_info{rp.PopRaw<CharInfo>()};
|
||||||
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
||||||
|
|
||||||
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
|
LOG_INFO(Service_Mii, "called with source_flag={}", source_flag);
|
||||||
|
|
||||||
CharInfo new_char_info{};
|
CharInfo new_char_info{};
|
||||||
const auto result = manager.UpdateLatest(metadata, new_char_info, char_info, source_flag);
|
const auto result = manager.UpdateLatest(metadata, new_char_info, char_info, source_flag);
|
||||||
|
@ -146,7 +153,7 @@ private:
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
|
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushRaw<CharInfo>(new_char_info);
|
rb.PushRaw(new_char_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildRandom(HLERequestContext& ctx) {
|
void BuildRandom(HLERequestContext& ctx) {
|
||||||
|
@ -180,14 +187,14 @@ private:
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
|
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushRaw<CharInfo>(char_info);
|
rb.PushRaw(char_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildDefault(HLERequestContext& ctx) {
|
void BuildDefault(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto index{rp.Pop<u32>()};
|
const auto index{rp.Pop<u32>()};
|
||||||
|
|
||||||
LOG_INFO(Service_Mii, "called with index={}", index);
|
LOG_DEBUG(Service_Mii, "called with index={}", index);
|
||||||
|
|
||||||
if (index > 5) {
|
if (index > 5) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
@ -200,7 +207,240 @@ private:
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
|
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushRaw<CharInfo>(char_info);
|
rb.PushRaw(char_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Get2(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
||||||
|
const auto output_size{ctx.GetWriteBufferNumElements<StoreDataElement>()};
|
||||||
|
|
||||||
|
u32 mii_count{};
|
||||||
|
std::vector<StoreDataElement> store_data_elements(output_size);
|
||||||
|
const auto result = manager.Get(metadata, store_data_elements, mii_count, source_flag);
|
||||||
|
|
||||||
|
if (mii_count != 0) {
|
||||||
|
ctx.WriteBuffer(store_data_elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag,
|
||||||
|
output_size, mii_count);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.Push(mii_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Get3(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
||||||
|
const auto output_size{ctx.GetWriteBufferNumElements<StoreData>()};
|
||||||
|
|
||||||
|
u32 mii_count{};
|
||||||
|
std::vector<StoreData> store_data(output_size);
|
||||||
|
const auto result = manager.Get(metadata, store_data, mii_count, source_flag);
|
||||||
|
|
||||||
|
if (mii_count != 0) {
|
||||||
|
ctx.WriteBuffer(store_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag,
|
||||||
|
output_size, mii_count);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.Push(mii_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateLatest1(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto store_data{rp.PopRaw<StoreData>()};
|
||||||
|
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called with source_flag={}", source_flag);
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
if (!is_system) {
|
||||||
|
result = ResultPermissionDenied;
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreData new_store_data{};
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
result = manager.UpdateLatest(metadata, new_store_data, store_data, source_flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.IsFailure()) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2 + sizeof(StoreData) / sizeof(u32)};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.PushRaw<StoreData>(new_store_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindIndex(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto create_id{rp.PopRaw<Common::UUID>()};
|
||||||
|
const auto is_special{rp.PopRaw<bool>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called with create_id={}, is_special={}",
|
||||||
|
create_id.FormattedString(), is_special);
|
||||||
|
|
||||||
|
s32 index = manager.FindIndex(create_id, is_special);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Move(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto create_id{rp.PopRaw<Common::UUID>()};
|
||||||
|
const auto new_index{rp.PopRaw<s32>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called with create_id={}, new_index={}", create_id.FormattedString(),
|
||||||
|
new_index);
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
|
||||||
|
if (!is_system) {
|
||||||
|
result = ResultPermissionDenied;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
const u32 count = manager.GetCount(metadata, SourceFlag::Database);
|
||||||
|
if (new_index < 0 || new_index >= static_cast<s32>(count)) {
|
||||||
|
result = ResultInvalidArgument;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
result = manager.Move(metadata, new_index, create_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddOrReplace(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto store_data{rp.PopRaw<StoreData>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called");
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
|
||||||
|
if (!is_system) {
|
||||||
|
result = ResultPermissionDenied;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
result = manager.AddOrReplace(metadata, store_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Delete(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto create_id{rp.PopRaw<Common::UUID>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called, create_id={}", create_id.FormattedString());
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
|
||||||
|
if (!is_system) {
|
||||||
|
result = ResultPermissionDenied;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
result = manager.Delete(metadata, create_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyFile(HLERequestContext& ctx) {
|
||||||
|
// This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled");
|
||||||
|
bool is_db_test_mode_enabled = false;
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled);
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
|
||||||
|
if (!is_db_test_mode_enabled) {
|
||||||
|
result = ResultTestModeOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
result = manager.DestroyFile(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteFile(HLERequestContext& ctx) {
|
||||||
|
// This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled");
|
||||||
|
bool is_db_test_mode_enabled = false;
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled);
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
|
||||||
|
if (!is_db_test_mode_enabled) {
|
||||||
|
result = ResultTestModeOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
result = manager.DeleteFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Format(HLERequestContext& ctx) {
|
||||||
|
// This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled");
|
||||||
|
bool is_db_test_mode_enabled = false;
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled);
|
||||||
|
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
|
||||||
|
if (!is_db_test_mode_enabled) {
|
||||||
|
result = ResultTestModeOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
result = manager.Format(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IsBrokenDatabaseWithClearFlag(HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_Mii, "called");
|
||||||
|
|
||||||
|
bool is_broken_with_clear_flag{};
|
||||||
|
Result result = ResultSuccess;
|
||||||
|
|
||||||
|
if (!is_system) {
|
||||||
|
result = ResultPermissionDenied;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.IsSuccess()) {
|
||||||
|
is_broken_with_clear_flag = manager.IsBrokenWithClearFlag(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.Push<u8>(is_broken_with_clear_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetIndex(HLERequestContext& ctx) {
|
void GetIndex(HLERequestContext& ctx) {
|
||||||
|
@ -236,13 +476,53 @@ private:
|
||||||
LOG_INFO(Service_Mii, "called");
|
LOG_INFO(Service_Mii, "called");
|
||||||
|
|
||||||
CharInfo char_info{};
|
CharInfo char_info{};
|
||||||
manager.ConvertV3ToCharInfo(char_info, mii_v3);
|
const auto result = manager.ConvertV3ToCharInfo(char_info, mii_v3);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
|
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(result);
|
||||||
rb.PushRaw<CharInfo>(char_info);
|
rb.PushRaw<CharInfo>(char_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConvertCoreDataToCharInfo(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto core_data{rp.PopRaw<CoreData>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called");
|
||||||
|
|
||||||
|
CharInfo char_info{};
|
||||||
|
const auto result = manager.ConvertCoreDataToCharInfo(char_info, core_data);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.PushRaw<CharInfo>(char_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConvertCharInfoToCoreData(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto char_info{rp.PopRaw<CharInfo>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called");
|
||||||
|
|
||||||
|
CoreData core_data{};
|
||||||
|
const auto result = manager.ConvertCharInfoToCoreData(core_data, char_info);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CoreData) / sizeof(u32)};
|
||||||
|
rb.Push(result);
|
||||||
|
rb.PushRaw<CoreData>(core_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Append(HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto char_info{rp.PopRaw<CharInfo>()};
|
||||||
|
|
||||||
|
LOG_INFO(Service_Mii, "called");
|
||||||
|
|
||||||
|
const auto result = manager.Append(metadata, char_info);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
}
|
||||||
|
|
||||||
MiiManager manager{};
|
MiiManager manager{};
|
||||||
DatabaseSessionMetadata metadata{};
|
DatabaseSessionMetadata metadata{};
|
||||||
bool is_system{};
|
bool is_system{};
|
||||||
|
@ -267,7 +547,7 @@ private:
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushIpcInterface<IDatabaseService>(system, is_system);
|
rb.PushIpcInterface<IDatabaseService>(system, is_system);
|
||||||
|
|
||||||
LOG_DEBUG(Service_Mii, "called");
|
LOG_CRITICAL(Service_Mii, "called");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_system{};
|
bool is_system{};
|
||||||
|
@ -278,9 +558,9 @@ public:
|
||||||
explicit MiiImg(Core::System& system_) : ServiceFramework{system_, "miiimg"} {
|
explicit MiiImg(Core::System& system_) : ServiceFramework{system_, "miiimg"} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, nullptr, "Initialize"},
|
{0, &MiiImg::Initialize, "Initialize"},
|
||||||
{10, nullptr, "Reload"},
|
{10, nullptr, "Reload"},
|
||||||
{11, nullptr, "GetCount"},
|
{11, &MiiImg::GetCount, "GetCount"},
|
||||||
{12, nullptr, "IsEmpty"},
|
{12, nullptr, "IsEmpty"},
|
||||||
{13, nullptr, "IsFull"},
|
{13, nullptr, "IsFull"},
|
||||||
{14, nullptr, "GetAttribute"},
|
{14, nullptr, "GetAttribute"},
|
||||||
|
@ -297,6 +577,22 @@ public:
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Initialize(HLERequestContext& ctx) {
|
||||||
|
LOG_CRITICAL(Service_Mii, "called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetCount(HLERequestContext& ctx) {
|
||||||
|
LOG_CRITICAL(Service_Mii, "called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(ResultSuccess);
|
||||||
|
rb.Push(0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void LoopProcess(Core::System& system) {
|
void LoopProcess(Core::System& system) {
|
||||||
|
|
|
@ -1,59 +1,26 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <random>
|
|
||||||
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/string_util.h"
|
#include "core/hle/service/mii/mii_database_manager.h"
|
||||||
|
|
||||||
#include "core/hle/service/acc/profile_manager.h"
|
|
||||||
#include "core/hle/service/mii/mii_manager.h"
|
#include "core/hle/service/mii/mii_manager.h"
|
||||||
#include "core/hle/service/mii/mii_result.h"
|
#include "core/hle/service/mii/mii_result.h"
|
||||||
#include "core/hle/service/mii/mii_util.h"
|
#include "core/hle/service/mii/mii_util.h"
|
||||||
|
#include "core/hle/service/mii/types/char_info.h"
|
||||||
#include "core/hle/service/mii/types/core_data.h"
|
#include "core/hle/service/mii/types/core_data.h"
|
||||||
#include "core/hle/service/mii/types/raw_data.h"
|
#include "core/hle/service/mii/types/raw_data.h"
|
||||||
|
#include "core/hle/service/mii/types/store_data.h"
|
||||||
|
#include "core/hle/service/mii/types/ver3_store_data.h"
|
||||||
|
|
||||||
namespace Service::Mii {
|
namespace Service::Mii {
|
||||||
constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()};
|
constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()};
|
||||||
|
|
||||||
MiiManager::MiiManager() {}
|
MiiManager::MiiManager() {}
|
||||||
|
|
||||||
bool MiiManager::IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const {
|
Result MiiManager::Initialize(DatabaseSessionMetadata& metadata) {
|
||||||
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
database_manager.MountSaveData();
|
||||||
return false;
|
database_manager.Initialize(metadata, is_broken_with_clear_flag);
|
||||||
}
|
return ResultSuccess;
|
||||||
|
|
||||||
const auto metadata_update_counter = metadata.update_counter;
|
|
||||||
metadata.update_counter = update_counter;
|
|
||||||
return metadata_update_counter != update_counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MiiManager::IsFullDatabase() const {
|
|
||||||
// TODO(bunnei): We don't implement the Mii database, so it cannot be full
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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::Database) != SourceFlag::None) {
|
|
||||||
// TODO(bunnei): We don't implement the Mii database, but when we do, update this
|
|
||||||
}
|
|
||||||
return mii_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(bunnei): We don't implement the Mii database, so we can't have an entry
|
|
||||||
return ResultNotFound;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MiiManager::BuildDefault(CharInfo& out_char_info, u32 index) const {
|
void MiiManager::BuildDefault(CharInfo& out_char_info, u32 index) const {
|
||||||
|
@ -74,39 +41,368 @@ void MiiManager::BuildRandom(CharInfo& out_char_info, Age age, Gender gender, Ra
|
||||||
out_char_info.SetFromStoreData(store_data);
|
out_char_info.SetFromStoreData(store_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MiiManager::ConvertV3ToCharInfo(CharInfo& out_char_info, const Ver3StoreData& mii_v3) const {
|
bool MiiManager::IsFullDatabase() const {
|
||||||
|
return database_manager.IsFullDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MiiManager::SetInterfaceVersion(DatabaseSessionMetadata& metadata, u32 version) const {
|
||||||
|
metadata.interface_version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MiiManager::IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const {
|
||||||
|
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u64 metadata_update_counter = metadata.update_counter;
|
||||||
|
const u64 database_update_counter = database_manager.GetUpdateCounter();
|
||||||
|
metadata.update_counter = database_update_counter;
|
||||||
|
return metadata_update_counter != database_update_counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
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::Database) != SourceFlag::None) {
|
||||||
|
mii_count += database_manager.GetCount(metadata);
|
||||||
|
}
|
||||||
|
return mii_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::Move(DatabaseSessionMetadata& metadata, u32 index,
|
||||||
|
const Common::UUID& create_id) {
|
||||||
|
const auto result = database_manager.Move(metadata, index, create_id);
|
||||||
|
|
||||||
|
if (result.IsFailure()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!database_manager.IsModified()) {
|
||||||
|
return ResultNotUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
return database_manager.SaveDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::AddOrReplace(DatabaseSessionMetadata& metadata, const StoreData& store_data) {
|
||||||
|
const auto result = database_manager.AddOrReplace(metadata, store_data);
|
||||||
|
|
||||||
|
if (result.IsFailure()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!database_manager.IsModified()) {
|
||||||
|
return ResultNotUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
return database_manager.SaveDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::Delete(DatabaseSessionMetadata& metadata, const Common::UUID& create_id) {
|
||||||
|
const auto result = database_manager.Delete(metadata, create_id);
|
||||||
|
|
||||||
|
if (result.IsFailure()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!database_manager.IsModified()) {
|
||||||
|
return ResultNotUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
return database_manager.SaveDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 MiiManager::FindIndex(const Common::UUID& create_id, bool is_special) const {
|
||||||
|
s32 index{};
|
||||||
|
const auto result = database_manager.FindIndex(index, create_id, is_special);
|
||||||
|
if (result.IsError()) {
|
||||||
|
index = -1;
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::GetIndex(const DatabaseSessionMetadata& metadata, const CharInfo& char_info,
|
||||||
|
s32& out_index) const {
|
||||||
|
if (char_info.Verify() != ValidationResult::NoErrors) {
|
||||||
|
return ResultInvalidCharInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 index{};
|
||||||
|
Result result = {};
|
||||||
|
// FindIndex(index);
|
||||||
|
|
||||||
|
if (result.IsError()) {
|
||||||
|
return ResultNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
return ResultNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_index = index;
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::Append(DatabaseSessionMetadata& metadata, const CharInfo& char_info) {
|
||||||
|
const auto result = database_manager.Append(metadata, char_info);
|
||||||
|
|
||||||
|
if (result.IsError()) {
|
||||||
|
return ResultNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!database_manager.IsModified()) {
|
||||||
|
return ResultNotUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
return database_manager.SaveDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MiiManager::IsBrokenWithClearFlag(DatabaseSessionMetadata& metadata) {
|
||||||
|
const bool is_broken = is_broken_with_clear_flag;
|
||||||
|
if (is_broken_with_clear_flag) {
|
||||||
|
is_broken_with_clear_flag = false;
|
||||||
|
database_manager.Format(metadata);
|
||||||
|
database_manager.SaveDatabase();
|
||||||
|
}
|
||||||
|
return is_broken;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::DestroyFile(DatabaseSessionMetadata& metadata) {
|
||||||
|
is_broken_with_clear_flag = true;
|
||||||
|
return database_manager.DestroyFile(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::DeleteFile() {
|
||||||
|
return database_manager.DeleteFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::Format(DatabaseSessionMetadata& metadata) {
|
||||||
|
database_manager.Format(metadata);
|
||||||
|
|
||||||
|
if (!database_manager.IsModified()) {
|
||||||
|
return ResultNotUpdated;
|
||||||
|
}
|
||||||
|
return database_manager.SaveDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::ConvertV3ToCharInfo(CharInfo& out_char_info, const Ver3StoreData& mii_v3) const {
|
||||||
|
if (!mii_v3.IsValid()) {
|
||||||
|
return ResultInvalidCharInfo;
|
||||||
|
}
|
||||||
|
|
||||||
StoreData store_data{};
|
StoreData store_data{};
|
||||||
mii_v3.BuildToStoreData(store_data);
|
mii_v3.BuildToStoreData(store_data);
|
||||||
|
const auto name = store_data.GetNickname();
|
||||||
|
if (!MiiUtil::IsFontRegionValid(store_data.GetFontRegion(), name.data)) {
|
||||||
|
store_data.SetInvalidName();
|
||||||
|
}
|
||||||
|
|
||||||
out_char_info.SetFromStoreData(store_data);
|
out_char_info.SetFromStoreData(store_data);
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::ConvertCoreDataToCharInfo(CharInfo& out_char_info,
|
||||||
|
const CoreData& core_data) const {
|
||||||
|
if (core_data.IsValid() != ValidationResult::NoErrors) {
|
||||||
|
return ResultInvalidCharInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreData store_data{};
|
||||||
|
store_data.BuildWithCoreData(core_data);
|
||||||
|
const auto name = store_data.GetNickname();
|
||||||
|
if (!MiiUtil::IsFontRegionValid(store_data.GetFontRegion(), name.data)) {
|
||||||
|
store_data.SetInvalidName();
|
||||||
|
}
|
||||||
|
|
||||||
|
out_char_info.SetFromStoreData(store_data);
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::ConvertCharInfoToCoreData(CoreData& out_core_data,
|
||||||
|
const CharInfo& char_info) const {
|
||||||
|
if (char_info.Verify() != ValidationResult::NoErrors) {
|
||||||
|
return ResultInvalidCharInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_core_data.BuildFromCharInfo(char_info);
|
||||||
|
const auto name = out_core_data.GetNickname();
|
||||||
|
if (!MiiUtil::IsFontRegionValid(out_core_data.GetFontRegion(), name.data)) {
|
||||||
|
out_core_data.SetNickname(out_core_data.GetInvalidNickname());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::UpdateLatest(const DatabaseSessionMetadata& metadata, CharInfo& out_char_info,
|
||||||
|
const CharInfo& char_info, SourceFlag source_flag) const {
|
||||||
|
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
||||||
|
return ResultNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata.IsInterfaceVersionSupported(1)) {
|
||||||
|
if (char_info.Verify() != ValidationResult::NoErrors) {
|
||||||
|
return ResultInvalidCharInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 index{};
|
||||||
|
Result result = database_manager.FindIndex(metadata, index, char_info.GetCreateId());
|
||||||
|
|
||||||
|
if (result.IsError()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreData store_data{};
|
||||||
|
database_manager.Get(store_data, index, metadata);
|
||||||
|
|
||||||
|
if (store_data.GetType() != char_info.GetType()) {
|
||||||
|
return ResultNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_char_info.SetFromStoreData(store_data);
|
||||||
|
|
||||||
|
if (char_info == out_char_info) {
|
||||||
|
return ResultNotUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::UpdateLatest(const DatabaseSessionMetadata& metadata, StoreData& out_store_data,
|
||||||
|
const StoreData& store_data, SourceFlag source_flag) const {
|
||||||
|
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
||||||
|
return ResultNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata.IsInterfaceVersionSupported(1)) {
|
||||||
|
if (store_data.IsValid() != ValidationResult::NoErrors) {
|
||||||
|
return ResultInvalidCharInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 index{};
|
||||||
|
Result result = database_manager.FindIndex(metadata, index, store_data.GetCreateId());
|
||||||
|
|
||||||
|
if (result.IsError()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
database_manager.Get(out_store_data, index, metadata);
|
||||||
|
|
||||||
|
if (out_store_data.GetType() != store_data.GetType()) {
|
||||||
|
return ResultNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store_data == out_store_data) {
|
||||||
|
return ResultNotUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MiiManager::Get(const DatabaseSessionMetadata& metadata,
|
Result MiiManager::Get(const DatabaseSessionMetadata& metadata,
|
||||||
std::span<CharInfoElement> out_elements, u32& out_count,
|
std::span<CharInfoElement> out_elements, u32& out_count,
|
||||||
SourceFlag source_flag) {
|
SourceFlag source_flag) const {
|
||||||
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
||||||
return BuildDefault(out_elements, out_count, source_flag);
|
return BuildDefault(out_elements, out_count, source_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(bunnei): We don't implement the Mii database, so we can't have an entry
|
const auto mii_count = database_manager.GetCount(metadata);
|
||||||
|
|
||||||
|
for (std::size_t index = 0; index < mii_count; ++index) {
|
||||||
|
if (out_elements.size() <= static_cast<std::size_t>(out_count)) {
|
||||||
|
return ResultInvalidArgumentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreData store_data{};
|
||||||
|
database_manager.Get(store_data, index, metadata);
|
||||||
|
|
||||||
|
out_elements[out_count].source = Source::Database;
|
||||||
|
out_elements[out_count].char_info.SetFromStoreData(store_data);
|
||||||
|
out_count++;
|
||||||
|
}
|
||||||
|
|
||||||
// Include default Mii at the end of the list
|
// Include default Mii at the end of the list
|
||||||
return BuildDefault(out_elements, out_count, source_flag);
|
return BuildDefault(out_elements, out_count, source_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MiiManager::Get(const DatabaseSessionMetadata& metadata, std::span<CharInfo> out_char_info,
|
Result MiiManager::Get(const DatabaseSessionMetadata& metadata, std::span<CharInfo> out_char_info,
|
||||||
u32& out_count, SourceFlag source_flag) {
|
u32& out_count, SourceFlag source_flag) const {
|
||||||
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
||||||
return BuildDefault(out_char_info, out_count, source_flag);
|
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
|
const auto mii_count = database_manager.GetCount(metadata);
|
||||||
|
|
||||||
|
for (std::size_t index = 0; index < mii_count; ++index) {
|
||||||
|
if (out_char_info.size() <= static_cast<std::size_t>(out_count)) {
|
||||||
|
return ResultInvalidArgumentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreData store_data{};
|
||||||
|
database_manager.Get(store_data, index, metadata);
|
||||||
|
|
||||||
|
out_char_info[out_count].SetFromStoreData(store_data);
|
||||||
|
out_count++;
|
||||||
|
}
|
||||||
|
|
||||||
// Include default Mii at the end of the list
|
// Include default Mii at the end of the list
|
||||||
return BuildDefault(out_char_info, out_count, source_flag);
|
return BuildDefault(out_char_info, out_count, source_flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result MiiManager::Get(const DatabaseSessionMetadata& metadata,
|
||||||
|
std::span<StoreDataElement> out_elements, u32& out_count,
|
||||||
|
SourceFlag source_flag) const {
|
||||||
|
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
||||||
|
return BuildDefault(out_elements, out_count, source_flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto mii_count = database_manager.GetCount(metadata);
|
||||||
|
|
||||||
|
for (std::size_t index = 0; index < mii_count; ++index) {
|
||||||
|
if (out_elements.size() <= static_cast<std::size_t>(out_count)) {
|
||||||
|
return ResultInvalidArgumentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreData store_data{};
|
||||||
|
database_manager.Get(store_data, index, metadata);
|
||||||
|
|
||||||
|
out_elements[out_count].store_data = store_data;
|
||||||
|
out_elements[out_count].source = Source::Database;
|
||||||
|
out_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<StoreData> out_store_data,
|
||||||
|
u32& out_count, SourceFlag source_flag) const {
|
||||||
|
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
||||||
|
return BuildDefault(out_store_data, out_count, source_flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto mii_count = database_manager.GetCount(metadata);
|
||||||
|
|
||||||
|
for (std::size_t index = 0; index < mii_count; ++index) {
|
||||||
|
if (out_store_data.size() <= static_cast<std::size_t>(out_count)) {
|
||||||
|
return ResultInvalidArgumentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreData store_data{};
|
||||||
|
database_manager.Get(store_data, index, metadata);
|
||||||
|
|
||||||
|
out_store_data[out_count] = store_data;
|
||||||
|
out_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include default Mii at the end of the list
|
||||||
|
return BuildDefault(out_store_data, out_count, source_flag);
|
||||||
|
}
|
||||||
Result MiiManager::BuildDefault(std::span<CharInfoElement> out_elements, u32& out_count,
|
Result MiiManager::BuildDefault(std::span<CharInfoElement> out_elements, u32& out_count,
|
||||||
SourceFlag source_flag) {
|
SourceFlag source_flag) const {
|
||||||
if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
|
if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +425,7 @@ Result MiiManager::BuildDefault(std::span<CharInfoElement> out_elements, u32& ou
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MiiManager::BuildDefault(std::span<CharInfo> out_char_info, u32& out_count,
|
Result MiiManager::BuildDefault(std::span<CharInfo> out_char_info, u32& out_count,
|
||||||
SourceFlag source_flag) {
|
SourceFlag source_flag) const {
|
||||||
if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
|
if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
@ -150,23 +446,41 @@ Result MiiManager::BuildDefault(std::span<CharInfo> out_char_info, u32& out_coun
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MiiManager::GetIndex(const DatabaseSessionMetadata& metadata, const CharInfo& char_info,
|
Result MiiManager::BuildDefault(std::span<StoreDataElement> out_elements, u32& out_count,
|
||||||
s32& out_index) {
|
SourceFlag source_flag) const {
|
||||||
|
if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
|
||||||
if (char_info.Verify() != ValidationResult::NoErrors) {
|
return ResultSuccess;
|
||||||
return ResultInvalidCharInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u32 INVALID_INDEX{0xFFFFFFFF};
|
for (std::size_t index = 0; index < DefaultMiiCount; ++index) {
|
||||||
|
if (out_elements.size() <= static_cast<std::size_t>(out_count)) {
|
||||||
out_index = INVALID_INDEX;
|
return ResultInvalidArgumentSize;
|
||||||
|
|
||||||
// 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) {
|
out_elements[out_count].store_data.BuildDefault(static_cast<u32>(index));
|
||||||
metadata.interface_version = version;
|
out_elements[out_count].source = Source::Default;
|
||||||
|
out_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::BuildDefault(std::span<StoreData> out_char_info, u32& out_count,
|
||||||
|
SourceFlag source_flag) const {
|
||||||
|
if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::size_t index = 0; index < DefaultMiiCount; ++index) {
|
||||||
|
if (out_char_info.size() <= static_cast<std::size_t>(out_count)) {
|
||||||
|
return ResultInvalidArgumentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_char_info[out_count].BuildDefault(static_cast<u32>(index));
|
||||||
|
out_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Mii
|
} // namespace Service::Mii
|
||||||
|
|
|
@ -3,47 +3,85 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <span>
|
||||||
|
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
#include "core/hle/service/mii/mii_database_manager.h"
|
||||||
#include "core/hle/service/mii/mii_types.h"
|
#include "core/hle/service/mii/mii_types.h"
|
||||||
#include "core/hle/service/mii/types/char_info.h"
|
|
||||||
#include "core/hle/service/mii/types/store_data.h"
|
|
||||||
#include "core/hle/service/mii/types/ver3_store_data.h"
|
|
||||||
|
|
||||||
namespace Service::Mii {
|
namespace Service::Mii {
|
||||||
|
class CharInfo;
|
||||||
|
class CoreData;
|
||||||
|
class StoreData;
|
||||||
|
class Ver3StoreData;
|
||||||
|
|
||||||
// The Mii manager is responsible for loading and storing the Miis to the database in NAND along
|
struct CharInfoElement;
|
||||||
// with providing an easy interface for HLE emulation of the mii service.
|
struct StoreDataElement;
|
||||||
|
|
||||||
|
// The Mii manager is responsible for handling mii operations along with providing an easy interface
|
||||||
|
// for HLE emulation of the mii service.
|
||||||
class MiiManager {
|
class MiiManager {
|
||||||
public:
|
public:
|
||||||
MiiManager();
|
MiiManager();
|
||||||
|
Result Initialize(DatabaseSessionMetadata& metadata);
|
||||||
|
|
||||||
bool IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const;
|
// Auto generated mii
|
||||||
|
|
||||||
bool IsFullDatabase() 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<CharInfoElement> out_elements,
|
|
||||||
u32& out_count, SourceFlag source_flag);
|
|
||||||
Result Get(const DatabaseSessionMetadata& metadata, std::span<CharInfo> out_char_info,
|
|
||||||
u32& out_count, SourceFlag source_flag);
|
|
||||||
void BuildDefault(CharInfo& out_char_info, u32 index) const;
|
void BuildDefault(CharInfo& out_char_info, u32 index) const;
|
||||||
void BuildBase(CharInfo& out_char_info, Gender gender) const;
|
void BuildBase(CharInfo& out_char_info, Gender gender) const;
|
||||||
void BuildRandom(CharInfo& out_char_info, Age age, Gender gender, Race race) 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<CharInfoElement> GetDefault(SourceFlag source_flag);
|
// Database operations
|
||||||
|
bool IsFullDatabase() const;
|
||||||
|
void SetInterfaceVersion(DatabaseSessionMetadata& metadata, u32 version) const;
|
||||||
|
bool IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const;
|
||||||
|
u32 GetCount(const DatabaseSessionMetadata& metadata, SourceFlag source_flag) const;
|
||||||
|
Result Move(DatabaseSessionMetadata& metadata, u32 index, const Common::UUID& create_id);
|
||||||
|
Result AddOrReplace(DatabaseSessionMetadata& metadata, const StoreData& store_data);
|
||||||
|
Result Delete(DatabaseSessionMetadata& metadata, const Common::UUID& create_id);
|
||||||
|
s32 FindIndex(const Common::UUID& create_id, bool is_special) const;
|
||||||
Result GetIndex(const DatabaseSessionMetadata& metadata, const CharInfo& char_info,
|
Result GetIndex(const DatabaseSessionMetadata& metadata, const CharInfo& char_info,
|
||||||
s32& out_index);
|
s32& out_index) const;
|
||||||
void SetInterfaceVersion(DatabaseSessionMetadata& metadata, u32 version);
|
Result Append(DatabaseSessionMetadata& metadata, const CharInfo& char_info);
|
||||||
|
|
||||||
|
// Test database operations
|
||||||
|
bool IsBrokenWithClearFlag(DatabaseSessionMetadata& metadata);
|
||||||
|
Result DestroyFile(DatabaseSessionMetadata& metadata);
|
||||||
|
Result DeleteFile();
|
||||||
|
Result Format(DatabaseSessionMetadata& metadata);
|
||||||
|
|
||||||
|
// Mii conversions
|
||||||
|
Result ConvertV3ToCharInfo(CharInfo& out_char_info, const Ver3StoreData& mii_v3) const;
|
||||||
|
Result ConvertCoreDataToCharInfo(CharInfo& out_char_info, const CoreData& core_data) const;
|
||||||
|
Result ConvertCharInfoToCoreData(CoreData& out_core_data, const CharInfo& char_info) const;
|
||||||
|
Result UpdateLatest(const DatabaseSessionMetadata& metadata, CharInfo& out_char_info,
|
||||||
|
const CharInfo& char_info, SourceFlag source_flag) const;
|
||||||
|
Result UpdateLatest(const DatabaseSessionMetadata& metadata, StoreData& out_store_data,
|
||||||
|
const StoreData& store_data, SourceFlag source_flag) const;
|
||||||
|
|
||||||
|
// Overloaded getters
|
||||||
|
Result Get(const DatabaseSessionMetadata& metadata, std::span<CharInfoElement> out_elements,
|
||||||
|
u32& out_count, SourceFlag source_flag) const;
|
||||||
|
Result Get(const DatabaseSessionMetadata& metadata, std::span<CharInfo> out_char_info,
|
||||||
|
u32& out_count, SourceFlag source_flag) const;
|
||||||
|
Result Get(const DatabaseSessionMetadata& metadata, std::span<StoreDataElement> out_elements,
|
||||||
|
u32& out_count, SourceFlag source_flag) const;
|
||||||
|
Result Get(const DatabaseSessionMetadata& metadata, std::span<StoreData> out_store_data,
|
||||||
|
u32& out_count, SourceFlag source_flag) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Result BuildDefault(std::span<CharInfoElement> out_elements, u32& out_count,
|
Result BuildDefault(std::span<CharInfoElement> out_elements, u32& out_count,
|
||||||
SourceFlag source_flag);
|
SourceFlag source_flag) const;
|
||||||
Result BuildDefault(std::span<CharInfo> out_char_info, u32& out_count, SourceFlag source_flag);
|
Result BuildDefault(std::span<CharInfo> out_char_info, u32& out_count,
|
||||||
|
SourceFlag source_flag) const;
|
||||||
|
Result BuildDefault(std::span<StoreDataElement> out_char_info, u32& out_count,
|
||||||
|
SourceFlag source_flag) const;
|
||||||
|
Result BuildDefault(std::span<StoreData> out_char_info, u32& out_count,
|
||||||
|
SourceFlag source_flag) const;
|
||||||
|
|
||||||
u64 update_counter{};
|
DatabaseManager database_manager{};
|
||||||
|
|
||||||
|
// This should be a global value
|
||||||
|
bool is_broken_with_clear_flag{};
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace Service::Mii
|
}; // namespace Service::Mii
|
||||||
|
|
Loading…
Reference in a new issue