mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-12-12 01:36:58 +00:00
1050 lines
No EOL
38 KiB
C++
1050 lines
No EOL
38 KiB
C++
#include "iosu_ioctl.h"
|
|
#include "iosu_act.h"
|
|
#include "iosu_fpd.h"
|
|
#include "Cemu/nex/nex.h"
|
|
#include "Cemu/nex/nexFriends.h"
|
|
#include "util/helpers/helpers.h"
|
|
#include "config/CemuConfig.h"
|
|
#include "Cafe/CafeSystem.h"
|
|
#include "config/ActiveSettings.h"
|
|
#include "Cemu/napi/napi.h"
|
|
#include "util/helpers/StringHelpers.h"
|
|
#include "Cafe/OS/libs/coreinit/coreinit.h"
|
|
|
|
uint32 memory_getVirtualOffsetFromPointer(void* ptr); // remove once we updated everything to MEMPTR
|
|
|
|
SysAllocator<uint32be> _fpdAsyncLoginRetCode;
|
|
SysAllocator<uint32be> _fpdAsyncAddFriendRetCode;
|
|
|
|
std::mutex g_friend_notification_mutex;
|
|
std::vector< std::pair<std::string, int> > g_friend_notifications;
|
|
|
|
namespace iosu
|
|
{
|
|
namespace fpd
|
|
{
|
|
|
|
struct
|
|
{
|
|
bool isThreadStarted;
|
|
bool isInitialized2;
|
|
NexFriends* nexFriendSession;
|
|
// notification handler
|
|
MPTR notificationFunc;
|
|
MPTR notificationCustomParam;
|
|
uint32 notificationMask;
|
|
// login callback
|
|
struct
|
|
{
|
|
MPTR func;
|
|
MPTR customParam;
|
|
}asyncLoginCallback;
|
|
// current state
|
|
nexPresenceV2 myPresence;
|
|
}g_fpd = {};
|
|
|
|
void notificationHandler(NexFriends::NOTIFICATION_TYPE type, uint32 pid)
|
|
{
|
|
forceLogDebug_printf("Friends::Notification %02x pid %08x", type, pid);
|
|
if(GetConfig().notification.friends)
|
|
{
|
|
std::unique_lock lock(g_friend_notification_mutex);
|
|
std::string message;
|
|
if(type == NexFriends::NOTIFICATION_TYPE::NOTIFICATION_TYPE_ONLINE)
|
|
{
|
|
g_friend_notifications.emplace_back("Connected to friend service", 5000);
|
|
if(g_fpd.nexFriendSession && g_fpd.nexFriendSession->getPendingFriendRequestCount() > 0)
|
|
g_friend_notifications.emplace_back(fmt::format("You have {} pending friend request(s)", g_fpd.nexFriendSession->getPendingFriendRequestCount()), 5000);
|
|
}
|
|
else
|
|
{
|
|
std::string msg_format;
|
|
switch(type)
|
|
{
|
|
case NexFriends::NOTIFICATION_TYPE_ONLINE: break;
|
|
case NexFriends::NOTIFICATION_TYPE_FRIEND_LOGIN: msg_format = "{} is now online"; break;
|
|
case NexFriends::NOTIFICATION_TYPE_FRIEND_LOGOFF: msg_format = "{} is now offline"; break;
|
|
case NexFriends::NOTIFICATION_TYPE_FRIEND_PRESENCE_CHANGE: break;
|
|
case NexFriends::NOTIFICATION_TYPE_ADDED_FRIEND: msg_format = "{} has been added to your friend list"; break;
|
|
case NexFriends::NOTIFICATION_TYPE_REMOVED_FRIEND: msg_format = "{} has been removed from your friend list"; break;
|
|
case NexFriends::NOTIFICATION_TYPE_ADDED_OUTGOING_REQUEST: break;
|
|
case NexFriends::NOTIFICATION_TYPE_REMOVED_OUTGOING_REQUEST: break;
|
|
case NexFriends::NOTIFICATION_TYPE_ADDED_INCOMING_REQUEST: msg_format = "{} wants to add you to his friend list"; break;
|
|
case NexFriends::NOTIFICATION_TYPE_REMOVED_INCOMING_REQUEST: break;
|
|
default: ;
|
|
}
|
|
|
|
if (!msg_format.empty())
|
|
{
|
|
std::string name = fmt::format("{:#x}", pid);
|
|
if (g_fpd.nexFriendSession)
|
|
{
|
|
const std::string tmp = g_fpd.nexFriendSession->getAccountNameByPid(pid);
|
|
if (!tmp.empty())
|
|
name = tmp;
|
|
}
|
|
|
|
g_friend_notifications.emplace_back(fmt::format(msg_format, name), 5000);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_fpd.notificationFunc == MPTR_NULL)
|
|
return;
|
|
uint32 notificationFlag = 1 << (type - 1);
|
|
if ( (notificationFlag&g_fpd.notificationMask) == 0 )
|
|
return;
|
|
coreinitAsyncCallback_add(g_fpd.notificationFunc, 3, type, pid, g_fpd.notificationCustomParam);
|
|
}
|
|
|
|
void convertMultiByteStringToBigEndianWidechar(const char* input, uint16be* output, sint32 maxOutputLength)
|
|
{
|
|
std::basic_string<uint16be> beStr = StringHelpers::FromUtf8(input);
|
|
if (beStr.size() >= maxOutputLength - 1)
|
|
beStr.resize(maxOutputLength-1);
|
|
for (size_t i = 0; i < beStr.size(); i++)
|
|
output[i] = beStr[i];
|
|
output[beStr.size()] = '\0';
|
|
}
|
|
|
|
void convertFPDTimestampToDate(uint64 timestamp, fpdDate_t* fpdDate)
|
|
{
|
|
// if the timestamp is zero then still return a valid date
|
|
if (timestamp == 0)
|
|
{
|
|
fpdDate->second = 0;
|
|
fpdDate->minute = 0;
|
|
fpdDate->hour = 0;
|
|
fpdDate->day = 1;
|
|
fpdDate->month = 1;
|
|
fpdDate->year = 1970;
|
|
return;
|
|
}
|
|
fpdDate->second = (uint8)((timestamp) & 0x3F);
|
|
fpdDate->minute = (uint8)((timestamp >> 6) & 0x3F);
|
|
fpdDate->hour = (uint8)((timestamp >> 12) & 0x1F);
|
|
fpdDate->day = (uint8)((timestamp >> 17) & 0x1F);
|
|
fpdDate->month = (uint8)((timestamp >> 22) & 0xF);
|
|
fpdDate->year = (uint16)((timestamp >> 26));
|
|
}
|
|
|
|
uint64 convertDateToFPDTimestamp(fpdDate_t* fpdDate)
|
|
{
|
|
uint64 t = 0;
|
|
t |= (uint64)fpdDate->second;
|
|
t |= ((uint64)fpdDate->minute<<6);
|
|
t |= ((uint64)fpdDate->hour<<12);
|
|
t |= ((uint64)fpdDate->day<<17);
|
|
t |= ((uint64)fpdDate->month<<22);
|
|
t |= ((uint64)(uint16)fpdDate->year<<26);
|
|
return t;
|
|
}
|
|
|
|
void startFriendSession()
|
|
{
|
|
cemu_assert(!g_fpd.nexFriendSession);
|
|
|
|
NAPI::AuthInfo authInfo;
|
|
NAPI::NAPI_MakeAuthInfoFromCurrentAccount(authInfo);
|
|
NAPI::ACTGetNexTokenResult nexTokenResult = NAPI::ACT_GetNexToken_WithCache(authInfo, 0x0005001010001C00, 0x0000, 0x00003200);
|
|
if (nexTokenResult.isValid())
|
|
{
|
|
// get values needed for friend session
|
|
uint32 myPid;
|
|
uint8 currentSlot = iosu::act::getCurrentAccountSlot();
|
|
iosu::act::getPrincipalId(currentSlot, &myPid);
|
|
char accountId[256] = { 0 };
|
|
iosu::act::getAccountId(currentSlot, accountId);
|
|
FFLData_t miiData;
|
|
act::getMii(currentSlot, &miiData);
|
|
uint16 screenName[ACT_NICKNAME_LENGTH + 1] = { 0 };
|
|
act::getScreenname(currentSlot, screenName);
|
|
uint32 countryCode = 0;
|
|
act::getCountryIndex(currentSlot, &countryCode);
|
|
// init presence
|
|
g_fpd.myPresence.isOnline = 1;
|
|
g_fpd.myPresence.gameKey.titleId = CafeSystem::GetForegroundTitleId();
|
|
g_fpd.myPresence.gameKey.ukn = CafeSystem::GetForegroundTitleVersion();
|
|
// start session
|
|
uint32 hostIp;
|
|
inet_pton(AF_INET, nexTokenResult.nexToken.host, &hostIp);
|
|
g_fpd.nexFriendSession = new NexFriends(hostIp, nexTokenResult.nexToken.port, "ridfebb9", myPid, nexTokenResult.nexToken.nexPassword, nexTokenResult.nexToken.token, accountId, (uint8*)&miiData, (wchar_t*)screenName, (uint8)countryCode, g_fpd.myPresence);
|
|
g_fpd.nexFriendSession->setNotificationHandler(notificationHandler);
|
|
forceLog_printf("IOSU_FPD: Created friend server session");
|
|
}
|
|
else
|
|
{
|
|
forceLogDebug_printf("IOSU_FPD: Failed to acquire nex token for friend server");
|
|
}
|
|
}
|
|
|
|
void handleRequest_GetFriendList(iosuFpdCemuRequest_t* fpdCemuRequest, bool getAll)
|
|
{
|
|
if (g_fpd.nexFriendSession == nullptr || g_fpd.nexFriendSession->isOnline() == false)
|
|
{
|
|
fpdCemuRequest->returnCode = 0;
|
|
fpdCemuRequest->resultU32.u32 = 0; // zero entries returned
|
|
return;
|
|
}
|
|
|
|
uint32 temporaryPidList[800];
|
|
uint32 pidCount = 0;
|
|
g_fpd.nexFriendSession->getFriendPIDs(temporaryPidList, &pidCount, fpdCemuRequest->getFriendList.startIndex, std::min<uint32>(sizeof(temporaryPidList) / sizeof(temporaryPidList[0]), fpdCemuRequest->getFriendList.maxCount), getAll);
|
|
uint32be* pidListOutput = fpdCemuRequest->getFriendList.pidList.GetPtr();
|
|
if (pidListOutput)
|
|
{
|
|
for (uint32 i = 0; i < pidCount; i++)
|
|
pidListOutput[i] = temporaryPidList[i];
|
|
}
|
|
fpdCemuRequest->returnCode = 0;
|
|
fpdCemuRequest->resultU32.u32 = pidCount;
|
|
}
|
|
|
|
void handleRequest_GetFriendRequestList(iosuFpdCemuRequest_t* fpdCemuRequest)
|
|
{
|
|
if (g_fpd.nexFriendSession == nullptr || g_fpd.nexFriendSession->isOnline() == false)
|
|
{
|
|
fpdCemuRequest->returnCode = 0;
|
|
fpdCemuRequest->resultU32.u32 = 0; // zero entries returned
|
|
return;
|
|
}
|
|
|
|
uint32 temporaryPidList[800];
|
|
uint32 pidCount = 0;
|
|
// get only incoming friend requests
|
|
g_fpd.nexFriendSession->getFriendRequestPIDs(temporaryPidList, &pidCount, fpdCemuRequest->getFriendList.startIndex, std::min<uint32>(sizeof(temporaryPidList) / sizeof(temporaryPidList[0]), fpdCemuRequest->getFriendList.maxCount), true, false);
|
|
uint32be* pidListOutput = fpdCemuRequest->getFriendList.pidList.GetPtr();
|
|
if (pidListOutput)
|
|
{
|
|
for (uint32 i = 0; i < pidCount; i++)
|
|
pidListOutput[i] = temporaryPidList[i];
|
|
}
|
|
fpdCemuRequest->returnCode = 0;
|
|
fpdCemuRequest->resultU32.u32 = pidCount;
|
|
}
|
|
|
|
void setFriendDataFromNexFriend(friendData_t* friendData, nexFriend* frd)
|
|
{
|
|
memset(friendData, 0, sizeof(friendData_t));
|
|
// setup friend data
|
|
friendData->type = 1; // friend
|
|
friendData->pid = frd->nnaInfo.principalInfo.principalId;
|
|
memcpy(friendData->mii, frd->nnaInfo.principalInfo.mii.miiData, FFL_SIZE);
|
|
strcpy((char*)friendData->nnid, frd->nnaInfo.principalInfo.nnid);
|
|
// screenname
|
|
convertMultiByteStringToBigEndianWidechar(frd->nnaInfo.principalInfo.mii.miiNickname, friendData->screenname, sizeof(friendData->screenname) / sizeof(uint16be));
|
|
|
|
//friendData->friendExtraData.ukn0E4 = 0;
|
|
friendData->friendExtraData.isOnline = frd->presence.isOnline != 0 ? 1 : 0;
|
|
|
|
friendData->friendExtraData.gameKeyTitleId = _swapEndianU64(frd->presence.gameKey.titleId);
|
|
friendData->friendExtraData.gameKeyUkn = frd->presence.gameKey.ukn;
|
|
|
|
friendData->friendExtraData.statusMessage[0] = '\0';
|
|
|
|
// set valid dates
|
|
friendData->uknDate.year = 2018;
|
|
friendData->uknDate.day = 1;
|
|
friendData->uknDate.month = 1;
|
|
friendData->uknDate.hour = 1;
|
|
friendData->uknDate.minute = 1;
|
|
friendData->uknDate.second = 1;
|
|
|
|
friendData->friendExtraData.uknDate218.year = 2018;
|
|
friendData->friendExtraData.uknDate218.day = 1;
|
|
friendData->friendExtraData.uknDate218.month = 1;
|
|
friendData->friendExtraData.uknDate218.hour = 1;
|
|
friendData->friendExtraData.uknDate218.minute = 1;
|
|
friendData->friendExtraData.uknDate218.second = 1;
|
|
|
|
convertFPDTimestampToDate(frd->lastOnlineTimestamp, &friendData->friendExtraData.lastOnline);
|
|
}
|
|
|
|
void setFriendDataFromNexFriendRequest(friendData_t* friendData, nexFriendRequest* frdReq, bool isIncoming)
|
|
{
|
|
memset(friendData, 0, sizeof(friendData_t));
|
|
// setup friend data
|
|
friendData->type = 0; // friend request
|
|
friendData->pid = frdReq->principalInfo.principalId;
|
|
memcpy(friendData->mii, frdReq->principalInfo.mii.miiData, FFL_SIZE);
|
|
strcpy((char*)friendData->nnid, frdReq->principalInfo.nnid);
|
|
// screenname
|
|
convertMultiByteStringToBigEndianWidechar(frdReq->principalInfo.mii.miiNickname, friendData->screenname, sizeof(friendData->screenname) / sizeof(uint16be));
|
|
|
|
convertMultiByteStringToBigEndianWidechar(frdReq->message.commentStr.c_str(), friendData->requestExtraData.comment, sizeof(friendData->requestExtraData.comment) / sizeof(uint16be));
|
|
|
|
fpdDate_t expireDate;
|
|
convertFPDTimestampToDate(frdReq->message.expireTimestamp, &expireDate);
|
|
|
|
bool isProvisional = frdReq->message.expireTimestamp == 0;
|
|
|
|
//friendData->requestExtraData.ukn0A8 = 0; // no change?
|
|
//friendData->requestExtraData.ukn0A0 = 0; // if not set -> provisional friend request
|
|
//friendData->requestExtraData.ukn0A4 = isProvisional ? 0 : 123; // no change?
|
|
|
|
friendData->requestExtraData.messageId = _swapEndianU64(frdReq->message.messageId);
|
|
|
|
|
|
//find the value for 'markedAsReceived'
|
|
|
|
///* +0x0A8 */ uint8 ukn0A8;
|
|
///* +0x0A9 */ uint8 ukn0A9; // comment language? (guessed)
|
|
///* +0x0AA */ uint16be comment[0x40];
|
|
///* +0x12A */ uint8 ukn12A; // ingame name language? (guessed)
|
|
///* +0x12B */ uint8 _padding12B;
|
|
|
|
// set valid dates
|
|
|
|
friendData->uknDate.year = 2018;
|
|
friendData->uknDate.day = 20;
|
|
friendData->uknDate.month = 4;
|
|
friendData->uknDate.hour = 12;
|
|
friendData->uknDate.minute = 1;
|
|
friendData->uknDate.second = 1;
|
|
|
|
friendData->requestExtraData.uknData0.year = 2018;
|
|
friendData->requestExtraData.uknData0.day = 24;
|
|
friendData->requestExtraData.uknData0.month = 4;
|
|
friendData->requestExtraData.uknData0.hour = 1;
|
|
friendData->requestExtraData.uknData0.minute = 1;
|
|
friendData->requestExtraData.uknData0.second = 1;
|
|
|
|
// this is the date used for 'Expires in'
|
|
convertFPDTimestampToDate(frdReq->message.expireTimestamp, &friendData->requestExtraData.uknData1);
|
|
}
|
|
|
|
void setFriendRequestFromNexFriendRequest(friendRequest_t* friendRequest, nexFriendRequest* frdReq, bool isIncoming)
|
|
{
|
|
memset(friendRequest, 0, sizeof(friendRequest_t));
|
|
|
|
friendRequest->pid = frdReq->principalInfo.principalId;
|
|
|
|
strncpy((char*)friendRequest->nnid, frdReq->principalInfo.nnid, sizeof(friendRequest->nnid));
|
|
friendRequest->nnid[sizeof(friendRequest->nnid) - 1] = '\0';
|
|
|
|
memcpy(friendRequest->miiData, frdReq->principalInfo.mii.miiData, sizeof(friendRequest->miiData));
|
|
|
|
convertMultiByteStringToBigEndianWidechar(frdReq->message.commentStr.c_str(), friendRequest->message, sizeof(friendRequest->message) / sizeof(friendRequest->message[0]));
|
|
convertMultiByteStringToBigEndianWidechar(frdReq->principalInfo.mii.miiNickname, friendRequest->screenname, sizeof(friendRequest->screenname) / sizeof(friendRequest->screenname[0]));
|
|
|
|
friendRequest->isMarkedAsReceived = 1;
|
|
|
|
friendRequest->ukn98 = _swapEndianU64(frdReq->message.messageId);
|
|
|
|
convertFPDTimestampToDate(0, &friendRequest->uknDate);
|
|
convertFPDTimestampToDate(0, &friendRequest->uknDate2);
|
|
convertFPDTimestampToDate(frdReq->message.expireTimestamp, &friendRequest->expireDate);
|
|
}
|
|
|
|
void handleRequest_GetFriendListEx(iosuFpdCemuRequest_t* fpdCemuRequest)
|
|
{
|
|
fpdCemuRequest->returnCode = 0;
|
|
if (g_fpd.nexFriendSession == nullptr || g_fpd.nexFriendSession->isOnline() == false)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000;
|
|
return;
|
|
}
|
|
for (uint32 i = 0; i < fpdCemuRequest->getFriendListEx.count; i++)
|
|
{
|
|
uint32 pid = fpdCemuRequest->getFriendListEx.pidList[i];
|
|
friendData_t* friendData = fpdCemuRequest->getFriendListEx.friendData.GetPtr() + i;
|
|
nexFriend frd;
|
|
nexFriendRequest frdReq;
|
|
if (g_fpd.nexFriendSession->getFriendByPID(frd, pid))
|
|
{
|
|
setFriendDataFromNexFriend(friendData, &frd);
|
|
continue;
|
|
}
|
|
bool incoming = false;
|
|
if (g_fpd.nexFriendSession->getFriendRequestByPID(frdReq, &incoming, pid))
|
|
{
|
|
setFriendDataFromNexFriendRequest(friendData, &frdReq, incoming);
|
|
continue;
|
|
}
|
|
fpdCemuRequest->returnCode = 0x80000000;
|
|
return;
|
|
}
|
|
}
|
|
|
|
void handleRequest_GetFriendRequestListEx(iosuFpdCemuRequest_t* fpdCemuRequest)
|
|
{
|
|
fpdCemuRequest->returnCode = 0;
|
|
if (g_fpd.nexFriendSession == nullptr || g_fpd.nexFriendSession->isOnline() == false)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000;
|
|
return;
|
|
}
|
|
for (uint32 i = 0; i < fpdCemuRequest->getFriendRequestListEx.count; i++)
|
|
{
|
|
uint32 pid = fpdCemuRequest->getFriendListEx.pidList[i];
|
|
friendRequest_t* friendRequest = fpdCemuRequest->getFriendRequestListEx.friendRequest.GetPtr() + i;
|
|
nexFriendRequest frdReq;
|
|
bool incoming = false;
|
|
if (!g_fpd.nexFriendSession->getFriendRequestByPID(frdReq, &incoming, pid))
|
|
{
|
|
cemuLog_log(LogType::Force, "Failed to get friend request");
|
|
fpdCemuRequest->returnCode = 0x80000000;
|
|
return;
|
|
}
|
|
setFriendRequestFromNexFriendRequest(friendRequest, &frdReq, incoming);
|
|
}
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
MPTR funcMPTR;
|
|
MPTR customParam;
|
|
}fpAsyncCallback_t;
|
|
|
|
typedef struct
|
|
{
|
|
nexPrincipalBasicInfo* principalBasicInfo;
|
|
uint32* pidList;
|
|
sint32 count;
|
|
friendBasicInfo_t* friendBasicInfo;
|
|
fpAsyncCallback_t fpCallback;
|
|
}getBasicInfoAsyncParams_t;
|
|
|
|
SysAllocator<uint32, 32> _fpCallbackResultArray; // use a ring buffer of results to avoid overwriting the result when multiple callbacks are queued at the same time
|
|
sint32 fpCallbackResultIndex = 0;
|
|
|
|
void handleFPCallback(fpAsyncCallback_t* fpCallback, uint32 resultCode)
|
|
{
|
|
fpCallbackResultIndex = (fpCallbackResultIndex + 1) % 32;
|
|
uint32* resultPtr = _fpCallbackResultArray.GetPtr() + fpCallbackResultIndex;
|
|
|
|
*resultPtr = resultCode;
|
|
|
|
coreinitAsyncCallback_add(fpCallback->funcMPTR, 2, memory_getVirtualOffsetFromPointer(resultPtr), fpCallback->customParam);
|
|
}
|
|
|
|
void handleFPCallback2(MPTR funcMPTR, MPTR custom, uint32 resultCode)
|
|
{
|
|
fpCallbackResultIndex = (fpCallbackResultIndex + 1) % 32;
|
|
uint32* resultPtr = _fpCallbackResultArray.GetPtr() + fpCallbackResultIndex;
|
|
|
|
*resultPtr = resultCode;
|
|
|
|
coreinitAsyncCallback_add(funcMPTR, 2, memory_getVirtualOffsetFromPointer(resultPtr), custom);
|
|
}
|
|
|
|
void handleResultCB_GetBasicInfoAsync(NexFriends* nexFriends, uint32 result, void* custom)
|
|
{
|
|
getBasicInfoAsyncParams_t* cbInfo = (getBasicInfoAsyncParams_t*)custom;
|
|
if (result != 0)
|
|
{
|
|
handleFPCallback(&cbInfo->fpCallback, 0x80000000); // todo - properly translate internal error to nn::fp error code
|
|
free(cbInfo->principalBasicInfo);
|
|
free(cbInfo->pidList);
|
|
free(cbInfo);
|
|
return;
|
|
}
|
|
|
|
// convert PrincipalBasicInfo into friendBasicInfo
|
|
for (sint32 i = 0; i < cbInfo->count; i++)
|
|
{
|
|
friendBasicInfo_t* basicInfo = cbInfo->friendBasicInfo + i;
|
|
nexPrincipalBasicInfo* principalBasicInfo = cbInfo->principalBasicInfo + i;
|
|
|
|
memset(basicInfo, 0, sizeof(friendBasicInfo_t));
|
|
basicInfo->pid = principalBasicInfo->principalId;
|
|
strcpy(basicInfo->nnid, principalBasicInfo->nnid);
|
|
|
|
convertMultiByteStringToBigEndianWidechar(principalBasicInfo->mii.miiNickname, basicInfo->screenname, sizeof(basicInfo->screenname) / sizeof(uint16be));
|
|
memcpy(basicInfo->miiData, principalBasicInfo->mii.miiData, FFL_SIZE);
|
|
|
|
basicInfo->uknDate90.day = 1;
|
|
basicInfo->uknDate90.month = 1;
|
|
basicInfo->uknDate90.hour = 1;
|
|
basicInfo->uknDate90.minute = 1;
|
|
basicInfo->uknDate90.second = 1;
|
|
|
|
// unknown values not set:
|
|
// ukn15
|
|
// ukn2E
|
|
// ukn2F
|
|
}
|
|
// success
|
|
handleFPCallback(&cbInfo->fpCallback, 0x00000000);
|
|
|
|
free(cbInfo->principalBasicInfo);
|
|
free(cbInfo->pidList);
|
|
free(cbInfo);
|
|
}
|
|
|
|
void handleRequest_GetBasicInfoAsync(iosuFpdCemuRequest_t* fpdCemuRequest)
|
|
{
|
|
fpdCemuRequest->returnCode = 0;
|
|
if (g_fpd.nexFriendSession == nullptr || g_fpd.nexFriendSession->isOnline() == false)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000;
|
|
return;
|
|
}
|
|
sint32 count = fpdCemuRequest->getBasicInfo.count;
|
|
|
|
nexPrincipalBasicInfo* principalBasicInfo = new nexPrincipalBasicInfo[count];
|
|
uint32* pidList = (uint32*)malloc(sizeof(uint32)*count);
|
|
for (sint32 i = 0; i < count; i++)
|
|
pidList[i] = fpdCemuRequest->getBasicInfo.pidList[i];
|
|
getBasicInfoAsyncParams_t* cbInfo = (getBasicInfoAsyncParams_t*)malloc(sizeof(getBasicInfoAsyncParams_t));
|
|
cbInfo->principalBasicInfo = principalBasicInfo;
|
|
cbInfo->pidList = pidList;
|
|
cbInfo->count = count;
|
|
cbInfo->friendBasicInfo = fpdCemuRequest->getBasicInfo.basicInfo.GetPtr();
|
|
cbInfo->fpCallback.funcMPTR = fpdCemuRequest->getBasicInfo.funcPtr;
|
|
cbInfo->fpCallback.customParam = fpdCemuRequest->getBasicInfo.custom;
|
|
g_fpd.nexFriendSession->requestPrincipleBaseInfoByPID(principalBasicInfo, pidList, count, handleResultCB_GetBasicInfoAsync, cbInfo);
|
|
}
|
|
|
|
void handleResponse_addOrRemoveFriend(uint32 errorCode, MPTR funcMPTR, MPTR custom)
|
|
{
|
|
if (errorCode == 0)
|
|
{
|
|
handleFPCallback2(funcMPTR, custom, 0);
|
|
g_fpd.nexFriendSession->requestGetAllInformation(); // refresh list
|
|
}
|
|
else
|
|
handleFPCallback2(funcMPTR, custom, 0x80000000);
|
|
}
|
|
|
|
void handleRequest_RemoveFriendAsync(iosuFpdCemuRequest_t* fpdCemuRequest)
|
|
{
|
|
fpdCemuRequest->returnCode = 0;
|
|
if (g_fpd.nexFriendSession == nullptr || g_fpd.nexFriendSession->isOnline() == false)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000;
|
|
return;
|
|
}
|
|
g_fpd.nexFriendSession->removeFriend(fpdCemuRequest->addOrRemoveFriend.pid, std::bind(handleResponse_addOrRemoveFriend, std::placeholders::_1, fpdCemuRequest->addOrRemoveFriend.funcPtr, fpdCemuRequest->addOrRemoveFriend.custom));
|
|
}
|
|
|
|
void handleResponse_MarkFriendRequestAsReceivedAsync(uint32 errorCode, MPTR funcMPTR, MPTR custom)
|
|
{
|
|
if (errorCode == 0)
|
|
handleFPCallback2(funcMPTR, custom, 0);
|
|
else
|
|
handleFPCallback2(funcMPTR, custom, 0x80000000);
|
|
}
|
|
|
|
void handleRequest_MarkFriendRequestAsReceivedAsync(iosuFpdCemuRequest_t* fpdCemuRequest)
|
|
{
|
|
fpdCemuRequest->returnCode = 0;
|
|
if (g_fpd.nexFriendSession == nullptr || g_fpd.nexFriendSession->isOnline() == false)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000;
|
|
return;
|
|
}
|
|
// convert messageId list to little endian
|
|
uint64 messageIds[100];
|
|
sint32 count = 0;
|
|
for (uint32 i = 0; i < fpdCemuRequest->markFriendRequest.count; i++)
|
|
{
|
|
uint64 mid = _swapEndianU64(fpdCemuRequest->markFriendRequest.messageIdList.GetPtr()[i]);
|
|
if (mid == 0)
|
|
{
|
|
forceLogDebug_printf("MarkFriendRequestAsReceivedAsync - Invalid messageId");
|
|
continue;
|
|
}
|
|
messageIds[count] = mid;
|
|
count++;
|
|
if (count >= sizeof(messageIds)/sizeof(messageIds[0]))
|
|
break;
|
|
}
|
|
// skipped for now
|
|
g_fpd.nexFriendSession->markFriendRequestsAsReceived(messageIds, count, std::bind(handleResponse_MarkFriendRequestAsReceivedAsync, std::placeholders::_1, fpdCemuRequest->markFriendRequest.funcPtr, fpdCemuRequest->markFriendRequest.custom));
|
|
}
|
|
|
|
void handleResponse_cancelMyFriendRequest(uint32 errorCode, uint32 pid, MPTR funcMPTR, MPTR custom)
|
|
{
|
|
if (errorCode == 0)
|
|
{
|
|
handleFPCallback2(funcMPTR, custom, 0);
|
|
}
|
|
else
|
|
handleFPCallback2(funcMPTR, custom, 0x80000000);
|
|
}
|
|
|
|
void handleRequest_CancelFriendRequestAsync(iosuFpdCemuRequest_t* fpdCemuRequest)
|
|
{
|
|
fpdCemuRequest->returnCode = 0;
|
|
if (g_fpd.nexFriendSession == nullptr || g_fpd.nexFriendSession->isOnline() == false)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000;
|
|
return;
|
|
}
|
|
// find friend request with matching pid
|
|
nexFriendRequest frq;
|
|
bool isIncoming;
|
|
if (g_fpd.nexFriendSession->getFriendRequestByMessageId(frq, &isIncoming, fpdCemuRequest->cancelOrAcceptFriendRequest.messageId))
|
|
{
|
|
g_fpd.nexFriendSession->removeFriend(frq.principalInfo.principalId, std::bind(handleResponse_cancelMyFriendRequest, std::placeholders::_1, frq.principalInfo.principalId, fpdCemuRequest->cancelOrAcceptFriendRequest.funcPtr, fpdCemuRequest->cancelOrAcceptFriendRequest.custom));
|
|
}
|
|
else
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000;
|
|
return;
|
|
}
|
|
}
|
|
|
|
void handleResponse_acceptFriendRequest(uint32 errorCode, uint32 pid, MPTR funcMPTR, MPTR custom)
|
|
{
|
|
if (errorCode == 0)
|
|
{
|
|
handleFPCallback2(funcMPTR, custom, 0);
|
|
g_fpd.nexFriendSession->requestGetAllInformation(); // refresh list
|
|
}
|
|
else
|
|
handleFPCallback2(funcMPTR, custom, 0x80000000);
|
|
}
|
|
|
|
void handleRequest_AcceptFriendRequestAsync(iosuFpdCemuRequest_t* fpdCemuRequest)
|
|
{
|
|
fpdCemuRequest->returnCode = 0;
|
|
if (g_fpd.nexFriendSession == nullptr || g_fpd.nexFriendSession->isOnline() == false)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000;
|
|
return;
|
|
}
|
|
// find friend request with matching pid
|
|
nexFriendRequest frq;
|
|
bool isIncoming;
|
|
if (g_fpd.nexFriendSession->getFriendRequestByMessageId(frq, &isIncoming, fpdCemuRequest->cancelOrAcceptFriendRequest.messageId))
|
|
{
|
|
g_fpd.nexFriendSession->acceptFriendRequest(fpdCemuRequest->cancelOrAcceptFriendRequest.messageId, std::bind(handleResponse_acceptFriendRequest, std::placeholders::_1, frq.principalInfo.principalId, fpdCemuRequest->cancelOrAcceptFriendRequest.funcPtr, fpdCemuRequest->cancelOrAcceptFriendRequest.custom));
|
|
}
|
|
else
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000;
|
|
return;
|
|
}
|
|
}
|
|
|
|
void handleResponse_addFriendRequest(uint32 errorCode, MPTR funcMPTR, MPTR custom)
|
|
{
|
|
if (errorCode == 0)
|
|
{
|
|
handleFPCallback2(funcMPTR, custom, 0);
|
|
g_fpd.nexFriendSession->requestGetAllInformation(); // refresh list
|
|
}
|
|
else
|
|
handleFPCallback2(funcMPTR, custom, 0x80000000);
|
|
}
|
|
|
|
void handleRequest_AddFriendRequest(iosuFpdCemuRequest_t* fpdCemuRequest)
|
|
{
|
|
fpdCemuRequest->returnCode = 0;
|
|
if (g_fpd.nexFriendSession == nullptr || g_fpd.nexFriendSession->isOnline() == false)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000;
|
|
return;
|
|
}
|
|
|
|
uint16be* input = fpdCemuRequest->addFriendRequest.message.GetPtr();
|
|
size_t inputLen = 0;
|
|
while (input[inputLen] != 0)
|
|
inputLen++;
|
|
std::string msg = StringHelpers::ToUtf8({ input, inputLen });
|
|
|
|
g_fpd.nexFriendSession->addFriendRequest(fpdCemuRequest->addFriendRequest.pid, msg.data(), std::bind(handleResponse_addFriendRequest, std::placeholders::_1, fpdCemuRequest->addFriendRequest.funcPtr, fpdCemuRequest->addFriendRequest.custom));
|
|
}
|
|
|
|
// called once a second to handle state checking and updates of the friends service
|
|
void iosuFpd_updateFriendsService()
|
|
{
|
|
if (g_fpd.nexFriendSession)
|
|
{
|
|
g_fpd.nexFriendSession->update();
|
|
|
|
if (g_fpd.asyncLoginCallback.func != MPTR_NULL)
|
|
{
|
|
if (g_fpd.nexFriendSession->isOnline())
|
|
{
|
|
*_fpdAsyncLoginRetCode.GetPtr() = 0x00000000;
|
|
coreinitAsyncCallback_add(g_fpd.asyncLoginCallback.func, 2, _fpdAsyncLoginRetCode.GetMPTR(), g_fpd.asyncLoginCallback.customParam);
|
|
g_fpd.asyncLoginCallback.func = MPTR_NULL;
|
|
g_fpd.asyncLoginCallback.customParam = MPTR_NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void iosuFpd_thread()
|
|
{
|
|
SetThreadName("iosuFpd_thread");
|
|
while (true)
|
|
{
|
|
uint32 returnValue = 0; // Ioctl return value
|
|
ioQueueEntry_t* ioQueueEntry = iosuIoctl_getNextWithTimeout(IOS_DEVICE_FPD, 1000);
|
|
if (ioQueueEntry == nullptr)
|
|
{
|
|
iosuFpd_updateFriendsService();
|
|
continue;
|
|
}
|
|
if (ioQueueEntry->request == IOSU_FPD_REQUEST_CEMU)
|
|
{
|
|
iosuFpdCemuRequest_t* fpdCemuRequest = (iosuFpdCemuRequest_t*)ioQueueEntry->bufferVectors[0].buffer.GetPtr();
|
|
if (fpdCemuRequest->requestCode == IOSU_FPD_INITIALIZE)
|
|
{
|
|
if (g_fpd.isInitialized2 == false)
|
|
{
|
|
if(ActiveSettings::IsOnlineEnabled())
|
|
startFriendSession();
|
|
|
|
g_fpd.isInitialized2 = true;
|
|
}
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_SET_NOTIFICATION_HANDLER)
|
|
{
|
|
g_fpd.notificationFunc = fpdCemuRequest->setNotificationHandler.funcPtr;
|
|
g_fpd.notificationCustomParam = fpdCemuRequest->setNotificationHandler.custom;
|
|
g_fpd.notificationMask = fpdCemuRequest->setNotificationHandler.notificationMask;
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_LOGIN_ASYNC)
|
|
{
|
|
if (g_fpd.nexFriendSession)
|
|
{
|
|
g_fpd.asyncLoginCallback.func = fpdCemuRequest->loginAsync.funcPtr;
|
|
g_fpd.asyncLoginCallback.customParam = fpdCemuRequest->loginAsync.custom;
|
|
}
|
|
else
|
|
{
|
|
// offline mode
|
|
*_fpdAsyncLoginRetCode.GetPtr() = 0; // if we return 0x80000000 here then Splatoon softlocks during boot
|
|
coreinitAsyncCallback_add(fpdCemuRequest->loginAsync.funcPtr, 2, _fpdAsyncLoginRetCode.GetMPTR(), fpdCemuRequest->loginAsync.custom);
|
|
}
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_IS_ONLINE)
|
|
{
|
|
fpdCemuRequest->resultU32.u32 = g_fpd.nexFriendSession ? g_fpd.nexFriendSession->isOnline() : 0;
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_IS_PREFERENCE_VALID)
|
|
{
|
|
fpdCemuRequest->resultU32.u32 = 1; // todo (if this returns 0, the friend app will show the first-time-setup screen and ask the user to configure preferences)
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_MY_PRINCIPAL_ID)
|
|
{
|
|
uint8 slot = iosu::act::getCurrentAccountSlot();
|
|
iosu::act::getPrincipalId(slot, &fpdCemuRequest->resultU32.u32);
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_MY_ACCOUNT_ID)
|
|
{
|
|
char* accountId = (char*)fpdCemuRequest->common.ptr.GetPtr();
|
|
uint8 slot = iosu::act::getCurrentAccountSlot();
|
|
if (iosu::act::getAccountId(slot, accountId) == false)
|
|
fpdCemuRequest->returnCode = 0x80000000; // todo - proper error code
|
|
else
|
|
fpdCemuRequest->returnCode = 0;
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_MY_MII)
|
|
{
|
|
FFLData_t* fflData = (FFLData_t*)fpdCemuRequest->common.ptr.GetPtr();
|
|
uint8 slot = iosu::act::getCurrentAccountSlot();
|
|
if (iosu::act::getMii(slot, fflData) == false)
|
|
fpdCemuRequest->returnCode = 0x80000000; // todo - proper error code
|
|
else
|
|
fpdCemuRequest->returnCode = 0;
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_MY_SCREENNAME)
|
|
{
|
|
uint16be* screennameOutput = (uint16be*)fpdCemuRequest->common.ptr.GetPtr();
|
|
uint8 slot = iosu::act::getCurrentAccountSlot();
|
|
uint16 screennameTemp[ACT_NICKNAME_LENGTH];
|
|
if (iosu::act::getScreenname(slot, screennameTemp))
|
|
{
|
|
for (sint32 i = 0; i < ACT_NICKNAME_LENGTH; i++)
|
|
{
|
|
screennameOutput[i] = screennameTemp[i];
|
|
}
|
|
screennameOutput[ACT_NICKNAME_LENGTH] = '\0'; // length is ACT_NICKNAME_LENGTH+1
|
|
fpdCemuRequest->returnCode = 0;
|
|
}
|
|
else
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000; // todo - proper error code
|
|
screennameOutput[0] = '\0';
|
|
}
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_FRIEND_ACCOUNT_ID)
|
|
{
|
|
if (g_fpd.nexFriendSession == nullptr)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000; // todo - proper error code
|
|
iosuIoctl_completeRequest(ioQueueEntry, returnValue);
|
|
return;
|
|
}
|
|
fpdCemuRequest->returnCode = 0;
|
|
for (sint32 i = 0; i < fpdCemuRequest->getFriendAccountId.count; i++)
|
|
{
|
|
char* nnidOutput = fpdCemuRequest->getFriendAccountId.accountIds.GetPtr()+i*17;
|
|
uint32 pid = fpdCemuRequest->getFriendAccountId.pidList[i];
|
|
if (g_fpd.nexFriendSession == nullptr)
|
|
{
|
|
nnidOutput[0] = '\0';
|
|
continue;
|
|
}
|
|
nexFriend frd;
|
|
nexFriendRequest frdReq;
|
|
if (g_fpd.nexFriendSession->getFriendByPID(frd, pid))
|
|
{
|
|
strcpy(nnidOutput, frd.nnaInfo.principalInfo.nnid);
|
|
continue;
|
|
}
|
|
bool incoming = false;
|
|
if (g_fpd.nexFriendSession->getFriendRequestByPID(frdReq, &incoming, pid))
|
|
{
|
|
strcpy(nnidOutput, frdReq.principalInfo.nnid);
|
|
continue;
|
|
}
|
|
nnidOutput[0] = '\0';
|
|
}
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_FRIEND_SCREENNAME)
|
|
{
|
|
if (g_fpd.nexFriendSession == nullptr)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000; // todo - proper error code
|
|
iosuIoctl_completeRequest(ioQueueEntry, returnValue);
|
|
return;
|
|
}
|
|
fpdCemuRequest->returnCode = 0;
|
|
for (sint32 i = 0; i < fpdCemuRequest->getFriendScreenname.count; i++)
|
|
{
|
|
uint16be* screennameOutput = fpdCemuRequest->getFriendScreenname.nameList.GetPtr()+i*11;
|
|
uint32 pid = fpdCemuRequest->getFriendScreenname.pidList[i];
|
|
if(fpdCemuRequest->getFriendScreenname.languageList.IsNull() == false)
|
|
fpdCemuRequest->getFriendScreenname.languageList.GetPtr()[i] = 0;
|
|
if (g_fpd.nexFriendSession == nullptr)
|
|
{
|
|
screennameOutput[0] = '\0';
|
|
continue;
|
|
}
|
|
nexFriend frd;
|
|
nexFriendRequest frdReq;
|
|
if (g_fpd.nexFriendSession->getFriendByPID(frd, pid))
|
|
{
|
|
convertMultiByteStringToBigEndianWidechar(frd.nnaInfo.principalInfo.mii.miiNickname, screennameOutput, 11);
|
|
if (fpdCemuRequest->getFriendScreenname.languageList.IsNull() == false)
|
|
fpdCemuRequest->getFriendScreenname.languageList.GetPtr()[i] = frd.nnaInfo.principalInfo.regionGuessed;
|
|
continue;
|
|
}
|
|
bool incoming = false;
|
|
if (g_fpd.nexFriendSession->getFriendRequestByPID(frdReq, &incoming, pid))
|
|
{
|
|
convertMultiByteStringToBigEndianWidechar(frdReq.principalInfo.mii.miiNickname, screennameOutput, 11);
|
|
if (fpdCemuRequest->getFriendScreenname.languageList.IsNull() == false)
|
|
fpdCemuRequest->getFriendScreenname.languageList.GetPtr()[i] = frdReq.principalInfo.regionGuessed;
|
|
continue;
|
|
}
|
|
screennameOutput[0] = '\0';
|
|
}
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_FRIEND_MII)
|
|
{
|
|
if (g_fpd.nexFriendSession == nullptr)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000; // todo - proper error code
|
|
iosuIoctl_completeRequest(ioQueueEntry, returnValue);
|
|
return;
|
|
}
|
|
fpdCemuRequest->returnCode = 0;
|
|
for (sint32 i = 0; i < fpdCemuRequest->getFriendMii.count; i++)
|
|
{
|
|
uint8* miiOutput = fpdCemuRequest->getFriendMii.miiList + i * FFL_SIZE;
|
|
uint32 pid = fpdCemuRequest->getFriendMii.pidList[i];
|
|
if (g_fpd.nexFriendSession == nullptr)
|
|
{
|
|
memset(miiOutput, 0, FFL_SIZE);
|
|
continue;
|
|
}
|
|
nexFriend frd;
|
|
nexFriendRequest frdReq;
|
|
if (g_fpd.nexFriendSession->getFriendByPID(frd, pid))
|
|
{
|
|
memcpy(miiOutput, frd.nnaInfo.principalInfo.mii.miiData, FFL_SIZE);
|
|
continue;
|
|
}
|
|
bool incoming = false;
|
|
if (g_fpd.nexFriendSession->getFriendRequestByPID(frdReq, &incoming, pid))
|
|
{
|
|
memcpy(miiOutput, frdReq.principalInfo.mii.miiData, FFL_SIZE);
|
|
continue;
|
|
}
|
|
memset(miiOutput, 0, FFL_SIZE);
|
|
}
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_FRIEND_PRESENCE)
|
|
{
|
|
if (g_fpd.nexFriendSession == nullptr)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000; // todo - proper error code
|
|
iosuIoctl_completeRequest(ioQueueEntry, returnValue);
|
|
return;
|
|
}
|
|
fpdCemuRequest->returnCode = 0;
|
|
for (sint32 i = 0; i < fpdCemuRequest->getFriendPresence.count; i++)
|
|
{
|
|
friendPresence_t* presenceOutput = (friendPresence_t*)(fpdCemuRequest->getFriendPresence.presenceList + i * sizeof(friendPresence_t));
|
|
memset(presenceOutput, 0, sizeof(friendPresence_t));
|
|
uint32 pid = fpdCemuRequest->getFriendPresence.pidList[i];
|
|
if (g_fpd.nexFriendSession == nullptr)
|
|
{
|
|
continue;
|
|
}
|
|
nexFriend frd;
|
|
nexFriendRequest frdReq;
|
|
if (g_fpd.nexFriendSession->getFriendByPID(frd, pid))
|
|
{
|
|
presenceOutput->isOnline = frd.presence.isOnline ? 1 : 0;
|
|
presenceOutput->isValid = 1;
|
|
|
|
presenceOutput->gameMode.joinFlagMask = frd.presence.joinFlagMask;
|
|
presenceOutput->gameMode.matchmakeType = frd.presence.joinAvailability;
|
|
presenceOutput->gameMode.joinGameId = frd.presence.gameId;
|
|
presenceOutput->gameMode.joinGameMode = frd.presence.gameMode;
|
|
presenceOutput->gameMode.hostPid = frd.presence.hostPid;
|
|
presenceOutput->gameMode.groupId = frd.presence.groupId;
|
|
|
|
memcpy(presenceOutput->gameMode.appSpecificData, frd.presence.appSpecificData, 0x14);
|
|
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_FRIEND_RELATIONSHIP)
|
|
{
|
|
if (g_fpd.nexFriendSession == nullptr)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000; // todo - proper error code
|
|
iosuIoctl_completeRequest(ioQueueEntry, returnValue);
|
|
return;
|
|
}
|
|
fpdCemuRequest->returnCode = 0;
|
|
for (sint32 i = 0; i < fpdCemuRequest->getFriendRelationship.count; i++)
|
|
{
|
|
uint8* relationshipOutput = (fpdCemuRequest->getFriendRelationship.relationshipList + i);
|
|
uint32 pid = fpdCemuRequest->getFriendRelationship.pidList[i];
|
|
*relationshipOutput = RELATIONSHIP_INVALID;
|
|
if (g_fpd.nexFriendSession == nullptr)
|
|
{
|
|
continue;
|
|
}
|
|
nexFriend frd;
|
|
nexFriendRequest frdReq;
|
|
bool incoming;
|
|
if (g_fpd.nexFriendSession->getFriendByPID(frd, pid))
|
|
{
|
|
*relationshipOutput = RELATIONSHIP_FRIEND;
|
|
continue;
|
|
}
|
|
else if (g_fpd.nexFriendSession->getFriendRequestByPID(frdReq, &incoming, pid))
|
|
{
|
|
if(incoming)
|
|
*relationshipOutput = RELATIONSHIP_FRIENDREQUEST_IN;
|
|
else
|
|
*relationshipOutput = RELATIONSHIP_FRIENDREQUEST_OUT;
|
|
}
|
|
}
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_FRIEND_LIST)
|
|
{
|
|
handleRequest_GetFriendList(fpdCemuRequest, false);
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_FRIENDREQUEST_LIST)
|
|
{
|
|
handleRequest_GetFriendRequestList(fpdCemuRequest);
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_FRIEND_LIST_ALL)
|
|
{
|
|
handleRequest_GetFriendList(fpdCemuRequest, true);
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_FRIEND_LIST_EX)
|
|
{
|
|
if (g_fpd.nexFriendSession == nullptr)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000; // todo - proper error code
|
|
iosuIoctl_completeRequest(ioQueueEntry, returnValue);
|
|
return;
|
|
}
|
|
handleRequest_GetFriendListEx(fpdCemuRequest);
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_FRIENDREQUEST_LIST_EX)
|
|
{
|
|
if (g_fpd.nexFriendSession == nullptr)
|
|
{
|
|
fpdCemuRequest->returnCode = 0x80000000; // todo - proper error code
|
|
iosuIoctl_completeRequest(ioQueueEntry, returnValue);
|
|
return;
|
|
}
|
|
handleRequest_GetFriendRequestListEx(fpdCemuRequest);
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_ADD_FRIEND)
|
|
{
|
|
// todo - figure out how this works
|
|
*_fpdAsyncAddFriendRetCode.GetPtr() = 0;
|
|
coreinitAsyncCallback_add(fpdCemuRequest->addOrRemoveFriend.funcPtr, 2, _fpdAsyncAddFriendRetCode.GetMPTR(), fpdCemuRequest->addOrRemoveFriend.custom);
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_ADD_FRIEND_REQUEST)
|
|
{
|
|
handleRequest_AddFriendRequest(fpdCemuRequest);
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_REMOVE_FRIEND_ASYNC)
|
|
{
|
|
handleRequest_RemoveFriendAsync(fpdCemuRequest);
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_MARK_FRIEND_REQUEST_AS_RECEIVED_ASYNC)
|
|
{
|
|
handleRequest_MarkFriendRequestAsReceivedAsync(fpdCemuRequest);
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_CANCEL_FRIEND_REQUEST_ASYNC)
|
|
{
|
|
handleRequest_CancelFriendRequestAsync(fpdCemuRequest);
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_ACCEPT_FRIEND_REQUEST_ASYNC)
|
|
{
|
|
handleRequest_AcceptFriendRequestAsync(fpdCemuRequest);
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_GET_BASIC_INFO_ASYNC)
|
|
{
|
|
handleRequest_GetBasicInfoAsync(fpdCemuRequest);
|
|
}
|
|
else if (fpdCemuRequest->requestCode == IOSU_FPD_UPDATE_GAMEMODE)
|
|
{
|
|
gameMode_t* gameMode = fpdCemuRequest->updateGameMode.gameMode.GetPtr();
|
|
uint16be* gameModeMessage = fpdCemuRequest->updateGameMode.gameModeMessage.GetPtr();
|
|
|
|
g_fpd.myPresence.joinFlagMask = gameMode->joinFlagMask;
|
|
|
|
g_fpd.myPresence.joinAvailability = (uint8)(uint32)gameMode->matchmakeType;
|
|
g_fpd.myPresence.gameId = gameMode->joinGameId;
|
|
g_fpd.myPresence.gameMode = gameMode->joinGameMode;
|
|
g_fpd.myPresence.hostPid = gameMode->hostPid;
|
|
g_fpd.myPresence.groupId = gameMode->groupId;
|
|
memcpy(g_fpd.myPresence.appSpecificData, gameMode->appSpecificData, 0x14);
|
|
|
|
if (g_fpd.nexFriendSession)
|
|
{
|
|
g_fpd.nexFriendSession->updateMyPresence(g_fpd.myPresence);
|
|
}
|
|
|
|
fpdCemuRequest->returnCode = 0;
|
|
}
|
|
else
|
|
cemu_assert_unimplemented();
|
|
}
|
|
else
|
|
assert_dbg();
|
|
iosuIoctl_completeRequest(ioQueueEntry, returnValue);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void Initialize()
|
|
{
|
|
if (g_fpd.isThreadStarted)
|
|
return;
|
|
std::thread t1(iosuFpd_thread);
|
|
t1.detach();
|
|
g_fpd.isThreadStarted = true;
|
|
}
|
|
}
|
|
} |