From 03d671fabc09e5d4f1032a4a0501a970598f9486 Mon Sep 17 00:00:00 2001
From: german77 <juangerman-13@hotmail.com>
Date: Sun, 27 Feb 2022 23:18:37 -0600
Subject: [PATCH] applet: mii: Simple implementation of mii applet

---
 src/core/CMakeLists.txt                       |   4 +
 src/core/frontend/applets/mii.cpp             |  19 ++++
 src/core/frontend/applets/mii.h               |  35 ++++++
 .../hle/service/am/applets/applet_mii.cpp     | 101 ++++++++++++++++++
 src/core/hle/service/am/applets/applet_mii.h  |  90 ++++++++++++++++
 src/core/hle/service/am/applets/applets.cpp   |  17 ++-
 src/core/hle/service/am/applets/applets.h     |   9 +-
 src/yuzu/main.cpp                             |   2 +
 8 files changed, 272 insertions(+), 5 deletions(-)
 create mode 100644 src/core/frontend/applets/mii.cpp
 create mode 100644 src/core/frontend/applets/mii.h
 create mode 100644 src/core/hle/service/am/applets/applet_mii.cpp
 create mode 100644 src/core/hle/service/am/applets/applet_mii.h

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 0c10cd019..7ed43bfb1 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -122,6 +122,8 @@ add_library(core STATIC
     frontend/applets/error.h
     frontend/applets/general_frontend.cpp
     frontend/applets/general_frontend.h
+    frontend/applets/mii.cpp
+    frontend/applets/mii.h
     frontend/applets/profile_select.cpp
     frontend/applets/profile_select.h
     frontend/applets/software_keyboard.cpp
@@ -298,6 +300,8 @@ add_library(core STATIC
     hle/service/am/applets/applet_error.h
     hle/service/am/applets/applet_general_backend.cpp
     hle/service/am/applets/applet_general_backend.h
+    hle/service/am/applets/applet_mii.cpp
+    hle/service/am/applets/applet_mii.h
     hle/service/am/applets/applet_profile_select.cpp
     hle/service/am/applets/applet_profile_select.h
     hle/service/am/applets/applet_software_keyboard.cpp
diff --git a/src/core/frontend/applets/mii.cpp b/src/core/frontend/applets/mii.cpp
new file mode 100644
index 000000000..1c05ff412
--- /dev/null
+++ b/src/core/frontend/applets/mii.cpp
@@ -0,0 +1,19 @@
+// Copyright 2022 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+#include "core/frontend/applets/mii.h"
+
+namespace Core::Frontend {
+
+MiiApplet::~MiiApplet() = default;
+
+void DefaultMiiApplet::ShowMii(
+    const MiiParameters& parameters,
+    const std::function<void(const Core::Frontend::MiiParameters& parameters)> callback) const {
+    LOG_INFO(Service_HID, "(STUBBED) called");
+    callback(parameters);
+}
+
+} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/mii.h b/src/core/frontend/applets/mii.h
new file mode 100644
index 000000000..1fc40a9c6
--- /dev/null
+++ b/src/core/frontend/applets/mii.h
@@ -0,0 +1,35 @@
+// Copyright 2022 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <functional>
+
+#include "core/hle/result.h"
+#include "core/hle/service/mii/mii_manager.h"
+
+namespace Core::Frontend {
+
+struct MiiParameters {
+    bool is_editable;
+    Service::Mii::MiiInfo mii_data{};
+};
+
+class MiiApplet {
+public:
+    virtual ~MiiApplet();
+
+    virtual void ShowMii(const MiiParameters& parameters,
+                         const std::function<void(const Core::Frontend::MiiParameters& parameters)>
+                             callback) const = 0;
+};
+
+class DefaultMiiApplet final : public MiiApplet {
+public:
+    void ShowMii(const MiiParameters& parameters,
+                 const std::function<void(const Core::Frontend::MiiParameters& parameters)>
+                     callback) const override;
+};
+
+} // namespace Core::Frontend
diff --git a/src/core/hle/service/am/applets/applet_mii.cpp b/src/core/hle/service/am/applets/applet_mii.cpp
new file mode 100644
index 000000000..8c4173737
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_mii.cpp
@@ -0,0 +1,101 @@
+// Copyright 2022 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/frontend/applets/mii.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/am/applets/applet_mii.h"
+#include "core/reporter.h"
+
+namespace Service::AM::Applets {
+
+Mii::Mii(Core::System& system_, LibraryAppletMode applet_mode_,
+         const Core::Frontend::MiiApplet& frontend_)
+    : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
+
+Mii::~Mii() = default;
+
+void Mii::Initialize() {
+    is_complete = false;
+
+    const auto storage = broker.PopNormalDataToApplet();
+    ASSERT(storage != nullptr);
+
+    const auto data = storage->GetData();
+    ASSERT(data.size() == sizeof(MiiAppletInput));
+
+    std::memcpy(&input_data, data.data(), sizeof(MiiAppletInput));
+}
+
+bool Mii::TransactionComplete() const {
+    return is_complete;
+}
+
+ResultCode Mii::GetStatus() const {
+    return ResultSuccess;
+}
+
+void Mii::ExecuteInteractive() {
+    UNREACHABLE_MSG("Unexpected interactive applet data!");
+}
+
+void Mii::Execute() {
+    if (is_complete) {
+        return;
+    }
+
+    const auto callback = [this](const Core::Frontend::MiiParameters& parameters) {
+        DisplayCompleted(parameters);
+    };
+
+    switch (input_data.applet_mode) {
+    case MiiAppletMode::ShowMiiEdit: {
+        Service::Mii::MiiManager manager;
+        Core::Frontend::MiiParameters params{
+            .is_editable = false,
+            .mii_data = input_data.mii_char_info.mii_data,
+        };
+        frontend.ShowMii(params, callback);
+        break;
+    }
+    case MiiAppletMode::EditMii: {
+        Service::Mii::MiiManager manager;
+        Core::Frontend::MiiParameters params{
+            .is_editable = true,
+            .mii_data = input_data.mii_char_info.mii_data,
+        };
+        frontend.ShowMii(params, callback);
+        break;
+    }
+    case MiiAppletMode::CreateMii: {
+        Service::Mii::MiiManager manager;
+        Core::Frontend::MiiParameters params{
+            .is_editable = true,
+            .mii_data = manager.BuildDefault(0),
+        };
+        frontend.ShowMii(params, callback);
+        break;
+    }
+    default:
+        UNIMPLEMENTED_MSG("Unimplemented LibAppletMiiEdit mode={:02X}!", input_data.applet_mode);
+    }
+}
+
+void Mii::DisplayCompleted(const Core::Frontend::MiiParameters& parameters) {
+    is_complete = true;
+
+    std::vector<u8> reply(sizeof(AppletOutputForCharInfoEditing));
+    output_data = {
+        .result = ResultSuccess,
+        .mii_data = parameters.mii_data,
+    };
+
+    std::memcpy(reply.data(), &output_data, sizeof(AppletOutputForCharInfoEditing));
+    broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(reply)));
+    broker.SignalStateChanged();
+}
+
+} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_mii.h b/src/core/hle/service/am/applets/applet_mii.h
new file mode 100644
index 000000000..42326bfc2
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_mii.h
@@ -0,0 +1,90 @@
+// Copyright 2022 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+
+#include "core/hle/result.h"
+#include "core/hle/service/am/applets/applets.h"
+#include "core/hle/service/mii/mii_manager.h"
+
+namespace Core {
+class System;
+}
+
+namespace Service::AM::Applets {
+
+// This is nn::mii::AppletMode
+enum class MiiAppletMode : u32 {
+    ShowMiiEdit = 0,
+    AppendMii = 1,
+    AppendMiiImage = 2,
+    UpdateMiiImage = 3,
+    CreateMii = 4,
+    EditMii = 5,
+};
+
+struct MiiCharInfo {
+    Service::Mii::MiiInfo mii_data{};
+    INSERT_PADDING_BYTES(0x28);
+};
+static_assert(sizeof(MiiCharInfo) == 0x80, "MiiCharInfo has incorrect size.");
+
+// This is nn::mii::AppletInput
+struct MiiAppletInput {
+    s32 version{};
+    MiiAppletMode applet_mode{};
+    u32 special_mii_key_code{};
+    union {
+        std::array<Common::UUID, 8> valid_uuid;
+        MiiCharInfo mii_char_info;
+    };
+    Common::UUID used_uuid;
+    INSERT_PADDING_BYTES(0x64);
+};
+static_assert(sizeof(MiiAppletInput) == 0x100, "MiiAppletInput has incorrect size.");
+
+// This is nn::mii::AppletOutput
+struct MiiAppletOutput {
+    ResultCode result{ResultSuccess};
+    s32 index{};
+    INSERT_PADDING_BYTES(0x18);
+};
+static_assert(sizeof(MiiAppletOutput) == 0x20, "MiiAppletOutput has incorrect size.");
+
+// This is nn::mii::AppletOutputForCharInfoEditing
+struct AppletOutputForCharInfoEditing {
+    ResultCode result{ResultSuccess};
+    Service::Mii::MiiInfo mii_data{};
+    INSERT_PADDING_BYTES(0x24);
+};
+static_assert(sizeof(AppletOutputForCharInfoEditing) == 0x80,
+              "AppletOutputForCharInfoEditing has incorrect size.");
+
+class Mii final : public Applet {
+public:
+    explicit Mii(Core::System& system_, LibraryAppletMode applet_mode_,
+                 const Core::Frontend::MiiApplet& frontend_);
+    ~Mii() override;
+
+    void Initialize() override;
+
+    bool TransactionComplete() const override;
+    ResultCode GetStatus() const override;
+    void ExecuteInteractive() override;
+    void Execute() override;
+
+    void DisplayCompleted(const Core::Frontend::MiiParameters& parameters);
+
+private:
+    const Core::Frontend::MiiApplet& frontend;
+    MiiAppletInput input_data{};
+    AppletOutputForCharInfoEditing output_data{};
+
+    bool is_complete = false;
+    Core::System& system;
+};
+
+} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index 134ac1ee2..79e62679d 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -9,6 +9,7 @@
 #include "core/frontend/applets/controller.h"
 #include "core/frontend/applets/error.h"
 #include "core/frontend/applets/general_frontend.h"
