#include "Cafe/OS/common/OSCommon.h" #include "Cafe/IOSU/legacy/iosu_act.h" #include "Cafe/IOSU/legacy/iosu_fpd.h" #include "Cafe/IOSU/legacy/iosu_ioctl.h" // deprecated #include "Cafe/IOSU/iosu_ipc_common.h" #include "Cafe/OS/libs/coreinit/coreinit_IOS.h" #include "Cafe/OS/libs/coreinit/coreinit_IPC.h" #include "Cafe/OS/libs/nn_common.h" #include "util/ChunkedHeap/ChunkedHeap.h" #include "Common/CafeString.h" namespace nn { namespace fp { static const auto FPResult_OkZero = 0; static const auto FPResult_Ok = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_FP, 0); static const auto FPResult_InvalidIPCParam = BUILD_NN_RESULT(NN_RESULT_LEVEL_LVL6, NN_RESULT_MODULE_NN_FP, 0x680); static const auto FPResult_RequestFailed = BUILD_NN_RESULT(NN_RESULT_LEVEL_FATAL, NN_RESULT_MODULE_NN_FP, 0); // figure out proper error code struct { uint32 initCounter; bool isAdminMode; bool isLoggedIn; IOSDevHandle fpdHandle; SysAllocator fpMutex; SysAllocator g_fpdAllocatorSpace; VHeap* fpBufferHeap{nullptr}; // PPC buffers for async notification query SysAllocator notificationCount; SysAllocator notificationBuffer; bool getNotificationCalled{false}; // notification handler MEMPTR notificationHandler{nullptr}; MEMPTR notificationHandlerParam{nullptr}; }g_fp = { }; class { public: void Init() { std::unique_lock _l(m_mtx); g_fp.fpBufferHeap = new VHeap(g_fp.g_fpdAllocatorSpace.GetPtr(), g_fp.g_fpdAllocatorSpace.GetByteSize()); } void Destroy() { std::unique_lock _l(m_mtx); delete g_fp.fpBufferHeap; } void* Allocate(uint32 size, uint32 alignment) { std::unique_lock _l(m_mtx); void* p = g_fp.fpBufferHeap->alloc(size, 32); if (!p) cemuLog_log(LogType::Force, "nn_fp: Internal heap is full"); return p; } void Free(void* ptr) { std::unique_lock _l(m_mtx); g_fp.fpBufferHeap->free(ptr); } private: std::mutex m_mtx; }FPIpcBufferAllocator; class FPIpcContext { static inline constexpr uint32 MAX_VEC_COUNT = 8; public: // use FP heap for this class static void* operator new(size_t size) { return FPIpcBufferAllocator.Allocate(size, (uint32)alignof(FPIpcContext)); } static void operator delete(void* ptr) { FPIpcBufferAllocator.Free(ptr); } FPIpcContext(iosu::fpd::FPD_REQUEST_ID requestId) : m_requestId(requestId) { } ~FPIpcContext() { if(m_dataBuffer) FPIpcBufferAllocator.Free(m_dataBuffer); } void AddInput(void* ptr, uint32 size) { size_t vecIndex = GetVecInIndex(m_numVecIn); m_vec[vecIndex].baseVirt = ptr; m_vec[vecIndex].size = size; m_numVecIn = m_numVecIn + 1; } void AddOutput(void* ptr, uint32 size) { cemu_assert_debug(m_numVecIn == 0); // all outputs need to be added before any inputs size_t vecIndex = GetVecOutIndex(m_numVecOut); m_vec[vecIndex].baseVirt = ptr; m_vec[vecIndex].size = size; m_numVecOut = m_numVecOut + 1; } uint32 Submit(std::unique_ptr owner) { InitSubmissionBuffer(); // note: While generally, Ioctlv() usage has the order as input (app->IOSU) followed by output (IOSU->app), FP uses it the other way around nnResult r = coreinit::IOS_Ioctlv(g_fp.fpdHandle, (uint32)m_requestId.value(), m_numVecOut, m_numVecIn, m_vec); CopyBackOutputs(); owner.reset(); return r; } nnResult SubmitAsync(std::unique_ptr owner, MEMPTR callbackFunc, MEMPTR callbackParam) { InitSubmissionBuffer(); this->m_callbackFunc = callbackFunc; this->m_callbackParam = callbackParam; nnResult r = coreinit::IOS_IoctlvAsync(g_fp.fpdHandle, (uint32)m_requestId.value(), m_numVecOut, m_numVecIn, m_vec, MEMPTR(PPCInterpreter_makeCallableExportDepr(AsyncHandler)), MEMPTR(this)); owner.release(); return r; } private: size_t GetVecInIndex(uint8 inIndex) { return m_numVecOut + inIndex; } size_t GetVecOutIndex(uint8 outIndex) { return outIndex; } void InitSubmissionBuffer() { // allocate a chunk of memory to hold the input/output vectors and their data uint32 vecOffset[MAX_VEC_COUNT]; uint32 totalBufferSize = 0; for(uint8 i=0; i 0) { m_dataBuffer = FPIpcBufferAllocator.Allocate(totalBufferSize, 32); cemu_assert_debug(m_dataBuffer); } // update Ioctl vector addresses for(uint8 i=0; i(m_vec[vecIndex].baseVirt).GetPtr(), MEMPTR(m_vecOriginalAddress[vecIndex]).GetPtr(), m_vec[vecIndex].size); } } static void AsyncHandler(PPCInterpreter_t* hCPU) { ppcDefineParamU32(result, 0); ppcDefineParamPtr(ipcCtx, FPIpcContext, 1); ipcCtx->m_asyncResult = result; // store result in variable since FP callbacks pass a pointer to nnResult and not the value directly ipcCtx->CopyBackOutputs(); PPCCoreCallback(ipcCtx->m_callbackFunc, &ipcCtx->m_asyncResult, ipcCtx->m_callbackParam); delete ipcCtx; osLib_returnFromFunction(hCPU, 0); } void CopyBackOutputs() { if(m_numVecOut > 0) { // copy output from temporary output buffers to the original addresses for(uint8 i=0; i m_requestId; uint8be m_numVecIn{0}; uint8be m_numVecOut{0}; IPCIoctlVector m_vec[MAX_VEC_COUNT]; MEMPTR m_vecOriginalAddress[MAX_VEC_COUNT]{}; MEMPTR m_dataBuffer{nullptr}; MEMPTR m_callbackFunc{nullptr}; MEMPTR m_callbackParam{nullptr}; betype m_asyncResult; }; struct FPGlobalLock { FPGlobalLock() { coreinit::OSLockMutex(&g_fp.fpMutex); } ~FPGlobalLock() { coreinit::OSUnlockMutex(&g_fp.fpMutex); } }; #define FP_API_BASE() if (g_fp.initCounter == 0) return 0xC0C00580; FPGlobalLock _fpLock; #define FP_API_BASE_ZeroOnError() if (g_fp.initCounter == 0) return 0; FPGlobalLock _fpLock; nnResult Initialize() { FPGlobalLock _fpLock; if (g_fp.initCounter == 0) { g_fp.fpdHandle = coreinit::IOS_Open("/dev/fpd", 0); } g_fp.initCounter++; return FPResult_OkZero; } uint32 IsInitialized() { FPGlobalLock _fpLock; return g_fp.initCounter > 0 ? 1 : 0; } nnResult InitializeAdmin(PPCInterpreter_t* hCPU) { FPGlobalLock _fpLock; g_fp.isAdminMode = true; return Initialize(); } uint32 IsInitializedAdmin() { FPGlobalLock _fpLock; return g_fp.initCounter > 0 ? 1 : 0; } nnResult Finalize() { FPGlobalLock _fpLock; if (g_fp.initCounter == 1) { g_fp.initCounter = 0; g_fp.isAdminMode = false; g_fp.isLoggedIn = false; coreinit::IOS_Close(g_fp.fpdHandle); g_fp.getNotificationCalled = false; } else if (g_fp.initCounter > 0) g_fp.initCounter--; return FPResult_OkZero; } nnResult FinalizeAdmin() { return Finalize(); } void GetNextNotificationAsync(); nnResult SetNotificationHandler(uint32 notificationMask, void* funcPtr, void* userParam) { FP_API_BASE(); g_fp.notificationHandler = funcPtr; g_fp.notificationHandlerParam = userParam; StackAllocator notificationMaskBuf; notificationMaskBuf = notificationMask; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::SetNotificationMask); ipcCtx->AddInput(¬ificationMaskBuf, sizeof(uint32be)); nnResult r = ipcCtx->Submit(std::move(ipcCtx)); if (NN_RESULT_IS_SUCCESS(r)) { // async query for notifications GetNextNotificationAsync(); } return r; } void GetNextNotificationAsyncHandler(PPCInterpreter_t* hCPU) { coreinit::OSLockMutex(&g_fp.fpMutex); cemu_assert_debug(g_fp.getNotificationCalled); g_fp.getNotificationCalled = false; auto bufPtr = g_fp.notificationBuffer.GetPtr(); uint32 count = g_fp.notificationCount->value(); if (count == 0) { GetNextNotificationAsync(); coreinit::OSUnlockMutex(&g_fp.fpMutex); osLib_returnFromFunction(hCPU, 0); return; } // copy notifications to temporary buffer using std::copy iosu::fpd::FPDNotification tempBuffer[256]; std::copy(g_fp.notificationBuffer.GetPtr(), g_fp.notificationBuffer.GetPtr() + count, tempBuffer); // call handler for each notification, but do it outside of the lock void* notificationHandler = g_fp.notificationHandler; void* notificationHandlerParam = g_fp.notificationHandlerParam; coreinit::OSUnlockMutex(&g_fp.fpMutex); iosu::fpd::FPDNotification* notificationBuffer = g_fp.notificationBuffer.GetPtr(); for (uint32 i = 0; i < count; i++) PPCCoreCallback(notificationHandler, (uint32)notificationBuffer[i].type, notificationBuffer[i].pid, notificationHandlerParam); coreinit::OSLockMutex(&g_fp.fpMutex); // query more notifications GetNextNotificationAsync(); coreinit::OSUnlockMutex(&g_fp.fpMutex); osLib_returnFromFunction(hCPU, 0); } void GetNextNotificationAsync() { if (g_fp.getNotificationCalled) return; g_fp.getNotificationCalled = true; g_fp.notificationCount = 0; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetNotificationAsync); ipcCtx->AddOutput(g_fp.notificationBuffer.GetPtr(), g_fp.notificationBuffer.GetByteSize()); ipcCtx->AddOutput(g_fp.notificationCount.GetPtr(), sizeof(uint32be)); cemu_assert_debug(g_fp.notificationBuffer.GetByteSize() == 0x800); nnResult r = ipcCtx->SubmitAsync(std::move(ipcCtx), MEMPTR(PPCInterpreter_makeCallableExportDepr(GetNextNotificationAsyncHandler)), nullptr); } nnResult LoginAsync(void* funcPtr, void* userParam) { FP_API_BASE(); auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::LoginAsync); return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, userParam); } uint32 HasLoggedIn() { FP_API_BASE_ZeroOnError(); // Sonic All Star Racing uses this // and Monster Hunter 3 Ultimate needs this to return false at least once to initiate login and not get stuck // this returns false until LoginAsync was called and has completed (?) even if the user is already logged in StackAllocator resultBuf; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::HasLoggedIn); ipcCtx->AddOutput(&resultBuf, sizeof(uint32be)); ipcCtx->Submit(std::move(ipcCtx)); return resultBuf != 0 ? 1 : 0; } uint32 IsOnline() { FP_API_BASE_ZeroOnError(); StackAllocator resultBuf; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::IsOnline); ipcCtx->AddOutput(&resultBuf, sizeof(uint32be)); ipcCtx->Submit(std::move(ipcCtx)); return resultBuf != 0 ? 1 : 0; } nnResult GetFriendList(uint32be* pidList, uint32be* returnedCount, uint32 startIndex, uint32 maxCount) { FP_API_BASE(); StackAllocator startIndexBuf; startIndexBuf = startIndex; StackAllocator maxCountBuf; maxCountBuf = maxCount; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetFriendList); ipcCtx->AddOutput(pidList, sizeof(uint32be) * maxCount); ipcCtx->AddOutput(returnedCount, sizeof(uint32be)); ipcCtx->AddInput(&startIndexBuf, sizeof(uint32be)); ipcCtx->AddInput(&maxCountBuf, sizeof(uint32be)); return ipcCtx->Submit(std::move(ipcCtx)); } nnResult GetFriendRequestList(uint32be* pidList, uint32be* returnedCount, uint32 startIndex, uint32 maxCount) { FP_API_BASE(); StackAllocator startIndexBuf; startIndexBuf = startIndex; StackAllocator maxCountBuf; maxCountBuf = maxCount; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetFriendRequestList); ipcCtx->AddOutput(pidList, sizeof(uint32be) * maxCount); ipcCtx->AddOutput(returnedCount, sizeof(uint32be)); ipcCtx->AddInput(&startIndexBuf, sizeof(uint32be)); ipcCtx->AddInput(&maxCountBuf, sizeof(uint32be)); return ipcCtx->Submit(std::move(ipcCtx)); } nnResult GetFriendListAll(uint32be* pidList, uint32be* returnedCount, uint32 startIndex, uint32 maxCount) { FP_API_BASE(); StackAllocator startIndexBuf; startIndexBuf = startIndex; StackAllocator maxCountBuf; maxCountBuf = maxCount; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetFriendListAll); ipcCtx->AddOutput(pidList, sizeof(uint32be) * maxCount); ipcCtx->AddOutput(returnedCount, sizeof(uint32be)); ipcCtx->AddInput(&startIndexBuf, sizeof(uint32be)); ipcCtx->AddInput(&maxCountBuf, sizeof(uint32be)); return ipcCtx->Submit(std::move(ipcCtx)); } nnResult GetFriendListEx(iosu::fpd::FriendData* friendData, uint32be* pidList, uint32 count) { FP_API_BASE(); StackAllocator countBuf; countBuf = count; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetFriendListEx); ipcCtx->AddOutput(friendData, sizeof(iosu::fpd::FriendData) * count); ipcCtx->AddInput(pidList, sizeof(uint32be) * count); ipcCtx->AddInput(&countBuf, sizeof(uint32be)); return ipcCtx->Submit(std::move(ipcCtx)); } nnResult GetFriendRequestListEx(iosu::fpd::FriendRequest* friendRequest, uint32be* pidList, uint32 count) { FP_API_BASE(); StackAllocator countBuf; countBuf = count; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetFriendRequestListEx); ipcCtx->AddOutput(friendRequest, sizeof(iosu::fpd::FriendRequest) * count); ipcCtx->AddInput(pidList, sizeof(uint32be) * count); ipcCtx->AddInput(&countBuf, sizeof(uint32be)); return ipcCtx->Submit(std::move(ipcCtx)); } nnResult GetBasicInfoAsync(iosu::fpd::FriendBasicInfo* basicInfo, uint32be* pidList, uint32 count, void* funcPtr, void* customParam) { FP_API_BASE(); StackAllocator countBuf; countBuf = count; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetBasicInfoAsync); ipcCtx->AddOutput(basicInfo, sizeof(iosu::fpd::FriendBasicInfo) * count); ipcCtx->AddInput(pidList, sizeof(uint32be) * count); ipcCtx->AddInput(&countBuf, sizeof(uint32be)); return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam); } uint32 GetMyPrincipalId() { FP_API_BASE_ZeroOnError(); StackAllocator resultBuf; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetMyPrincipalId); ipcCtx->AddOutput(&resultBuf, sizeof(uint32be)); ipcCtx->Submit(std::move(ipcCtx)); return resultBuf->value(); } nnResult GetMyAccountId(uint8be* accountId) { FP_API_BASE(); auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetMyAccountId); ipcCtx->AddOutput(accountId, ACT_ACCOUNTID_LENGTH); return ipcCtx->Submit(std::move(ipcCtx)); } nnResult GetMyScreenName(uint16be* screenname) { FP_API_BASE(); auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetMyScreenName); ipcCtx->AddOutput(screenname, ACT_NICKNAME_SIZE*sizeof(uint16)); return ipcCtx->Submit(std::move(ipcCtx)); } nnResult GetMyPreference(iosu::fpd::FPDPreference* myPreference) { FP_API_BASE(); auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetMyPreference); ipcCtx->AddOutput(myPreference, sizeof(iosu::fpd::FPDPreference)); return ipcCtx->Submit(std::move(ipcCtx)); } nnResult GetMyMii(FFLData_t* fflData) { FP_API_BASE(); auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetMyMii); ipcCtx->AddOutput(fflData, sizeof(FFLData_t)); return ipcCtx->Submit(std::move(ipcCtx)); } nnResult GetFriendAccountId(uint8be* accountIdArray, uint32be* pidList, uint32 count) { FP_API_BASE(); if (count == 0) return 0; StackAllocator countBuf; countBuf = count; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetFriendAccountId); ipcCtx->AddOutput(accountIdArray, ACT_ACCOUNTID_LENGTH * count); ipcCtx->AddInput(pidList, sizeof(uint32be) * count); ipcCtx->AddInput(&countBuf, sizeof(uint32be)); return ipcCtx->Submit(std::move(ipcCtx)); } nnResult GetFriendScreenName(uint16be* nameList, uint32be* pidList, uint32 count, uint8 replaceNonAscii, uint8be* languageList) { FP_API_BASE(); if (count == 0) return 0; StackAllocator countBuf; countBuf = count; StackAllocator replaceNonAsciiBuf; replaceNonAsciiBuf = replaceNonAscii; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetFriendScreenName); ipcCtx->AddOutput(nameList, ACT_NICKNAME_SIZE * sizeof(uint16be) * count); ipcCtx->AddOutput(languageList, languageList ? sizeof(uint8be) * count : 0); ipcCtx->AddInput(pidList, sizeof(uint32be) * count); ipcCtx->AddInput(&countBuf, sizeof(uint32be)); ipcCtx->AddInput(&replaceNonAsciiBuf, sizeof(uint8be)); return ipcCtx->Submit(std::move(ipcCtx)); } nnResult GetFriendMii(FFLData_t* miiList, uint32be* pidList, uint32 count) { FP_API_BASE(); if(count == 0) return 0; StackAllocator countBuf; countBuf = count; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetFriendMii); ipcCtx->AddOutput(miiList, sizeof(FFLData_t) * count); ipcCtx->AddInput(pidList, sizeof(uint32be) * count); ipcCtx->AddInput(&countBuf, sizeof(uint32be)); return ipcCtx->Submit(std::move(ipcCtx)); } nnResult GetFriendPresence(iosu::fpd::FriendPresence* presenceList, uint32be* pidList, uint32 count) { FP_API_BASE(); if(count == 0) return 0; StackAllocator countBuf; countBuf = count; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetFriendPresence); ipcCtx->AddOutput(presenceList, sizeof(iosu::fpd::FriendPresence) * count); ipcCtx->AddInput(pidList, sizeof(uint32be) * count); ipcCtx->AddInput(&countBuf, sizeof(uint32be)); return ipcCtx->Submit(std::move(ipcCtx)); } nnResult GetFriendRelationship(uint8* relationshipList, uint32be* pidList, uint32 count) { FP_API_BASE(); if(count == 0) return 0; StackAllocator countBuf; countBuf = count; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetFriendRelationship); ipcCtx->AddOutput(relationshipList, sizeof(uint8) * count); ipcCtx->AddInput(pidList, sizeof(uint32be) * count); ipcCtx->AddInput(&countBuf, sizeof(uint32be)); return ipcCtx->Submit(std::move(ipcCtx)); } uint32 IsJoinable(iosu::fpd::FriendPresence* presence, uint64 joinMask) { if (presence->isValid == 0 || presence->isOnline == 0 || presence->gameMode.joinGameId == 0 || presence->gameMode.matchmakeType == 0 || presence->gameMode.groupId == 0 || presence->gameMode.joinGameMode >= 64 ) { return 0; } uint32 joinGameMode = presence->gameMode.joinGameMode; uint64 joinModeMask = (1ULL<gameMode.joinFlagMask; if (joinFlagMask == 0) return 0; if (joinFlagMask == 1) return 1; if (joinFlagMask == 2) { // check relationship uint8 relationship[1] = { 0 }; StackAllocator pidList; pidList = presence->gameMode.hostPid; GetFriendRelationship(relationship, &pidList, 1); if(relationship[0] == iosu::fpd::RELATIONSHIP_FRIEND) return 1; return 0; } if (joinFlagMask == 0x65 || joinFlagMask == 0x66) { cemuLog_log(LogType::Force, "Unsupported friend invite"); } return 0; } nnResult CheckSettingStatusAsync(uint8* status, void* funcPtr, void* customParam) { FP_API_BASE(); auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::CheckSettingStatusAsync); ipcCtx->AddOutput(status, sizeof(uint8be)); return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam); } uint32 IsPreferenceValid() { FP_API_BASE_ZeroOnError(); StackAllocator resultBuf; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::IsPreferenceValid); ipcCtx->AddOutput(&resultBuf, sizeof(uint32be)); ipcCtx->Submit(std::move(ipcCtx)); return resultBuf != 0 ? 1 : 0; } nnResult UpdatePreferenceAsync(iosu::fpd::FPDPreference* newPreference, void* funcPtr, void* customParam) { FP_API_BASE(); auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::UpdatePreferenceAsync); ipcCtx->AddInput(newPreference, sizeof(iosu::fpd::FPDPreference)); return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam); } nnResult UpdateGameModeWithUnusedParam(iosu::fpd::GameMode* gameMode, uint16be* gameModeMessage, uint32 unusedParam) { FP_API_BASE(); uint32 messageLen = CafeStringHelpers::Length(gameModeMessage, iosu::fpd::GAMEMODE_MAX_MESSAGE_LENGTH); if(messageLen >= iosu::fpd::GAMEMODE_MAX_MESSAGE_LENGTH) { cemuLog_log(LogType::Force, "UpdateGameMode: message too long"); return FPResult_InvalidIPCParam; } auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::UpdateGameModeVariation2); ipcCtx->AddInput(gameMode, sizeof(iosu::fpd::GameMode)); ipcCtx->AddInput(gameModeMessage, sizeof(uint16be) * (messageLen + 1)); return ipcCtx->Submit(std::move(ipcCtx)); } nnResult UpdateGameMode(iosu::fpd::GameMode* gameMode, uint16be* gameModeMessage) { return UpdateGameModeWithUnusedParam(gameMode, gameModeMessage, 0); } nnResult GetRequestBlockSettingAsync(uint8* blockSettingList, uint32be* pidList, uint32 count, void* funcPtr, void* customParam) { FP_API_BASE(); StackAllocator countBuf; countBuf = count; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::GetRequestBlockSettingAsync); ipcCtx->AddOutput(blockSettingList, sizeof(uint8be) * count); ipcCtx->AddInput(pidList, sizeof(uint32be) * count); ipcCtx->AddInput(&countBuf, sizeof(uint32be)); return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam); } // overload of AddFriendAsync nnResult AddFriendAsyncByPid(uint32 pid, void* funcPtr, void* customParam) { FP_API_BASE(); StackAllocator pidBuf; pidBuf = pid; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::AddFriendAsyncByPid); ipcCtx->AddInput(&pidBuf, sizeof(uint32be)); return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam); } nnResult DeleteFriendFlagsAsync(uint32be* pidList, uint32 pidCount, uint32 ukn, void* funcPtr, void* customParam) { // admin function? FP_API_BASE(); StackAllocator pidCountBuf; pidCountBuf = pidCount; StackAllocator uknBuf; uknBuf = ukn; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::DeleteFriendFlagsAsync); ipcCtx->AddInput(pidList, sizeof(uint32be) * pidCount); ipcCtx->AddInput(&pidCountBuf, sizeof(uint32be)); ipcCtx->AddInput(&uknBuf, sizeof(uint32be)); return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam); } // overload of AddFriendRequestAsync nnResult AddFriendRequestByPlayRecordAsync(iosu::fpd::RecentPlayRecordEx* playRecord, uint16be* message, void* funcPtr, void* customParam) { FP_API_BASE(); auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::AddFriendRequestByPlayRecordAsync); uint32 messageLen = 0; while(message[messageLen] != 0) messageLen++; ipcCtx->AddInput(playRecord, sizeof(iosu::fpd::RecentPlayRecordEx)); ipcCtx->AddInput(message, sizeof(uint16be) * (messageLen+1)); return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam); } nnResult RemoveFriendAsync(uint32 pid, void* funcPtr, void* customParam) { FP_API_BASE(); StackAllocator pidBuf; pidBuf = pid; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::RemoveFriendAsync); ipcCtx->AddInput(&pidBuf, sizeof(uint32be)); return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam); } nnResult MarkFriendRequestsAsReceivedAsync(uint64be* messageIdList, uint32 count, void* funcPtr, void* customParam) { FP_API_BASE(); StackAllocator countBuf; countBuf = count; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::MarkFriendRequestsAsReceivedAsync); ipcCtx->AddInput(messageIdList, sizeof(uint64be) * count); ipcCtx->AddInput(&countBuf, sizeof(uint32be)); return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam); } nnResult CancelFriendRequestAsync(uint64 requestId, void* funcPtr, void* customParam) { FP_API_BASE(); StackAllocator requestIdBuf; requestIdBuf = requestId; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::CancelFriendRequestAsync); ipcCtx->AddInput(&requestIdBuf, sizeof(uint64be)); return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam); } nnResult DeleteFriendRequestAsync(uint64 requestId, void* funcPtr, void* customParam) { FP_API_BASE(); StackAllocator requestIdBuf; requestIdBuf = requestId; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::DeleteFriendRequestAsync); ipcCtx->AddInput(&requestIdBuf, sizeof(uint64be)); return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam); } nnResult AcceptFriendRequestAsync(uint64 requestId, void* funcPtr, void* customParam) { FP_API_BASE(); StackAllocator requestIdBuf; requestIdBuf = requestId; auto ipcCtx = std::make_unique(iosu::fpd::FPD_REQUEST_ID::AcceptFriendRequestAsync); ipcCtx->AddInput(&requestIdBuf, sizeof(uint64be)); return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam); } void load() { g_fp.initCounter = 0; g_fp.isAdminMode = false; g_fp.isLoggedIn = false; g_fp.getNotificationCalled = false; g_fp.notificationHandler = nullptr; g_fp.notificationHandlerParam = nullptr; coreinit::OSInitMutex(&g_fp.fpMutex); FPIpcBufferAllocator.Init(); cafeExportRegisterFunc(Initialize, "nn_fp", "Initialize__Q2_2nn2fpFv", LogType::NN_FP); cafeExportRegisterFunc(InitializeAdmin, "nn_fp", "InitializeAdmin__Q2_2nn2fpFv", LogType::NN_FP); cafeExportRegisterFunc(IsInitialized, "nn_fp", "IsInitialized__Q2_2nn2fpFv", LogType::NN_FP); cafeExportRegisterFunc(IsInitializedAdmin, "nn_fp", "IsInitializedAdmin__Q2_2nn2fpFv", LogType::NN_FP); cafeExportRegisterFunc(Finalize, "nn_fp", "Finalize__Q2_2nn2fpFv", LogType::NN_FP); cafeExportRegisterFunc(FinalizeAdmin, "nn_fp", "FinalizeAdmin__Q2_2nn2fpFv", LogType::NN_FP); cafeExportRegisterFunc(SetNotificationHandler, "nn_fp", "SetNotificationHandler__Q2_2nn2fpFUiPFQ3_2nn2fp16NotificationTypeUiPv_vPv", LogType::NN_FP); cafeExportRegisterFunc(LoginAsync, "nn_fp", "LoginAsync__Q2_2nn2fpFPFQ2_2nn6ResultPv_vPv", LogType::NN_FP); cafeExportRegisterFunc(HasLoggedIn, "nn_fp", "HasLoggedIn__Q2_2nn2fpFv", LogType::NN_FP); cafeExportRegisterFunc(IsOnline, "nn_fp", "IsOnline__Q2_2nn2fpFv", LogType::NN_FP); cafeExportRegisterFunc(GetFriendList, "nn_fp", "GetFriendList__Q2_2nn2fpFPUiT1UiT3", LogType::NN_FP); cafeExportRegisterFunc(GetFriendRequestList, "nn_fp", "GetFriendRequestList__Q2_2nn2fpFPUiT1UiT3", LogType::NN_FP); cafeExportRegisterFunc(GetFriendListAll, "nn_fp", "GetFriendListAll__Q2_2nn2fpFPUiT1UiT3", LogType::NN_FP); cafeExportRegisterFunc(GetFriendListEx, "nn_fp", "GetFriendListEx__Q2_2nn2fpFPQ3_2nn2fp10FriendDataPCUiUi", LogType::NN_FP); cafeExportRegisterFunc(GetFriendRequestListEx, "nn_fp", "GetFriendRequestListEx__Q2_2nn2fpFPQ3_2nn2fp13FriendRequestPCUiUi", LogType::NN_FP); cafeExportRegisterFunc(GetBasicInfoAsync, "nn_fp", "GetBasicInfoAsync__Q2_2nn2fpFPQ3_2nn2fp9BasicInfoPCUiUiPFQ2_2nn6ResultPv_vPv", LogType::NN_FP); cafeExportRegisterFunc(GetMyPrincipalId, "nn_fp", "GetMyPrincipalId__Q2_2nn2fpFv", LogType::NN_FP); cafeExportRegisterFunc(GetMyAccountId, "nn_fp", "GetMyAccountId__Q2_2nn2fpFPc", LogType::NN_FP); cafeExportRegisterFunc(GetMyScreenName, "nn_fp", "GetMyScreenName__Q2_2nn2fpFPw", LogType::NN_FP); cafeExportRegisterFunc(GetMyMii, "nn_fp", "GetMyMii__Q2_2nn2fpFP12FFLStoreData", LogType::NN_FP); cafeExportRegisterFunc(GetMyPreference, "nn_fp", "GetMyPreference__Q2_2nn2fpFPQ3_2nn2fp10Preference", LogType::NN_FP); cafeExportRegisterFunc(GetFriendAccountId, "nn_fp", "GetFriendAccountId__Q2_2nn2fpFPA17_cPCUiUi", LogType::NN_FP); cafeExportRegisterFunc(GetFriendScreenName, "nn_fp", "GetFriendScreenName__Q2_2nn2fpFPA11_wPCUiUibPUc", LogType::NN_FP); cafeExportRegisterFunc(GetFriendMii, "nn_fp", "GetFriendMii__Q2_2nn2fpFP12FFLStoreDataPCUiUi", LogType::NN_FP); cafeExportRegisterFunc(GetFriendPresence, "nn_fp", "GetFriendPresence__Q2_2nn2fpFPQ3_2nn2fp14FriendPresencePCUiUi", LogType::NN_FP); cafeExportRegisterFunc(GetFriendRelationship, "nn_fp", "GetFriendRelationship__Q2_2nn2fpFPUcPCUiUi", LogType::NN_FP); cafeExportRegisterFunc(IsJoinable, "nn_fp", "IsJoinable__Q2_2nn2fpFPCQ3_2nn2fp14FriendPresenceUL", LogType::NN_FP); cafeExportRegisterFunc(CheckSettingStatusAsync, "nn_fp", "CheckSettingStatusAsync__Q2_2nn2fpFPUcPFQ2_2nn6ResultPv_vPv", LogType::NN_FP); cafeExportRegisterFunc(IsPreferenceValid, "nn_fp", "IsPreferenceValid__Q2_2nn2fpFv", LogType::NN_FP); cafeExportRegisterFunc(UpdatePreferenceAsync, "nn_fp", "UpdatePreferenceAsync__Q2_2nn2fpFPCQ3_2nn2fp10PreferencePFQ2_2nn6ResultPv_vPv", LogType::NN_FP); cafeExportRegisterFunc(GetRequestBlockSettingAsync, "nn_fp", "GetRequestBlockSettingAsync__Q2_2nn2fpFPUcPCUiUiPFQ2_2nn6ResultPv_vPv", LogType::NN_FP); cafeExportRegisterFunc(UpdateGameModeWithUnusedParam, "nn_fp", "UpdateGameMode__Q2_2nn2fpFPCQ3_2nn2fp8GameModePCwUi", LogType::NN_FP); cafeExportRegisterFunc(UpdateGameMode, "nn_fp", "UpdateGameMode__Q2_2nn2fpFPCQ3_2nn2fp8GameModePCw", LogType::NN_FP); cafeExportRegisterFunc(AddFriendAsyncByPid, "nn_fp", "AddFriendAsync__Q2_2nn2fpFUiPFQ2_2nn6ResultPv_vPv", LogType::NN_FP); cafeExportRegisterFunc(AddFriendRequestByPlayRecordAsync, "nn_fp", "AddFriendRequestAsync__Q2_2nn2fpFPCQ3_2nn2fp18RecentPlayRecordExPCwPFQ2_2nn6ResultPv_vPv", LogType::NN_FP); cafeExportRegisterFunc(DeleteFriendFlagsAsync, "nn_fp", "DeleteFriendFlagsAsync__Q2_2nn2fpFPCUiUiT2PFQ2_2nn6ResultPv_vPv", LogType::NN_FP); cafeExportRegisterFunc(RemoveFriendAsync, "nn_fp", "RemoveFriendAsync__Q2_2nn2fpFUiPFQ2_2nn6ResultPv_vPv", LogType::NN_FP); cafeExportRegisterFunc(MarkFriendRequestsAsReceivedAsync, "nn_fp", "MarkFriendRequestsAsReceivedAsync__Q2_2nn2fpFPCULUiPFQ2_2nn6ResultPv_vPv", LogType::NN_FP); cafeExportRegisterFunc(CancelFriendRequestAsync, "nn_fp", "CancelFriendRequestAsync__Q2_2nn2fpFULPFQ2_2nn6ResultPv_vPv", LogType::NN_FP); cafeExportRegisterFunc(DeleteFriendRequestAsync, "nn_fp", "DeleteFriendRequestAsync__Q2_2nn2fpFULPFQ2_2nn6ResultPv_vPv", LogType::NN_FP); cafeExportRegisterFunc(AcceptFriendRequestAsync, "nn_fp", "AcceptFriendRequestAsync__Q2_2nn2fpFULPFQ2_2nn6ResultPv_vPv", LogType::NN_FP); } } }