mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-25 16:22:47 +01:00
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;
|
||||
case MiiEditAppletMode::CreateMii:
|
||||
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
|
||||
? 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;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -15,8 +15,8 @@ namespace Service::Mii {
|
|||
|
||||
class IDatabaseService final : public ServiceFramework<IDatabaseService> {
|
||||
public:
|
||||
explicit IDatabaseService(Core::System& system_)
|
||||
: ServiceFramework{system_, "IDatabaseService"} {
|
||||
explicit IDatabaseService(Core::System& system_, bool is_system_)
|
||||
: ServiceFramework{system_, "IDatabaseService"}, is_system{is_system_} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IDatabaseService::IsUpdated, "IsUpdated"},
|
||||
|
@ -53,34 +53,27 @@ public:
|
|||
}
|
||||
|
||||
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) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto source_flag{rp.PopRaw<SourceFlag>()};
|
||||
|
||||
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
|
||||
|
||||
const bool is_updated = manager.IsUpdated(metadata, source_flag);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(manager.CheckAndResetUpdateCounter(source_flag, current_update_counter));
|
||||
rb.Push<u8>(is_updated);
|
||||
}
|
||||
|
||||
void IsFullDatabase(HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Mii, "called");
|
||||
|
||||
const bool is_full_database = manager.IsFullDatabase();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(manager.IsFullDatabase());
|
||||
rb.Push<u8>(is_full_database);
|
||||
}
|
||||
|
||||
void GetCount(HLERequestContext& ctx) {
|
||||
|
@ -89,57 +82,63 @@ private:
|
|||
|
||||
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
|
||||
|
||||
const u32 mii_count = manager.GetCount(metadata, source_flag);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(manager.GetCount(source_flag));
|
||||
rb.Push(mii_count);
|
||||
}
|
||||
|
||||
void Get(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
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)};
|
||||
if (default_miis.size() > 0) {
|
||||
ctx.WriteBuffer(SerializeArray(default_miis));
|
||||
u32 mii_count{};
|
||||
std::vector<CharInfoElement> char_info_elements(output_size);
|
||||
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};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(static_cast<u32>(default_miis.size()));
|
||||
rb.Push(result);
|
||||
rb.Push(mii_count);
|
||||
}
|
||||
|
||||
void Get1(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
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;
|
||||
for (const auto& element : default_miis) {
|
||||
values.emplace_back(element.char_info);
|
||||
if (mii_count != 0) {
|
||||
ctx.WriteBuffer(char_info);
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(SerializeArray(values));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push<u32>(static_cast<u32>(default_miis.size()));
|
||||
rb.Push(result);
|
||||
rb.Push(mii_count);
|
||||
}
|
||||
|
||||
void UpdateLatest(HLERequestContext& 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>()};
|
||||
|
||||
LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
|
||||
|
||||
CharInfo new_char_info{};
|
||||
const auto result{manager.UpdateLatest(&new_char_info, info, source_flag)};
|
||||
if (result != ResultSuccess) {
|
||||
const auto result = manager.UpdateLatest(metadata, new_char_info, char_info, source_flag);
|
||||
if (result.IsFailure()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(result);
|
||||
return;
|
||||
|
@ -152,7 +151,6 @@ private:
|
|||
|
||||
void BuildRandom(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto age{rp.PopRaw<Age>()};
|
||||
const auto gender{rp.PopRaw<Gender>()};
|
||||
const auto race{rp.PopRaw<Race>()};
|
||||
|
@ -162,46 +160,47 @@ private:
|
|||
if (age > Age::All) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultInvalidArgument);
|
||||
LOG_ERROR(Service_Mii, "invalid age={}", age);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gender > Gender::All) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultInvalidArgument);
|
||||
LOG_ERROR(Service_Mii, "invalid gender={}", gender);
|
||||
return;
|
||||
}
|
||||
|
||||
if (race > Race::All) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultInvalidArgument);
|
||||
LOG_ERROR(Service_Mii, "invalid race={}", race);
|
||||
return;
|
||||
}
|
||||
|
||||
CharInfo char_info{};
|
||||
manager.BuildRandom(char_info, age, gender, race);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw<CharInfo>(manager.BuildRandom(age, gender, race));
|
||||
rb.PushRaw<CharInfo>(char_info);
|
||||
}
|
||||
|
||||
void BuildDefault(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
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) {
|
||||
LOG_ERROR(Service_Mii, "invalid argument, index cannot be greater than 5 but is {:08X}",
|
||||
index);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultInvalidArgument);
|
||||
return;
|
||||
}
|
||||
|
||||
CharInfo char_info{};
|
||||
manager.BuildDefault(char_info, index);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw<CharInfo>(manager.BuildDefault(index));
|
||||
rb.PushRaw<CharInfo>(char_info);
|
||||
}
|
||||
|
||||
void GetIndex(HLERequestContext& ctx) {
|
||||
|
@ -210,19 +209,21 @@ private:
|
|||
|
||||
LOG_DEBUG(Service_Mii, "called");
|
||||
|
||||
u32 index{};
|
||||
s32 index{};
|
||||
const Result result = manager.GetIndex(metadata, info, index);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(manager.GetIndex(info, index));
|
||||
rb.Push(result);
|
||||
rb.Push(index);
|
||||
}
|
||||
|
||||
void SetInterfaceVersion(HLERequestContext& 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};
|
||||
rb.Push(ResultSuccess);
|
||||
|
@ -230,30 +231,27 @@ private:
|
|||
|
||||
void Convert(HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
|
||||
const auto mii_v3{rp.PopRaw<Ver3StoreData>()};
|
||||
|
||||
LOG_INFO(Service_Mii, "called");
|
||||
|
||||
CharInfo char_info{};
|
||||
manager.ConvertV3ToCharInfo(char_info, mii_v3);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw<CharInfo>(manager.ConvertV3ToCharInfo(mii_v3));
|
||||
rb.PushRaw<CharInfo>(char_info);
|
||||
}
|
||||
|
||||
constexpr bool IsInterfaceVersionSupported(u32 interface_version) const {
|
||||
return current_interface_version >= interface_version;
|
||||
}
|
||||
|
||||
MiiManager manager;
|
||||
|
||||
u32 current_interface_version{};
|
||||
u64 current_update_counter{};
|
||||
MiiManager manager{};
|
||||
DatabaseSessionMetadata metadata{};
|
||||
bool is_system{};
|
||||
};
|
||||
|
||||
class MiiDBModule final : public ServiceFramework<MiiDBModule> {
|
||||
public:
|
||||
explicit MiiDBModule(Core::System& system_, const char* name_)
|
||||
: ServiceFramework{system_, name_} {
|
||||
explicit MiiDBModule(Core::System& system_, const char* name_, bool is_system_)
|
||||
: ServiceFramework{system_, name_}, is_system{is_system_} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"},
|
||||
|
@ -267,10 +265,12 @@ private:
|
|||
void GetDatabaseService(HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushIpcInterface<IDatabaseService>(system);
|
||||
rb.PushIpcInterface<IDatabaseService>(system, is_system);
|
||||
|
||||
LOG_DEBUG(Service_Mii, "called");
|
||||
}
|
||||
|
||||
bool is_system{};
|
||||
};
|
||||
|
||||
class MiiImg final : public ServiceFramework<MiiImg> {
|
||||
|
@ -302,8 +302,10 @@ public:
|
|||
void LoopProcess(Core::System& 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:u", std::make_shared<MiiDBModule>(system, "mii:u"));
|
||||
server_manager->RegisterNamedService("mii:e",
|
||||
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));
|
||||
ServerManager::RunServer(std::move(server_manager));
|
||||
}
|
||||
|
|
|
@ -16,45 +16,18 @@
|
|||
#include "core/hle/service/mii/types/raw_data.h"
|
||||
|
||||
namespace Service::Mii {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()};
|
||||
|
||||
CharInfo ConvertStoreDataToInfo(const StoreData& data) {
|
||||
CharInfo char_info{};
|
||||
char_info.SetFromStoreData(data);
|
||||
return char_info;
|
||||
}
|
||||
MiiManager::MiiManager() {}
|
||||
|
||||
StoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Common::UUID& user_id) {
|
||||
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) {
|
||||
bool MiiManager::IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const {
|
||||
if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool result{current_update_counter != update_counter};
|
||||
|
||||
current_update_counter = update_counter;
|
||||
|
||||
return result;
|
||||
const auto metadata_update_counter = metadata.update_counter;
|
||||
metadata.update_counter = update_counter;
|
||||
return metadata_update_counter != update_counter;
|
||||
}
|
||||
|
||||
bool MiiManager::IsFullDatabase() const {
|
||||
|
@ -62,19 +35,19 @@ bool MiiManager::IsFullDatabase() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
u32 MiiManager::GetCount(SourceFlag source_flag) const {
|
||||
std::size_t count{};
|
||||
if ((source_flag & SourceFlag::Database) != SourceFlag::None) {
|
||||
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
|
||||
count += 0;
|
||||
}
|
||||
if ((source_flag & SourceFlag::Default) != SourceFlag::None) {
|
||||
count += DefaultMiiCount;
|
||||
}
|
||||
return static_cast<u32>(count);
|
||||
return mii_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) {
|
||||
return ResultNotFound;
|
||||
}
|
||||
|
@ -83,48 +56,117 @@ Result MiiManager::UpdateLatest(CharInfo* out_info, const CharInfo& info, Source
|
|||
return ResultNotFound;
|
||||
}
|
||||
|
||||
CharInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) {
|
||||
return ConvertStoreDataToInfo(BuildRandomStoreData(age, gender, race, user_id));
|
||||
void MiiManager::BuildDefault(CharInfo& out_char_info, u32 index) const {
|
||||
StoreData store_data{};
|
||||
store_data.BuildDefault(index);
|
||||
out_char_info.SetFromStoreData(store_data);
|
||||
}
|
||||
|
||||
CharInfo MiiManager::BuildBase(Gender gender) {
|
||||
const std::size_t index = gender == Gender::Female ? 1 : 0;
|
||||
return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::BaseMii.at(index), user_id));
|
||||
void MiiManager::BuildBase(CharInfo& out_char_info, Gender gender) const {
|
||||
StoreData store_data{};
|
||||
store_data.BuildBase(gender);
|
||||
out_char_info.SetFromStoreData(store_data);
|
||||
}
|
||||
|
||||
CharInfo MiiManager::BuildDefault(std::size_t index) {
|
||||
return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::DefaultMii.at(index), user_id));
|
||||
void MiiManager::BuildRandom(CharInfo& out_char_info, Age age, Gender gender, Race race) const {
|
||||
StoreData store_data{};
|
||||
store_data.BuildRandom(age, gender, race);
|
||||
out_char_info.SetFromStoreData(store_data);
|
||||
}
|
||||
|
||||
CharInfo MiiManager::ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const {
|
||||
CharInfo char_info{};
|
||||
void MiiManager::ConvertV3ToCharInfo(CharInfo& out_char_info, const Ver3StoreData& mii_v3) const {
|
||||
StoreData store_data{};
|
||||
mii_v3.BuildToStoreData(store_data);
|
||||
char_info.SetFromStoreData(store_data);
|
||||
return char_info;
|
||||
out_char_info.SetFromStoreData(store_data);
|
||||
}
|
||||
|
||||
std::vector<CharInfoElement> MiiManager::GetDefault(SourceFlag source_flag) {
|
||||
std::vector<CharInfoElement> result;
|
||||
Result MiiManager::Get(const DatabaseSessionMetadata& metadata,
|
||||
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) {
|
||||
return result;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
for (std::size_t index = 0; index < DefaultMiiCount; index++) {
|
||||
result.emplace_back(BuildDefault(index), Source::Default);
|
||||
StoreData store_data{};
|
||||
|
||||
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};
|
||||
|
||||
index = INVALID_INDEX;
|
||||
out_index = INVALID_INDEX;
|
||||
|
||||
// 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) {
|
||||
metadata.interface_version = version;
|
||||
}
|
||||
|
||||
} // namespace Service::Mii
|
||||
|
|
|
@ -19,16 +19,24 @@ class MiiManager {
|
|||
public:
|
||||
MiiManager();
|
||||
|
||||
bool CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter);
|
||||
bool IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const;
|
||||
|
||||
bool IsFullDatabase() const;
|
||||
u32 GetCount(SourceFlag source_flag) const;
|
||||
Result UpdateLatest(CharInfo* out_info, const CharInfo& info, SourceFlag source_flag);
|
||||
CharInfo BuildRandom(Age age, Gender gender, Race race);
|
||||
CharInfo BuildBase(Gender gender);
|
||||
CharInfo BuildDefault(std::size_t index);
|
||||
CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) 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 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);
|
||||
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 {
|
||||
u32 magic{}; // 'NFDB'
|
||||
|
@ -40,7 +48,10 @@ public:
|
|||
static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size.");
|
||||
|
||||
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{};
|
||||
};
|
||||
|
||||
|
|
|
@ -165,4 +165,14 @@ struct DefaultMii {
|
|||
};
|
||||
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
|
||||
|
|
|
@ -680,12 +680,16 @@ Result NfcDevice::GetRegisterInfo(NFP::RegisterInfo& register_info) const {
|
|||
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;
|
||||
|
||||
// TODO: Validate this data
|
||||
register_info = {
|
||||
.mii_char_info = manager.ConvertV3ToCharInfo(tag_data.owner_mii),
|
||||
.mii_char_info = char_info,
|
||||
.creation_date = settings.init_date.GetWriteDate(),
|
||||
.amiibo_name = GetAmiiboName(settings),
|
||||
.font_region = settings.settings.font_region,
|
||||
|
|
Loading…
Reference in a new issue