From 22c4eb86d7d103d9708cfe9cb2a359ff19f3ae4c Mon Sep 17 00:00:00 2001
From: Tobias <thm.frey@gmail.com>
Date: Sun, 30 Jul 2023 04:18:52 +0200
Subject: [PATCH] core/frd: Correct FunctionInfo and stub more functions
 (#6209)

---
 src/core/hle/service/frd/frd.cpp   | 39 ++++++++++++++++++++++++++++++
 src/core/hle/service/frd/frd.h     | 36 +++++++++++++++++++++++++++
 src/core/hle/service/frd/frd_a.cpp | 14 ++++++++---
 src/core/hle/service/frd/frd_u.cpp |  6 ++---
 4 files changed, 89 insertions(+), 6 deletions(-)

diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp
index e3629a996..a8628b315 100644
--- a/src/core/hle/service/frd/frd.cpp
+++ b/src/core/hle/service/frd/frd.cpp
@@ -10,6 +10,7 @@
 #include "common/string_util.h"
 #include "core/core.h"
 #include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/event.h"
 #include "core/hle/result.h"
 #include "core/hle/service/cfg/cfg.h"
 #include "core/hle/service/frd/frd.h"
@@ -157,6 +158,44 @@ void Module::Interface::SetClientSdkVersion(Kernel::HLERequestContext& ctx) {
     LOG_WARNING(Service_FRD, "(STUBBED) called, version: 0x{:08X}", version);
 }
 
+void Module::Interface::HasLoggedIn(Kernel::HLERequestContext& ctx) {
+    LOG_WARNING(Service_FRD, "(STUBBED) called");
+
+    IPC::RequestParser rp(ctx);
+    IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
+    rb.Push(RESULT_SUCCESS);
+    rb.Push(frd->logged_in);
+}
+
+void Module::Interface::Login(Kernel::HLERequestContext& ctx) {
+    LOG_WARNING(Service_FRD, "(STUBBED) called");
+
+    IPC::RequestParser rp(ctx);
+    frd->login_event = rp.PopObject<Kernel::Event>();
+
+    constexpr auto login_delay_ms = 500;
+    frd->login_delay_event = frd->system.CoreTiming().RegisterEvent(
+        "frd::login_event",
+        // Simulate a small login delay
+        [this](u64 thread_id, s64 cycle_late) {
+            frd->logged_in = true;
+            frd->login_event->Signal();
+            frd->system.CoreTiming().RemoveEvent(frd->login_delay_event);
+        });
+    frd->system.CoreTiming().ScheduleEvent(msToCycles(login_delay_ms), frd->login_delay_event);
+
+    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Module::Interface::GetLastResponseResult(Kernel::HLERequestContext& ctx) {
+    LOG_WARNING(Service_FRD, "(STUBBED) called");
+
+    IPC::RequestParser rp(ctx);
+    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
+    rb.Push(RESULT_SUCCESS);
+}
+
 Module::Module(Core::System& system) : system(system){};
 Module::~Module() = default;
 
diff --git a/src/core/hle/service/frd/frd.h b/src/core/hle/service/frd/frd.h
index 16902e45d..064e7f7f1 100644
--- a/src/core/hle/service/frd/frd.h
+++ b/src/core/hle/service/frd/frd.h
@@ -12,6 +12,10 @@ namespace Core {
 class System;
 }
 
+namespace Kernel {
+class Event;
+}
+
 namespace Service::FRD {
 
 struct FriendKey {
@@ -146,6 +150,34 @@ public:
          */
         void SetClientSdkVersion(Kernel::HLERequestContext& ctx);
 
+        /**
+         * FRD::Login service function
+         *  Inputs:
+         *      65 : Address of unknown event
+         *  Outputs:
+         *      1  : Result of function, 0 on success, otherwise error code
+         */
+        void Login(Kernel::HLERequestContext& ctx);
+
+        /**
+         * FRD::HasLoggedIn service function
+         *  Inputs:
+         *      none
+         *  Outputs:
+         *      1 : Result of function, 0 on success, otherwise error code
+         *      2 : If the user has logged in 1, otherwise 0
+         */
+        void HasLoggedIn(Kernel::HLERequestContext& ctx);
+
+        /**
+         * FRD::GetLastResponseResult service function
+         *  Inputs:
+         *      none
+         *  Outputs:
+         *      1 : Result of function, 0 on success, otherwise error code
+         */
+        void GetLastResponseResult(Kernel::HLERequestContext& ctx);
+
     protected:
         std::shared_ptr<Module> frd;
     };
@@ -153,12 +185,16 @@ public:
 private:
     FriendKey my_friend_key = {0, 0, 0ull};
     MyPresence my_presence = {};
+    bool logged_in = false;
+    std::shared_ptr<Kernel::Event> login_event;
+    Core::TimingEventType* login_delay_event;
     Core::System& system;
 
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
         ar& my_friend_key;
         ar& my_presence;
+        ar& logged_in;
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/service/frd/frd_a.cpp b/src/core/hle/service/frd/frd_a.cpp
index 4fcf04b94..f0d95e8da 100644
--- a/src/core/hle/service/frd/frd_a.cpp
+++ b/src/core/hle/service/frd/frd_a.cpp
@@ -11,9 +11,9 @@ namespace Service::FRD {
 
 FRD_A::FRD_A(std::shared_ptr<Module> frd) : Module::Interface(std::move(frd), "frd:a", 8) {
     static const FunctionInfo functions[] = {
-        {0x0001, nullptr, "HasLoggedIn"},
+        {0x0001, &FRD_A::HasLoggedIn, "HasLoggedIn"},
         {0x0002, nullptr, "IsOnline"},
-        {0x0003, nullptr, "Login"},
+        {0x0003, &FRD_A::Login, "Login"},
         {0x0004, nullptr, "Logout"},
         {0x0005, &FRD_A::GetMyFriendKey, "GetMyFriendKey"},
         {0x0006, nullptr, "GetMyPreference"},
@@ -45,7 +45,7 @@ FRD_A::FRD_A(std::shared_ptr<Module> frd) : Module::Interface(std::move(frd), "f
         {0x0020, nullptr, "AttachToEventNotification"},
         {0x0021, nullptr, "SetNotificationMask"},
         {0x0022, nullptr, "GetEventNotification"},
-        {0x0023, nullptr, "GetLastResponseResult"},
+        {0x0023, &FRD_A::GetLastResponseResult, "GetLastResponseResult"},
         {0x0024, nullptr, "PrincipalIdToFriendCode"},
         {0x0025, nullptr, "FriendCodeToPrincipalId"},
         {0x0026, nullptr, "IsValidFriendCode"},
@@ -64,6 +64,14 @@ FRD_A::FRD_A(std::shared_ptr<Module> frd) : Module::Interface(std::move(frd), "f
         {0x0033, nullptr, "GetMyApproachContext"},
         {0x0034, nullptr, "AddFriendWithApproach"},
         {0x0035, nullptr, "DecryptApproachContext"},
+        {0x0406, nullptr, "AddFriendOnline"},
+        {0x0409, nullptr, "RemoveFriend"},
+        {0x040a, nullptr, "UpdatePlayingGame"},
+        {0x040b, nullptr, "UpdatePreference"},
+        {0x040c, nullptr, "UpdateMii"},
+        {0x040d, nullptr, "UpdateFavoriteGame"},
+        {0x040e, nullptr, "UpdateNcPrincipalId"},
+        {0x040f, nullptr, "UpdateComment"},
     };
     RegisterHandlers(functions);
 }
diff --git a/src/core/hle/service/frd/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp
index 46e5f23c3..33b6b6f3f 100644
--- a/src/core/hle/service/frd/frd_u.cpp
+++ b/src/core/hle/service/frd/frd_u.cpp
@@ -11,9 +11,9 @@ namespace Service::FRD {
 
 FRD_U::FRD_U(std::shared_ptr<Module> frd) : Module::Interface(std::move(frd), "frd:u", 8) {
     static const FunctionInfo functions[] = {
-        {0x0001, nullptr, "HasLoggedIn"},
+        {0x0001, &FRD_U::HasLoggedIn, "HasLoggedIn"},
         {0x0002, nullptr, "IsOnline"},
-        {0x0003, nullptr, "Login"},
+        {0x0003, &FRD_U::Login, "Login"},
         {0x0004, nullptr, "Logout"},
         {0x0005, &FRD_U::GetMyFriendKey, "GetMyFriendKey"},
         {0x0006, nullptr, "GetMyPreference"},
@@ -45,7 +45,7 @@ FRD_U::FRD_U(std::shared_ptr<Module> frd) : Module::Interface(std::move(frd), "f
         {0x0020, nullptr, "AttachToEventNotification"},
         {0x0021, nullptr, "SetNotificationMask"},
         {0x0022, nullptr, "GetEventNotification"},
-        {0x0023, nullptr, "GetLastResponseResult"},
+        {0x0023, &FRD_U::GetLastResponseResult, "GetLastResponseResult"},
         {0x0024, nullptr, "PrincipalIdToFriendCode"},
         {0x0025, nullptr, "FriendCodeToPrincipalId"},
         {0x0026, nullptr, "IsValidFriendCode"},