+#include "core/frontend/applets/mii.h"
 #include "core/frontend/applets/profile_select.h"
 #include "core/frontend/applets/software_keyboard.h"
 #include "core/frontend/applets/web_browser.h"
@@ -19,6 +20,7 @@
 #include "core/hle/service/am/applets/applet_controller.h"
 #include "core/hle/service/am/applets/applet_error.h"
 #include "core/hle/service/am/applets/applet_general_backend.h"
+#include "core/hle/service/am/applets/applet_mii.h"
 #include "core/hle/service/am/applets/applet_profile_select.h"
 #include "core/hle/service/am/applets/applet_software_keyboard.h"
 #include "core/hle/service/am/applets/applet_web_browser.h"
@@ -172,10 +174,11 @@ AppletFrontendSet::AppletFrontendSet() = default;
 
 AppletFrontendSet::AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet,
                                      ParentalControlsApplet parental_controls_applet,
-                                     PhotoViewer photo_viewer_, ProfileSelect profile_select_,
+                                     MiiApplet mii_applet, PhotoViewer photo_viewer_,
+                                     ProfileSelect profile_select_,
                                      SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
     : controller{std::move(controller_applet)}, error{std::move(error_applet)},
-      parental_controls{std::move(parental_controls_applet)},
+      parental_controls{std::move(parental_controls_applet)}, mii{std::move(mii_applet)},
       photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
       software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
 
