summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/mii/mii.cpp362
-rw-r--r--src/core/hle/service/mii/mii_manager.cpp410
-rw-r--r--src/core/hle/service/mii/mii_manager.h82
3 files changed, 751 insertions, 103 deletions
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index 3b83c5ed7..dae95ea68 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -8,6 +8,9 @@
8#include "core/hle/service/mii/mii.h" 8#include "core/hle/service/mii/mii.h"
9#include "core/hle/service/mii/mii_manager.h" 9#include "core/hle/service/mii/mii_manager.h"
10#include "core/hle/service/mii/mii_result.h" 10#include "core/hle/service/mii/mii_result.h"
11#include "core/hle/service/mii/types/char_info.h"
12#include "core/hle/service/mii/types/store_data.h"
13#include "core/hle/service/mii/types/ver3_store_data.h"
11#include "core/hle/service/server_manager.h" 14#include "core/hle/service/server_manager.h"
12#include "core/hle/service/service.h" 15#include "core/hle/service/service.h"
13 16
@@ -27,29 +30,31 @@ public:
27 {5, &IDatabaseService::UpdateLatest, "UpdateLatest"}, 30 {5, &IDatabaseService::UpdateLatest, "UpdateLatest"},
28 {6, &IDatabaseService::BuildRandom, "BuildRandom"}, 31 {6, &IDatabaseService::BuildRandom, "BuildRandom"},
29 {7, &IDatabaseService::BuildDefault, "BuildDefault"}, 32 {7, &IDatabaseService::BuildDefault, "BuildDefault"},
30 {8, nullptr, "Get2"}, 33 {8, &IDatabaseService::Get2, "Get2"},
31 {9, nullptr, "Get3"}, 34 {9, &IDatabaseService::Get3, "Get3"},
32 {10, nullptr, "UpdateLatest1"}, 35 {10, &IDatabaseService::UpdateLatest1, "UpdateLatest1"},
33 {11, nullptr, "FindIndex"}, 36 {11, &IDatabaseService::FindIndex, "FindIndex"},
34 {12, nullptr, "Move"}, 37 {12, &IDatabaseService::Move, "Move"},
35 {13, nullptr, "AddOrReplace"}, 38 {13, &IDatabaseService::AddOrReplace, "AddOrReplace"},
36 {14, nullptr, "Delete"}, 39 {14, &IDatabaseService::Delete, "Delete"},
37 {15, nullptr, "DestroyFile"}, 40 {15, &IDatabaseService::DestroyFile, "DestroyFile"},
38 {16, nullptr, "DeleteFile"}, 41 {16, &IDatabaseService::DeleteFile, "DeleteFile"},
39 {17, nullptr, "Format"}, 42 {17, &IDatabaseService::Format, "Format"},
40 {18, nullptr, "Import"}, 43 {18, nullptr, "Import"},
41 {19, nullptr, "Export"}, 44 {19, nullptr, "Export"},
42 {20, nullptr, "IsBrokenDatabaseWithClearFlag"}, 45 {20, &IDatabaseService::IsBrokenDatabaseWithClearFlag, "IsBrokenDatabaseWithClearFlag"},
43 {21, &IDatabaseService::GetIndex, "GetIndex"}, 46 {21, &IDatabaseService::GetIndex, "GetIndex"},
44 {22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"}, 47 {22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"},
45 {23, &IDatabaseService::Convert, "Convert"}, 48 {23, &IDatabaseService::Convert, "Convert"},
46 {24, nullptr, "ConvertCoreDataToCharInfo"}, 49 {24, &IDatabaseService::ConvertCoreDataToCharInfo, "ConvertCoreDataToCharInfo"},
47 {25, nullptr, "ConvertCharInfoToCoreData"}, 50 {25, &IDatabaseService::ConvertCharInfoToCoreData, "ConvertCharInfoToCoreData"},
48 {26, nullptr, "Append"}, 51 {26, &IDatabaseService::Append, "Append"},
49 }; 52 };
50 // clang-format on 53 // clang-format on
51 54
52 RegisterHandlers(functions); 55 RegisterHandlers(functions);
56
57 manager.Initialize(metadata);
53 } 58 }
54 59
55private: 60private:
@@ -80,10 +85,10 @@ private:
80 IPC::RequestParser rp{ctx}; 85 IPC::RequestParser rp{ctx};
81 const auto source_flag{rp.PopRaw<SourceFlag>()}; 86 const auto source_flag{rp.PopRaw<SourceFlag>()};
82 87
83 LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
84
85 const u32 mii_count = manager.GetCount(metadata, source_flag); 88 const u32 mii_count = manager.GetCount(metadata, source_flag);
86 89
90 LOG_DEBUG(Service_Mii, "called with source_flag={}, mii_count={}", source_flag, mii_count);
91
87 IPC::ResponseBuilder rb{ctx, 3}; 92 IPC::ResponseBuilder rb{ctx, 3};
88 rb.Push(ResultSuccess); 93 rb.Push(ResultSuccess);
89 rb.Push(mii_count); 94 rb.Push(mii_count);
@@ -94,16 +99,17 @@ private:
94 const auto source_flag{rp.PopRaw<SourceFlag>()}; 99 const auto source_flag{rp.PopRaw<SourceFlag>()};
95 const auto output_size{ctx.GetWriteBufferNumElements<CharInfoElement>()}; 100 const auto output_size{ctx.GetWriteBufferNumElements<CharInfoElement>()};
96 101
97 LOG_DEBUG(Service_Mii, "called with source_flag={}, out_size={}", source_flag, output_size);
98
99 u32 mii_count{}; 102 u32 mii_count{};
100 std::vector<CharInfoElement> char_info_elements(output_size); 103 std::vector<CharInfoElement> char_info_elements(output_size);
101 Result result = manager.Get(metadata, char_info_elements, mii_count, source_flag); 104 const auto result = manager.Get(metadata, char_info_elements, mii_count, source_flag);
102 105
103 if (mii_count != 0) { 106 if (mii_count != 0) {
104 ctx.WriteBuffer(char_info_elements); 107 ctx.WriteBuffer(char_info_elements);
105 } 108 }
106 109
110 LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag,
111 output_size, mii_count);
112
107 IPC::ResponseBuilder rb{ctx, 3}; 113 IPC::ResponseBuilder rb{ctx, 3};
108 rb.Push(result); 114 rb.Push(result);
109 rb.Push(mii_count); 115 rb.Push(mii_count);
@@ -114,16 +120,17 @@ private:
114 const auto source_flag{rp.PopRaw<SourceFlag>()}; 120 const auto source_flag{rp.PopRaw<SourceFlag>()};
115 const auto output_size{ctx.GetWriteBufferNumElements<CharInfo>()}; 121 const auto output_size{ctx.GetWriteBufferNumElements<CharInfo>()};
116 122
117 LOG_DEBUG(Service_Mii, "called with source_flag={}, out_size={}", source_flag, output_size);
118
119 u32 mii_count{}; 123 u32 mii_count{};
120 std::vector<CharInfo> char_info(output_size); 124 std::vector<CharInfo> char_info(output_size);
121 Result result = manager.Get(metadata, char_info, mii_count, source_flag); 125 const auto result = manager.Get(metadata, char_info, mii_count, source_flag);
122 126
123 if (mii_count != 0) { 127 if (mii_count != 0) {
124 ctx.WriteBuffer(char_info); 128 ctx.WriteBuffer(char_info);
125 } 129 }
126 130
131 LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag,
132 output_size, mii_count);
133
127 IPC::ResponseBuilder rb{ctx, 3}; 134 IPC::ResponseBuilder rb{ctx, 3};
128 rb.Push(result); 135 rb.Push(result);
129 rb.Push(mii_count); 136 rb.Push(mii_count);
@@ -134,7 +141,7 @@ private:
134 const auto char_info{rp.PopRaw<CharInfo>()}; 141 const auto char_info{rp.PopRaw<CharInfo>()};
135 const auto source_flag{rp.PopRaw<SourceFlag>()}; 142 const auto source_flag{rp.PopRaw<SourceFlag>()};
136 143
137 LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); 144 LOG_INFO(Service_Mii, "called with source_flag={}", source_flag);
138 145
139 CharInfo new_char_info{}; 146 CharInfo new_char_info{};
140 const auto result = manager.UpdateLatest(metadata, new_char_info, char_info, source_flag); 147 const auto result = manager.UpdateLatest(metadata, new_char_info, char_info, source_flag);
@@ -146,7 +153,7 @@ private:
146 153
147 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; 154 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
148 rb.Push(ResultSuccess); 155 rb.Push(ResultSuccess);
149 rb.PushRaw<CharInfo>(new_char_info); 156 rb.PushRaw(new_char_info);
150 } 157 }
151 158
152 void BuildRandom(HLERequestContext& ctx) { 159 void BuildRandom(HLERequestContext& ctx) {
@@ -180,14 +187,14 @@ private:
180 187
181 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; 188 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
182 rb.Push(ResultSuccess); 189 rb.Push(ResultSuccess);
183 rb.PushRaw<CharInfo>(char_info); 190 rb.PushRaw(char_info);
184 } 191 }
185 192
186 void BuildDefault(HLERequestContext& ctx) { 193 void BuildDefault(HLERequestContext& ctx) {
187 IPC::RequestParser rp{ctx}; 194 IPC::RequestParser rp{ctx};
188 const auto index{rp.Pop<u32>()}; 195 const auto index{rp.Pop<u32>()};
189 196
190 LOG_INFO(Service_Mii, "called with index={}", index); 197 LOG_DEBUG(Service_Mii, "called with index={}", index);
191 198
192 if (index > 5) { 199 if (index > 5) {
193 IPC::ResponseBuilder rb{ctx, 2}; 200 IPC::ResponseBuilder rb{ctx, 2};
@@ -200,7 +207,240 @@ private:
200 207
201 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; 208 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
202 rb.Push(ResultSuccess); 209 rb.Push(ResultSuccess);
203 rb.PushRaw<CharInfo>(char_info); 210 rb.PushRaw(char_info);
211 }
212
213 void Get2(HLERequestContext& ctx) {
214 IPC::RequestParser rp{ctx};
215 const auto source_flag{rp.PopRaw<SourceFlag>()};
216 const auto output_size{ctx.GetWriteBufferNumElements<StoreDataElement>()};
217
218 u32 mii_count{};
219 std::vector<StoreDataElement> store_data_elements(output_size);
220 const auto result = manager.Get(metadata, store_data_elements, mii_count, source_flag);
221
222 if (mii_count != 0) {
223 ctx.WriteBuffer(store_data_elements);
224 }
225
226 LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag,
227 output_size, mii_count);
228
229 IPC::ResponseBuilder rb{ctx, 3};
230 rb.Push(result);
231 rb.Push(mii_count);
232 }
233
234 void Get3(HLERequestContext& ctx) {
235 IPC::RequestParser rp{ctx};
236 const auto source_flag{rp.PopRaw<SourceFlag>()};
237 const auto output_size{ctx.GetWriteBufferNumElements<StoreData>()};
238
239 u32 mii_count{};
240 std::vector<StoreData> store_data(output_size);
241 const auto result = manager.Get(metadata, store_data, mii_count, source_flag);
242
243 if (mii_count != 0) {
244 ctx.WriteBuffer(store_data);
245 }
246
247 LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag,
248 output_size, mii_count);
249
250 IPC::ResponseBuilder rb{ctx, 3};
251 rb.Push(result);
252 rb.Push(mii_count);
253 }
254
255 void UpdateLatest1(HLERequestContext& ctx) {
256 IPC::RequestParser rp{ctx};
257 const auto store_data{rp.PopRaw<StoreData>()};
258 const auto source_flag{rp.PopRaw<SourceFlag>()};
259
260 LOG_INFO(Service_Mii, "called with source_flag={}", source_flag);
261
262 Result result = ResultSuccess;
263 if (!is_system) {
264 result = ResultPermissionDenied;
265 }
266
267 StoreData new_store_data{};
268 if (result.IsSuccess()) {
269 result = manager.UpdateLatest(metadata, new_store_data, store_data, source_flag);
270 }
271
272 if (result.IsFailure()) {
273 IPC::ResponseBuilder rb{ctx, 2};
274 rb.Push(result);
275 return;
276 }
277
278 IPC::ResponseBuilder rb{ctx, 2 + sizeof(StoreData) / sizeof(u32)};
279 rb.Push(ResultSuccess);
280 rb.PushRaw<StoreData>(new_store_data);
281 }
282
283 void FindIndex(HLERequestContext& ctx) {
284 IPC::RequestParser rp{ctx};
285 const auto create_id{rp.PopRaw<Common::UUID>()};
286 const auto is_special{rp.PopRaw<bool>()};
287
288 LOG_INFO(Service_Mii, "called with create_id={}, is_special={}",
289 create_id.FormattedString(), is_special);
290
291 s32 index = manager.FindIndex(create_id, is_special);
292
293 IPC::ResponseBuilder rb{ctx, 3};
294 rb.Push(ResultSuccess);
295 rb.Push(index);
296 }
297
298 void Move(HLERequestContext& ctx) {
299 IPC::RequestParser rp{ctx};
300 const auto create_id{rp.PopRaw<Common::UUID>()};
301 const auto new_index{rp.PopRaw<s32>()};
302
303 LOG_INFO(Service_Mii, "called with create_id={}, new_index={}", create_id.FormattedString(),
304 new_index);
305
306 Result result = ResultSuccess;
307
308 if (!is_system) {
309 result = ResultPermissionDenied;
310 }
311
312 if (result.IsSuccess()) {
313 const u32 count = manager.GetCount(metadata, SourceFlag::Database);
314 if (new_index < 0 || new_index >= static_cast<s32>(count)) {
315 result = ResultInvalidArgument;
316 }
317 }
318
319 if (result.IsSuccess()) {
320 result = manager.Move(metadata, new_index, create_id);
321 }
322
323 IPC::ResponseBuilder rb{ctx, 2};
324 rb.Push(result);
325 }
326
327 void AddOrReplace(HLERequestContext& ctx) {
328 IPC::RequestParser rp{ctx};
329 const auto store_data{rp.PopRaw<StoreData>()};
330
331 LOG_INFO(Service_Mii, "called");
332
333 Result result = ResultSuccess;
334
335 if (!is_system) {
336 result = ResultPermissionDenied;
337 }
338
339 if (result.IsSuccess()) {
340 result = manager.AddOrReplace(metadata, store_data);
341 }
342
343 IPC::ResponseBuilder rb{ctx, 2};
344 rb.Push(result);
345 }
346
347 void Delete(HLERequestContext& ctx) {
348 IPC::RequestParser rp{ctx};
349 const auto create_id{rp.PopRaw<Common::UUID>()};
350
351 LOG_INFO(Service_Mii, "called, create_id={}", create_id.FormattedString());
352
353 Result result = ResultSuccess;
354
355 if (!is_system) {
356 result = ResultPermissionDenied;
357 }
358
359 if (result.IsSuccess()) {
360 result = manager.Delete(metadata, create_id);
361 }
362
363 IPC::ResponseBuilder rb{ctx, 2};
364 rb.Push(result);
365 }
366
367 void DestroyFile(HLERequestContext& ctx) {
368 // This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled");
369 bool is_db_test_mode_enabled = false;
370
371 LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled);
372
373 Result result = ResultSuccess;
374
375 if (!is_db_test_mode_enabled) {
376 result = ResultTestModeOnly;
377 }
378
379 if (result.IsSuccess()) {
380 result = manager.DestroyFile(metadata);
381 }
382
383 IPC::ResponseBuilder rb{ctx, 2};
384 rb.Push(result);
385 }
386
387 void DeleteFile(HLERequestContext& ctx) {
388 // This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled");
389 bool is_db_test_mode_enabled = false;
390
391 LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled);
392
393 Result result = ResultSuccess;
394
395 if (!is_db_test_mode_enabled) {
396 result = ResultTestModeOnly;
397 }
398
399 if (result.IsSuccess()) {
400 result = manager.DeleteFile();
401 }
402
403 IPC::ResponseBuilder rb{ctx, 2};
404 rb.Push(result);
405 }
406
407 void Format(HLERequestContext& ctx) {
408 // This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled");
409 bool is_db_test_mode_enabled = false;
410
411 LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled);
412
413 Result result = ResultSuccess;
414
415 if (!is_db_test_mode_enabled) {
416 result = ResultTestModeOnly;
417 }
418
419 if (result.IsSuccess()) {
420 result = manager.Format(metadata);
421 }
422
423 IPC::ResponseBuilder rb{ctx, 2};
424 rb.Push(result);
425 }
426
427 void IsBrokenDatabaseWithClearFlag(HLERequestContext& ctx) {
428 LOG_DEBUG(Service_Mii, "called");
429
430 bool is_broken_with_clear_flag{};
431 Result result = ResultSuccess;
432
433 if (!is_system) {
434 result = ResultPermissionDenied;
435 }
436
437 if (result.IsSuccess()) {
438 is_broken_with_clear_flag = manager.IsBrokenWithClearFlag(metadata);
439 }
440
441 IPC::ResponseBuilder rb{ctx, 3};
442 rb.Push(result);
443 rb.Push<u8>(is_broken_with_clear_flag);
204 } 444 }
205 445
206 void GetIndex(HLERequestContext& ctx) { 446 void GetIndex(HLERequestContext& ctx) {
@@ -236,13 +476,53 @@ private:
236 LOG_INFO(Service_Mii, "called"); 476 LOG_INFO(Service_Mii, "called");
237 477
238 CharInfo char_info{}; 478 CharInfo char_info{};
239 manager.ConvertV3ToCharInfo(char_info, mii_v3); 479 const auto result = manager.ConvertV3ToCharInfo(char_info, mii_v3);
240 480
241 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; 481 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
242 rb.Push(ResultSuccess); 482 rb.Push(result);
483 rb.PushRaw<CharInfo>(char_info);
484 }
485
486 void ConvertCoreDataToCharInfo(HLERequestContext& ctx) {
487 IPC::RequestParser rp{ctx};
488 const auto core_data{rp.PopRaw<CoreData>()};
489
490 LOG_INFO(Service_Mii, "called");
491
492 CharInfo char_info{};
493 const auto result = manager.ConvertCoreDataToCharInfo(char_info, core_data);
494
495 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
496 rb.Push(result);
243 rb.PushRaw<CharInfo>(char_info); 497 rb.PushRaw<CharInfo>(char_info);
244 } 498 }
245 499
500 void ConvertCharInfoToCoreData(HLERequestContext& ctx) {
501 IPC::RequestParser rp{ctx};
502 const auto char_info{rp.PopRaw<CharInfo>()};
503
504 LOG_INFO(Service_Mii, "called");
505
506 CoreData core_data{};
507 const auto result = manager.ConvertCharInfoToCoreData(core_data, char_info);
508
509 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CoreData) / sizeof(u32)};
510 rb.Push(result);
511 rb.PushRaw<CoreData>(core_data);
512 }
513
514 void Append(HLERequestContext& ctx) {
515 IPC::RequestParser rp{ctx};
516 const auto char_info{rp.PopRaw<CharInfo>()};
517
518 LOG_INFO(Service_Mii, "called");
519
520 const auto result = manager.Append(metadata, char_info);
521
522 IPC::ResponseBuilder rb{ctx, 2};
523 rb.Push(result);
524 }
525
246 MiiManager manager{}; 526 MiiManager manager{};
247 DatabaseSessionMetadata metadata{}; 527 DatabaseSessionMetadata metadata{};
248 bool is_system{}; 528 bool is_system{};
@@ -267,7 +547,7 @@ private:
267 rb.Push(ResultSuccess); 547 rb.Push(ResultSuccess);
268 rb.PushIpcInterface<IDatabaseService>(system, is_system); 548 rb.PushIpcInterface<IDatabaseService>(system, is_system);
269 549
270 LOG_DEBUG(Service_Mii, "called"); 550 LOG_CRITICAL(Service_Mii, "called");
271 } 551 }
272 552
273 bool is_system{}; 553 bool is_system{};
@@ -278,9 +558,9 @@ public:
278 explicit MiiImg(Core::System& system_) : ServiceFramework{system_, "miiimg"} { 558 explicit MiiImg(Core::System& system_) : ServiceFramework{system_, "miiimg"} {
279 // clang-format off 559 // clang-format off
280 static const FunctionInfo functions[] = { 560 static const FunctionInfo functions[] = {
281 {0, nullptr, "Initialize"}, 561 {0, &MiiImg::Initialize, "Initialize"},
282 {10, nullptr, "Reload"}, 562 {10, nullptr, "Reload"},
283 {11, nullptr, "GetCount"}, 563 {11, &MiiImg::GetCount, "GetCount"},
284 {12, nullptr, "IsEmpty"}, 564 {12, nullptr, "IsEmpty"},
285 {13, nullptr, "IsFull"}, 565 {13, nullptr, "IsFull"},
286 {14, nullptr, "GetAttribute"}, 566 {14, nullptr, "GetAttribute"},
@@ -297,6 +577,22 @@ public:
297 577
298 RegisterHandlers(functions); 578 RegisterHandlers(functions);
299 } 579 }
580
581private:
582 void Initialize(HLERequestContext& ctx) {
583 LOG_CRITICAL(Service_Mii, "called");
584
585 IPC::ResponseBuilder rb{ctx, 2};
586 rb.Push(ResultSuccess);
587 }
588
589 void GetCount(HLERequestContext& ctx) {
590 LOG_CRITICAL(Service_Mii, "called");
591
592 IPC::ResponseBuilder rb{ctx, 3};
593 rb.Push(ResultSuccess);
594 rb.Push(0);
595 }
300}; 596};
301 597
302void LoopProcess(Core::System& system) { 598void LoopProcess(Core::System& system) {
@@ -310,4 +606,4 @@ void LoopProcess(Core::System& system) {
310 ServerManager::RunServer(std::move(server_manager)); 606 ServerManager::RunServer(std::move(server_manager));
311} 607}
312 608
313} // namespace Service::Mii 609} // namespace Service::Mii \ No newline at end of file
diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp
index 292d63777..a5a2a9232 100644
--- a/src/core/hle/service/mii/mii_manager.cpp
+++ b/src/core/hle/service/mii/mii_manager.cpp
@@ -1,38 +1,63 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <cstring>
5#include <random>
6
7#include "common/assert.h"
8#include "common/logging/log.h" 4#include "common/logging/log.h"
9#include "common/string_util.h" 5#include "core/hle/service/mii/mii_database_manager.h"
10
11#include "core/hle/service/acc/profile_manager.h"
12#include "core/hle/service/mii/mii_manager.h" 6#include "core/hle/service/mii/mii_manager.h"
13#include "core/hle/service/mii/mii_result.h" 7#include "core/hle/service/mii/mii_result.h"
14#include "core/hle/service/mii/mii_util.h" 8#include "core/hle/service/mii/mii_util.h"
9#include "core/hle/service/mii/types/char_info.h"
15#include "core/hle/service/mii/types/core_data.h" 10#include "core/hle/service/mii/types/core_data.h"
16#include "core/hle/service/mii/types/raw_data.h" 11#include "core/hle/service/mii/types/raw_data.h"
12#include "core/hle/service/mii/types/store_data.h"
13#include "core/hle/service/mii/types/ver3_store_data.h"
17 14
18namespace Service::Mii { 15namespace Service::Mii {
19constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()}; 16constexpr std::size_t DefaultMiiCount{RawData::DefaultMii.size()};
20 17
21MiiManager::MiiManager() {} 18MiiManager::MiiManager() {}
22 19
20Result MiiManager::Initialize(DatabaseSessionMetadata& metadata) {
21 database_manager.MountSaveData();
22 database_manager.Initialize(metadata, is_broken_with_clear_flag);
23 return ResultSuccess;
24}
25
26void MiiManager::BuildDefault(CharInfo& out_char_info, u32 index) const {
27 StoreData store_data{};
28 store_data.BuildDefault(index);
29 out_char_info.SetFromStoreData(store_data);
30}
31
32void MiiManager::BuildBase(CharInfo& out_char_info, Gender gender) const {
33 StoreData store_data{};
34 store_data.BuildBase(gender);
35 out_char_info.SetFromStoreData(store_data);
36}
37
38void MiiManager::BuildRandom(CharInfo& out_char_info, Age age, Gender gender, Race race) const {
39 StoreData store_data{};
40 store_data.BuildRandom(age, gender, race);
41 out_char_info.SetFromStoreData(store_data);
42}
43
44bool MiiManager::IsFullDatabase() const {
45 return database_manager.IsFullDatabase();
46}
47
48void MiiManager::SetInterfaceVersion(DatabaseSessionMetadata& metadata, u32 version) const {
49 metadata.interface_version = version;
50}
51
23bool MiiManager::IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const { 52bool MiiManager::IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const {
24 if ((source_flag & SourceFlag::Database) == SourceFlag::None) { 53 if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
25 return false; 54 return false;
26 } 55 }
27 56
28 const auto metadata_update_counter = metadata.update_counter; 57 const u64 metadata_update_counter = metadata.update_counter;
29 metadata.update_counter = update_counter; 58 const u64 database_update_counter = database_manager.GetUpdateCounter();
30 return metadata_update_counter != update_counter; 59 metadata.update_counter = database_update_counter;
31} 60 return metadata_update_counter != database_update_counter;
32
33bool MiiManager::IsFullDatabase() const {
34 // TODO(bunnei): We don't implement the Mii database, so it cannot be full
35 return false;
36} 61}
37 62
38u32 MiiManager::GetCount(const DatabaseSessionMetadata& metadata, SourceFlag source_flag) const { 63u32 MiiManager::GetCount(const DatabaseSessionMetadata& metadata, SourceFlag source_flag) const {
@@ -41,72 +66,343 @@ u32 MiiManager::GetCount(const DatabaseSessionMetadata& metadata, SourceFlag sou
41 mii_count += DefaultMiiCount; 66 mii_count += DefaultMiiCount;
42 } 67 }
43 if ((source_flag & SourceFlag::Database) != SourceFlag::None) { 68 if ((source_flag & SourceFlag::Database) != SourceFlag::None) {
44 // TODO(bunnei): We don't implement the Mii database, but when we do, update this 69 mii_count += database_manager.GetCount(metadata);
45 } 70 }
46 return mii_count; 71 return mii_count;
47} 72}
48 73
49Result MiiManager::UpdateLatest(DatabaseSessionMetadata& metadata, CharInfo& out_char_info, 74Result MiiManager::Move(DatabaseSessionMetadata& metadata, u32 index,
50 const CharInfo& char_info, SourceFlag source_flag) { 75 const Common::UUID& create_id) {
51 if ((source_flag & SourceFlag::Database) == SourceFlag::None) { 76 const auto result = database_manager.Move(metadata, index, create_id);
77
78 if (result.IsFailure()) {
79 return result;
80 }
81
82 if (!database_manager.IsModified()) {
83 return ResultNotUpdated;
84 }
85
86 return database_manager.SaveDatabase();
87}
88
89Result MiiManager::AddOrReplace(DatabaseSessionMetadata& metadata, const StoreData& store_data) {
90 const auto result = database_manager.AddOrReplace(metadata, store_data);
91
92 if (result.IsFailure()) {
93 return result;
94 }
95
96 if (!database_manager.IsModified()) {
97 return ResultNotUpdated;
98 }
99
100 return database_manager.SaveDatabase();
101}
102
103Result MiiManager::Delete(DatabaseSessionMetadata& metadata, const Common::UUID& create_id) {
104 const auto result = database_manager.Delete(metadata, create_id);
105
106 if (result.IsFailure()) {
107 return result;
108 }
109
110 if (!database_manager.IsModified()) {
111 return ResultNotUpdated;
112 }
113
114 return database_manager.SaveDatabase();
115}
116
117s32 MiiManager::FindIndex(const Common::UUID& create_id, bool is_special) const {
118 s32 index{};
119 const auto result = database_manager.FindIndex(index, create_id, is_special);
120 if (result.IsError()) {
121 index = -1;
122 }
123 return index;
124}
125
126Result MiiManager::GetIndex(const DatabaseSessionMetadata& metadata, const CharInfo& char_info,
127 s32& out_index) const {
128 if (char_info.Verify() != ValidationResult::NoErrors) {
129 return ResultInvalidCharInfo;
130 }
131
132 s32 index{};
133 Result result = {};
134 // FindIndex(index);
135
136 if (result.IsError()) {
137 return ResultNotFound;
138 }
139
140 if (index == -1) {
52 return ResultNotFound; 141 return ResultNotFound;
53 } 142 }
54 143
55 // TODO(bunnei): We don't implement the Mii database, so we can't have an entry 144 out_index = index;
56 return ResultNotFound; 145 return ResultSuccess;
57} 146}
58 147
59void MiiManager::BuildDefault(CharInfo& out_char_info, u32 index) const { 148Result MiiManager::Append(DatabaseSessionMetadata& metadata, const CharInfo& char_info) {
60 StoreData store_data{}; 149 const auto result = database_manager.Append(metadata, char_info);
61 store_data.BuildDefault(index); 150
62 out_char_info.SetFromStoreData(store_data); 151 if (result.IsError()) {
152 return ResultNotFound;
153 }
154
155 if (!database_manager.IsModified()) {
156 return ResultNotUpdated;
157 }
158
159 return database_manager.SaveDatabase();
63} 160}
64 161
65void MiiManager::BuildBase(CharInfo& out_char_info, Gender gender) const { 162bool MiiManager::IsBrokenWithClearFlag(DatabaseSessionMetadata& metadata) {
163 const bool is_broken = is_broken_with_clear_flag;
164 if (is_broken_with_clear_flag) {
165 is_broken_with_clear_flag = false;
166 database_manager.Format(metadata);
167 database_manager.SaveDatabase();
168 }
169 return is_broken;
170}
171
172Result MiiManager::DestroyFile(DatabaseSessionMetadata& metadata) {
173 is_broken_with_clear_flag = true;
174 return database_manager.DestroyFile(metadata);
175}
176
177Result MiiManager::DeleteFile() {
178 return database_manager.DeleteFile();
179}
180
181Result MiiManager::Format(DatabaseSessionMetadata& metadata) {
182 database_manager.Format(metadata);
183
184 if (!database_manager.IsModified()) {
185 return ResultNotUpdated;
186 }
187 return database_manager.SaveDatabase();
188}
189
190Result MiiManager::ConvertV3ToCharInfo(CharInfo& out_char_info, const Ver3StoreData& mii_v3) const {
191 if (!mii_v3.IsValid()) {
192 return ResultInvalidCharInfo;
193 }
194
66 StoreData store_data{}; 195 StoreData store_data{};
67 store_data.BuildBase(gender); 196 mii_v3.BuildToStoreData(store_data);
197 const auto name = store_data.GetNickname();
198 if (!MiiUtil::IsFontRegionValid(store_data.GetFontRegion(), name.data)) {
199 store_data.SetInvalidName();
200 }
201
68 out_char_info.SetFromStoreData(store_data); 202 out_char_info.SetFromStoreData(store_data);
203 return ResultSuccess;
69} 204}
70 205
71void MiiManager::BuildRandom(CharInfo& out_char_info, Age age, Gender gender, Race race) const { 206Result MiiManager::ConvertCoreDataToCharInfo(CharInfo& out_char_info,
207 const CoreData& core_data) const {
208 if (core_data.IsValid() != ValidationResult::NoErrors) {
209 return ResultInvalidCharInfo;
210 }
211
72 StoreData store_data{}; 212 StoreData store_data{};
73 store_data.BuildRandom(age, gender, race); 213 store_data.BuildWithCoreData(core_data);
214 const auto name = store_data.GetNickname();
215 if (!MiiUtil::IsFontRegionValid(store_data.GetFontRegion(), name.data)) {
216 store_data.SetInvalidName();
217 }
218
74 out_char_info.SetFromStoreData(store_data); 219 out_char_info.SetFromStoreData(store_data);
220 return ResultSuccess;
221}
222
223Result MiiManager::ConvertCharInfoToCoreData(CoreData& out_core_data,
224 const CharInfo& char_info) const {
225 if (char_info.Verify() != ValidationResult::NoErrors) {
226 return ResultInvalidCharInfo;
227 }
228
229 out_core_data.BuildFromCharInfo(char_info);
230 const auto name = out_core_data.GetNickname();
231 if (!MiiUtil::IsFontRegionValid(out_core_data.GetFontRegion(), name.data)) {
232 out_core_data.SetNickname(out_core_data.GetInvalidNickname());
233 }
234
235 return ResultSuccess;
75} 236}
76 237
77void MiiManager::ConvertV3ToCharInfo(CharInfo& out_char_info, const Ver3StoreData& mii_v3) const { 238Result MiiManager::UpdateLatest(const DatabaseSessionMetadata& metadata, CharInfo& out_char_info,
239 const CharInfo& char_info, SourceFlag source_flag) const {
240 if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
241 return ResultNotFound;
242 }
243
244 if (metadata.IsInterfaceVersionSupported(1)) {
245 if (char_info.Verify() != ValidationResult::NoErrors) {
246 return ResultInvalidCharInfo;
247 }
248 }
249
250 u32 index{};
251 Result result = database_manager.FindIndex(metadata, index, char_info.GetCreateId());
252
253 if (result.IsError()) {
254 return result;
255 }
256
78 StoreData store_data{}; 257 StoreData store_data{};
79 mii_v3.BuildToStoreData(store_data); 258 database_manager.Get(store_data, index, metadata);
259
260 if (store_data.GetType() != char_info.GetType()) {
261 return ResultNotFound;
262 }
263
80 out_char_info.SetFromStoreData(store_data); 264 out_char_info.SetFromStoreData(store_data);
265
266 if (char_info == out_char_info) {
267 return ResultNotUpdated;
268 }
269
270 return ResultSuccess;
271}
272
273Result MiiManager::UpdateLatest(const DatabaseSessionMetadata& metadata, StoreData& out_store_data,
274 const StoreData& store_data, SourceFlag source_flag) const {
275 if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
276 return ResultNotFound;
277 }
278
279 if (metadata.IsInterfaceVersionSupported(1)) {
280 if (store_data.IsValid() != ValidationResult::NoErrors) {
281 return ResultInvalidCharInfo;
282 }
283 }
284
285 u32 index{};
286 Result result = database_manager.FindIndex(metadata, index, store_data.GetCreateId());
287
288 if (result.IsError()) {
289 return result;
290 }
291
292 database_manager.Get(out_store_data, index, metadata);
293
294 if (out_store_data.GetType() != store_data.GetType()) {
295 return ResultNotFound;
296 }
297
298 if (store_data == out_store_data) {
299 return ResultNotUpdated;
300 }
301
302 return ResultSuccess;
81} 303}
82 304
83Result MiiManager::Get(const DatabaseSessionMetadata& metadata, 305Result MiiManager::Get(const DatabaseSessionMetadata& metadata,
84 std::span<CharInfoElement> out_elements, u32& out_count, 306 std::span<CharInfoElement> out_elements, u32& out_count,
85 SourceFlag source_flag) { 307 SourceFlag source_flag) const {
86 if ((source_flag & SourceFlag::Database) == SourceFlag::None) { 308 if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
87 return BuildDefault(out_elements, out_count, source_flag); 309 return BuildDefault(out_elements, out_count, source_flag);
88 } 310 }
89 311
90 // TODO(bunnei): We don't implement the Mii database, so we can't have an entry 312 const auto mii_count = database_manager.GetCount(metadata);
313
314 for (std::size_t index = 0; index < mii_count; ++index) {
315 if (out_elements.size() <= static_cast<std::size_t>(out_count)) {
316 return ResultInvalidArgumentSize;
317 }
318
319 StoreData store_data{};
320 database_manager.Get(store_data, index, metadata);
321
322 out_elements[out_count].source = Source::Database;
323 out_elements[out_count].char_info.SetFromStoreData(store_data);
324 out_count++;
325 }
91 326
92 // Include default Mii at the end of the list 327 // Include default Mii at the end of the list
93 return BuildDefault(out_elements, out_count, source_flag); 328 return BuildDefault(out_elements, out_count, source_flag);
94} 329}
95 330
96Result MiiManager::Get(const DatabaseSessionMetadata& metadata, std::span<CharInfo> out_char_info, 331Result MiiManager::Get(const DatabaseSessionMetadata& metadata, std::span<CharInfo> out_char_info,
97 u32& out_count, SourceFlag source_flag) { 332 u32& out_count, SourceFlag source_flag) const {
98 if ((source_flag & SourceFlag::Database) == SourceFlag::None) { 333 if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
99 return BuildDefault(out_char_info, out_count, source_flag); 334 return BuildDefault(out_char_info, out_count, source_flag);
100 } 335 }
101 336
102 // TODO(bunnei): We don't implement the Mii database, so we can't have an entry 337 const auto mii_count = database_manager.GetCount(metadata);
338
339 for (std::size_t index = 0; index < mii_count; ++index) {
340 if (out_char_info.size() <= static_cast<std::size_t>(out_count)) {
341 return ResultInvalidArgumentSize;
342 }
343
344 StoreData store_data{};
345 database_manager.Get(store_data, index, metadata);
346
347 out_char_info[out_count].SetFromStoreData(store_data);
348 out_count++;
349 }
103 350
104 // Include default Mii at the end of the list 351 // Include default Mii at the end of the list
105 return BuildDefault(out_char_info, out_count, source_flag); 352 return BuildDefault(out_char_info, out_count, source_flag);
106} 353}
107 354
355Result MiiManager::Get(const DatabaseSessionMetadata& metadata,
356 std::span<StoreDataElement> out_elements, u32& out_count,
357 SourceFlag source_flag) const {
358 if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
359 return BuildDefault(out_elements, out_count, source_flag);
360 }
361
362 const auto mii_count = database_manager.GetCount(metadata);
363
364 for (std::size_t index = 0; index < mii_count; ++index) {
365 if (out_elements.size() <= static_cast<std::size_t>(out_count)) {
366 return ResultInvalidArgumentSize;
367 }
368
369 StoreData store_data{};
370 database_manager.Get(store_data, index, metadata);
371
372 out_elements[out_count].store_data = store_data;
373 out_elements[out_count].source = Source::Database;
374 out_count++;
375 }
376
377 // Include default Mii at the end of the list
378 return BuildDefault(out_elements, out_count, source_flag);
379}
380
381Result MiiManager::Get(const DatabaseSessionMetadata& metadata, std::span<StoreData> out_store_data,
382 u32& out_count, SourceFlag source_flag) const {
383 if ((source_flag & SourceFlag::Database) == SourceFlag::None) {
384 return BuildDefault(out_store_data, out_count, source_flag);
385 }
386
387 const auto mii_count = database_manager.GetCount(metadata);
388
389 for (std::size_t index = 0; index < mii_count; ++index) {
390 if (out_store_data.size() <= static_cast<std::size_t>(out_count)) {
391 return ResultInvalidArgumentSize;
392 }
393
394 StoreData store_data{};
395 database_manager.Get(store_data, index, metadata);
396
397 out_store_data[out_count] = store_data;
398 out_count++;
399 }
400
401 // Include default Mii at the end of the list
402 return BuildDefault(out_store_data, out_count, source_flag);
403}
108Result MiiManager::BuildDefault(std::span<CharInfoElement> out_elements, u32& out_count, 404Result MiiManager::BuildDefault(std::span<CharInfoElement> out_elements, u32& out_count,
109 SourceFlag source_flag) { 405 SourceFlag source_flag) const {
110 if ((source_flag & SourceFlag::Default) == SourceFlag::None) { 406 if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
111 return ResultSuccess; 407 return ResultSuccess;
112 } 408 }
@@ -129,7 +425,7 @@ Result MiiManager::BuildDefault(std::span<CharInfoElement> out_elements, u32& ou
129} 425}
130 426
131Result MiiManager::BuildDefault(std::span<CharInfo> out_char_info, u32& out_count, 427Result MiiManager::BuildDefault(std::span<CharInfo> out_char_info, u32& out_count,
132 SourceFlag source_flag) { 428 SourceFlag source_flag) const {
133 if ((source_flag & SourceFlag::Default) == SourceFlag::None) { 429 if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
134 return ResultSuccess; 430 return ResultSuccess;
135 } 431 }
@@ -150,23 +446,41 @@ Result MiiManager::BuildDefault(std::span<CharInfo> out_char_info, u32& out_coun
150 return ResultSuccess; 446 return ResultSuccess;
151} 447}
152 448
153Result MiiManager::GetIndex(const DatabaseSessionMetadata& metadata, const CharInfo& char_info, 449Result MiiManager::BuildDefault(std::span<StoreDataElement> out_elements, u32& out_count,
154 s32& out_index) { 450 SourceFlag source_flag) const {
155 451 if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
156 if (char_info.Verify() != ValidationResult::NoErrors) { 452 return ResultSuccess;
157 return ResultInvalidCharInfo;
158 } 453 }
159 454
160 constexpr u32 INVALID_INDEX{0xFFFFFFFF}; 455 for (std::size_t index = 0; index < DefaultMiiCount; ++index) {
456 if (out_elements.size() <= static_cast<std::size_t>(out_count)) {
457 return ResultInvalidArgumentSize;
458 }
161 459
162 out_index = INVALID_INDEX; 460 out_elements[out_count].store_data.BuildDefault(static_cast<u32>(index));
461 out_elements[out_count].source = Source::Default;
462 out_count++;
463 }
163 464
164 // TODO(bunnei): We don't implement the Mii database, so we can't have an index 465 return ResultSuccess;
165 return ResultNotFound;
166} 466}
167 467
168void MiiManager::SetInterfaceVersion(DatabaseSessionMetadata& metadata, u32 version) { 468Result MiiManager::BuildDefault(std::span<StoreData> out_char_info, u32& out_count,
169 metadata.interface_version = version; 469 SourceFlag source_flag) const {
470 if ((source_flag & SourceFlag::Default) == SourceFlag::None) {
471 return ResultSuccess;
472 }
473
474 for (std::size_t index = 0; index < DefaultMiiCount; ++index) {
475 if (out_char_info.size() <= static_cast<std::size_t>(out_count)) {
476 return ResultInvalidArgumentSize;
477 }
478
479 out_char_info[out_count].BuildDefault(static_cast<u32>(index));
480 out_count++;
481 }
482
483 return ResultSuccess;
170} 484}
171 485
172} // namespace Service::Mii 486} // namespace Service::Mii
diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h
index a2e7a6d73..48d8e8bb7 100644
--- a/src/core/hle/service/mii/mii_manager.h
+++ b/src/core/hle/service/mii/mii_manager.h
@@ -3,47 +3,85 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <vector> 6#include <span>
7 7
8#include "core/hle/result.h" 8#include "core/hle/result.h"
9#include "core/hle/service/mii/mii_database_manager.h"
9#include "core/hle/service/mii/mii_types.h" 10#include "core/hle/service/mii/mii_types.h"
10#include "core/hle/service/mii/types/char_info.h"
11#include "core/hle/service/mii/types/store_data.h"
12#include "core/hle/service/mii/types/ver3_store_data.h"
13 11
14namespace Service::Mii { 12namespace Service::Mii {
13class CharInfo;
14class CoreData;
15class StoreData;
16class Ver3StoreData;
15 17
16// The Mii manager is responsible for loading and storing the Miis to the database in NAND along 18struct CharInfoElement;
17// with providing an easy interface for HLE emulation of the mii service. 19struct StoreDataElement;
20
21// The Mii manager is responsible for handling mii operations along with providing an easy interface
22// for HLE emulation of the mii service.
18class MiiManager { 23class MiiManager {
19public: 24public:
20 MiiManager(); 25 MiiManager();
26 Result Initialize(DatabaseSessionMetadata& metadata);
21 27
22 bool IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const; 28 // Auto generated mii
29 void BuildDefault(CharInfo& out_char_info, u32 index) const;
30 void BuildBase(CharInfo& out_char_info, Gender gender) const;
31 void BuildRandom(CharInfo& out_char_info, Age age, Gender gender, Race race) const;
23 32
33 // Database operations
24 bool IsFullDatabase() const; 34 bool IsFullDatabase() const;
35 void SetInterfaceVersion(DatabaseSessionMetadata& metadata, u32 version) const;
36 bool IsUpdated(DatabaseSessionMetadata& metadata, SourceFlag source_flag) const;
25 u32 GetCount(const DatabaseSessionMetadata& metadata, SourceFlag source_flag) const; 37 u32 GetCount(const DatabaseSessionMetadata& metadata, SourceFlag source_flag) const;
26 Result UpdateLatest(DatabaseSessionMetadata& metadata, CharInfo& out_char_info, 38 Result Move(DatabaseSessionMetadata& metadata, u32 index, const Common::UUID& create_id);
27 const CharInfo& char_info, SourceFlag source_flag); 39 Result AddOrReplace(DatabaseSessionMetadata& metadata, const StoreData& store_data);
40 Result Delete(DatabaseSessionMetadata& metadata, const Common::UUID& create_id);
41 s32 FindIndex(const Common::UUID& create_id, bool is_special) const;
42 Result GetIndex(const DatabaseSessionMetadata& metadata, const CharInfo& char_info,
43 s32& out_index) const;
44 Result Append(DatabaseSessionMetadata& metadata, const CharInfo& char_info);
45
46 // Test database operations
47 bool IsBrokenWithClearFlag(DatabaseSessionMetadata& metadata);
48 Result DestroyFile(DatabaseSessionMetadata& metadata);
49 Result DeleteFile();
50 Result Format(DatabaseSessionMetadata& metadata);
51
52 // Mii conversions
53 Result ConvertV3ToCharInfo(CharInfo& out_char_info, const Ver3StoreData& mii_v3) const;
54 Result ConvertCoreDataToCharInfo(CharInfo& out_char_info, const CoreData& core_data) const;
55 Result ConvertCharInfoToCoreData(CoreData& out_core_data, const CharInfo& char_info) const;
56 Result UpdateLatest(const DatabaseSessionMetadata& metadata, CharInfo& out_char_info,
57 const CharInfo& char_info, SourceFlag source_flag) const;
58 Result UpdateLatest(const DatabaseSessionMetadata& metadata, StoreData& out_store_data,
59 const StoreData& store_data, SourceFlag source_flag) const;
60
61 // Overloaded getters
28 Result Get(const DatabaseSessionMetadata& metadata, std::span<CharInfoElement> out_elements, 62 Result Get(const DatabaseSessionMetadata& metadata, std::span<CharInfoElement> out_elements,
29 u32& out_count, SourceFlag source_flag); 63 u32& out_count, SourceFlag source_flag) const;
30 Result Get(const DatabaseSessionMetadata& metadata, std::span<CharInfo> out_char_info, 64 Result Get(const DatabaseSessionMetadata& metadata, std::span<CharInfo> out_char_info,
31 u32& out_count, SourceFlag source_flag); 65 u32& out_count, SourceFlag source_flag) const;
32 void BuildDefault(CharInfo& out_char_info, u32 index) const; 66 Result Get(const DatabaseSessionMetadata& metadata, std::span<StoreDataElement> out_elements,
33 void BuildBase(CharInfo& out_char_info, Gender gender) const; 67 u32& out_count, SourceFlag source_flag) const;
34 void BuildRandom(CharInfo& out_char_info, Age age, Gender gender, Race race) const; 68 Result Get(const DatabaseSessionMetadata& metadata, std::span<StoreData> out_store_data,
35 void ConvertV3ToCharInfo(CharInfo& out_char_info, const Ver3StoreData& mii_v3) const; 69 u32& out_count, SourceFlag source_flag) const;
36 std::vector<CharInfoElement> GetDefault(SourceFlag source_flag);
37 Result GetIndex(const DatabaseSessionMetadata& metadata, const CharInfo& char_info,
38 s32& out_index);
39 void SetInterfaceVersion(DatabaseSessionMetadata& metadata, u32 version);
40 70
41private: 71private:
42 Result BuildDefault(std::span<CharInfoElement> out_elements, u32& out_count, 72 Result BuildDefault(std::span<CharInfoElement> out_elements, u32& out_count,
43 SourceFlag source_flag); 73 SourceFlag source_flag) const;
44 Result BuildDefault(std::span<CharInfo> out_char_info, u32& out_count, SourceFlag source_flag); 74 Result BuildDefault(std::span<CharInfo> out_char_info, u32& out_count,
75 SourceFlag source_flag) const;
76 Result BuildDefault(std::span<StoreDataElement> out_char_info, u32& out_count,
77 SourceFlag source_flag) const;
78 Result BuildDefault(std::span<StoreData> out_char_info, u32& out_count,
79 SourceFlag source_flag) const;
80
81 DatabaseManager database_manager{};
45 82
46 u64 update_counter{}; 83 // This should be a global value
84 bool is_broken_with_clear_flag{};
47}; 85};
48 86
49}; // namespace Service::Mii 87}; // namespace Service::Mii