forked from suyu/suyu
mii: Prepare Interface for new implementation
This commit is contained in:
parent
571399930c
commit
bd169f417f
6 changed files with 210 additions and 138 deletions
|
@ -85,15 +85,18 @@ void MiiEdit::Execute() {
|
||||||
break;
|
break;
|
||||||
case MiiEditAppletMode::CreateMii:
|
case MiiEditAppletMode::CreateMii:
|
||||||
case MiiEditAppletMode::EditMii: {
|
case MiiEditAppletMode::EditMii: {
|
||||||
Service::Mii::MiiManager mii_manager;
|
Mii::CharInfo char_info{};
|
||||||
|
Mii::StoreData store_data{};
|
||||||
|
store_data.BuildBase(Mii::Gender::Male);
|
||||||
|
char_info.SetFromStoreData(store_data);
|
||||||
|
|
||||||
const MiiEditCharInfo char_info{
|
const MiiEditCharInfo edit_char_info{
|
||||||
.mii_info{applet_input_common.applet_mode == MiiEditAppletMode::EditMii
|
.mii_info{applet_input_common.applet_mode == MiiEditAppletMode::EditMii
|
||||||
? applet_input_v4.char_info.mii_info
|
? applet_input_v4.char_info.mii_info
|
||||||
: mii_manager.BuildBase(Mii::Gender::Male)},
|
: char_info},
|
||||||
};
|
};
|
||||||
|
|
||||||
MiiEditOutputForCharInfoEditing(MiiEditResult::Success, char_info);
|
MiiEditOutputForCharInfoEditing(MiiEditResult::Success, edit_char_info);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -15,8 +15,8 @@ namespace Service::Mii {
|
||||||
|
|
||||||
class IDatabaseService final : public ServiceFramework<IDatabaseService> {
|
class IDatabaseService final : public ServiceFramework<IDatabaseService> {
|
||||||
public:
|
public:
|
||||||
explicit IDatabaseService(Core::System& system_)
|
explicit IDatabaseService(Core::System& system_, bool is_system_)
|
||||||
: ServiceFramework{system_, "IDatabaseService"} {
|
: ServiceFramework{system_, "IDatabaseService"}, is_system{is_system_} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &IDatabaseService::IsUpdated, "IsUpdated"},
|
{0, &IDatabaseService::IsUpdated, "IsUpdated"},
|
||||||
|
@ -53,34 +53,27 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename T>
|
|
||||||
std::vector<u8> SerializeArray(const std::vector<T>& values) {
|
|
||||||
std::vector<u8> out(values.size() * sizeof(T));
|
|
||||||
std::size_t offset{};
|
|
||||||
for (const auto& value : values) {
|
|
||||||
std::memcpy(out.data() + offset, &value, sizeof(T));
|
|
||||||
offset += sizeof(T);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IsUpdated(HLERequestContext& ctx) {
|
void IsUpdated(HLERequestContext& ctx) {
|
||||||
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);
|
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
|
||||||
|
|
||||||
|
const bool is_updated = manager.IsUpdated(metadata, source_flag);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push(manager.CheckAndResetUpdateCounter(source_flag, current_update_counter));
|
rb.Push<u8>(is_updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IsFullDatabase(HLERequestContext& ctx) {
|
void IsFullDatabase(HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_Mii, "called");
|
LOG_DEBUG(Service_Mii, "called");
|
||||||
|
|
||||||
|
const bool is_full_database = manager.IsFullDatabase();
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push(manager.IsFullDatabase());
|
rb.Push<u8>(is_full_database);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetCount(HLERequestContext& ctx) {
|
void GetCount(HLERequestContext& ctx) {
|
||||||
|
@ -89,57 +82,63 @@ private:
|
||||||
|
|
||||||
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
|
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
|
||||||
|
|
||||||
|
const u32 mii_count = manager.GetCount(metadata, source_flag);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push<u32>(manager.GetCount(source_flag));
|
rb.Push(mii_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Get(HLERequestContext& ctx) {
|
void Get(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
||||||
|
const auto output_size{ctx.GetWriteBufferNumElements<CharInfoElement>()};
|
||||||
|
|
||||||
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
|
LOG_DEBUG(Service_Mii, "called with source_flag={}, out_size={}", source_flag, output_size);
|
||||||
|
|
||||||
const auto default_miis{manager.GetDefault(source_flag)};
|
u32 mii_count{};
|
||||||
if (default_miis.size() > 0) {
|
std::vector<CharInfoElement> char_info_elements(output_size);
|
||||||
ctx.WriteBuffer(SerializeArray(default_miis));
|
Result result = manager.Get(metadata, char_info_elements, mii_count, source_flag);
|
||||||
|
|
||||||
|
if (mii_count != 0) {
|
||||||
|
ctx.WriteBuffer(char_info_elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(result);
|
||||||
rb.Push<u32>(static_cast<u32>(default_miis.size()));
|
rb.Push(mii_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Get1(HLERequestContext& ctx) {
|
void Get1(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
||||||
|
const auto output_size{ctx.GetWriteBufferNumElements<CharInfo>()};
|
||||||
|
|
||||||
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
|
LOG_DEBUG(Service_Mii, "called with source_flag={}, out_size={}", source_flag, output_size);
|
||||||
|
|
||||||
const auto default_miis{manager.GetDefault(source_flag)};
|
u32 mii_count{};
|
||||||
|
std::vector<CharInfo> char_info(output_size);
|
||||||
|
Result result = manager.Get(metadata, char_info, mii_count, source_flag);
|
||||||
|
|
||||||
std::vector<CharInfo> values;
|
if (mii_count != 0) {
|
||||||
for (const auto& element : default_miis) {
|
ctx.WriteBuffer(char_info);
|
||||||
values.emplace_back(element.char_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.WriteBuffer(SerializeArray(values));
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(result);
|
||||||
rb.Push<u32>(static_cast<u32>(default_miis.size()));
|
rb.Push(mii_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateLatest(HLERequestContext& ctx) {
|
void UpdateLatest(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto 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_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
|
||||||
|
|
||||||
CharInfo new_char_info{};
|
CharInfo new_char_info{};
|
||||||
const auto result{manager.UpdateLatest(&new_char_info, info, source_flag)};
|
const auto result = manager.UpdateLatest(metadata, new_char_info, char_info, source_flag);
|
||||||
if (result != ResultSuccess) {
|
if (result.IsFailure()) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(result);
|
rb.Push(result);
|
||||||
return;
|
return;
|
||||||
|
@ -152,7 +151,6 @@ private:
|
||||||
|
|
||||||
void BuildRandom(HLERequestContext& ctx) {
|
void BuildRandom(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const auto age{rp.PopRaw<Age>()};
|
const auto age{rp.PopRaw<Age>()};
|
||||||
const auto gender{rp.PopRaw<Gender>()};
|
const auto gender{rp.PopRaw<Gender>()};
|
||||||
const auto race{rp.PopRaw<Race>()};
|
const auto race{rp.PopRaw<Race>()};
|
||||||
|
@ -162,46 +160,47 @@ private:
|
||||||
if (age > Age::All) {
|
if (age > Age::All) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultInvalidArgument);
|
rb.Push(ResultInvalidArgument);
|
||||||
LOG_ERROR(Service_Mii, "invalid age={}", age);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gender > Gender::All) {
|
if (gender > Gender::All) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultInvalidArgument);
|
rb.Push(ResultInvalidArgument);
|
||||||
LOG_ERROR(Service_Mii, "invalid gender={}", gender);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (race > Race::All) {
|
if (race > Race::All) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultInvalidArgument);
|
rb.Push(ResultInvalidArgument);
|
||||||
LOG_ERROR(Service_Mii, "invalid race={}", race);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CharInfo char_info{};
|
||||||
|
manager.BuildRandom(char_info, age, gender, race);
|
||||||
|
|
||||||
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>(manager.BuildRandom(age, gender, race));
|
rb.PushRaw<CharInfo>(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_DEBUG(Service_Mii, "called with index={}", index);
|
LOG_INFO(Service_Mii, "called with index={}", index);
|
||||||
|
|
||||||
if (index > 5) {
|
if (index > 5) {
|
||||||
LOG_ERROR(Service_Mii, "invalid argument, index cannot be greater than 5 but is {:08X}",
|
|
||||||
index);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultInvalidArgument);
|
rb.Push(ResultInvalidArgument);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CharInfo char_info{};
|
||||||
|
manager.BuildDefault(char_info, index);
|
||||||
|
|
||||||
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>(manager.BuildDefault(index));
|
rb.PushRaw<CharInfo>(char_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetIndex(HLERequestContext& ctx) {
|
void GetIndex(HLERequestContext& ctx) {
|
||||||
|
@ -210,19 +209,21 @@ private:
|
||||||
|
|
||||||
LOG_DEBUG(Service_Mii, "called");
|
LOG_DEBUG(Service_Mii, "called");
|
||||||
|
|
||||||
u32 index{};
|
s32 index{};
|
||||||
|
const Result result = manager.GetIndex(metadata, info, index);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(manager.GetIndex(info, index));
|
rb.Push(result);
|
||||||
rb.Push(index);
|
rb.Push(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetInterfaceVersion(HLERequestContext& ctx) {
|
void SetInterfaceVersion(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
current_interface_version = rp.PopRaw<u32>();
|
const auto interface_version{rp.PopRaw<u32>()};
|
||||||
|
|
||||||
LOG_DEBUG(Service_Mii, "called, interface_version={:08X}", current_interface_version);
|
LOG_INFO(Service_Mii, "called, interface_version={:08X}", interface_version);
|
||||||
|
|
||||||
UNIMPLEMENTED_IF(current_interface_version != 1);
|
manager.SetInterfaceVersion(metadata, interface_version);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
@ -230,30 +231,27 @@ private:
|
||||||
|
|
||||||
void Convert(HLERequestContext& ctx) {
|
void Convert(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const auto mii_v3{rp.PopRaw<Ver3StoreData>()};
|
const auto mii_v3{rp.PopRaw<Ver3StoreData>()};
|
||||||
|
|
||||||
LOG_INFO(Service_Mii, "called");
|
LOG_INFO(Service_Mii, "called");
|
||||||
|
|
||||||
|
CharInfo char_info{};
|
||||||
|
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(ResultSuccess);
|
||||||
rb.PushRaw<CharInfo>(manager.ConvertV3ToCharInfo(mii_v3));
|
rb.PushRaw<CharInfo>(char_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool IsInterfaceVersionSupported(u32 interface_version) const {
|
MiiManager manager{};
|
||||||
return current_interface_version >= interface_version;
|
DatabaseSessionMetadata metadata{};
|
||||||
}
|
bool is_system{};
|
||||||
|
|
||||||
MiiManager manager;
|
|
||||||
|
|
||||||
u32 current_interface_version{};
|
|
||||||
u64 current_update_counter{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class MiiDBModule final : public ServiceFramework<MiiDBModule> {
|
class MiiDBModule final : public ServiceFramework<MiiDBModule> {
|
||||||
public:
|
public:
|
||||||
explicit MiiDBModule(Core::System& system_, const char* name_)
|
explicit MiiDBModule(Core::System& system_, const char* name_, bool is_system_)
|
||||||
: ServiceFramework{system_, name_} {
|
: ServiceFramework{system_, name_}, is_system{is_system_} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"},
|
{0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"},
|
||||||
|
@ -267,10 +265,12 @@ private:
|
||||||
void GetDatabaseService(HLERequestContext& ctx) {
|
void GetDatabaseService(HLERequestContext& ctx) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushIpcInterface<IDatabaseService>(system);
|
rb.PushIpcInterface<IDatabaseService>(system, is_system);
|
||||||
|
|
||||||
LOG_DEBUG(Service_Mii, "called");
|
LOG_DEBUG(Service_Mii, "called");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_system{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class MiiImg final : public ServiceFramework<MiiImg> {
|
class MiiImg final : public ServiceFramework<MiiImg> {
|
||||||
|
@ -302,8 +302,10 @@ public:
|
||||||
void LoopProcess(Core::System& system) {
|
void LoopProcess(Core::System& system) {
|
||||||
auto server_manager = std::make_unique<ServerManager>(system);
|
auto server_manager = std::make_unique<ServerManager>(system);
|
||||||
|
|
||||||
server_manager->RegisterNamedService("mii:e", std::make_shared<MiiDBModule>(system, "mii:e"));
|
server_manager->RegisterNamedService("mii:e",
|
||||||
server_manager->RegisterNamedService("mii:u", std::make_shared<MiiDBModule>(system, "mii:u"));
|
std::make_shared<MiiDBModule>(system, "mii:e", true));
|
||||||
|
server_manager->RegisterNamedService("mii:u",
|
||||||
|
std::make_shared<MiiDBModule>(system, "mii:u", false));
|
||||||
server_manager->RegisterNamedService("miiimg", std::make_shared<MiiImg>(system));
|
server_manager->RegisterNamedService("miiimg", std::make_shared<MiiImg>(system));
|
||||||
ServerManager::RunServer(std::move(server_manager));
|
ServerManager::RunServer(std::move(server_manager));
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,45 +16,18 @@
|
||||||
#include "core/hle/service/mii/types/raw_data.h"
|
#include "core/hle/service/mii/types/raw_data.h"
|
||||||
|
|
||||||
namespace Service::Mii {
|
namespace Service::Mii {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()};
|
constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()};
|
||||||
|
|
||||||
CharInfo ConvertStoreDataToInfo(const StoreData& data) {
|
MiiManager::MiiManager() {}
|
||||||
CharInfo char_info{};
|
|
||||||
char_info.SetFromStoreData(data);
|
|
||||||
return char_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
StoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Common::UUID& user_id) {
|
bool MiiManager::IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const {
|
||||||
StoreData store_data{};
|
|
||||||
store_data.BuildRandom(age, gender, race);
|
|
||||||
|
|
||||||
return store_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
StoreData BuildDefaultStoreData(const DefaultMii& info, const Common::UUID& user_id) {
|
|
||||||
StoreData store_data{};
|
|
||||||
store_data.BuildDefault(0);
|
|
||||||
|
|
||||||
return store_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
MiiManager::MiiManager() : user_id{Service::Account::ProfileManager().GetLastOpenedUser()} {}
|
|
||||||
|
|
||||||
bool MiiManager::CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter) {
|
|
||||||
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool result{current_update_counter != update_counter};
|
const auto metadata_update_counter = metadata.update_counter;
|
||||||
|
metadata.update_counter = update_counter;
|
||||||
current_update_counter = update_counter;
|
return metadata_update_counter != update_counter;
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MiiManager::IsFullDatabase() const {
|
bool MiiManager::IsFullDatabase() const {
|
||||||
|
@ -62,19 +35,19 @@ bool MiiManager::IsFullDatabase() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 MiiManager::GetCount(SourceFlag source_flag) const {
|
u32 MiiManager::GetCount(const DatabaseSessionMetadata& metadata, SourceFlag source_flag) const {
|
||||||
std::size_t count{};
|
u32 mii_count{};
|
||||||
if ((source_flag & SourceFlag::Database) != SourceFlag::None) {
|
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
|
// TODO(bunnei): We don't implement the Mii database, but when we do, update this
|
||||||
count += 0;
|
|
||||||
}
|
}
|
||||||
if ((source_flag & SourceFlag::Default) != SourceFlag::None) {
|
return mii_count;
|
||||||
count += DefaultMiiCount;
|
|
||||||
}
|
|
||||||
return static_cast<u32>(count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MiiManager::UpdateLatest(CharInfo* out_info, const CharInfo& info, SourceFlag source_flag) {
|
Result MiiManager::UpdateLatest(DatabaseSessionMetadata& metadata, CharInfo& out_char_info,
|
||||||
|
const CharInfo& char_info, SourceFlag source_flag) {
|
||||||
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
||||||
return ResultNotFound;
|
return ResultNotFound;
|
||||||
}
|
}
|
||||||
|
@ -83,48 +56,117 @@ Result MiiManager::UpdateLatest(CharInfo* out_info, const CharInfo& info, Source
|
||||||
return ResultNotFound;
|
return ResultNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
CharInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) {
|
void MiiManager::BuildDefault(CharInfo& out_char_info, u32 index) const {
|
||||||
return ConvertStoreDataToInfo(BuildRandomStoreData(age, gender, race, user_id));
|
StoreData store_data{};
|
||||||
|
store_data.BuildDefault(index);
|
||||||
|
out_char_info.SetFromStoreData(store_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
CharInfo MiiManager::BuildBase(Gender gender) {
|
void MiiManager::BuildBase(CharInfo& out_char_info, Gender gender) const {
|
||||||
const std::size_t index = gender == Gender::Female ? 1 : 0;
|
StoreData store_data{};
|
||||||
return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::BaseMii.at(index), user_id));
|
store_data.BuildBase(gender);
|
||||||
|
out_char_info.SetFromStoreData(store_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
CharInfo MiiManager::BuildDefault(std::size_t index) {
|
void MiiManager::BuildRandom(CharInfo& out_char_info, Age age, Gender gender, Race race) const {
|
||||||
return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::DefaultMii.at(index), user_id));
|
StoreData store_data{};
|
||||||
|
store_data.BuildRandom(age, gender, race);
|
||||||
|
out_char_info.SetFromStoreData(store_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
CharInfo MiiManager::ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const {
|
void MiiManager::ConvertV3ToCharInfo(CharInfo& out_char_info, const Ver3StoreData& mii_v3) const {
|
||||||
CharInfo char_info{};
|
|
||||||
StoreData store_data{};
|
StoreData store_data{};
|
||||||
mii_v3.BuildToStoreData(store_data);
|
mii_v3.BuildToStoreData(store_data);
|
||||||
char_info.SetFromStoreData(store_data);
|
out_char_info.SetFromStoreData(store_data);
|
||||||
return char_info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<CharInfoElement> MiiManager::GetDefault(SourceFlag source_flag) {
|
Result MiiManager::Get(const DatabaseSessionMetadata& metadata,
|
||||||
std::vector<CharInfoElement> result;
|
std::span<CharInfoElement> out_elements, u32& out_count,
|
||||||
|
SourceFlag source_flag) {
|
||||||
|
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
||||||
|
return BuildDefault(out_elements, out_count, source_flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(bunnei): We don't implement the Mii database, so we can't have an entry
|
||||||
|
|
||||||
|
// 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<CharInfo> out_char_info,
|
||||||
|
u32& out_count, SourceFlag source_flag) {
|
||||||
|
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
||||||
|
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
|
||||||
|
|
||||||
|
// Include default Mii at the end of the list
|
||||||
|
return BuildDefault(out_char_info, out_count, source_flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::BuildDefault(std::span<CharInfoElement> out_elements, u32& out_count,
|
||||||
|
SourceFlag source_flag) {
|
||||||
if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
|
if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
|
||||||
return result;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::size_t index = 0; index < DefaultMiiCount; index++) {
|
StoreData store_data{};
|
||||||
result.emplace_back(BuildDefault(index), Source::Default);
|
|
||||||
|
for (std::size_t index = 0; index < DefaultMiiCount; ++index) {
|
||||||
|
if (out_elements.size() <= static_cast<std::size_t>(out_count)) {
|
||||||
|
return ResultInvalidArgumentSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
store_data.BuildDefault(static_cast<u32>(index));
|
||||||
|
|
||||||
|
out_elements[out_count].source = Source::Default;
|
||||||
|
out_elements[out_count].char_info.SetFromStoreData(store_data);
|
||||||
|
out_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MiiManager::GetIndex([[maybe_unused]] const CharInfo& info, u32& index) {
|
Result MiiManager::BuildDefault(std::span<CharInfo> out_char_info, u32& out_count,
|
||||||
|
SourceFlag source_flag) {
|
||||||
|
if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreData store_data{};
|
||||||
|
|
||||||
|
for (std::size_t index = 0; index < DefaultMiiCount; ++index) {
|
||||||
|
if (out_char_info.size() <= static_cast<std::size_t>(out_count)) {
|
||||||
|
return ResultInvalidArgumentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
store_data.BuildDefault(static_cast<u32>(index));
|
||||||
|
|
||||||
|
out_char_info[out_count].SetFromStoreData(store_data);
|
||||||
|
out_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MiiManager::GetIndex(const DatabaseSessionMetadata& metadata, const CharInfo& char_info,
|
||||||
|
s32& out_index) {
|
||||||
|
|
||||||
|
if (char_info.Verify() != 0) {
|
||||||
|
return ResultInvalidCharInfo;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr u32 INVALID_INDEX{0xFFFFFFFF};
|
constexpr u32 INVALID_INDEX{0xFFFFFFFF};
|
||||||
|
|
||||||
index = INVALID_INDEX;
|
out_index = INVALID_INDEX;
|
||||||
|
|
||||||
// TODO(bunnei): We don't implement the Mii database, so we can't have an index
|
// TODO(bunnei): We don't implement the Mii database, so we can't have an index
|
||||||
return ResultNotFound;
|
return ResultNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MiiManager::SetInterfaceVersion(DatabaseSessionMetadata& metadata, u32 version) {
|
||||||
|
metadata.interface_version = version;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Service::Mii
|
} // namespace Service::Mii
|
||||||
|
|
|
@ -19,16 +19,24 @@ class MiiManager {
|
||||||
public:
|
public:
|
||||||
MiiManager();
|
MiiManager();
|
||||||
|
|
||||||
bool CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter);
|
bool IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const;
|
||||||
|
|
||||||
bool IsFullDatabase() const;
|
bool IsFullDatabase() const;
|
||||||
u32 GetCount(SourceFlag source_flag) const;
|
u32 GetCount(const DatabaseSessionMetadata& metadata, SourceFlag source_flag) const;
|
||||||
Result UpdateLatest(CharInfo* out_info, const CharInfo& info, SourceFlag source_flag);
|
Result UpdateLatest(DatabaseSessionMetadata& metadata, CharInfo& out_char_info,
|
||||||
CharInfo BuildRandom(Age age, Gender gender, Race race);
|
const CharInfo& char_info, SourceFlag source_flag);
|
||||||
CharInfo BuildBase(Gender gender);
|
Result Get(const DatabaseSessionMetadata& metadata, std::span<CharInfoElement> out_elements,
|
||||||
CharInfo BuildDefault(std::size_t index);
|
u32& out_count, SourceFlag source_flag);
|
||||||
CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const;
|
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 BuildBase(CharInfo& out_char_info, Gender gender) 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);
|
std::vector<CharInfoElement> GetDefault(SourceFlag source_flag);
|
||||||
Result GetIndex(const CharInfo& info, u32& index);
|
Result GetIndex(const DatabaseSessionMetadata& metadata, const CharInfo& char_info,
|
||||||
|
s32& out_index);
|
||||||
|
void SetInterfaceVersion(DatabaseSessionMetadata& metadata, u32 version);
|
||||||
|
|
||||||
struct MiiDatabase {
|
struct MiiDatabase {
|
||||||
u32 magic{}; // 'NFDB'
|
u32 magic{}; // 'NFDB'
|
||||||
|
@ -40,7 +48,10 @@ public:
|
||||||
static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size.");
|
static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size.");
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Common::UUID user_id{};
|
Result BuildDefault(std::span<CharInfoElement> out_elements, u32& out_count,
|
||||||
|
SourceFlag source_flag);
|
||||||
|
Result BuildDefault(std::span<CharInfo> out_char_info, u32& out_count, SourceFlag source_flag);
|
||||||
|
|
||||||
u64 update_counter{};
|
u64 update_counter{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -165,4 +165,14 @@ struct DefaultMii {
|
||||||
};
|
};
|
||||||
static_assert(sizeof(DefaultMii) == 0xd8, "MiiStoreData has incorrect size.");
|
static_assert(sizeof(DefaultMii) == 0xd8, "MiiStoreData has incorrect size.");
|
||||||
|
|
||||||
|
struct DatabaseSessionMetadata {
|
||||||
|
u32 interface_version;
|
||||||
|
u32 magic;
|
||||||
|
u64 update_counter;
|
||||||
|
|
||||||
|
bool IsInterfaceVersionSupported(u32 version) const {
|
||||||
|
return version <= interface_version;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Service::Mii
|
} // namespace Service::Mii
|
||||||
|
|
|
@ -680,12 +680,16 @@ Result NfcDevice::GetRegisterInfo(NFP::RegisterInfo& register_info) const {
|
||||||
return ResultRegistrationIsNotInitialized;
|
return ResultRegistrationIsNotInitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
Service::Mii::MiiManager manager;
|
Mii::CharInfo char_info{};
|
||||||
|
Mii::StoreData store_data{};
|
||||||
|
tag_data.owner_mii.BuildToStoreData(store_data);
|
||||||
|
char_info.SetFromStoreData(store_data);
|
||||||
|
|
||||||
const auto& settings = tag_data.settings;
|
const auto& settings = tag_data.settings;
|
||||||
|
|
||||||
// TODO: Validate this data
|
// TODO: Validate this data
|
||||||
register_info = {
|
register_info = {
|
||||||
.mii_char_info = manager.ConvertV3ToCharInfo(tag_data.owner_mii),
|
.mii_char_info = char_info,
|
||||||
.creation_date = settings.init_date.GetWriteDate(),
|
.creation_date = settings.init_date.GetWriteDate(),
|
||||||
.amiibo_name = GetAmiiboName(settings),
|
.amiibo_name = GetAmiiboName(settings),
|
||||||
.font_region = settings.settings.font_region,
|
.font_region = settings.settings.font_region,
|
||||||
|
|
Loading…
Reference in a new issue