@@ -206,6 +209,10 @@ void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
         frontend.parental_controls = std::move(set.parental_controls);
     }
 
+    if (set.mii != nullptr) {
+        frontend.mii = std::move(set.mii);
+    }
+
     if (set.photo_viewer != nullptr) {
         frontend.photo_viewer = std::move(set.photo_viewer);
     }
@@ -243,6 +250,10 @@ void AppletManager::SetDefaultAppletsIfMissing() {
             std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
     }
 
+    if (frontend.mii == nullptr) {
+        frontend.mii = std::make_unique<Core::Frontend::DefaultMiiApplet>();
+    }
+
     if (frontend.photo_viewer == nullptr) {
         frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
     }
@@ -277,6 +288,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode
         return std::make_shared<ProfileSelect>(system, mode, *frontend.profile_select);
     case AppletId::SoftwareKeyboard:
         return std::make_shared<SoftwareKeyboard>(system, mode, *frontend.software_keyboard);
+    case AppletId::MiiEdit:
+        return std::make_shared<Mii>(system, mode, *frontend.mii);
     case AppletId::Web:
     case AppletId::Shop:
     case AppletId::OfflineWeb:
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 15eeb4ee1..0c44aec79 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -21,6 +21,7 @@ class ControllerApplet;
 class ECommerceApplet;
 class ErrorApplet;
 class ParentalControlsApplet;
+class MiiApplet;
 class PhotoViewerApplet;
 class ProfileSelectApplet;
 class SoftwareKeyboardApplet;
@@ -179,6 +180,7 @@ struct AppletFrontendSet {
     using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
     using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
     using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
+    using MiiApplet = std::unique_ptr<Core::Frontend::MiiApplet>;
     using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
     using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
     using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
@@ -186,9 +188,9 @@ struct AppletFrontendSet {
 
     AppletFrontendSet();
     AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet,
-                      ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
-                      ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
-                      WebBrowser web_browser_);
+                      ParentalControlsApplet parental_controls_applet, MiiApplet mii_applet,
+                      PhotoViewer photo_viewer_, ProfileSelect profile_select_,
+                      SoftwareKeyboard software_keyboard_, WebBrowser web_browser_);
     ~AppletFrontendSet();
 
     AppletFrontendSet(const AppletFrontendSet&) = delete;
@@ -200,6 +202,7 @@ struct AppletFrontendSet {
     ControllerApplet controller;
     ErrorApplet error;
     ParentalControlsApplet parental_controls;
+    MiiApplet mii;
     PhotoViewer photo_viewer;
     ProfileSelect profile_select;
     SoftwareKeyboard software_keyboard;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index b3a8da0ea..d573829be 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -25,6 +25,7 @@
 #include "core/file_sys/vfs_real.h"
 #include "core/frontend/applets/controller.h"
 #include "core/frontend/applets/general_frontend.h"
+#include "core/frontend/applets/mii.h"
 #include "core/frontend/applets/software_keyboard.h"
 #include "core/hid/emulated_controller.h"
 #include "core/hid/hid_core.h"
@@ -1285,6 +1286,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
         std::make_unique<QtControllerSelector>(*this), // Controller Selector
         std::make_unique<QtErrorDisplay>(*this),       // Error Display
         nullptr,                                       // Parental Controls
+        nullptr,                                       // Mii editor
         nullptr,                                       // Photo Viewer
         std::make_unique<QtProfileSelector>(*this),    // Profile Selector
         std::make_unique<QtSoftwareKeyboard>(*this),   // Software Keyboard