summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt8
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt8
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt53
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/EmulationViewModel.kt33
-rw-r--r--src/android/app/src/main/jni/id_cache.cpp7
-rw-r--r--src/android/app/src/main/jni/id_cache.h1
-rw-r--r--src/android/app/src/main/jni/native.cpp34
-rw-r--r--src/android/app/src/main/jni/native.h7
-rw-r--r--src/android/app/src/main/res/layout/fragment_emulation.xml4
-rw-r--r--src/core/hle/service/am/applets/applet_mii_edit.cpp2
-rw-r--r--src/core/hle/service/mii/mii.cpp563
-rw-r--r--src/core/hle/service/mii/mii.h15
-rw-r--r--src/core/hle/service/set/system_settings_server.cpp3
13 files changed, 291 insertions, 447 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
index 55abba093..53137b2e2 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
@@ -261,7 +261,7 @@ object NativeLibrary {
261 /** 261 /**
262 * Begins emulation. 262 * Begins emulation.
263 */ 263 */
264 external fun run(path: String?) 264 external fun run(path: String?, programIndex: Int = 0)
265 265
266 // Surface Handling 266 // Surface Handling
267 external fun surfaceChanged(surf: Surface?) 267 external fun surfaceChanged(surf: Surface?)
@@ -489,6 +489,12 @@ object NativeLibrary {
489 sEmulationActivity.get()!!.onEmulationStopped(status) 489 sEmulationActivity.get()!!.onEmulationStopped(status)
490 } 490 }
491 491
492 @Keep
493 @JvmStatic
494 fun onProgramChanged(programIndex: Int) {
495 sEmulationActivity.get()!!.onProgramChanged(programIndex)
496 }
497
492 /** 498 /**
493 * Logs the Yuzu version, Android version and, CPU. 499 * Logs the Yuzu version, Android version and, CPU.
494 */ 500 */
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
index 26cddecf4..564aaf305 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
@@ -76,7 +76,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
76 76
77 override fun onDestroy() { 77 override fun onDestroy() {
78 stopForegroundService(this) 78 stopForegroundService(this)
79 emulationViewModel.clear()
80 super.onDestroy() 79 super.onDestroy()
81 } 80 }
82 81
@@ -446,9 +445,14 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
446 } 445 }
447 446
448 fun onEmulationStopped(status: Int) { 447 fun onEmulationStopped(status: Int) {
449 if (status == 0) { 448 if (status == 0 && emulationViewModel.programChanged.value == -1) {
450 finish() 449 finish()
451 } 450 }
451 emulationViewModel.setEmulationStopped(true)
452 }
453
454 fun onProgramChanged(programIndex: Int) {
455 emulationViewModel.setProgramChanged(programIndex)
452 } 456 }
453 457
454 private fun startMotionSensorListener() { 458 private fun startMotionSensorListener() {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index ef393c4be..1f591ced1 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -424,10 +424,38 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
424 } 424 }
425 } 425 }
426 } 426 }
427 launch {
428 repeatOnLifecycle(Lifecycle.State.CREATED) {
429 emulationViewModel.programChanged.collect {
430 if (it != 0) {
431 emulationViewModel.setEmulationStarted(false)
432 binding.drawerLayout.close()
433 binding.drawerLayout
434 .setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
435 ViewUtils.hideView(binding.surfaceInputOverlay)
436 ViewUtils.showView(binding.loadingIndicator)
437 }
438 }
439 }
440 }
441 launch {
442 repeatOnLifecycle(Lifecycle.State.CREATED) {
443 emulationViewModel.emulationStopped.collect {
444 if (it && emulationViewModel.programChanged.value != -1) {
445 if (perfStatsUpdater != null) {
446 perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
447 }
448 emulationState.changeProgram(emulationViewModel.programChanged.value)
449 emulationViewModel.setProgramChanged(-1)
450 emulationViewModel.setEmulationStopped(false)
451 }
452 }
453 }
454 }
427 } 455 }
428 } 456 }
429 457
430 private fun startEmulation() { 458 private fun startEmulation(programIndex: Int = 0) {
431 if (!NativeLibrary.isRunning() && !NativeLibrary.isPaused()) { 459 if (!NativeLibrary.isRunning() && !NativeLibrary.isPaused()) {
432 if (!DirectoryInitialization.areDirectoriesReady) { 460 if (!DirectoryInitialization.areDirectoriesReady) {
433 DirectoryInitialization.start() 461 DirectoryInitialization.start()
@@ -435,7 +463,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
435 463
436 updateScreenLayout() 464 updateScreenLayout()
437 465
438 emulationState.run(emulationActivity!!.isActivityRecreated) 466 emulationState.run(emulationActivity!!.isActivityRecreated, programIndex)
439 } 467 }
440 } 468 }
441 469
@@ -833,6 +861,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
833 ) { 861 ) {
834 private var state: State 862 private var state: State
835 private var surface: Surface? = null 863 private var surface: Surface? = null
864 lateinit var emulationThread: Thread
836 865
837 init { 866 init {
838 // Starting state is stopped. 867 // Starting state is stopped.
@@ -878,7 +907,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
878 } 907 }
879 908
880 @Synchronized 909 @Synchronized
881 fun run(isActivityRecreated: Boolean) { 910 fun run(isActivityRecreated: Boolean, programIndex: Int = 0) {
882 if (isActivityRecreated) { 911 if (isActivityRecreated) {
883 if (NativeLibrary.isRunning()) { 912 if (NativeLibrary.isRunning()) {
884 state = State.PAUSED 913 state = State.PAUSED
@@ -889,10 +918,20 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
889 918
890 // If the surface is set, run now. Otherwise, wait for it to get set. 919 // If the surface is set, run now. Otherwise, wait for it to get set.
891 if (surface != null) { 920 if (surface != null) {
892 runWithValidSurface() 921 runWithValidSurface(programIndex)
893 } 922 }
894 } 923 }
895 924
925 @Synchronized
926 fun changeProgram(programIndex: Int) {
927 emulationThread.join()
928 emulationThread = Thread({
929 Log.debug("[EmulationFragment] Starting emulation thread.")
930 NativeLibrary.run(gamePath, programIndex)
931 }, "NativeEmulation")
932 emulationThread.start()
933 }
934
896 // Surface callbacks 935 // Surface callbacks
897 @Synchronized 936 @Synchronized
898 fun newSurface(surface: Surface?) { 937 fun newSurface(surface: Surface?) {
@@ -932,7 +971,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
932 } 971 }
933 } 972 }
934 973
935 private fun runWithValidSurface() { 974 private fun runWithValidSurface(programIndex: Int = 0) {
936 NativeLibrary.surfaceChanged(surface) 975 NativeLibrary.surfaceChanged(surface)
937 if (!emulationCanStart.invoke()) { 976 if (!emulationCanStart.invoke()) {
938 return 977 return
@@ -940,9 +979,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
940 979
941 when (state) { 980 when (state) {
942 State.STOPPED -> { 981 State.STOPPED -> {
943 val emulationThread = Thread({ 982 emulationThread = Thread({
944 Log.debug("[EmulationFragment] Starting emulation thread.") 983 Log.debug("[EmulationFragment] Starting emulation thread.")
945 NativeLibrary.run(gamePath) 984 NativeLibrary.run(gamePath, programIndex)
946 }, "NativeEmulation") 985 }, "NativeEmulation")
947 emulationThread.start() 986 emulationThread.start()
948 } 987 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/EmulationViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/EmulationViewModel.kt
index b66f47fe7..d024493cd 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/EmulationViewModel.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/EmulationViewModel.kt
@@ -15,6 +15,12 @@ class EmulationViewModel : ViewModel() {
15 val isEmulationStopping: StateFlow<Boolean> get() = _isEmulationStopping 15 val isEmulationStopping: StateFlow<Boolean> get() = _isEmulationStopping
16 private val _isEmulationStopping = MutableStateFlow(false) 16 private val _isEmulationStopping = MutableStateFlow(false)
17 17
18 private val _emulationStopped = MutableStateFlow(false)
19 val emulationStopped = _emulationStopped.asStateFlow()
20
21 private val _programChanged = MutableStateFlow(-1)
22 val programChanged = _programChanged.asStateFlow()
23
18 val shaderProgress: StateFlow<Int> get() = _shaderProgress 24 val shaderProgress: StateFlow<Int> get() = _shaderProgress
19 private val _shaderProgress = MutableStateFlow(0) 25 private val _shaderProgress = MutableStateFlow(0)
20 26
@@ -35,6 +41,17 @@ class EmulationViewModel : ViewModel() {
35 _isEmulationStopping.value = value 41 _isEmulationStopping.value = value
36 } 42 }
37 43
44 fun setEmulationStopped(value: Boolean) {
45 if (value) {
46 _emulationStarted.value = false
47 }
48 _emulationStopped.value = value
49 }
50
51 fun setProgramChanged(programIndex: Int) {
52 _programChanged.value = programIndex
53 }
54
38 fun setShaderProgress(progress: Int) { 55 fun setShaderProgress(progress: Int) {
39 _shaderProgress.value = progress 56 _shaderProgress.value = progress
40 } 57 }
@@ -56,20 +73,4 @@ class EmulationViewModel : ViewModel() {
56 fun setDrawerOpen(value: Boolean) { 73 fun setDrawerOpen(value: Boolean) {
57 _drawerOpen.value = value 74 _drawerOpen.value = value
58 } 75 }
59
60 fun clear() {
61 setEmulationStarted(false)
62 setIsEmulationStopping(false)
63 setShaderProgress(0)
64 setTotalShaders(0)
65 setShaderMessage("")
66 }
67
68 companion object {
69 const val KEY_EMULATION_STARTED = "EmulationStarted"
70 const val KEY_IS_EMULATION_STOPPING = "IsEmulationStarting"
71 const val KEY_SHADER_PROGRESS = "ShaderProgress"
72 const val KEY_TOTAL_SHADERS = "TotalShaders"
73 const val KEY_SHADER_MESSAGE = "ShaderMessage"
74 }
75} 76}
diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp
index 96f2ad3d4..f30100bd8 100644
--- a/src/android/app/src/main/jni/id_cache.cpp
+++ b/src/android/app/src/main/jni/id_cache.cpp
@@ -19,6 +19,7 @@ static jmethodID s_exit_emulation_activity;
19static jmethodID s_disk_cache_load_progress; 19static jmethodID s_disk_cache_load_progress;
20static jmethodID s_on_emulation_started; 20static jmethodID s_on_emulation_started;
21static jmethodID s_on_emulation_stopped; 21static jmethodID s_on_emulation_stopped;
22static jmethodID s_on_program_changed;
22 23
23static jclass s_game_class; 24static jclass s_game_class;
24static jmethodID s_game_constructor; 25static jmethodID s_game_constructor;
@@ -123,6 +124,10 @@ jmethodID GetOnEmulationStopped() {
123 return s_on_emulation_stopped; 124 return s_on_emulation_stopped;
124} 125}
125 126
127jmethodID GetOnProgramChanged() {
128 return s_on_program_changed;
129}
130
126jclass GetGameClass() { 131jclass GetGameClass() {
127 return s_game_class; 132 return s_game_class;
128} 133}
@@ -306,6 +311,8 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
306 env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V"); 311 env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V");
307 s_on_emulation_stopped = 312 s_on_emulation_stopped =
308 env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V"); 313 env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V");
314 s_on_program_changed =
315 env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V");
309 316
310 const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game"); 317 const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game");
311 s_game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class)); 318 s_game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class));
diff --git a/src/android/app/src/main/jni/id_cache.h b/src/android/app/src/main/jni/id_cache.h
index a002e705d..00e48afc0 100644
--- a/src/android/app/src/main/jni/id_cache.h
+++ b/src/android/app/src/main/jni/id_cache.h
@@ -19,6 +19,7 @@ jmethodID GetExitEmulationActivity();
19jmethodID GetDiskCacheLoadProgress(); 19jmethodID GetDiskCacheLoadProgress();
20jmethodID GetOnEmulationStarted(); 20jmethodID GetOnEmulationStarted();
21jmethodID GetOnEmulationStopped(); 21jmethodID GetOnEmulationStopped();
22jmethodID GetOnProgramChanged();
22 23
23jclass GetGameClass(); 24jclass GetGameClass();
24jmethodID GetGameConstructor(); 25jmethodID GetGameConstructor();
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 3fd9a500c..958a77ac7 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -208,7 +208,8 @@ void EmulationSession::InitializeSystem(bool reload) {
208 m_system.GetFileSystemController().CreateFactories(*m_vfs); 208 m_system.GetFileSystemController().CreateFactories(*m_vfs);
209} 209}
210 210
211Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string& filepath) { 211Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string& filepath,
212 const std::size_t program_index) {
212 std::scoped_lock lock(m_mutex); 213 std::scoped_lock lock(m_mutex);
213 214
214 // Create the render window. 215 // Create the render window.
@@ -238,7 +239,8 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
238 ConfigureFilesystemProvider(filepath); 239 ConfigureFilesystemProvider(filepath);
239 240
240 // Load the ROM. 241 // Load the ROM.
241 m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath); 242 m_load_result =
243 m_system.Load(EmulationSession::GetInstance().Window(), filepath, 0, program_index);
242 if (m_load_result != Core::SystemResultStatus::Success) { 244 if (m_load_result != Core::SystemResultStatus::Success) {
243 return m_load_result; 245 return m_load_result;
244 } 246 }
@@ -248,6 +250,12 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
248 m_system.GetCpuManager().OnGpuReady(); 250 m_system.GetCpuManager().OnGpuReady();
249 m_system.RegisterExitCallback([&] { HaltEmulation(); }); 251 m_system.RegisterExitCallback([&] { HaltEmulation(); });
250 252
253 // Register an ExecuteProgram callback such that Core can execute a sub-program
254 m_system.RegisterExecuteProgramCallback([&](std::size_t program_index_) {
255 m_next_program_index = program_index_;
256 EmulationSession::GetInstance().HaltEmulation();
257 });
258
251 OnEmulationStarted(); 259 OnEmulationStarted();
252 return Core::SystemResultStatus::Success; 260 return Core::SystemResultStatus::Success;
253} 261}
@@ -255,6 +263,11 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
255void EmulationSession::ShutdownEmulation() { 263void EmulationSession::ShutdownEmulation() {
256 std::scoped_lock lock(m_mutex); 264 std::scoped_lock lock(m_mutex);
257 265
266 if (m_next_program_index != -1) {
267 ChangeProgram(m_next_program_index);
268 m_next_program_index = -1;
269 }
270
258 m_is_running = false; 271 m_is_running = false;
259 272
260 // Unload user input. 273 // Unload user input.
@@ -402,6 +415,12 @@ void EmulationSession::OnEmulationStopped(Core::SystemResultStatus result) {
402 static_cast<jint>(result)); 415 static_cast<jint>(result));
403} 416}
404 417
418void EmulationSession::ChangeProgram(std::size_t program_index) {
419 JNIEnv* env = IDCache::GetEnvForThread();
420 env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetOnProgramChanged(),
421 static_cast<jint>(program_index));
422}
423
405u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) { 424u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) {
406 auto program_id_string = GetJString(env, jprogramId); 425 auto program_id_string = GetJString(env, jprogramId);
407 try { 426 try {
@@ -411,7 +430,8 @@ u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) {
411 } 430 }
412} 431}
413 432
414static Core::SystemResultStatus RunEmulation(const std::string& filepath) { 433static Core::SystemResultStatus RunEmulation(const std::string& filepath,
434 const size_t program_index = 0) {
415 MicroProfileOnThreadCreate("EmuThread"); 435 MicroProfileOnThreadCreate("EmuThread");
416 SCOPE_EXIT({ MicroProfileShutdown(); }); 436 SCOPE_EXIT({ MicroProfileShutdown(); });
417 437
@@ -424,7 +444,7 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
424 444
425 SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); }); 445 SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
426 446
427 jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath); 447 jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index);
428 if (result != Core::SystemResultStatus::Success) { 448 if (result != Core::SystemResultStatus::Success) {
429 return result; 449 return result;
430 } 450 }
@@ -689,11 +709,11 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_logSettings(JNIEnv* env, jobject jobj
689 Settings::LogSettings(); 709 Settings::LogSettings();
690} 710}
691 711
692void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2(JNIEnv* env, jclass clazz, 712void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path,
693 jstring j_path) { 713 jint j_program_index) {
694 const std::string path = GetJString(env, j_path); 714 const std::string path = GetJString(env, j_path);
695 715
696 const Core::SystemResultStatus result{RunEmulation(path)}; 716 const Core::SystemResultStatus result{RunEmulation(path, j_program_index)};
697 if (result != Core::SystemResultStatus::Success) { 717 if (result != Core::SystemResultStatus::Success) {
698 env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), 718 env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
699 IDCache::GetExitEmulationActivity(), static_cast<int>(result)); 719 IDCache::GetExitEmulationActivity(), static_cast<int>(result));
diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h
index dadb138ad..bfe3fccca 100644
--- a/src/android/app/src/main/jni/native.h
+++ b/src/android/app/src/main/jni/native.h
@@ -45,7 +45,8 @@ public:
45 const Core::PerfStatsResults& PerfStats(); 45 const Core::PerfStatsResults& PerfStats();
46 void ConfigureFilesystemProvider(const std::string& filepath); 46 void ConfigureFilesystemProvider(const std::string& filepath);
47 void InitializeSystem(bool reload); 47 void InitializeSystem(bool reload);
48 Core::SystemResultStatus InitializeEmulation(const std::string& filepath); 48 Core::SystemResultStatus InitializeEmulation(const std::string& filepath,
49 const std::size_t program_index = 0);
49 50
50 bool IsHandheldOnly(); 51 bool IsHandheldOnly();
51 void SetDeviceType([[maybe_unused]] int index, int type); 52 void SetDeviceType([[maybe_unused]] int index, int type);
@@ -60,6 +61,7 @@ public:
60private: 61private:
61 static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max); 62 static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max);
62 static void OnEmulationStopped(Core::SystemResultStatus result); 63 static void OnEmulationStopped(Core::SystemResultStatus result);
64 static void ChangeProgram(std::size_t program_index);
63 65
64private: 66private:
65 // Window management 67 // Window management
@@ -84,4 +86,7 @@ private:
84 // Synchronization 86 // Synchronization
85 std::condition_variable_any m_cv; 87 std::condition_variable_any m_cv;
86 mutable std::mutex m_mutex; 88 mutable std::mutex m_mutex;
89
90 // Program index for next boot
91 std::atomic<s32> m_next_program_index = -1;
87}; 92};
diff --git a/src/android/app/src/main/res/layout/fragment_emulation.xml b/src/android/app/src/main/res/layout/fragment_emulation.xml
index c01117d14..0d2bfe8d6 100644
--- a/src/android/app/src/main/res/layout/fragment_emulation.xml
+++ b/src/android/app/src/main/res/layout/fragment_emulation.xml
@@ -34,8 +34,10 @@
34 android:layout_width="wrap_content" 34 android:layout_width="wrap_content"
35 android:layout_height="wrap_content" 35 android:layout_height="wrap_content"
36 android:layout_gravity="center" 36 android:layout_gravity="center"
37 android:focusable="false"
37 android:defaultFocusHighlightEnabled="false" 38 android:defaultFocusHighlightEnabled="false"
38 android:clickable="false"> 39 android:clickable="false"
40 app:rippleColor="@android:color/transparent">
39 41
40 <androidx.constraintlayout.widget.ConstraintLayout 42 <androidx.constraintlayout.widget.ConstraintLayout
41 android:id="@+id/loading_layout" 43 android:id="@+id/loading_layout"
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 50adc7c02..e83e931c5 100644
--- a/src/core/hle/service/am/applets/applet_mii_edit.cpp
+++ b/src/core/hle/service/am/applets/applet_mii_edit.cpp
@@ -59,7 +59,7 @@ void MiiEdit::Initialize() {
59 break; 59 break;
60 } 60 }
61 61
62 manager = system.ServiceManager().GetService<Mii::MiiDBModule>("mii:e")->GetMiiManager(); 62 manager = system.ServiceManager().GetService<Mii::IStaticService>("mii:e")->GetMiiManager();
63 if (manager == nullptr) { 63 if (manager == nullptr) {
64 manager = std::make_shared<Mii::MiiManager>(); 64 manager = std::make_shared<Mii::MiiManager>();
65 } 65 }
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index c28eed926..b4d16fed5 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -4,15 +4,18 @@
4#include <memory> 4#include <memory>
5 5
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/hle/service/cmif_serialization.h"
7#include "core/hle/service/ipc_helpers.h" 8#include "core/hle/service/ipc_helpers.h"
8#include "core/hle/service/mii/mii.h" 9#include "core/hle/service/mii/mii.h"
9#include "core/hle/service/mii/mii_manager.h" 10#include "core/hle/service/mii/mii_manager.h"
10#include "core/hle/service/mii/mii_result.h" 11#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/char_info.h"
13#include "core/hle/service/mii/types/raw_data.h"
12#include "core/hle/service/mii/types/store_data.h" 14#include "core/hle/service/mii/types/store_data.h"
13#include "core/hle/service/mii/types/ver3_store_data.h" 15#include "core/hle/service/mii/types/ver3_store_data.h"
14#include "core/hle/service/server_manager.h" 16#include "core/hle/service/server_manager.h"
15#include "core/hle/service/service.h" 17#include "core/hle/service/set/system_settings_server.h"
18#include "core/hle/service/sm/sm.h"
16 19
17namespace Service::Mii { 20namespace Service::Mii {
18 21
@@ -24,549 +27,302 @@ public:
24 is_system_} { 27 is_system_} {
25 // clang-format off 28 // clang-format off
26 static const FunctionInfo functions[] = { 29 static const FunctionInfo functions[] = {
27 {0, &IDatabaseService::IsUpdated, "IsUpdated"}, 30 {0, D<&IDatabaseService::IsUpdated>, "IsUpdated"},
28 {1, &IDatabaseService::IsFullDatabase, "IsFullDatabase"}, 31 {1, D<&IDatabaseService::IsFullDatabase>, "IsFullDatabase"},
29 {2, &IDatabaseService::GetCount, "GetCount"}, 32 {2, D<&IDatabaseService::GetCount>, "GetCount"},
30 {3, &IDatabaseService::Get, "Get"}, 33 {3, D<&IDatabaseService::Get>, "Get"},
31 {4, &IDatabaseService::Get1, "Get1"}, 34 {4, D<&IDatabaseService::Get1>, "Get1"},
32 {5, &IDatabaseService::UpdateLatest, "UpdateLatest"}, 35 {5, D<&IDatabaseService::UpdateLatest>, "UpdateLatest"},
33 {6, &IDatabaseService::BuildRandom, "BuildRandom"}, 36 {6, D<&IDatabaseService::BuildRandom>, "BuildRandom"},
34 {7, &IDatabaseService::BuildDefault, "BuildDefault"}, 37 {7, D<&IDatabaseService::BuildDefault>, "BuildDefault"},
35 {8, &IDatabaseService::Get2, "Get2"}, 38 {8, D<&IDatabaseService::Get2>, "Get2"},
36 {9, &IDatabaseService::Get3, "Get3"}, 39 {9, D<&IDatabaseService::Get3>, "Get3"},
37 {10, &IDatabaseService::UpdateLatest1, "UpdateLatest1"}, 40 {10, D<&IDatabaseService::UpdateLatest1>, "UpdateLatest1"},
38 {11, &IDatabaseService::FindIndex, "FindIndex"}, 41 {11, D<&IDatabaseService::FindIndex>, "FindIndex"},
39 {12, &IDatabaseService::Move, "Move"}, 42 {12, D<&IDatabaseService::Move>, "Move"},
40 {13, &IDatabaseService::AddOrReplace, "AddOrReplace"}, 43 {13, D<&IDatabaseService::AddOrReplace>, "AddOrReplace"},
41 {14, &IDatabaseService::Delete, "Delete"}, 44 {14, D<&IDatabaseService::Delete>, "Delete"},
42 {15, &IDatabaseService::DestroyFile, "DestroyFile"}, 45 {15, D<&IDatabaseService::DestroyFile>, "DestroyFile"},
43 {16, &IDatabaseService::DeleteFile, "DeleteFile"}, 46 {16, D<&IDatabaseService::DeleteFile>, "DeleteFile"},
44 {17, &IDatabaseService::Format, "Format"}, 47 {17, D<&IDatabaseService::Format>, "Format"},
45 {18, nullptr, "Import"}, 48 {18, nullptr, "Import"},
46 {19, nullptr, "Export"}, 49 {19, nullptr, "Export"},
47 {20, &IDatabaseService::IsBrokenDatabaseWithClearFlag, "IsBrokenDatabaseWithClearFlag"}, 50 {20, D<&IDatabaseService::IsBrokenDatabaseWithClearFlag>, "IsBrokenDatabaseWithClearFlag"},
48 {21, &IDatabaseService::GetIndex, "GetIndex"}, 51 {21, D<&IDatabaseService::GetIndex>, "GetIndex"},
49 {22, &IDatabaseService::SetInterfaceVersion, "SetInterfaceVersion"}, 52 {22, D<&IDatabaseService::SetInterfaceVersion>, "SetInterfaceVersion"},
50 {23, &IDatabaseService::Convert, "Convert"}, 53 {23, D<&IDatabaseService::Convert>, "Convert"},
51 {24, &IDatabaseService::ConvertCoreDataToCharInfo, "ConvertCoreDataToCharInfo"}, 54 {24, D<&IDatabaseService::ConvertCoreDataToCharInfo>, "ConvertCoreDataToCharInfo"},
52 {25, &IDatabaseService::ConvertCharInfoToCoreData, "ConvertCharInfoToCoreData"}, 55 {25, D<&IDatabaseService::ConvertCharInfoToCoreData>, "ConvertCharInfoToCoreData"},
53 {26, &IDatabaseService::Append, "Append"}, 56 {26, D<&IDatabaseService::Append>, "Append"},
54 }; 57 };
55 // clang-format on 58 // clang-format on
56 59
57 RegisterHandlers(functions); 60 RegisterHandlers(functions);
58 61
62 m_set_sys = system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>(
63 "set:sys", true);
59 manager->Initialize(metadata); 64 manager->Initialize(metadata);
60 } 65 }
61 66
62private: 67private:
63 void IsUpdated(HLERequestContext& ctx) { 68 Result IsUpdated(Out<bool> out_is_updated, SourceFlag source_flag) {
64 IPC::RequestParser rp{ctx};
65 const auto source_flag{rp.PopRaw<SourceFlag>()};
66
67 LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag); 69 LOG_DEBUG(Service_Mii, "called with source_flag={}", source_flag);
68 70
69 const bool is_updated = manager->IsUpdated(metadata, source_flag); 71 *out_is_updated = manager->IsUpdated(metadata, source_flag);
70 72
71 IPC::ResponseBuilder rb{ctx, 3}; 73 R_SUCCEED();
72 rb.Push(ResultSuccess);
73 rb.Push<u8>(is_updated);
74 } 74 }
75 75
76 void IsFullDatabase(HLERequestContext& ctx) { 76 Result IsFullDatabase(Out<bool> out_is_full_database) {
77 LOG_DEBUG(Service_Mii, "called"); 77 LOG_DEBUG(Service_Mii, "called");
78 78
79 const bool is_full_database = manager->IsFullDatabase(); 79 *out_is_full_database = manager->IsFullDatabase();
80 80
81 IPC::ResponseBuilder rb{ctx, 3}; 81 R_SUCCEED();
82 rb.Push(ResultSuccess);
83 rb.Push<u8>(is_full_database);
84 } 82 }
85 83
86 void GetCount(HLERequestContext& ctx) { 84 Result GetCount(Out<u32> out_mii_count, SourceFlag source_flag) {
87 IPC::RequestParser rp{ctx}; 85 *out_mii_count = manager->GetCount(metadata, source_flag);
88 const auto source_flag{rp.PopRaw<SourceFlag>()};
89
90 const u32 mii_count = manager->GetCount(metadata, source_flag);
91 86
92 LOG_DEBUG(Service_Mii, "called with source_flag={}, mii_count={}", source_flag, mii_count); 87 LOG_DEBUG(Service_Mii, "called with source_flag={}, mii_count={}", source_flag,
88 *out_mii_count);
93 89
94 IPC::ResponseBuilder rb{ctx, 3}; 90 R_SUCCEED();
95 rb.Push(ResultSuccess);
96 rb.Push(mii_count);
97 } 91 }
98 92
99 void Get(HLERequestContext& ctx) { 93 Result Get(Out<u32> out_mii_count, SourceFlag source_flag,
100 IPC::RequestParser rp{ctx}; 94 OutArray<CharInfoElement, BufferAttr_HipcMapAlias> char_info_element_buffer) {
101 const auto source_flag{rp.PopRaw<SourceFlag>()}; 95 const auto result =
102 const auto output_size{ctx.GetWriteBufferNumElements<CharInfoElement>()}; 96 manager->Get(metadata, char_info_element_buffer, *out_mii_count, source_flag);
103
104 u32 mii_count{};
105 std::vector<CharInfoElement> char_info_elements(output_size);
106 const auto result = manager->Get(metadata, char_info_elements, mii_count, source_flag);
107
108 if (mii_count != 0) {
109 ctx.WriteBuffer(char_info_elements);
110 }
111 97
112 LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag, 98 LOG_INFO(Service_Mii, "called with source_flag={}, mii_count={}", source_flag,
113 output_size, mii_count); 99 *out_mii_count);
114 100
115 IPC::ResponseBuilder rb{ctx, 3}; 101 R_RETURN(result);
116 rb.Push(result);
117 rb.Push(mii_count);
118 } 102 }
119 103
120 void Get1(HLERequestContext& ctx) { 104 Result Get1(Out<u32> out_mii_count, SourceFlag source_flag,
121 IPC::RequestParser rp{ctx}; 105 OutArray<CharInfo, BufferAttr_HipcMapAlias> char_info_buffer) {
122 const auto source_flag{rp.PopRaw<SourceFlag>()}; 106 const auto result = manager->Get(metadata, char_info_buffer, *out_mii_count, source_flag);
123 const auto output_size{ctx.GetWriteBufferNumElements<CharInfo>()};
124 107
125 u32 mii_count{}; 108 LOG_INFO(Service_Mii, "called with source_flag={}, mii_count={}", source_flag,
126 std::vector<CharInfo> char_info(output_size); 109 *out_mii_count);
127 const auto result = manager->Get(metadata, char_info, mii_count, source_flag);
128 110
129 if (mii_count != 0) { 111 R_RETURN(result);
130 ctx.WriteBuffer(char_info);
131 }
132
133 LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag,
134 output_size, mii_count);
135
136 IPC::ResponseBuilder rb{ctx, 3};
137 rb.Push(result);
138 rb.Push(mii_count);
139 } 112 }
140 113
141 void UpdateLatest(HLERequestContext& ctx) { 114 Result UpdateLatest(Out<CharInfo> out_char_info, CharInfo& char_info, SourceFlag source_flag) {
142 IPC::RequestParser rp{ctx};
143 const auto char_info{rp.PopRaw<CharInfo>()};
144 const auto source_flag{rp.PopRaw<SourceFlag>()};
145
146 LOG_INFO(Service_Mii, "called with source_flag={}", source_flag); 115 LOG_INFO(Service_Mii, "called with source_flag={}", source_flag);
147 116
148 CharInfo new_char_info{}; 117 R_RETURN(manager->UpdateLatest(metadata, *out_char_info, char_info, source_flag));
149 const auto result = manager->UpdateLatest(metadata, new_char_info, char_info, source_flag);
150 if (result.IsFailure()) {
151 IPC::ResponseBuilder rb{ctx, 2};
152 rb.Push(result);
153 return;
154 }
155
156 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
157 rb.Push(ResultSuccess);
158 rb.PushRaw(new_char_info);
159 } 118 }
160 119
161 void BuildRandom(HLERequestContext& ctx) { 120 Result BuildRandom(Out<CharInfo> out_char_info, Age age, Gender gender, Race race) {
162 IPC::RequestParser rp{ctx};
163 const auto age{rp.PopRaw<Age>()};
164 const auto gender{rp.PopRaw<Gender>()};
165 const auto race{rp.PopRaw<Race>()};
166
167 LOG_DEBUG(Service_Mii, "called with age={}, gender={}, race={}", age, gender, race); 121 LOG_DEBUG(Service_Mii, "called with age={}, gender={}, race={}", age, gender, race);
168 122
169 if (age > Age::All) { 123 R_UNLESS(age <= Age::All, ResultInvalidArgument);
170 IPC::ResponseBuilder rb{ctx, 2}; 124 R_UNLESS(gender <= Gender::All, ResultInvalidArgument);
171 rb.Push(ResultInvalidArgument); 125 R_UNLESS(race <= Race::All, ResultInvalidArgument);
172 return;
173 }
174
175 if (gender > Gender::All) {
176 IPC::ResponseBuilder rb{ctx, 2};
177 rb.Push(ResultInvalidArgument);
178 return;
179 }
180
181 if (race > Race::All) {
182 IPC::ResponseBuilder rb{ctx, 2};
183 rb.Push(ResultInvalidArgument);
184 return;
185 }
186
187 CharInfo char_info{};
188 manager->BuildRandom(char_info, age, gender, race);
189
190 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
191 rb.Push(ResultSuccess);
192 rb.PushRaw(char_info);
193 }
194 126
195 void BuildDefault(HLERequestContext& ctx) { 127 manager->BuildRandom(*out_char_info, age, gender, race);
196 IPC::RequestParser rp{ctx};
197 const auto index{rp.Pop<u32>()};
198 128
199 LOG_DEBUG(Service_Mii, "called with index={}", index); 129 R_SUCCEED();
130 }
200 131
201 if (index > 5) { 132 Result BuildDefault(Out<CharInfo> out_char_info, s32 index) {
202 IPC::ResponseBuilder rb{ctx, 2}; 133 LOG_DEBUG(Service_Mii, "called with index={}", index);
203 rb.Push(ResultInvalidArgument); 134 R_UNLESS(index < static_cast<s32>(RawData::DefaultMii.size()), ResultInvalidArgument);
204 return;
205 }
206 135
207 CharInfo char_info{}; 136 manager->BuildDefault(*out_char_info, index);
208 manager->BuildDefault(char_info, index);
209 137
210 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)}; 138 R_SUCCEED();
211 rb.Push(ResultSuccess);
212 rb.PushRaw(char_info);
213 } 139 }
214 140
215 void Get2(HLERequestContext& ctx) { 141 Result Get2(Out<u32> out_mii_count, SourceFlag source_flag,
216 IPC::RequestParser rp{ctx}; 142 OutArray<StoreDataElement, BufferAttr_HipcMapAlias> store_data_element_buffer) {
217 const auto source_flag{rp.PopRaw<SourceFlag>()}; 143 const auto result =
218 const auto output_size{ctx.GetWriteBufferNumElements<StoreDataElement>()}; 144 manager->Get(metadata, store_data_element_buffer, *out_mii_count, source_flag);
219 145
220 u32 mii_count{}; 146 LOG_INFO(Service_Mii, "called with source_flag={}, mii_count={}", source_flag,
221 std::vector<StoreDataElement> store_data_elements(output_size); 147 *out_mii_count);
222 const auto result = manager->Get(metadata, store_data_elements, mii_count, source_flag);
223 148
224 if (mii_count != 0) { 149 R_RETURN(result);
225 ctx.WriteBuffer(store_data_elements);
226 }
227
228 LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag,
229 output_size, mii_count);
230
231 IPC::ResponseBuilder rb{ctx, 3};
232 rb.Push(result);
233 rb.Push(mii_count);
234 } 150 }
235 151
236 void Get3(HLERequestContext& ctx) { 152 Result Get3(Out<u32> out_mii_count, SourceFlag source_flag,
237 IPC::RequestParser rp{ctx}; 153 OutArray<StoreData, BufferAttr_HipcMapAlias> store_data_buffer) {
238 const auto source_flag{rp.PopRaw<SourceFlag>()}; 154 const auto result = manager->Get(metadata, store_data_buffer, *out_mii_count, source_flag);
239 const auto output_size{ctx.GetWriteBufferNumElements<StoreData>()};
240
241 u32 mii_count{};
242 std::vector<StoreData> store_data(output_size);
243 const auto result = manager->Get(metadata, store_data, mii_count, source_flag);
244 155
245 if (mii_count != 0) { 156 LOG_INFO(Service_Mii, "called with source_flag={}, mii_count={}", source_flag,
246 ctx.WriteBuffer(store_data); 157 *out_mii_count);
247 }
248 158
249 LOG_INFO(Service_Mii, "called with source_flag={}, out_size={}, mii_count={}", source_flag, 159 R_RETURN(result);
250 output_size, mii_count);
251
252 IPC::ResponseBuilder rb{ctx, 3};
253 rb.Push(result);
254 rb.Push(mii_count);
255 } 160 }
256 161
257 void UpdateLatest1(HLERequestContext& ctx) { 162 Result UpdateLatest1(Out<StoreData> out_store_data, StoreData& store_data,
258 IPC::RequestParser rp{ctx}; 163 SourceFlag source_flag) {
259 const auto store_data{rp.PopRaw<StoreData>()};
260 const auto source_flag{rp.PopRaw<SourceFlag>()};
261
262 LOG_INFO(Service_Mii, "called with source_flag={}", source_flag); 164 LOG_INFO(Service_Mii, "called with source_flag={}", source_flag);
165 R_UNLESS(is_system, ResultPermissionDenied);
263 166
264 Result result = ResultSuccess; 167 R_RETURN(manager->UpdateLatest(metadata, *out_store_data, store_data, source_flag));
265 if (!is_system) {
266 result = ResultPermissionDenied;
267 }
268
269 StoreData new_store_data{};
270 if (result.IsSuccess()) {
271 result = manager->UpdateLatest(metadata, new_store_data, store_data, source_flag);
272 }
273
274 if (result.IsFailure()) {
275 IPC::ResponseBuilder rb{ctx, 2};
276 rb.Push(result);
277 return;
278 }
279
280 IPC::ResponseBuilder rb{ctx, 2 + sizeof(StoreData) / sizeof(u32)};
281 rb.Push(ResultSuccess);
282 rb.PushRaw<StoreData>(new_store_data);
283 } 168 }
284 169
285 void FindIndex(HLERequestContext& ctx) { 170 Result FindIndex(Out<s32> out_index, Common::UUID create_id, bool is_special) {
286 IPC::RequestParser rp{ctx};
287 const auto create_id{rp.PopRaw<Common::UUID>()};
288 const auto is_special{rp.PopRaw<bool>()};
289
290 LOG_INFO(Service_Mii, "called with create_id={}, is_special={}", 171 LOG_INFO(Service_Mii, "called with create_id={}, is_special={}",
291 create_id.FormattedString(), is_special); 172 create_id.FormattedString(), is_special);
292 173
293 const s32 index = manager->FindIndex(create_id, is_special); 174 *out_index = manager->FindIndex(create_id, is_special);
294 175
295 IPC::ResponseBuilder rb{ctx, 3}; 176 R_SUCCEED();
296 rb.Push(ResultSuccess);
297 rb.Push(index);
298 } 177 }
299 178
300 void Move(HLERequestContext& ctx) { 179 Result Move(Common::UUID create_id, s32 new_index) {
301 IPC::RequestParser rp{ctx};
302 const auto create_id{rp.PopRaw<Common::UUID>()};
303 const auto new_index{rp.PopRaw<s32>()};
304
305 LOG_INFO(Service_Mii, "called with create_id={}, new_index={}", create_id.FormattedString(), 180 LOG_INFO(Service_Mii, "called with create_id={}, new_index={}", create_id.FormattedString(),
306 new_index); 181 new_index);
182 R_UNLESS(is_system, ResultPermissionDenied);
307 183
308 Result result = ResultSuccess; 184 const u32 count = manager->GetCount(metadata, SourceFlag::Database);
309 if (!is_system) {
310 result = ResultPermissionDenied;
311 }
312 185
313 if (result.IsSuccess()) { 186 R_UNLESS(new_index >= 0 && new_index < static_cast<s32>(count), ResultInvalidArgument);
314 const u32 count = manager->GetCount(metadata, SourceFlag::Database);
315 if (new_index < 0 || new_index >= static_cast<s32>(count)) {
316 result = ResultInvalidArgument;
317 }
318 }
319 187
320 if (result.IsSuccess()) { 188 R_RETURN(manager->Move(metadata, new_index, create_id));
321 result = manager->Move(metadata, new_index, create_id);
322 }
323
324 IPC::ResponseBuilder rb{ctx, 2};
325 rb.Push(result);
326 } 189 }
327 190
328 void AddOrReplace(HLERequestContext& ctx) { 191 Result AddOrReplace(StoreData& store_data) {
329 IPC::RequestParser rp{ctx};
330 const auto store_data{rp.PopRaw<StoreData>()};
331
332 LOG_INFO(Service_Mii, "called"); 192 LOG_INFO(Service_Mii, "called");
193 R_UNLESS(is_system, ResultPermissionDenied);
333 194
334 Result result = ResultSuccess; 195 const auto result = manager->AddOrReplace(metadata, store_data);
335
336 if (!is_system) {
337 result = ResultPermissionDenied;
338 }
339 196
340 if (result.IsSuccess()) { 197 R_RETURN(result);
341 result = manager->AddOrReplace(metadata, store_data);
342 }
343
344 IPC::ResponseBuilder rb{ctx, 2};
345 rb.Push(result);
346 } 198 }
347 199
348 void Delete(HLERequestContext& ctx) { 200 Result Delete(Common::UUID create_id) {
349 IPC::RequestParser rp{ctx};
350 const auto create_id{rp.PopRaw<Common::UUID>()};
351
352 LOG_INFO(Service_Mii, "called, create_id={}", create_id.FormattedString()); 201 LOG_INFO(Service_Mii, "called, create_id={}", create_id.FormattedString());
202 R_UNLESS(is_system, ResultPermissionDenied);
353 203
354 Result result = ResultSuccess; 204 R_RETURN(manager->Delete(metadata, create_id));
355
356 if (!is_system) {
357 result = ResultPermissionDenied;
358 }
359
360 if (result.IsSuccess()) {
361 result = manager->Delete(metadata, create_id);
362 }
363
364 IPC::ResponseBuilder rb{ctx, 2};
365 rb.Push(result);
366 } 205 }
367 206
368 void DestroyFile(HLERequestContext& ctx) { 207 Result DestroyFile() {
369 // This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled"); 208 bool is_db_test_mode_enabled{};
370 const bool is_db_test_mode_enabled = false; 209 m_set_sys->GetSettingsItemValue(is_db_test_mode_enabled, "mii", "is_db_test_mode_enabled");
371 210
372 LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled); 211 LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled);
212 R_UNLESS(is_db_test_mode_enabled, ResultTestModeOnly);
373 213
374 Result result = ResultSuccess; 214 R_RETURN(manager->DestroyFile(metadata));
375
376 if (!is_db_test_mode_enabled) {
377 result = ResultTestModeOnly;
378 }
379
380 if (result.IsSuccess()) {
381 result = manager->DestroyFile(metadata);
382 }
383
384 IPC::ResponseBuilder rb{ctx, 2};
385 rb.Push(result);
386 } 215 }
387 216
388 void DeleteFile(HLERequestContext& ctx) { 217 Result DeleteFile() {
389 // This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled"); 218 bool is_db_test_mode_enabled{};
390 const bool is_db_test_mode_enabled = false; 219 m_set_sys->GetSettingsItemValue(is_db_test_mode_enabled, "mii", "is_db_test_mode_enabled");
391 220
392 LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled); 221 LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled);
222 R_UNLESS(is_db_test_mode_enabled, ResultTestModeOnly);
393 223
394 Result result = ResultSuccess; 224 R_RETURN(manager->DeleteFile());
395
396 if (!is_db_test_mode_enabled) {
397 result = ResultTestModeOnly;
398 }
399
400 if (result.IsSuccess()) {
401 result = manager->DeleteFile();
402 }
403
404 IPC::ResponseBuilder rb{ctx, 2};
405 rb.Push(result);
406 } 225 }
407 226
408 void Format(HLERequestContext& ctx) { 227 Result Format() {
409 // This calls nn::settings::fwdbg::GetSettingsItemValue("is_db_test_mode_enabled"); 228 bool is_db_test_mode_enabled{};
410 const bool is_db_test_mode_enabled = false; 229 m_set_sys->GetSettingsItemValue(is_db_test_mode_enabled, "mii", "is_db_test_mode_enabled");
411 230
412 LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled); 231 LOG_INFO(Service_Mii, "called is_db_test_mode_enabled={}", is_db_test_mode_enabled);
232 R_UNLESS(is_db_test_mode_enabled, ResultTestModeOnly);
413 233
414 Result result = ResultSuccess; 234 R_RETURN(manager->Format(metadata));
415
416 if (!is_db_test_mode_enabled) {
417 result = ResultTestModeOnly;
418 }
419
420 if (result.IsSuccess()) {
421 result = manager->Format(metadata);
422 }
423
424 IPC::ResponseBuilder rb{ctx, 2};
425 rb.Push(result);
426 } 235 }
427 236
428 void IsBrokenDatabaseWithClearFlag(HLERequestContext& ctx) { 237 Result IsBrokenDatabaseWithClearFlag(Out<bool> out_is_broken_with_clear_flag) {
429 LOG_DEBUG(Service_Mii, "called"); 238 LOG_DEBUG(Service_Mii, "called");
239 R_UNLESS(is_system, ResultPermissionDenied);
430 240
431 bool is_broken_with_clear_flag = false; 241 *out_is_broken_with_clear_flag = manager->IsBrokenWithClearFlag(metadata);
432 Result result = ResultSuccess;
433 242
434 if (!is_system) { 243 R_SUCCEED();
435 result = ResultPermissionDenied;
436 }
437
438 if (result.IsSuccess()) {
439 is_broken_with_clear_flag = manager->IsBrokenWithClearFlag(metadata);
440 }
441
442 IPC::ResponseBuilder rb{ctx, 3};
443 rb.Push(result);
444 rb.Push<u8>(is_broken_with_clear_flag);
445 } 244 }
446 245
447 void GetIndex(HLERequestContext& ctx) { 246 Result GetIndex(Out<s32> out_index, CharInfo& char_info) {
448 IPC::RequestParser rp{ctx};
449 const auto info{rp.PopRaw<CharInfo>()};
450
451 LOG_DEBUG(Service_Mii, "called"); 247 LOG_DEBUG(Service_Mii, "called");
452 248
453 s32 index{}; 249 R_RETURN(manager->GetIndex(metadata, char_info, *out_index));
454 const auto result = manager->GetIndex(metadata, info, index);
455
456 IPC::ResponseBuilder rb{ctx, 3};
457 rb.Push(result);
458 rb.Push(index);
459 } 250 }
460 251
461 void SetInterfaceVersion(HLERequestContext& ctx) { 252 Result SetInterfaceVersion(u32 interface_version) {
462 IPC::RequestParser rp{ctx};
463 const auto interface_version{rp.PopRaw<u32>()};
464
465 LOG_INFO(Service_Mii, "called, interface_version={:08X}", interface_version); 253 LOG_INFO(Service_Mii, "called, interface_version={:08X}", interface_version);
466 254
467 manager->SetInterfaceVersion(metadata, interface_version); 255 manager->SetInterfaceVersion(metadata, interface_version);
468 256
469 IPC::ResponseBuilder rb{ctx, 2}; 257 R_SUCCEED();
470 rb.Push(ResultSuccess);
471 } 258 }
472 259
473 void Convert(HLERequestContext& ctx) { 260 Result Convert(Out<CharInfo> out_char_info, Ver3StoreData& mii_v3) {
474 IPC::RequestParser rp{ctx};
475 const auto mii_v3{rp.PopRaw<Ver3StoreData>()};
476
477 LOG_INFO(Service_Mii, "called"); 261 LOG_INFO(Service_Mii, "called");
478 262
479 CharInfo char_info{}; 263 R_RETURN(manager->ConvertV3ToCharInfo(*out_char_info, mii_v3));
480 const auto result = manager->ConvertV3ToCharInfo(char_info, mii_v3);
481
482 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
483 rb.Push(result);
484 rb.PushRaw<CharInfo>(char_info);
485 } 264 }
486 265
487 void ConvertCoreDataToCharInfo(HLERequestContext& ctx) { 266 Result ConvertCoreDataToCharInfo(Out<CharInfo> out_char_info, CoreData& core_data) {
488 IPC::RequestParser rp{ctx};
489 const auto core_data{rp.PopRaw<CoreData>()};
490
491 LOG_INFO(Service_Mii, "called"); 267 LOG_INFO(Service_Mii, "called");
492 268
493 CharInfo char_info{}; 269 R_RETURN(manager->ConvertCoreDataToCharInfo(*out_char_info, core_data));
494 const auto result = manager->ConvertCoreDataToCharInfo(char_info, core_data);
495
496 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CharInfo) / sizeof(u32)};
497 rb.Push(result);
498 rb.PushRaw<CharInfo>(char_info);
499 } 270 }
500 271
501 void ConvertCharInfoToCoreData(HLERequestContext& ctx) { 272 Result ConvertCharInfoToCoreData(Out<CoreData> out_core_data, CharInfo& char_info) {
502 IPC::RequestParser rp{ctx};
503 const auto char_info{rp.PopRaw<CharInfo>()};
504
505 LOG_INFO(Service_Mii, "called"); 273 LOG_INFO(Service_Mii, "called");
506 274
507 CoreData core_data{}; 275 R_RETURN(manager->ConvertCharInfoToCoreData(*out_core_data, char_info));
508 const auto result = manager->ConvertCharInfoToCoreData(core_data, char_info);
509
510 IPC::ResponseBuilder rb{ctx, 2 + sizeof(CoreData) / sizeof(u32)};
511 rb.Push(result);
512 rb.PushRaw<CoreData>(core_data);
513 } 276 }
514 277
515 void Append(HLERequestContext& ctx) { 278 Result Append(CharInfo& char_info) {
516 IPC::RequestParser rp{ctx};
517 const auto char_info{rp.PopRaw<CharInfo>()};
518
519 LOG_INFO(Service_Mii, "called"); 279 LOG_INFO(Service_Mii, "called");
520 280
521 const auto result = manager->Append(metadata, char_info); 281 R_RETURN(manager->Append(metadata, char_info));
522
523 IPC::ResponseBuilder rb{ctx, 2};
524 rb.Push(result);
525 } 282 }
526 283
527 std::shared_ptr<MiiManager> manager = nullptr; 284 std::shared_ptr<MiiManager> manager = nullptr;
528 DatabaseSessionMetadata metadata{}; 285 DatabaseSessionMetadata metadata{};
529 bool is_system{}; 286 bool is_system{};
287
288 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
530}; 289};
531 290
532MiiDBModule::MiiDBModule(Core::System& system_, const char* name_, 291IStaticService::IStaticService(Core::System& system_, const char* name_,
533 std::shared_ptr<MiiManager> mii_manager, bool is_system_) 292 std::shared_ptr<MiiManager> mii_manager, bool is_system_)
534 : ServiceFramework{system_, name_}, manager{mii_manager}, is_system{is_system_} { 293 : ServiceFramework{system_, name_}, manager{mii_manager}, is_system{is_system_} {
535 // clang-format off 294 // clang-format off
536 static const FunctionInfo functions[] = { 295 static const FunctionInfo functions[] = {
537 {0, &MiiDBModule::GetDatabaseService, "GetDatabaseService"}, 296 {0, D<&IStaticService::GetDatabaseService>, "GetDatabaseService"},
538 }; 297 };
539 // clang-format on 298 // clang-format on
540 299
541 RegisterHandlers(functions); 300 RegisterHandlers(functions);
542
543 if (manager == nullptr) {
544 manager = std::make_shared<MiiManager>();
545 }
546} 301}
547 302
548MiiDBModule::~MiiDBModule() = default; 303IStaticService::~IStaticService() = default;
549
550void MiiDBModule::GetDatabaseService(HLERequestContext& ctx) {
551 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
552 rb.Push(ResultSuccess);
553 rb.PushIpcInterface<IDatabaseService>(system, manager, is_system);
554 304
305Result IStaticService::GetDatabaseService(
306 Out<SharedPointer<IDatabaseService>> out_database_service) {
555 LOG_DEBUG(Service_Mii, "called"); 307 LOG_DEBUG(Service_Mii, "called");
308
309 *out_database_service = std::make_shared<IDatabaseService>(system, manager, is_system);
310
311 R_SUCCEED();
556} 312}
557 313
558std::shared_ptr<MiiManager> MiiDBModule::GetMiiManager() { 314std::shared_ptr<MiiManager> IStaticService::GetMiiManager() {
559 return manager; 315 return manager;
560} 316}
561 317
562class MiiImg final : public ServiceFramework<MiiImg> { 318class IImageDatabaseService final : public ServiceFramework<IImageDatabaseService> {
563public: 319public:
564 explicit MiiImg(Core::System& system_) : ServiceFramework{system_, "miiimg"} { 320 explicit IImageDatabaseService(Core::System& system_) : ServiceFramework{system_, "miiimg"} {
565 // clang-format off 321 // clang-format off
566 static const FunctionInfo functions[] = { 322 static const FunctionInfo functions[] = {
567 {0, &MiiImg::Initialize, "Initialize"}, 323 {0, D<&IImageDatabaseService::Initialize>, "Initialize"},
568 {10, nullptr, "Reload"}, 324 {10, nullptr, "Reload"},
569 {11, &MiiImg::GetCount, "GetCount"}, 325 {11, D<&IImageDatabaseService::GetCount>, "GetCount"},
570 {12, nullptr, "IsEmpty"}, 326 {12, nullptr, "IsEmpty"},
571 {13, nullptr, "IsFull"}, 327 {13, nullptr, "IsFull"},
572 {14, nullptr, "GetAttribute"}, 328 {14, nullptr, "GetAttribute"},
@@ -585,31 +341,30 @@ public:
585 } 341 }
586 342
587private: 343private:
588 void Initialize(HLERequestContext& ctx) { 344 Result Initialize() {
589 LOG_INFO(Service_Mii, "called"); 345 LOG_INFO(Service_Mii, "called");
590 346
591 IPC::ResponseBuilder rb{ctx, 2}; 347 R_SUCCEED();
592 rb.Push(ResultSuccess);
593 } 348 }
594 349
595 void GetCount(HLERequestContext& ctx) { 350 Result GetCount(Out<u32> out_count) {
596 LOG_DEBUG(Service_Mii, "called"); 351 LOG_DEBUG(Service_Mii, "called");
597 352
598 IPC::ResponseBuilder rb{ctx, 3}; 353 *out_count = 0;
599 rb.Push(ResultSuccess); 354
600 rb.Push(0); 355 R_SUCCEED();
601 } 356 }
602}; 357};
603 358
604void LoopProcess(Core::System& system) { 359void LoopProcess(Core::System& system) {
605 auto server_manager = std::make_unique<ServerManager>(system); 360 auto server_manager = std::make_unique<ServerManager>(system);
606 std::shared_ptr<MiiManager> manager = nullptr; 361 std::shared_ptr<MiiManager> manager = std::make_shared<MiiManager>();
607 362
608 server_manager->RegisterNamedService( 363 server_manager->RegisterNamedService(
609 "mii:e", std::make_shared<MiiDBModule>(system, "mii:e", manager, true)); 364 "mii:e", std::make_shared<IStaticService>(system, "mii:e", manager, true));
610 server_manager->RegisterNamedService( 365 server_manager->RegisterNamedService(
611 "mii:u", std::make_shared<MiiDBModule>(system, "mii:u", manager, false)); 366 "mii:u", std::make_shared<IStaticService>(system, "mii:u", manager, false));
612 server_manager->RegisterNamedService("miiimg", std::make_shared<MiiImg>(system)); 367 server_manager->RegisterNamedService("miiimg", std::make_shared<IImageDatabaseService>(system));
613 ServerManager::RunServer(std::move(server_manager)); 368 ServerManager::RunServer(std::move(server_manager));
614} 369}
615 370
diff --git a/src/core/hle/service/mii/mii.h b/src/core/hle/service/mii/mii.h
index 9aa4426f6..8683ac1a5 100644
--- a/src/core/hle/service/mii/mii.h
+++ b/src/core/hle/service/mii/mii.h
@@ -3,7 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/service.h" 6#include "core/hle/service/cmif_types.h"
7 7
8namespace Core { 8namespace Core {
9class System; 9class System;
@@ -11,19 +11,20 @@ class System;
11 11
12namespace Service::Mii { 12namespace Service::Mii {
13class MiiManager; 13class MiiManager;
14class IDatabaseService;
14 15
15class MiiDBModule final : public ServiceFramework<MiiDBModule> { 16class IStaticService final : public ServiceFramework<IStaticService> {
16public: 17public:
17 explicit MiiDBModule(Core::System& system_, const char* name_, 18 explicit IStaticService(Core::System& system_, const char* name_,
18 std::shared_ptr<MiiManager> mii_manager, bool is_system_); 19 std::shared_ptr<MiiManager> mii_manager, bool is_system_);
19 ~MiiDBModule() override; 20 ~IStaticService() override;
20 21
21 std::shared_ptr<MiiManager> GetMiiManager(); 22 std::shared_ptr<MiiManager> GetMiiManager();
22 23
23private: 24private:
24 void GetDatabaseService(HLERequestContext& ctx); 25 Result GetDatabaseService(Out<SharedPointer<IDatabaseService>> out_database_service);
25 26
26 std::shared_ptr<MiiManager> manager = nullptr; 27 std::shared_ptr<MiiManager> manager{nullptr};
27 bool is_system{}; 28 bool is_system{};
28}; 29};
29 30
diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp
index 24350a1e5..100cb2db4 100644
--- a/src/core/hle/service/set/system_settings_server.cpp
+++ b/src/core/hle/service/set/system_settings_server.cpp
@@ -722,6 +722,9 @@ static Settings GetSettings() {
722 ret["hid_debug"]["disabled_features_per_id"] = std::vector<u8>(0xa8); 722 ret["hid_debug"]["disabled_features_per_id"] = std::vector<u8>(0xa8);
723 ret["hid_debug"]["touch_firmware_auto_update_disabled"] = ToBytes(bool{false}); 723 ret["hid_debug"]["touch_firmware_auto_update_disabled"] = ToBytes(bool{false});
724 724
725 // Mii
726 ret["mii"]["is_db_test_mode_enabled"] = ToBytes(bool{false});
727
725 // Settings 728 // Settings
726 ret["settings_debug"]["is_debug_mode_enabled"] = ToBytes(bool{false}); 729 ret["settings_debug"]["is_debug_mode_enabled"] = ToBytes(bool{false});
727 730