summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/am/applets/applet_mii_edit.cpp11
-rw-r--r--src/core/hle/service/mii/mii.cpp128
-rw-r--r--src/core/hle/service/mii/mii_manager.cpp162
-rw-r--r--src/core/hle/service/mii/mii_manager.h29
-rw-r--r--src/core/hle/service/mii/mii_types.h10
-rw-r--r--src/core/hle/service/nfc/common/device.cpp8
6 files changed, 210 insertions, 138 deletions
diff --git a/src/core/hle/service/am/applets/applet_mii_edit.cpp b/src/core/hle/service/am/applets/applet_mii_edit.cpp
index f8e2bac32..350a90818 100644
--- a/src/core/hle/service/am/applets/applet_mii_edit.cpp
+++ b/src/core/hle/service/am/applets/applet_mii_edit.cpp
@@ -85,15 +85,18 @@ void MiiEdit::Execute() {
85 break; 85 break;
86 case MiiEditAppletMode::CreateMii: 86 case MiiEditAppletMode::CreateMii:
87 case MiiEditAppletMode::EditMii: { 87 case MiiEditAppletMode::EditMii: {
88 Service::Mii::MiiManager mii_manager; 88 Mii::CharInfo char_info{};
89 Mii::StoreData store_data{};
90 store_data.BuildBase(Mii::Gender::Male);
91 char_info.SetFromStoreData(store_data);
89 92
90 const MiiEditCharInfo char_info{ 93 const MiiEditCharInfo edit_char_info{
91 .mii_info{applet_input_common.applet_mode == MiiEditAppletMode::EditMii 94 .mii_info{applet_input_common.applet_mode == MiiEditAppletMode::EditMii
92 ? applet_input_v4.char_info.mii_info 95 ? applet_input_v4.char_info.mii_info
93 : mii_manager.BuildBase(Mii::Gender::Male)}, 96 : char_info},
94 }; 97 };
95 98
96 MiiEditOutputForCharInfoEditing(MiiEditResult::Success, char_info); 99 MiiEditOutputForCharInfoEditing(MiiEditResult::Success, edit_char_info);
97 break; 100 break;
98 } 101 }
99 default: 102 default:
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index 680f06beb..653c36740 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -15,8 +15,8 @@ namespace Service::Mii {
15 15
16class IDatabaseService final : public ServiceFramework<IDatabaseService> { 16class IDatabaseService final : public ServiceFramework<IDatabaseService> {
17public: 17public:
18 explicit IDatabaseService(Core::System& system_) 18 explicit IDatabaseService(Core::System& system_, bool is_system_)
19 : ServiceFramework{system_, "IDatabaseService"} { 19 : ServiceFramework{system_, "IDatabaseService"}, is_system{is_system_} {
20 // clang-format off 20 // clang-format off
21 static const FunctionInfo functions[] = { 21 static const FunctionInfo functions[] = {
22 {0, &IDatabaseService::IsUpdated, "IsUpdated"}, 22 {0, &IDatabaseService::IsUpdated, "IsUpdated"},
@@ -53,34 +53,27 @@ public:
53 } 53 }
54 54
55private: 55private:
56 template <typename T>
57 std::vector<u8> SerializeArray(const std::vector<T>& values) {
58 std::vector<u8> out(values.size() * sizeof(T));
59 std::size_t offset{};
60 for (const auto& value : values) {
61 std::memcpy(out.data() + offset, &value, sizeof(T));
62 offset += sizeof(T);
63 }
64 return out;
65 }
66
67 void IsUpdated(HLERequestContext& ctx) { 56 void IsUpdated(HLERequestContext& ctx) {
68 IPC::RequestParser rp{ctx}; 57 IPC::RequestParser rp{ctx};
69 const auto source_flag{rp.PopRaw<SourceFlag>()}; 58 const auto source_flag{rp.PopRaw<SourceFlag>()};
70 59
71 LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); 60 LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
72 61
62 const bool is_updated = manager.IsUpdated(metadata, source_flag);
63
73 IPC::ResponseBuilder rb{ctx, 3}; 64 IPC::ResponseBuilder rb{ctx, 3};
74 rb.Push(ResultSuccess); 65 rb.Push(ResultSuccess);
75 rb.Push(manager.CheckAndResetUpdateCounter(source_flag, current_update_counter)); 66 rb.Push<u8>(is_updated);
76 } 67 }
77 68
78 void IsFullDatabase(HLERequestContext& ctx) { 69 void IsFullDatabase(HLERequestContext& ctx) {
79 LOG_DEBUG(Service_Mii, "called"); 70 LOG_DEBUG(Service_Mii, "called");
80 71
72 const bool is_full_database = manager.IsFullDatabase();
73
81 IPC::ResponseBuilder rb{ctx, 3}; 74 IPC::ResponseBuilder rb{ctx, 3};
82 rb.Push(ResultSuccess); 75 rb.Push(ResultSuccess);
83 rb.Push(manager.IsFullDatabase()); 76 rb.Push<u8>(is_full_database);
84 } 77 }
85 78
86 void GetCount(HLERequestContext& ctx) { 79 void GetCount(HLERequestContext& ctx) {
@@ -89,57 +82,63 @@ private:
89 82
90 LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); 83 LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
91 84
85 const u32 mii_count = manager.GetCount(metadata, source_flag);
86
92 IPC::ResponseBuilder rb{ctx, 3}; 87 IPC::ResponseBuilder rb{ctx, 3};
93 rb.Push(ResultSuccess); 88 rb.Push(ResultSuccess);
94 rb.Push<u32>(manager.GetCount(source_flag)); 89 rb.Push(mii_count);
95 } 90 }
96 91
97 void Get(HLERequestContext& ctx) { 92 void Get(HLERequestContext& ctx) {
98 IPC::RequestParser rp{ctx}; 93 IPC::RequestParser rp{ctx};
99 const auto source_flag{rp.PopRaw<SourceFlag>()}; 94 const auto source_flag{rp.PopRaw<SourceFlag>()};
95 const auto output_size{ctx.GetWriteBufferNumElements<CharInfoElement>()};
100 96
101 LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); 97 LOG_DEBUG(Service_Mii, "called with source_flag={}, out_size={}", source_flag, output_size);
98
99 u32 mii_count{};
100 std::vector<CharInfoElement> char_info_elements(output_size);
101 Result result = manager.Get(metadata, char_info_elements, mii_count, source_flag);
102 102
103 const auto default_miis{manager.GetDefault(source_flag)}; 103 if (mii_count != 0) {
104 if (default_miis.size() > 0) { 104 ctx.WriteBuffer(char_info_elements);
105 ctx.WriteBuffer(SerializeArray(default_miis));
106 } 105 }
107 106
108 IPC::ResponseBuilder rb{ctx, 3}; 107 IPC::ResponseBuilder rb{ctx, 3};
109 rb.Push(ResultSuccess); 108 rb.Push(result);
110 rb.Push<u32>(static_cast<u32>(default_miis.size())); 109 rb.Push(mii_count);
111 } 110 }
112 111
113 void Get1(HLERequestContext& ctx) { 112 void Get1(HLERequestContext& ctx) {
114 IPC::RequestParser rp{ctx}; 113 IPC::RequestParser rp{ctx};
115 const auto source_flag{rp.PopRaw<SourceFlag>()}; 114 const auto source_flag{rp.PopRaw<SourceFlag>()};
115 const auto output_size{ctx.GetWriteBufferNumElements<CharInfo>()};
116 116
117 LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); 117 LOG_DEBUG(Service_Mii, "called with source_flag={}, out_size={}", source_flag, output_size);
118 118
119 const auto default_miis{manager.GetDefault(source_flag)}; 119 u32 mii_count{};
120 std::vector<CharInfo> char_info(output_size);
121 Result result = manager.Get(metadata, char_info, mii_count, source_flag);
120 122
121 std::vector<CharInfo> values; 123 if (mii_count != 0) {
122 for (const auto& element : default_miis) { 124 ctx.WriteBuffer(char_info);
123 values.emplace_back(element.char_info);
124 } 125 }
125 126
126 ctx.WriteBuffer(SerializeArray(values));
127
128 IPC::ResponseBuilder rb{ctx, 3}; 127 IPC::ResponseBuilder rb{ctx, 3};
129 rb.Push(ResultSuccess); 128 rb.Push(result);
130 rb.Push<u32>(static_cast<u32>(default_miis.size())); 129 rb.Push(mii_count);
131 } 130 }
132 131
133 void UpdateLatest(HLERequestContext& ctx) { 132 void UpdateLatest(HLERequestContext& ctx) {
134 IPC::RequestParser rp{ctx}; 133 IPC::RequestParser rp{ctx};
135 const auto info{rp.PopRaw<CharInfo>()}; 134 const auto char_info{rp.PopRaw<CharInfo>()};
136 const auto source_flag{rp.PopRaw<SourceFlag>()}; 135 const auto source_flag{rp.PopRaw<SourceFlag>()};
137 136
138 LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); 137 LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
139 138
140 CharInfo new_char_info{}; 139 CharInfo new_char_info{};
141 const auto result{manager.UpdateLatest(&new_char_info, info, source_flag)}; 140 const auto result = manager.UpdateLatest(metadata, new_char_info, char_info, source_flag);
142 if (result != ResultSuccess) { 141 if (result.IsFailure()) {
143 IPC::ResponseBuilder rb{ctx, 2}; 142 IPC::ResponseBuilder rb{ctx, 2};
144 rb.Push(result); 143 rb.Push(result);
145 return; 144 return;
@@ -152,7 +151,6 @@ private:
152 151
153 void BuildRandom(HLERequestContext& ctx) { 152 void BuildRandom(HLERequestContext& ctx) {
154 IPC::RequestParser rp{ctx}; 153 IPC::RequestParser rp{ctx};
155
156 const auto age{rp.PopRaw<Age>()}; 154 const auto age{rp.PopRaw<Age>()};
157 const auto gender{rp.PopRaw<Gender>()}; 155 const auto gender{rp.PopRaw<Gender>()};
158 const auto race{rp.PopRaw<Race>()}; 156 const auto race{rp.PopRaw<Race>()};
@@ -162,46 +160,47 @@ private:
162 if (age > Age::All) { 160 if (age > Age::All) {
163 IPC::ResponseBuilder rb{ctx, 2}; 161 IPC::ResponseBuilder rb{ctx, 2};
164 rb.Push(ResultInvalidArgument); 162 rb.Push(ResultInvalidArgument);
165 LOG_ERROR(Service_Mii, "invalid age={}", age);
166 return; 163 return;
167 } 164 }
168 165
169 if (gender > Gender::All) { 166 if (gender > Gender::All) {
170 IPC::ResponseBuilder rb{ctx, 2}; 167 IPC::ResponseBuilder rb{ctx, 2};
171 rb.Push(ResultInvalidArgument); 168 rb.Push(ResultInvalidArgument);
172 LOG_ERROR(Service_Mii, "invalid gender={}", gender);
173 return; 169 return;
174 } 170 }
175 171
176 if (race > Race::All) { 172 if (race > Race::All) {
177 IPC::ResponseBuilder rb{ctx, 2}; 173 IPC::ResponseBuilder rb{ctx, 2};
178 rb.Push(ResultInvalidArgument); 174 rb.Push(ResultInvalidArgument);
179 LOG_ERROR(Service_Mii, "invalid race={}", race);
180 return; 175 return;
181 } 176 }
182 177
178 CharInfo char_info{};
179 manager.BuildRandom(char_info, age, gender, race);
180
183 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; 181 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
184 rb.Push(ResultSuccess); 182 rb.Push(ResultSuccess);
185 rb.PushRaw<CharInfo>(manager.BuildRandom(age, gender, race)); 183 rb.PushRaw<CharInfo>(char_info);
186 } 184 }
187 185
188 void BuildDefault(HLERequestContext& ctx) { 186 void BuildDefault(HLERequestContext& ctx) {
189 IPC::RequestParser rp{ctx}; 187 IPC::RequestParser rp{ctx};
190 const auto index{rp.Pop<u32>()}; 188 const auto index{rp.Pop<u32>()};
191 189
192 LOG_DEBUG(Service_Mii, "called with index={}", index); 190 LOG_INFO(Service_Mii, "called with index={}", index);
193 191
194 if (index > 5) { 192 if (index > 5) {
195 LOG_ERROR(Service_Mii, "invalid argument, index cannot be greater than 5 but is {:08X}",
196 index);
197 IPC::ResponseBuilder rb{ctx, 2}; 193 IPC::ResponseBuilder rb{ctx, 2};
198 rb.Push(ResultInvalidArgument); 194 rb.Push(ResultInvalidArgument);
199 return; 195 return;
200 } 196 }
201 197
198 CharInfo char_info{};
199 manager.BuildDefault(char_info, index);
200
202 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; 201 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
203 rb.Push(ResultSuccess); 202 rb.Push(ResultSuccess);
204 rb.PushRaw<CharInfo>(manager.BuildDefault(index)); 203 rb.PushRaw<CharInfo>(char_info);
205 } 204 }
206 205
207 void GetIndex(HLERequestContext& ctx) { 206 void GetIndex(HLERequestContext& ctx) {
@@ -210,19 +209,21 @@ private:
210 209
211 LOG_DEBUG(Service_Mii, "called"); 210 LOG_DEBUG(Service_Mii, "called");
212 211
213 u32 index{}; 212 s32 index{};
213 const Result result = manager.GetIndex(metadata, info, index);
214
214 IPC::ResponseBuilder rb{ctx, 3}; 215 IPC::ResponseBuilder rb{ctx, 3};
215 rb.Push(manager.GetIndex(info, index)); 216 rb.Push(result);
216 rb.Push(index); 217 rb.Push(index);
217 } 218 }
218 219
219 void SetInterfaceVersion(HLERequestContext& ctx) { 220 void SetInterfaceVersion(HLERequestContext& ctx) {
220 IPC::RequestParser rp{ctx}; 221 IPC::RequestParser rp{ctx};
221 current_interface_version = rp.PopRaw<u32>(); 222 const auto interface_version{rp.PopRaw<u32>()};
222 223
223 LOG_DEBUG(Service_Mii, "called, interface_version={:08X}", current_interface_version); 224 LOG_INFO(Service_Mii, "called, interface_version={:08X}", interface_version);
224 225
225 UNIMPLEMENTED_IF(current_interface_version != 1); 226 manager.SetInterfaceVersion(metadata, interface_version);
226 227
227 IPC::ResponseBuilder rb{ctx, 2}; 228 IPC::ResponseBuilder rb{ctx, 2};
228 rb.Push(ResultSuccess); 229 rb.Push(ResultSuccess);
@@ -230,30 +231,27 @@ private:
230 231
231 void Convert(HLERequestContext& ctx) { 232 void Convert(HLERequestContext& ctx) {
232 IPC::RequestParser rp{ctx}; 233 IPC::RequestParser rp{ctx};
233
234 const auto mii_v3{rp.PopRaw<Ver3StoreData>()}; 234 const auto mii_v3{rp.PopRaw<Ver3StoreData>()};
235 235
236 LOG_INFO(Service_Mii, "called"); 236 LOG_INFO(Service_Mii, "called");
237 237
238 CharInfo char_info{};
239 manager.ConvertV3ToCharInfo(char_info, mii_v3);
240
238 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; 241 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
239 rb.Push(ResultSuccess); 242 rb.Push(ResultSuccess);
240 rb.PushRaw<CharInfo>(manager.ConvertV3ToCharInfo(mii_v3)); 243 rb.PushRaw<CharInfo>(char_info);
241 }
242
243 constexpr bool IsInterfaceVersionSupported(u32 interface_version) const {
244 return current_interface_version >= interface_version;
245 } 244 }
246 245
247 MiiManager manager; 246 MiiManager manager{};
248 247 DatabaseSessionMetadata metadata{};
249 u32 current_interface_version{}; 248 bool is_system{};
250 u64 current_update_counter{};
251}; 249};
252 250
253class MiiDBModule final : public ServiceFramework<MiiDBModule> { 251class MiiDBModule final : public ServiceFramework<MiiDBModule> {
254public: 252public:
255 explicit MiiDBModule(Core::System& system_, const char* name_) 253 explicit MiiDBModule(Core::System& system_, const char* name_, bool is_system_)
256 : ServiceFramework{system_, name_} { 254 : ServiceFramework{system_, name_}, is_system{is_system_} {
257 // clang-format off 255 // clang-format off
258 static const FunctionInfo functions[] = { 256 static const FunctionInfo functions[] = {
259 {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"}, 257 {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"},
@@ -267,10 +265,12 @@ private:
267 void GetDatabaseService(HLERequestContext& ctx) { 265 void GetDatabaseService(HLERequestContext& ctx) {
268 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 266 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
269 rb.Push(ResultSuccess); 267 rb.Push(ResultSuccess);
270 rb.PushIpcInterface<IDatabaseService>(system); 268 rb.PushIpcInterface<IDatabaseService>(system, is_system);
271 269
272 LOG_DEBUG(Service_Mii, "called"); 270 LOG_DEBUG(Service_Mii, "called");
273 } 271 }
272
273 bool is_system{};
274}; 274};
275 275
276class MiiImg final : public ServiceFramework<MiiImg> { 276class MiiImg final : public ServiceFramework<MiiImg> {
@@ -302,8 +302,10 @@ public:
302void LoopProcess(Core::System& system) { 302void LoopProcess(Core::System& system) {
303 auto server_manager = std::make_unique<ServerManager>(system); 303 auto server_manager = std::make_unique<ServerManager>(system);
304 304
305 server_manager->RegisterNamedService("mii:e", std::make_shared<MiiDBModule>(system, "mii:e")); 305 server_manager->RegisterNamedService("mii:e",
306 server_manager->RegisterNamedService("mii:u", std::make_shared<MiiDBModule>(system, "mii:u")); 306 std::make_shared<MiiDBModule>(system, "mii:e", true));
307 server_manager->RegisterNamedService("mii:u",
308 std::make_shared<MiiDBModule>(system, "mii:u", false));
307 server_manager->RegisterNamedService("miiimg", std::make_shared<MiiImg>(system)); 309 server_manager->RegisterNamedService("miiimg", std::make_shared<MiiImg>(system));
308 ServerManager::RunServer(std::move(server_manager)); 310 ServerManager::RunServer(std::move(server_manager));
309} 311}
diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp
index 3951e0b9c..153a484c0 100644
--- a/src/core/hle/service/mii/mii_manager.cpp
+++ b/src/core/hle/service/mii/mii_manager.cpp
@@ -16,45 +16,18 @@
16#include "core/hle/service/mii/types/raw_data.h" 16#include "core/hle/service/mii/types/raw_data.h"
17 17
18namespace Service::Mii { 18namespace Service::Mii {
19
20namespace {
21
22constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()}; 19constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()};
23 20
24CharInfo ConvertStoreDataToInfo(const StoreData& data) { 21MiiManager::MiiManager() {}
25 CharInfo char_info{};
26 char_info.SetFromStoreData(data);
27 return char_info;
28}
29
30StoreData BuildRandomStoreData(Age age, Gender gender, Race race, const Common::UUID& user_id) {
31 StoreData store_data{};
32 store_data.BuildRandom(age, gender, race);
33
34 return store_data;
35}
36 22
37StoreData BuildDefaultStoreData(const DefaultMii& info, const Common::UUID& user_id) { 23bool MiiManager::IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const {
38 StoreData store_data{};
39 store_data.BuildDefault(0);
40
41 return store_data;
42}
43
44} // namespace
45
46MiiManager::MiiManager() : user_id{Service::Account::ProfileManager().GetLastOpenedUser()} {}
47
48bool MiiManager::CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter) {
49 if ((source_flag & SourceFlag::Database) == SourceFlag::None) { 24 if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
50 return false; 25 return false;
51 } 26 }
52 27
53 const bool result{current_update_counter != update_counter}; 28 const auto metadata_update_counter = metadata.update_counter;
54 29 metadata.update_counter = update_counter;
55 current_update_counter = update_counter; 30 return metadata_update_counter != update_counter;
56
57 return result;
58} 31}
59 32
60bool MiiManager::IsFullDatabase() const { 33bool MiiManager::IsFullDatabase() const {
@@ -62,19 +35,19 @@ bool MiiManager::IsFullDatabase() const {
62 return false; 35 return false;
63} 36}
64 37
65u32 MiiManager::GetCount(SourceFlag source_flag) const { 38u32 MiiManager::GetCount(const DatabaseSessionMetadata& metadata, SourceFlag source_flag) const {
66 std::size_t count{}; 39 u32 mii_count{};
67 if ((source_flag & SourceFlag::Database) != SourceFlag::None) { 40 if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
68 // TODO(bunnei): We don't implement the Mii database, but when we do, update this 41 mii_count += DefaultMiiCount;
69 count += 0;
70 } 42 }
71 if ((source_flag & SourceFlag::Default) != SourceFlag::None) { 43 if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
72 count += DefaultMiiCount; 44 // TODO(bunnei): We don't implement the Mii database, but when we do, update this
73 } 45 }
74 return static_cast<u32>(count); 46 return mii_count;
75} 47}
76 48
77Result MiiManager::UpdateLatest(CharInfo* out_info, const CharInfo& info, SourceFlag source_flag) { 49Result MiiManager::UpdateLatest(DatabaseSessionMetadata& metadata, CharInfo& out_char_info,
50 const CharInfo& char_info, SourceFlag source_flag) {
78 if ((source_flag & SourceFlag::Database) == SourceFlag::None) { 51 if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
79 return ResultNotFound; 52 return ResultNotFound;
80 } 53 }
@@ -83,48 +56,117 @@ Result MiiManager::UpdateLatest(CharInfo* out_info, const CharInfo& info, Source
83 return ResultNotFound; 56 return ResultNotFound;
84} 57}
85 58
86CharInfo MiiManager::BuildRandom(Age age, Gender gender, Race race) { 59void MiiManager::BuildDefault(CharInfo& out_char_info, u32 index) const {
87 return ConvertStoreDataToInfo(BuildRandomStoreData(age, gender, race, user_id)); 60 StoreData store_data{};
61 store_data.BuildDefault(index);
62 out_char_info.SetFromStoreData(store_data);
88} 63}
89 64
90CharInfo MiiManager::BuildBase(Gender gender) { 65void MiiManager::BuildBase(CharInfo& out_char_info, Gender gender) const {
91 const std::size_t index = gender == Gender::Female ? 1 : 0; 66 StoreData store_data{};
92 return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::BaseMii.at(index), user_id)); 67 store_data.BuildBase(gender);
68 out_char_info.SetFromStoreData(store_data);
93} 69}
94 70
95CharInfo MiiManager::BuildDefault(std::size_t index) { 71void MiiManager::BuildRandom(CharInfo& out_char_info, Age age, Gender gender, Race race) const {
96 return ConvertStoreDataToInfo(BuildDefaultStoreData(RawData::DefaultMii.at(index), user_id)); 72 StoreData store_data{};
73 store_data.BuildRandom(age, gender, race);
74 out_char_info.SetFromStoreData(store_data);
97} 75}
98 76
99CharInfo MiiManager::ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const { 77void MiiManager::ConvertV3ToCharInfo(CharInfo& out_char_info, const Ver3StoreData& mii_v3) const {
100 CharInfo char_info{};
101 StoreData store_data{}; 78 StoreData store_data{};
102 mii_v3.BuildToStoreData(store_data); 79 mii_v3.BuildToStoreData(store_data);
103 char_info.SetFromStoreData(store_data); 80 out_char_info.SetFromStoreData(store_data);
104 return char_info;
105} 81}
106 82
107std::vector<CharInfoElement> MiiManager::GetDefault(SourceFlag source_flag) { 83Result MiiManager::Get(const DatabaseSessionMetadata& metadata,
108 std::vector<CharInfoElement> result; 84 std::span<CharInfoElement> out_elements, u32& out_count,
85 SourceFlag source_flag) {
86 if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
87 return BuildDefault(out_elements, out_count, source_flag);
88 }
109 89
90 // TODO(bunnei): We don't implement the Mii database, so we can't have an entry
91
92 // Include default Mii at the end of the list
93 return BuildDefault(out_elements, out_count, source_flag);
94}
95
96Result MiiManager::Get(const DatabaseSessionMetadata& metadata, std::span<CharInfo> out_char_info,
97 u32& out_count, SourceFlag source_flag) {
98 if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
99 return BuildDefault(out_char_info, out_count, source_flag);
100 }
101
102 // TODO(bunnei): We don't implement the Mii database, so we can't have an entry
103
104 // Include default Mii at the end of the list
105 return BuildDefault(out_char_info, out_count, source_flag);
106}
107
108Result MiiManager::BuildDefault(std::span<CharInfoElement> out_elements, u32& out_count,
109 SourceFlag source_flag) {
110 if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
111 return ResultSuccess;
112 }
113
114 StoreData store_data{};
115
116 for (std::size_t index = 0; index < DefaultMiiCount; ++index) {
117 if (out_elements.size() <= static_cast<std::size_t>(out_count)) {
118 return ResultInvalidArgumentSize;
119 }
120
121 store_data.BuildDefault(static_cast<u32>(index));
122
123 out_elements[out_count].source = Source::Default;
124 out_elements[out_count].char_info.SetFromStoreData(store_data);
125 out_count++;
126 }
127
128 return ResultSuccess;
129}
130
131Result MiiManager::BuildDefault(std::span<CharInfo> out_char_info, u32& out_count,
132 SourceFlag source_flag) {
110 if ((source_flag & SourceFlag::Default) == SourceFlag::None) { 133 if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
111 return result; 134 return ResultSuccess;
112 } 135 }
113 136
114 for (std::size_t index = 0; index < DefaultMiiCount; index++) { 137 StoreData store_data{};
115 result.emplace_back(BuildDefault(index), Source::Default); 138
139 for (std::size_t index = 0; index < DefaultMiiCount; ++index) {
140 if (out_char_info.size() <= static_cast<std::size_t>(out_count)) {
141 return ResultInvalidArgumentSize;
142 }
143
144 store_data.BuildDefault(static_cast<u32>(index));
145
146 out_char_info[out_count].SetFromStoreData(store_data);
147 out_count++;
116 } 148 }
117 149
118 return result; 150 return ResultSuccess;
119} 151}
120 152
121Result MiiManager::GetIndex([[maybe_unused]] const CharInfo& info, u32& index) { 153Result MiiManager::GetIndex(const DatabaseSessionMetadata& metadata, const CharInfo& char_info,
154 s32& out_index) {
155
156 if (char_info.Verify() != 0) {
157 return ResultInvalidCharInfo;
158 }
159
122 constexpr u32 INVALID_INDEX{0xFFFFFFFF}; 160 constexpr u32 INVALID_INDEX{0xFFFFFFFF};
123 161
124 index = INVALID_INDEX; 162 out_index = INVALID_INDEX;
125 163
126 // TODO(bunnei): We don't implement the Mii database, so we can't have an index 164 // TODO(bunnei): We don't implement the Mii database, so we can't have an index
127 return ResultNotFound; 165 return ResultNotFound;
128} 166}
129 167
168void MiiManager::SetInterfaceVersion(DatabaseSessionMetadata& metadata, u32 version) {
169 metadata.interface_version = version;
170}
171
130} // namespace Service::Mii 172} // namespace Service::Mii
diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h
index 6098474e9..4f8be06c3 100644
--- a/src/core/hle/service/mii/mii_manager.h
+++ b/src/core/hle/service/mii/mii_manager.h
@@ -19,16 +19,24 @@ class MiiManager {
19public: 19public:
20 MiiManager(); 20 MiiManager();
21 21
22 bool CheckAndResetUpdateCounter(SourceFlag source_flag, u64& current_update_counter); 22 bool IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const;
23
23 bool IsFullDatabase() const; 24 bool IsFullDatabase() const;
24 u32 GetCount(SourceFlag source_flag) const; 25 u32 GetCount(const DatabaseSessionMetadata& metadata, SourceFlag source_flag) const;
25 Result UpdateLatest(CharInfo* out_info, const CharInfo& info, SourceFlag source_flag); 26 Result UpdateLatest(DatabaseSessionMetadata& metadata, CharInfo& out_char_info,
26 CharInfo BuildRandom(Age age, Gender gender, Race race); 27 const CharInfo& char_info, SourceFlag source_flag);
27 CharInfo BuildBase(Gender gender); 28 Result Get(const DatabaseSessionMetadata& metadata, std::span<CharInfoElement> out_elements,
28 CharInfo BuildDefault(std::size_t index); 29 u32& out_count, SourceFlag source_flag);
29 CharInfo ConvertV3ToCharInfo(const Ver3StoreData& mii_v3) const; 30 Result Get(const DatabaseSessionMetadata& metadata, std::span<CharInfo> out_char_info,
31 u32& out_count, SourceFlag source_flag);
32 void BuildDefault(CharInfo& out_char_info, u32 index) const;
33 void BuildBase(CharInfo& out_char_info, Gender gender) const;
34 void BuildRandom(CharInfo& out_char_info, Age age, Gender gender, Race race) const;
35 void ConvertV3ToCharInfo(CharInfo& out_char_info, const Ver3StoreData& mii_v3) const;
30 std::vector<CharInfoElement> GetDefault(SourceFlag source_flag); 36 std::vector<CharInfoElement> GetDefault(SourceFlag source_flag);
31 Result GetIndex(const CharInfo& info, u32& index); 37 Result GetIndex(const DatabaseSessionMetadata& metadata, const CharInfo& char_info,
38 s32& out_index);
39 void SetInterfaceVersion(DatabaseSessionMetadata& metadata, u32 version);
32 40
33 struct MiiDatabase { 41 struct MiiDatabase {
34 u32 magic{}; // 'NFDB' 42 u32 magic{}; // 'NFDB'
@@ -40,7 +48,10 @@ public:
40 static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size."); 48 static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size.");
41 49
42private: 50private:
43 const Common::UUID user_id{}; 51 Result BuildDefault(std::span<CharInfoElement> out_elements, u32& out_count,
52 SourceFlag source_flag);
53 Result BuildDefault(std::span<CharInfo> out_char_info, u32& out_count, SourceFlag source_flag);
54
44 u64 update_counter{}; 55 u64 update_counter{};
45}; 56};
46 57
diff --git a/src/core/hle/service/mii/mii_types.h b/src/core/hle/service/mii/mii_types.h
index d62005f61..b23ce477d 100644
--- a/src/core/hle/service/mii/mii_types.h
+++ b/src/core/hle/service/mii/mii_types.h
@@ -165,4 +165,14 @@ struct DefaultMii {
165}; 165};
166static_assert(sizeof(DefaultMii) == 0xd8, "MiiStoreData has incorrect size."); 166static_assert(sizeof(DefaultMii) == 0xd8, "MiiStoreData has incorrect size.");
167 167
168struct DatabaseSessionMetadata {
169 u32 interface_version;
170 u32 magic;
171 u64 update_counter;
172
173 bool IsInterfaceVersionSupported(u32 version) const {
174 return version <= interface_version;
175 }
176};
177
168} // namespace Service::Mii 178} // namespace Service::Mii
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index eb7706015..5dda12343 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -680,12 +680,16 @@ Result NfcDevice::GetRegisterInfo(NFP::RegisterInfo& register_info) const {
680 return ResultRegistrationIsNotInitialized; 680 return ResultRegistrationIsNotInitialized;
681 } 681 }
682 682
683 Service::Mii::MiiManager manager; 683 Mii::CharInfo char_info{};
684 Mii::StoreData store_data{};
685 tag_data.owner_mii.BuildToStoreData(store_data);
686 char_info.SetFromStoreData(store_data);
687
684 const auto& settings = tag_data.settings; 688 const auto& settings = tag_data.settings;
685 689
686 // TODO: Validate this data 690 // TODO: Validate this data
687 register_info = { 691 register_info = {
688 .mii_char_info = manager.ConvertV3ToCharInfo(tag_data.owner_mii), 692 .mii_char_info = char_info,
689 .creation_date = settings.init_date.GetWriteDate(), 693 .creation_date = settings.init_date.GetWriteDate(),
690 .amiibo_name = GetAmiiboName(settings), 694 .amiibo_name = GetAmiiboName(settings),
691 .font_region = settings.settings.font_region, 695 .font_region = settings.settings.font_region,