nn_fp: Full rework of friend service

This commit is contained in:
Exzap 2023-10-17 04:41:22 +02:00
parent 13a50a915e
commit 0d71885c88
37 changed files with 2862 additions and 1991 deletions

View File

@ -526,6 +526,13 @@ namespace CafeSystem
cemuLog_log(LogType::Force, "Platform: {}", platform);
}
static std::vector<IOSUModule*> s_iosuModules =
{
// entries in this list are ordered by initialization order. Shutdown in reverse order
iosu::kernel::GetModule(),
iosu::fpd::GetModule()
};
// initialize all subsystems which are persistent and don't depend on a game running
void Initialize()
{
@ -550,14 +557,15 @@ namespace CafeSystem
// allocate memory for all SysAllocators
// must happen before COS module init, but also before iosu::kernel::Initialize()
SysAllocatorContainer::GetInstance().Initialize();
// init IOSU
// init IOSU modules
for(auto& module : s_iosuModules)
module->SystemLaunch();
// init IOSU (deprecated manual init)
iosuCrypto_init();
iosu::kernel::Initialize();
iosu::fsa::Initialize();
iosuIoctl_init();
iosuAct_init_depr();
iosu::act::Initialize();
iosu::fpd::Initialize();
iosu::iosuMcp_init();
iosu::mcp::Init();
iosu::iosuAcp_init();
@ -593,11 +601,14 @@ namespace CafeSystem
// if a title is running, shut it down
if (sSystemRunning)
ShutdownTitle();
// shutdown persistent subsystems
// shutdown persistent subsystems (deprecated manual shutdown)
iosu::odm::Shutdown();
iosu::act::Stop();
iosu::mcp::Shutdown();
iosu::fsa::Shutdown();
// shutdown IOSU modules
for(auto it = s_iosuModules.rbegin(); it != s_iosuModules.rend(); ++it)
(*it)->SystemExit();
s_initialized = false;
}
@ -821,7 +832,8 @@ namespace CafeSystem
void _LaunchTitleThread()
{
// init
for(auto& module : s_iosuModules)
module->TitleStart();
cemu_initForGame();
// enter scheduler
if (ActiveSettings::GetCPUMode() == CPUMode::MulticoreRecompiler)
@ -956,6 +968,8 @@ namespace CafeSystem
nn::save::ResetToDefaultState();
coreinit::__OSDeleteAllActivePPCThreads();
RPLLoader_ResetState();
for(auto it = s_iosuModules.rbegin(); it != s_iosuModules.rend(); ++it)
(*it)->TitleStop();
// stop time tracking
iosu::pdm::Stop();
// reset Cemu subsystems

View File

@ -19,7 +19,7 @@ void PPCInterpreter_handleUnsupportedHLECall(PPCInterpreter_t* hCPU)
std::vector<void(*)(PPCInterpreter_t* hCPU)>* sPPCHLETable{};
HLEIDX PPCInterpreter_registerHLECall(HLECALL hleCall)
HLEIDX PPCInterpreter_registerHLECall(HLECALL hleCall, std::string hleName)
{
if (!sPPCHLETable)
sPPCHLETable = new std::vector<void(*)(PPCInterpreter_t* hCPU)>();

View File

@ -230,7 +230,7 @@ static inline float flushDenormalToZero(float f)
typedef void(*HLECALL)(PPCInterpreter_t* hCPU);
typedef sint32 HLEIDX;
HLEIDX PPCInterpreter_registerHLECall(HLECALL hleCall);
HLEIDX PPCInterpreter_registerHLECall(HLECALL hleCall, std::string hleName);
HLECALL PPCInterpreter_getHLECall(HLEIDX funcIndex);
// HLE scheduler

View File

@ -1,6 +1,9 @@
#pragma once
using IOSMsgQueueId = uint32;
using IOSTimerId = uint32;
static constexpr IOSTimerId IOSInvalidTimerId = 0xFFFFFFFF;
// returned for syscalls
// maybe also shared with IPC?
@ -20,3 +23,12 @@ inline bool IOS_ResultIsError(const IOS_ERROR err)
{
return (err & 0x80000000) != 0;
}
class IOSUModule
{
public:
virtual void SystemLaunch() {}; // CafeSystem is initialized
virtual void SystemExit() {}; // CafeSystem is shutdown
virtual void TitleStart() {}; // foreground title is launched
virtual void TitleStop() {}; // foreground title is closed
};

View File

@ -1,6 +1,8 @@
#include "iosu_kernel.h"
#include "util/helpers/fspinlock.h"
#include "util/helpers/helpers.h"
#include "Cafe/OS/libs/coreinit/coreinit_IPC.h"
#include "util/highresolutiontimer/HighResolutionTimer.h"
namespace iosu
{
@ -8,6 +10,9 @@ namespace iosu
{
std::mutex sInternalMutex;
void IOS_DestroyResourceManagerForQueueId(IOSMsgQueueId msgQueueId);
void _IPCDestroyAllHandlesForMsgQueue(IOSMsgQueueId msgQueueId);
static void _assume_lock()
{
#ifdef CEMU_DEBUG_ASSERT
@ -84,6 +89,19 @@ namespace iosu
return queueHandle;
}
IOS_ERROR IOS_DestroyMessageQueue(IOSMsgQueueId msgQueueId)
{
std::unique_lock _l(sInternalMutex);
IOSMessageQueue* msgQueue = nullptr;
IOS_ERROR r = _IOS_GetMessageQueue(msgQueueId, msgQueue);
if (r != IOS_ERROR_OK)
return r;
msgQueue->msgArraySize = 0;
msgQueue->queueHandle = 0;
IOS_DestroyResourceManagerForQueueId(msgQueueId);
return IOS_ERROR_OK;
}
IOS_ERROR IOS_SendMessage(IOSMsgQueueId msgQueueId, IOSMessage message, uint32 flags)
{
std::unique_lock _l(sInternalMutex);
@ -146,6 +164,133 @@ namespace iosu
return IOS_ERROR_OK;
}
/* timer */
std::mutex sTimerMutex;
std::condition_variable sTimerCV;
std::atomic_bool sTimerThreadStop;
struct IOSTimer
{
IOSMsgQueueId queueId;
uint32 message;
HRTick nextFire;
HRTick repeat;
bool isValid;
};
std::vector<IOSTimer> sTimers;
std::vector<IOSTimerId> sTimersFreeHandles;
auto sTimerSortComparator = [](const IOSTimerId& idA, const IOSTimerId& idB)
{
// order by nextFire, then by timerId to avoid duplicate keys
IOSTimer& timerA = sTimers[idA];
IOSTimer& timerB = sTimers[idB];
if (timerA.nextFire != timerB.nextFire)
return timerA.nextFire < timerB.nextFire;
return idA < idB;
};
std::set<IOSTimerId, decltype(sTimerSortComparator)> sTimerByFireTime;
IOSTimer& IOS_GetFreeTimer()
{
cemu_assert_debug(!sTimerMutex.try_lock()); // lock must be held by current thread
if (sTimersFreeHandles.empty())
return sTimers.emplace_back();
IOSTimerId timerId = sTimersFreeHandles.back();
sTimersFreeHandles.pop_back();
return sTimers[timerId];
}
void IOS_TimerSetNextFireTime(IOSTimer& timer, HRTick nextFire)
{
cemu_assert_debug(!sTimerMutex.try_lock()); // lock must be held by current thread
IOSTimerId timerId = &timer - sTimers.data();
auto it = sTimerByFireTime.find(timerId);
if(it != sTimerByFireTime.end())
sTimerByFireTime.erase(it);
timer.nextFire = nextFire;
if(nextFire != 0)
sTimerByFireTime.insert(timerId);
}
void IOS_StopTimerInternal(IOSTimerId timerId)
{
cemu_assert_debug(!sTimerMutex.try_lock());
IOS_TimerSetNextFireTime(sTimers[timerId], 0);
}
IOS_ERROR IOS_CreateTimer(uint32 startMicroseconds, uint32 repeatMicroseconds, uint32 queueId, uint32 message)
{
std::unique_lock _l(sTimerMutex);
IOSTimer& timer = IOS_GetFreeTimer();
timer.queueId = queueId;
timer.message = message;
HRTick nextFire = HighResolutionTimer::now().getTick() + HighResolutionTimer::microsecondsToTicks(startMicroseconds);
timer.repeat = HighResolutionTimer::microsecondsToTicks(repeatMicroseconds);
IOS_TimerSetNextFireTime(timer, nextFire);
timer.isValid = true;
sTimerCV.notify_one();
return (IOS_ERROR)(&timer - sTimers.data());
}
IOS_ERROR IOS_StopTimer(IOSTimerId timerId)
{
std::unique_lock _l(sTimerMutex);
if (timerId >= sTimers.size() || !sTimers[timerId].isValid)
return IOS_ERROR_INVALID;
IOS_StopTimerInternal(timerId);
return IOS_ERROR_OK;
}
IOS_ERROR IOS_DestroyTimer(IOSTimerId timerId)
{
std::unique_lock _l(sTimerMutex);
if (timerId >= sTimers.size() || !sTimers[timerId].isValid)
return IOS_ERROR_INVALID;
IOS_StopTimerInternal(timerId);
sTimers[timerId].isValid = false;
sTimersFreeHandles.push_back(timerId);
return IOS_ERROR_OK;
}
void IOSTimerThread()
{
SetThreadName("IOS-Timer");
std::unique_lock _l(sTimerMutex);
while (!sTimerThreadStop)
{
if (sTimerByFireTime.empty())
{
sTimerCV.wait_for(_l, std::chrono::milliseconds(10000));
continue;
}
IOSTimerId timerId = *sTimerByFireTime.begin();
IOSTimer& timer = sTimers[timerId];
HRTick now = HighResolutionTimer::now().getTick();
if (now >= timer.nextFire)
{
if(timer.repeat == 0)
IOS_TimerSetNextFireTime(timer, 0);
else
IOS_TimerSetNextFireTime(timer, timer.nextFire + timer.repeat);
IOSMsgQueueId queueId = timer.queueId;
uint32 message = timer.message;
// fire timer
_l.unlock();
IOSMessage msg;
IOS_SendMessage(queueId, message, 1);
_l.lock();
continue;
}
else
{
sTimerCV.wait_for(_l, std::chrono::microseconds(HighResolutionTimer::ticksToMicroseconds(timer.nextFire - now)));
}
}
}
/* devices and IPC */
struct IOSResourceManager
@ -209,6 +354,23 @@ namespace iosu
return IOS_ERROR_OK;
}
void IOS_DestroyResourceManagerForQueueId(IOSMsgQueueId msgQueueId)
{
_assume_lock();
// destroy all IPC handles associated with this queue
_IPCDestroyAllHandlesForMsgQueue(msgQueueId);
// destroy device resource manager
for (auto& it : sDeviceResources)
{
if (it.isSet && it.msgQueueId == msgQueueId)
{
it.isSet = false;
it.path.clear();
it.msgQueueId = 0;
}
}
}
IOS_ERROR IOS_DeviceAssociateId(const char* devicePath, uint32 id)
{
// not yet implemented
@ -344,6 +506,22 @@ namespace iosu
return IOS_ERROR_OK;
}
void _IPCDestroyAllHandlesForMsgQueue(IOSMsgQueueId msgQueueId)
{
_assume_lock();
for (auto& it : sActiveDeviceHandles)
{
if (it.isSet && it.msgQueueId == msgQueueId)
{
it.isSet = false;
it.path.clear();
it.handleCheckValue = 0;
it.hasDispatchTargetHandle = false;
it.msgQueueId = 0;
}
}
}
IOS_ERROR _IPCAssignDispatchTargetHandle(IOSDevHandle devHandle, IOSDevHandle internalHandle)
{
std::unique_lock _lock(sInternalMutex);
@ -453,7 +631,6 @@ namespace iosu
uint32 numIn = dispatchCmd->body.args[1];
uint32 numOut = dispatchCmd->body.args[2];
IPCIoctlVector* vec = MEMPTR<IPCIoctlVector>(cmd.args[3]).GetPtr();
// copy the vector array
uint32 numVec = numIn + numOut;
if (numVec <= 8)
@ -466,8 +643,23 @@ namespace iosu
// reuse the original vector pointer
cemuLog_log(LogType::Force, "Info: Ioctlv command with more than 8 vectors");
}
IOS_ERROR r = _IPCDispatchToResourceManager(dispatchCmd->body.devHandle, dispatchCmd);
return r;
return _IPCDispatchToResourceManager(dispatchCmd->body.devHandle, dispatchCmd);
}
// normally COS kernel handles this, but currently we skip the IPC getting proxied through it
IOS_ERROR _IPCHandlerIn_TranslateVectorAddresses(IOSDispatchableCommand* dispatchCmd)
{
uint32 numIn = dispatchCmd->body.args[1];
uint32 numOut = dispatchCmd->body.args[2];
IPCIoctlVector* vec = MEMPTR<IPCIoctlVector>(dispatchCmd->body.args[3]).GetPtr();
for (uint32 i = 0; i < numIn + numOut; i++)
{
if (vec[i].baseVirt == nullptr && vec[i].size != 0)
return IOS_ERROR_INVALID;
// todo - check for valid pointer range
vec[i].basePhys = vec[i].baseVirt;
}
return IOS_ERROR_OK;
}
// called by COS directly
@ -494,6 +686,10 @@ namespace iosu
r = _IPCHandlerIn_IOS_Ioctl(dispatchCmd);
break;
case IPCCommandId::IOS_IOCTLV:
r = _IPCHandlerIn_TranslateVectorAddresses(dispatchCmd);
if(r < 0)
cemuLog_log(LogType::Force, "Ioctlv error");
else
r = _IPCHandlerIn_IOS_Ioctlv(dispatchCmd);
break;
default:
@ -547,10 +743,34 @@ namespace iosu
return IOS_ERROR_OK;
}
void Initialize()
class : public ::IOSUModule
{
void SystemLaunch() override
{
_IPCInitDispatchablePool();
// start timer thread
sTimerThreadStop = false;
m_timerThread = std::thread(IOSTimerThread);
}
void SystemExit() override
{
// stop timer thread
sTimerThreadStop = true;
sTimerCV.notify_one();
m_timerThread.join();
// reset resources
// todo
}
std::thread m_timerThread;
}sIOSUModuleKernel;
IOSUModule* GetModule()
{
return static_cast<IOSUModule*>(&sIOSUModuleKernel);
}
}
}

View File

@ -9,15 +9,20 @@ namespace iosu
using IOSMessage = uint32;
IOSMsgQueueId IOS_CreateMessageQueue(IOSMessage* messageArray, uint32 messageCount);
IOS_ERROR IOS_DestroyMessageQueue(IOSMsgQueueId msgQueueId);
IOS_ERROR IOS_SendMessage(IOSMsgQueueId msgQueueId, IOSMessage message, uint32 flags);
IOS_ERROR IOS_ReceiveMessage(IOSMsgQueueId msgQueueId, IOSMessage* messageOut, uint32 flags);
IOS_ERROR IOS_CreateTimer(uint32 startMicroseconds, uint32 repeatMicroseconds, uint32 queueId, uint32 message);
IOS_ERROR IOS_StopTimer(IOSTimerId timerId);
IOS_ERROR IOS_DestroyTimer(IOSTimerId timerId);
IOS_ERROR IOS_RegisterResourceManager(const char* devicePath, IOSMsgQueueId msgQueueId);
IOS_ERROR IOS_DeviceAssociateId(const char* devicePath, uint32 id);
IOS_ERROR IOS_ResourceReply(IPCCommandBody* cmd, IOS_ERROR result);
void IPCSubmitFromCOS(uint32 ppcCoreIndex, IPCCommandBody* cmd);
void Initialize();
IOSUModule* GetModule();
}
}

View File

@ -192,6 +192,15 @@ namespace iosu
return true;
}
// returns empty string if invalid
std::string getAccountId2(uint8 slot)
{
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
if (_actAccountData[accountIndex].isValid == false)
return {};
return {_actAccountData[accountIndex].accountId};
}
bool getMii(uint8 slot, FFLData_t* fflData)
{
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);

View File

@ -3,6 +3,8 @@
void iosuAct_init_depr();
bool iosuAct_isInitialized();
#define ACT_ACCOUNTID_LENGTH (17) // includes '\0'
// Mii
#define MII_FFL_STORAGE_SIZE (96)
@ -48,6 +50,8 @@ namespace iosu
bool getScreenname(uint8 slot, uint16 screenname[ACT_NICKNAME_LENGTH]);
bool getCountryIndex(uint8 slot, uint32* countryIndex);
std::string getAccountId2(uint8 slot);
const uint8 ACT_SLOT_CURRENT = 0xFE;
void Initialize();

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,12 @@
#pragma once
#include "Cafe/IOSU/iosu_types_common.h"
#include "Common/CafeString.h"
namespace iosu
{
namespace fpd
{
typedef struct
struct FPDDate
{
/* +0x0 */ uint16be year;
/* +0x2 */ uint8 month;
@ -13,11 +15,59 @@ namespace iosu
/* +0x5 */ uint8 minute;
/* +0x6 */ uint8 second;
/* +0x7 */ uint8 padding;
}fpdDate_t;
};
static_assert(sizeof(fpdDate_t) == 8);
static_assert(sizeof(FPDDate) == 8);
typedef struct
struct RecentPlayRecordEx
{
/* +0x00 */ uint32be pid;
/* +0x04 */ uint8 ukn04;
/* +0x05 */ uint8 ukn05;
/* +0x06 */ uint8 ukn06[0x22];
/* +0x28 */ uint8 ukn28[0x22];
/* +0x4A */ uint8 _uknOrPadding4A[6];
/* +0x50 */ uint32be ukn50;
/* +0x54 */ uint32be ukn54;
/* +0x58 */ uint16be ukn58;
/* +0x5C */ uint8 _padding5C[4];
/* +0x60 */ iosu::fpd::FPDDate date;
};
static_assert(sizeof(RecentPlayRecordEx) == 0x68, "");
static_assert(offsetof(RecentPlayRecordEx, ukn06) == 0x06, "");
static_assert(offsetof(RecentPlayRecordEx, ukn50) == 0x50, "");
struct GameKey
{
/* +0x00 */ uint64be titleId;
/* +0x08 */ uint16be ukn08;
/* +0x0A */ uint8 _padding0A[6];
};
static_assert(sizeof(GameKey) == 0x10);
struct Profile
{
uint8be region;
uint8be regionSubcode;
uint8be platform;
uint8be ukn3;
};
static_assert(sizeof(Profile) == 0x4);
struct GameMode
{
/* +0x00 */ uint32be joinFlagMask;
/* +0x04 */ uint32be matchmakeType;
/* +0x08 */ uint32be joinGameId;
/* +0x0C */ uint32be joinGameMode;
/* +0x10 */ uint32be hostPid;
/* +0x14 */ uint32be groupId;
/* +0x18 */ uint8 appSpecificData[0x14];
};
static_assert(sizeof(GameMode) == 0x2C);
struct FriendData
{
/* +0x000 */ uint8 type; // type (Non-Zero -> Friend, 0 -> Friend request ? )
/* +0x001 */ uint8 _padding1[7];
@ -29,43 +79,29 @@ namespace iosu
/* +0x036 */ uint8 ukn036;
/* +0x037 */ uint8 _padding037;
/* +0x038 */ uint8 mii[0x60];
/* +0x098 */ fpdDate_t uknDate;
/* +0x098 */ FPDDate uknDate;
// sub struct (the part above seems to be shared with friend requests)
union
{
struct
{
/* +0x0A0 */ uint8 ukn0A0; // country code?
/* +0x0A1 */ uint8 ukn0A1; // country subcode?
/* +0x0A2 */ uint8 _paddingA2[2];
/* +0x0A0 */ Profile profile; // this is returned for nn_fp.GetFriendProfile
/* +0x0A4 */ uint32be ukn0A4;
/* +0x0A8 */ uint64 gameKeyTitleId;
/* +0x0B0 */ uint16be gameKeyUkn;
/* +0x0B2 */ uint8 _paddingB2[6];
/* +0x0B8 */ uint32 ukn0B8;
/* +0x0BC */ uint32 ukn0BC;
/* +0x0C0 */ uint32 ukn0C0;
/* +0x0C4 */ uint32 ukn0C4;
/* +0x0C8 */ uint32 ukn0C8;
/* +0x0CC */ uint32 ukn0CC;
/* +0x0D0 */ uint8 appSpecificData[0x14];
/* +0x0E4 */ uint8 ukn0E4;
/* +0x0E5 */ uint8 _paddingE5;
/* +0x0E6 */ uint16 uknStr[0x80]; // game mode description (could be larger)
/* +0x1E6 */ uint8 _padding1E6[0x1EC - 0x1E6];
/* +0x0A8 */ GameKey gameKey;
/* +0x0B8 */ GameMode gameMode;
/* +0x0E4 */ CafeWideString<0x82> gameModeDescription;
/* +0x1E8 */ Profile profile1E8; // how does it differ from the one at 0xA0? Returned by GetFriendPresence
/* +0x1EC */ uint8 isOnline;
/* +0x1ED */ uint8 _padding1ED[3];
// some other sub struct?
/* +0x1F0 */ uint8 ukn1F0;
/* +0x1F1 */ uint8 _padding1F1;
/* +0x1F2 */ uint16be statusMessage[16 + 1]; // pops up every few seconds in friend list (ingame character name?)
/* +0x214 */ uint8 _padding214[4];
/* +0x218 */ fpdDate_t uknDate218;
/* +0x220 */ fpdDate_t lastOnline;
/* +0x1F0 */ char comment[36]; // pops up every few seconds in friend list
/* +0x214 */ uint32be _padding214;
/* +0x218 */ FPDDate approvalTime;
/* +0x220 */ FPDDate lastOnline;
}friendExtraData;
struct
{
/* +0x0A0 */ uint64 messageId; // guessed
/* +0x0A0 */ uint64be messageId; // guessed. If 0, then relationship is FRIENDSHIP_REQUEST_OUT, otherwise FRIENDSHIP_REQUEST_IN
/* +0x0A8 */ uint8 ukn0A8;
/* +0x0A9 */ uint8 ukn0A9; // comment language? (guessed)
/* +0x0AA */ uint16be comment[0x40];
@ -75,26 +111,23 @@ namespace iosu
/* +0x150 */ uint64 gameKeyTitleId;
/* +0x158 */ uint16be gameKeyUkn;
/* +0x15A */ uint8 _padding[6];
/* +0x160 */ fpdDate_t uknData0;
/* +0x168 */ fpdDate_t uknData1;
/* +0x160 */ FPDDate uknData0;
/* +0x168 */ FPDDate uknData1;
}requestExtraData;
};
}friendData_t;
};
static_assert(sizeof(FriendData) == 0x228);
static_assert(offsetof(FriendData, friendExtraData.gameKey) == 0x0A8);
static_assert(offsetof(FriendData, friendExtraData.gameModeDescription) == 0x0E4);
static_assert(offsetof(FriendData, friendExtraData.comment) == 0x1F0);
static_assert(sizeof(friendData_t) == 0x228, "");
static_assert(offsetof(friendData_t, nnid) == 0x00C, "");
static_assert(offsetof(friendData_t, friendExtraData.gameKeyTitleId) == 0x0A8, "");
static_assert(offsetof(friendData_t, friendExtraData.appSpecificData) == 0x0D0, "");
static_assert(offsetof(friendData_t, friendExtraData.uknStr) == 0x0E6, "");
static_assert(offsetof(friendData_t, friendExtraData.ukn1F0) == 0x1F0, "");
static_assert(offsetof(FriendData, requestExtraData.messageId) == 0x0A0);
static_assert(offsetof(FriendData, requestExtraData.comment) == 0x0AA);
static_assert(offsetof(FriendData, requestExtraData.uknMessage) == 0x12C);
static_assert(offsetof(FriendData, requestExtraData.gameKeyTitleId) == 0x150);
static_assert(offsetof(FriendData, requestExtraData.uknData1) == 0x168);
static_assert(offsetof(friendData_t, requestExtraData.messageId) == 0x0A0, "");
static_assert(offsetof(friendData_t, requestExtraData.comment) == 0x0AA, "");
static_assert(offsetof(friendData_t, requestExtraData.uknMessage) == 0x12C, "");
static_assert(offsetof(friendData_t, requestExtraData.gameKeyTitleId) == 0x150, "");
static_assert(offsetof(friendData_t, requestExtraData.uknData1) == 0x168, "");
typedef struct
struct FriendBasicInfo
{
/* +0x00 */ uint32be pid;
/* +0x04 */ char nnid[0x11];
@ -104,17 +137,17 @@ namespace iosu
/* +0x2E */ uint8 ukn2E; // bool option
/* +0x2F */ uint8 ukn2F;
/* +0x30 */ uint8 miiData[0x60];
/* +0x90 */ fpdDate_t uknDate90;
}friendBasicInfo_t; // size is 0x98
/* +0x90 */ FPDDate uknDate90;
};
static_assert(sizeof(friendBasicInfo_t) == 0x98, "");
static_assert(offsetof(friendBasicInfo_t, nnid) == 0x04, "");
static_assert(offsetof(friendBasicInfo_t, ukn15) == 0x15, "");
static_assert(offsetof(friendBasicInfo_t, screenname) == 0x18, "");
static_assert(offsetof(friendBasicInfo_t, ukn2E) == 0x2E, "");
static_assert(offsetof(friendBasicInfo_t, miiData) == 0x30, "");
static_assert(sizeof(FriendBasicInfo) == 0x98);
static_assert(offsetof(FriendBasicInfo, nnid) == 0x04);
static_assert(offsetof(FriendBasicInfo, ukn15) == 0x15);
static_assert(offsetof(FriendBasicInfo, screenname) == 0x18);
static_assert(offsetof(FriendBasicInfo, ukn2E) == 0x2E);
static_assert(offsetof(FriendBasicInfo, miiData) == 0x30);
typedef struct
struct FriendRequest
{
/* +0x000 */ uint32be pid;
/* +0x004 */ uint8 nnid[17]; // guessed type
@ -125,7 +158,7 @@ namespace iosu
/* +0x02E */ uint8 ukn2E; // bool option
/* +0x02F */ uint8 ukn2F; // ukn
/* +0x030 */ uint8 miiData[0x60];
/* +0x090 */ fpdDate_t uknDate;
/* +0x090 */ FPDDate uknDate;
/* +0x098 */ uint64 ukn98;
/* +0x0A0 */ uint8 isMarkedAsReceived;
/* +0x0A1 */ uint8 uknA1;
@ -136,216 +169,98 @@ namespace iosu
/* +0x148 */ uint64 gameKeyTitleId;
/* +0x150 */ uint16be gameKeyUkn;
/* +0x152 */ uint8 _padding152[6];
/* +0x158 */ fpdDate_t uknDate2;
/* +0x160 */ fpdDate_t expireDate;
}friendRequest_t;
/* +0x158 */ FPDDate uknDate2;
/* +0x160 */ FPDDate expireDate;
};
static_assert(sizeof(friendRequest_t) == 0x168, "");
static_assert(offsetof(friendRequest_t, uknDate) == 0x090, "");
static_assert(offsetof(friendRequest_t, message) == 0x0A2, "");
static_assert(offsetof(friendRequest_t, uknString2) == 0x124, "");
static_assert(offsetof(friendRequest_t, gameKeyTitleId) == 0x148, "");
static_assert(sizeof(FriendRequest) == 0x168);
static_assert(offsetof(FriendRequest, uknDate) == 0x090);
static_assert(offsetof(FriendRequest, message) == 0x0A2);
static_assert(offsetof(FriendRequest, uknString2) == 0x124);
static_assert(offsetof(FriendRequest, gameKeyTitleId) == 0x148);
typedef struct
struct FriendPresence
{
/* +0x00 */ uint32be joinFlagMask;
/* +0x04 */ uint32be matchmakeType;
/* +0x08 */ uint32be joinGameId;
/* +0x0C */ uint32be joinGameMode;
/* +0x10 */ uint32be hostPid;
/* +0x14 */ uint32be groupId;
/* +0x18 */ uint8 appSpecificData[0x14];
}gameMode_t;
static_assert(sizeof(gameMode_t) == 0x2C, "");
typedef struct
{
gameMode_t gameMode;
/* +0x2C */ uint8 region;
/* +0x2D */ uint8 regionSubcode;
/* +0x2E */ uint8 platform;
/* +0x2F */ uint8 _padding2F;
GameMode gameMode;
/* +0x2C */ Profile profile;
/* +0x30 */ uint8 isOnline;
/* +0x31 */ uint8 isValid;
/* +0x32 */ uint8 padding[2]; // guessed
}friendPresence_t;
};
static_assert(sizeof(FriendPresence) == 0x34);
static_assert(offsetof(FriendPresence, isOnline) == 0x30);
static_assert(sizeof(friendPresence_t) == 0x34, "");
static_assert(offsetof(friendPresence_t, region) == 0x2C, "");
static_assert(offsetof(friendPresence_t, isOnline) == 0x30, "");
struct FPDNotification
{
betype<uint32> type;
betype<uint32> pid;
};
static_assert(sizeof(FPDNotification) == 8);
struct FPDPreference
{
uint8be showOnline; // show online status to others
uint8be showGame; // show played game to others
uint8be blockFriendRequests; // block friend requests
uint8be ukn; // probably padding?
};
static_assert(sizeof(FPDPreference) == 4);
static const int RELATIONSHIP_INVALID = 0;
static const int RELATIONSHIP_FRIENDREQUEST_OUT = 1;
static const int RELATIONSHIP_FRIENDREQUEST_IN = 2;
static const int RELATIONSHIP_FRIEND = 3;
typedef struct
static const int GAMEMODE_MAX_MESSAGE_LENGTH = 0x80; // limit includes null-terminator character, so only 0x7F actual characters can be used
enum class FPD_REQUEST_ID
{
uint32 requestCode;
union
{
struct
{
MEMPTR<void> ptr;
}common;
struct
{
MPTR funcPtr;
MPTR custom;
}loginAsync;
struct
{
MEMPTR<uint32be> pidList;
uint32 startIndex;
uint32 maxCount;
}getFriendList;
struct
{
MEMPTR<friendData_t> friendData;
MEMPTR<uint32be> pidList;
uint32 count;
}getFriendListEx;
struct
{
MEMPTR<friendRequest_t> friendRequest;
MEMPTR<uint32be> pidList;
uint32 count;
}getFriendRequestListEx;
struct
{
uint32 pid;
MPTR funcPtr;
MPTR custom;
}addOrRemoveFriend;
struct
{
uint64 messageId;
MPTR funcPtr;
MPTR custom;
}cancelOrAcceptFriendRequest;
struct
{
uint32 pid;
MEMPTR<uint16be> message;
MPTR funcPtr;
MPTR custom;
}addFriendRequest;
struct
{
MEMPTR<uint64> messageIdList;
uint32 count;
MPTR funcPtr;
MPTR custom;
}markFriendRequest;
struct
{
MEMPTR<friendBasicInfo_t> basicInfo;
MEMPTR<uint32be> pidList;
sint32 count;
MPTR funcPtr;
MPTR custom;
}getBasicInfo;
struct
{
uint32 notificationMask;
MPTR funcPtr;
MPTR custom;
}setNotificationHandler;
struct
{
MEMPTR<char> accountIds;
MEMPTR<uint32be> pidList;
sint32 count;
}getFriendAccountId;
struct
{
MEMPTR<uint16be> nameList;
MEMPTR<uint32be> pidList;
sint32 count;
bool replaceNonAscii;
MEMPTR<uint8> languageList;
}getFriendScreenname;
struct
{
uint8* miiList;
MEMPTR<uint32be> pidList;
sint32 count;
}getFriendMii;
struct
{
uint8* presenceList;
MEMPTR<uint32be> pidList;
sint32 count;
}getFriendPresence;
struct
{
uint8* relationshipList;
MEMPTR<uint32be> pidList;
sint32 count;
}getFriendRelationship;
struct
{
MEMPTR<gameMode_t> gameMode;
MEMPTR<uint16be> gameModeMessage;
}updateGameMode;
LoginAsync = 0x2775,
HasLoggedIn = 0x2777,
IsOnline = 0x2778,
GetMyPrincipalId = 0x27D9,
GetMyAccountId = 0x27DA,
GetMyScreenName = 0x27DB,
GetMyMii = 0x27DC,
GetMyProfile = 0x27DD,
GetMyPreference = 0x27DE,
GetMyPresence = 0x27DF,
IsPreferenceValid = 0x27E0,
GetFriendList = 0x283D,
GetFriendListAll = 0x283E,
GetFriendAccountId = 0x283F,
GetFriendScreenName = 0x2840,
GetFriendPresence = 0x2845,
GetFriendRelationship = 0x2846,
GetFriendMii = 0x2841,
GetBlackList = 0x28A1,
GetFriendRequestList = 0x2905,
UpdateGameModeVariation1 = 0x2969, // there seem to be two different requestIds for the 2-param and 3-param version of UpdateGameMode,
UpdateGameModeVariation2 = 0x296A, // but the third parameter is never used and the same handler is used for both
AddFriendAsyncByPid = 0x29CD,
AddFriendAsyncByXXX = 0x29CE, // probably by name?
GetRequestBlockSettingAsync = 0x2B5D,
GetMyComment = 0x4EE9,
GetMyPlayingGame = 0x4EEA,
CheckSettingStatusAsync = 0x7596,
GetFriendListEx = 0x75F9,
GetFriendRequestListEx = 0x76C1,
UpdatePreferenceAsync = 0x7727,
RemoveFriendAsync = 0x7789,
DeleteFriendFlagsAsync = 0x778A,
AddFriendRequestByPlayRecordAsync = 0x778B,
CancelFriendRequestAsync = 0x778C,
AcceptFriendRequestAsync = 0x7851,
DeleteFriendRequestAsync = 0x7852,
MarkFriendRequestsAsReceivedAsync = 0x7854,
GetBasicInfoAsync = 0x7919,
SetLedEventMask = 0x9D0B,
SetNotificationMask = 0x15ff5,
GetNotificationAsync = 0x15FF6,
};
// output
uint32 returnCode; // return value
union
{
struct
{
uint32 numReturnedCount;
}resultGetFriendList;
struct
{
uint32 u32;
}resultU32;
};
}iosuFpdCemuRequest_t;
using FriendPID = uint32;
// custom dev/fpd protocol (Cemu only)
#define IOSU_FPD_REQUEST_CEMU (0xEE)
// FPD request Cemu subcodes
enum
{
_IOSU_FPD_NONE,
IOSU_FPD_INITIALIZE,
IOSU_FPD_SET_NOTIFICATION_HANDLER,
IOSU_FPD_LOGIN_ASYNC,
IOSU_FPD_IS_ONLINE,
IOSU_FPD_IS_PREFERENCE_VALID,
IOSU_FPD_UPDATE_GAMEMODE,
IOSU_FPD_GET_MY_PRINCIPAL_ID,
IOSU_FPD_GET_MY_ACCOUNT_ID,
IOSU_FPD_GET_MY_MII,
IOSU_FPD_GET_MY_SCREENNAME,
IOSU_FPD_GET_FRIEND_ACCOUNT_ID,
IOSU_FPD_GET_FRIEND_SCREENNAME,
IOSU_FPD_GET_FRIEND_MII,
IOSU_FPD_GET_FRIEND_PRESENCE,
IOSU_FPD_GET_FRIEND_RELATIONSHIP,
IOSU_FPD_GET_FRIEND_LIST,
IOSU_FPD_GET_FRIENDREQUEST_LIST,
IOSU_FPD_GET_FRIEND_LIST_ALL,
IOSU_FPD_GET_FRIEND_LIST_EX,
IOSU_FPD_GET_FRIENDREQUEST_LIST_EX,
IOSU_FPD_ADD_FRIEND,
IOSU_FPD_ADD_FRIEND_REQUEST,
IOSU_FPD_REMOVE_FRIEND_ASYNC,
IOSU_FPD_CANCEL_FRIEND_REQUEST_ASYNC,
IOSU_FPD_ACCEPT_FRIEND_REQUEST_ASYNC,
IOSU_FPD_MARK_FRIEND_REQUEST_AS_RECEIVED_ASYNC,
IOSU_FPD_GET_BASIC_INFO_ASYNC,
};
void Initialize();
IOSUModule* GetModule();
}
}

View File

@ -1,5 +1,6 @@
#include "iosu_nn_service.h"
#include "../kernel/iosu_kernel.h"
#include "util/helpers/helpers.h"
using namespace iosu::kernel;
@ -7,6 +8,132 @@ namespace iosu
{
namespace nn
{
/* IPCSimpleService */
void IPCSimpleService::Start()
{
if (m_isRunning.exchange(true))
return;
m_threadInitialized = false;
m_requestStop = false;
m_serviceThread = std::thread(&IPCSimpleService::ServiceThread, this);
while (!m_threadInitialized) std::this_thread::sleep_for(std::chrono::milliseconds(10));
StartService();
}
void IPCSimpleService::Stop()
{
if (!m_isRunning.exchange(false))
return;
m_requestStop = true;
StopService();
if(m_timerId != IOSInvalidTimerId)
IOS_DestroyTimer(m_timerId);
m_timerId = IOSInvalidTimerId;
IOS_SendMessage(m_msgQueueId, 0, 0); // wake up thread
m_serviceThread.join();
}
void IPCSimpleService::ServiceThread()
{
if(!GetThreadName().empty())
SetThreadName(GetThreadName().c_str());
m_msgQueueId = IOS_CreateMessageQueue(_m_msgBuffer.GetPtr(), _m_msgBuffer.GetCount());
cemu_assert(!IOS_ResultIsError((IOS_ERROR)m_msgQueueId));
IOS_ERROR r = IOS_RegisterResourceManager(m_devicePath.c_str(), m_msgQueueId);
cemu_assert(!IOS_ResultIsError(r));
m_threadInitialized = true;
while (true)
{
IOSMessage msg;
r = IOS_ReceiveMessage(m_msgQueueId, &msg, 0);
cemu_assert(!IOS_ResultIsError(r));
if (msg == 0)
{
cemu_assert_debug(m_requestStop);
break;
}
else if(msg == 1)
{
TimerUpdate();
continue;
}
IPCCommandBody* cmd = MEMPTR<IPCCommandBody>(msg).GetPtr();
if (cmd->cmdId == IPCCommandId::IOS_OPEN)
{
void* clientObject = CreateClientObject();
if(clientObject == nullptr)
{
cemuLog_log(LogType::Force, "IPCSimpleService[{}]: Maximum handle count reached or handle rejected", m_devicePath);
IOS_ResourceReply(cmd, IOS_ERROR_MAXIMUM_REACHED);
continue;
}
IOSDevHandle newHandle = GetFreeHandle();
m_clientObjects[newHandle] = clientObject;
IOS_ResourceReply(cmd, (IOS_ERROR)newHandle);
continue;
}
else if (cmd->cmdId == IPCCommandId::IOS_CLOSE)
{
void* clientObject = GetClientObjectByHandle(cmd->devHandle);
if (clientObject)
DestroyClientObject(clientObject);
IOS_ResourceReply(cmd, IOS_ERROR_OK);
continue;
}
else if (cmd->cmdId == IPCCommandId::IOS_IOCTLV)
{
void* clientObject = GetClientObjectByHandle(cmd->devHandle);
if (!clientObject)
{
cemuLog_log(LogType::Force, "IPCSimpleService[{}]: Invalid IPC handle", m_devicePath);
IOS_ResourceReply(cmd, IOS_ERROR_INVALID);
continue;
}
uint32 requestId = cmd->args[0];
uint32 numIn = cmd->args[1];
uint32 numOut = cmd->args[2];
IPCIoctlVector* vec = MEMPTR<IPCIoctlVector>{ cmd->args[3] }.GetPtr();
IPCIoctlVector* vecIn = vec + 0; // the ordering of vecIn/vecOut differs from IPCService
IPCIoctlVector* vecOut = vec + numIn;
m_delayResponse = false;
m_activeCmd = cmd;
uint32 result = ServiceCall(clientObject, requestId, vecIn, numIn, vecOut, numOut);
if (!m_delayResponse)
IOS_ResourceReply(cmd, (IOS_ERROR)result);
m_activeCmd = nullptr;
continue;
}
else
{
cemuLog_log(LogType::Force, "IPCSimpleService[{}]: Unsupported IPC cmdId {}", m_devicePath, (uint32)cmd->cmdId.value());
cemu_assert_unimplemented();
IOS_ResourceReply(cmd, IOS_ERROR_INVALID);
}
}
IOS_DestroyMessageQueue(m_msgQueueId);
m_threadInitialized = false;
}
void IPCSimpleService::SetTimerUpdate(uint32 milliseconds)
{
if(m_timerId != IOSInvalidTimerId)
IOS_DestroyTimer(m_timerId);
m_timerId = IOS_CreateTimer(milliseconds * 1000, milliseconds * 1000, m_msgQueueId, 1);
}
IPCCommandBody* IPCSimpleService::ServiceCallDelayCurrentResponse()
{
cemu_assert_debug(m_activeCmd);
m_delayResponse = true;
return m_activeCmd;
}
void IPCSimpleService::ServiceCallAsyncRespond(IPCCommandBody* response, uint32 r)
{
IOS_ResourceReply(response, (IOS_ERROR)r);
}
/* IPCService */
void IPCService::Start()
{
if (m_isRunning.exchange(true))

View File

@ -8,6 +8,71 @@ namespace iosu
{
namespace nn
{
// a simple service interface which wraps handle management and Ioctlv/IoctlvAsync
class IPCSimpleService
{
public:
IPCSimpleService(std::string_view devicePath) : m_devicePath(devicePath) {};
virtual ~IPCSimpleService() {};
virtual void StartService() {};
virtual void StopService() {};
virtual std::string GetThreadName() = 0;
virtual void* CreateClientObject() = 0;
virtual void DestroyClientObject(void* clientObject) = 0;
virtual uint32 ServiceCall(void* clientObject, uint32 requestId, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut) = 0;
virtual void TimerUpdate() {};
IPCCommandBody* ServiceCallDelayCurrentResponse();
static void ServiceCallAsyncRespond(IPCCommandBody* response, uint32 r);
void Start();
void Stop();
void SetTimerUpdate(uint32 milliseconds);
private:
void ServiceThread();
IOSDevHandle GetFreeHandle()
{
while(m_clientObjects.find(m_nextHandle) != m_clientObjects.end() || m_nextHandle == 0)
{
m_nextHandle++;
m_nextHandle &= 0x7FFFFFFF;
}
IOSDevHandle newHandle = m_nextHandle;
m_nextHandle++;
m_nextHandle &= 0x7FFFFFFF;
return newHandle;
}
void* GetClientObjectByHandle(IOSDevHandle handle) const
{
auto it = m_clientObjects.find(handle);
if(it == m_clientObjects.end())
return nullptr;
return it->second;
}
std::string m_devicePath;
std::thread m_serviceThread;
std::atomic_bool m_requestStop{false};
std::atomic_bool m_isRunning{false};
std::atomic_bool m_threadInitialized{ false };
std::unordered_map<IOSDevHandle, void*> m_clientObjects;
IOSDevHandle m_nextHandle{1};
IOSTimerId m_timerId{IOSInvalidTimerId};
IPCCommandBody* m_activeCmd{nullptr};
bool m_delayResponse{false};
IOSMsgQueueId m_msgQueueId;
SysAllocator<iosu::kernel::IOSMessage, 128> _m_msgBuffer;
};
struct IPCServiceRequest
{
uint32be ukn00;
@ -23,6 +88,7 @@ namespace iosu
uint32be nnResultCode;
};
// a complex service interface which wraps Ioctlv and adds an additional service channel, used by /dev/act, ?
class IPCService
{
public:
@ -60,5 +126,6 @@ namespace iosu
IOSMsgQueueId m_msgQueueId;
SysAllocator<iosu::kernel::IOSMessage, 128> _m_msgBuffer;
};
};
};

View File

@ -724,7 +724,7 @@ uint32 RPLLoader_MakePPCCallable(void(*ppcCallableExport)(PPCInterpreter_t* hCPU
if (it != g_map_callableExports.end())
return it->second;
// get HLE function index
sint32 functionIndex = PPCInterpreter_registerHLECall(ppcCallableExport);
sint32 functionIndex = PPCInterpreter_registerHLECall(ppcCallableExport, fmt::format("PPCCallback{:x}", (uintptr_t)ppcCallableExport));
MPTR codeAddr = memory_getVirtualOffsetFromPointer(RPLLoader_AllocateTrampolineCodeSpace(4));
uint32 opcode = (1 << 26) | functionIndex;
memory_write<uint32>(codeAddr, opcode);

View File

@ -85,6 +85,7 @@ void osLib_addFunctionInternal(const char* libraryName, const char* functionName
uint32 funcHashA, funcHashB;
osLib_generateHashFromName(libraryName, &libHashA, &libHashB);
osLib_generateHashFromName(functionName, &funcHashA, &funcHashB);
std::string hleName = fmt::format("{}.{}", libraryName, functionName);
// if entry already exists, update it
for (auto& it : *s_osFunctionTable)
{
@ -93,11 +94,11 @@ void osLib_addFunctionInternal(const char* libraryName, const char* functionName
it.funcHashA == funcHashA &&
it.funcHashB == funcHashB)
{
it.hleFunc = PPCInterpreter_registerHLECall(osFunction);
it.hleFunc = PPCInterpreter_registerHLECall(osFunction, hleName);
return;
}
}
s_osFunctionTable->emplace_back(libHashA, libHashB, funcHashA, funcHashB, fmt::format("{}.{}", libraryName, functionName), PPCInterpreter_registerHLECall(osFunction));
s_osFunctionTable->emplace_back(libHashA, libHashB, funcHashA, funcHashB, hleName, PPCInterpreter_registerHLECall(osFunction, hleName));
}
extern "C" DLLEXPORT void osLib_registerHLEFunction(const char* libraryName, const char* functionName, void(*osFunction)(PPCInterpreter_t * hCPU))

View File

@ -912,8 +912,8 @@ namespace coreinit
sint32 FSOpenFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandleDepr_t* fileHandle, uint32 errHandling)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSOpenFileAsync(fsClient, fsCmdBlock, path, mode, fileHandle, errHandling, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSOpenFileAsync(fsClient, fsCmdBlock, path, mode, fileHandle, errHandling, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);
}
@ -941,8 +941,8 @@ namespace coreinit
sint32 FSOpenFileEx(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, uint32 createMode, uint32 openFlag, uint32 preallocSize, FSFileHandleDepr_t* fileHandle, uint32 errHandling)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSOpenFileExAsync(fsClient, fsCmdBlock, path, mode, createMode, openFlag, preallocSize, fileHandle, errHandling, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSOpenFileExAsync(fsClient, fsCmdBlock, path, mode, createMode, openFlag, preallocSize, fileHandle, errHandling, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);
}
@ -975,8 +975,8 @@ namespace coreinit
sint32 FSCloseFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errHandling)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSCloseFileAsync(fsClient, fsCmdBlock, fileHandle, errHandling, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSCloseFileAsync(fsClient, fsCmdBlock, fileHandle, errHandling, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);
}
@ -1009,8 +1009,8 @@ namespace coreinit
sint32 FSFlushFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errHandling)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSFlushFileAsync(fsClient, fsCmdBlock, fileHandle, errHandling, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSFlushFileAsync(fsClient, fsCmdBlock, fileHandle, errHandling, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling);
}
@ -1090,7 +1090,7 @@ namespace coreinit
sint32 FSReadFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSReadFileAsync(fsClient, fsCmdBlock, dst, size, count, fileHandle, flag, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1105,7 +1105,7 @@ namespace coreinit
sint32 FSReadFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSReadFileWithPosAsync(fsClient, fsCmdBlock, dst, size, count, filePos, fileHandle, flag, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1183,7 +1183,7 @@ namespace coreinit
sint32 FSWriteFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSWriteFileAsync(fsClient, fsCmdBlock, src, size, count, fileHandle, flag, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1196,7 +1196,7 @@ namespace coreinit
sint32 FSWriteFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSWriteFileWithPosAsync(fsClient, fsCmdBlock, src, size, count, filePos, fileHandle, flag, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1228,7 +1228,7 @@ namespace coreinit
{
// used by games: Mario Kart 8
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSSetPosFileAsync(fsClient, fsCmdBlock, fileHandle, filePos, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1259,7 +1259,7 @@ namespace coreinit
sint32 FSGetPosFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32be* returnedFilePos, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSGetPosFileAsync(fsClient, fsCmdBlock, fileHandle, returnedFilePos, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1307,8 +1307,8 @@ namespace coreinit
sint32 FSOpenDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, FSDirHandlePtr dirHandleOut, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSOpenDirAsync(fsClient, fsCmdBlock, path, dirHandleOut, errorMask, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSOpenDirAsync(fsClient, fsCmdBlock, path, dirHandleOut, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1337,8 +1337,8 @@ namespace coreinit
sint32 FSReadDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSReadDirAsync(fsClient, fsCmdBlock, dirHandle, dirEntryOut, errorMask, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSReadDirAsync(fsClient, fsCmdBlock, dirHandle, dirEntryOut, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1367,8 +1367,8 @@ namespace coreinit
sint32 FSCloseDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSCloseDirAsync(fsClient, fsCmdBlock, dirHandle, errorMask, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSCloseDirAsync(fsClient, fsCmdBlock, dirHandle, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1400,8 +1400,8 @@ namespace coreinit
sint32 FSRewindDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSRewindDirAsync(fsClient, fsCmdBlock, dirHandle, errorMask, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSRewindDirAsync(fsClient, fsCmdBlock, dirHandle, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1435,7 +1435,7 @@ namespace coreinit
sint32 FSAppendFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 size, uint32 count, uint32 fileHandle, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSAppendFileAsync(fsClient, fsCmdBlock, size, count, fileHandle, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1467,7 +1467,7 @@ namespace coreinit
sint32 FSTruncateFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSTruncateFileAsync(fsClient, fsCmdBlock, fileHandle, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1531,7 +1531,7 @@ namespace coreinit
sint32 FSRename(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* srcPath, char* dstPath, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSRenameAsync(fsClient, fsCmdBlock, srcPath, dstPath, errorMask, asyncParams.GetPointer());
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1582,8 +1582,8 @@ namespace coreinit
sint32 FSRemove(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* filePath, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSRemoveAsync(fsClient, fsCmdBlock, filePath, errorMask, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSRemoveAsync(fsClient, fsCmdBlock, filePath, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1634,8 +1634,8 @@ namespace coreinit
sint32 FSMakeDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSMakeDirAsync(fsClient, fsCmdBlock, path, errorMask, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSMakeDirAsync(fsClient, fsCmdBlock, path, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1683,8 +1683,8 @@ namespace coreinit
sint32 FSChangeDir(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSChangeDirAsync(fsClient, fsCmdBlock, path, errorMask, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSChangeDirAsync(fsClient, fsCmdBlock, path, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1718,8 +1718,8 @@ namespace coreinit
sint32 FSGetCwd(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* dirPathOut, sint32 dirPathMaxLen, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSGetCwdAsync(fsClient, fsCmdBlock, dirPathOut, dirPathMaxLen, errorMask, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSGetCwdAsync(fsClient, fsCmdBlock, dirPathOut, dirPathMaxLen, errorMask, &asyncParams);
auto r = __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
return r;
}
@ -1763,8 +1763,8 @@ namespace coreinit
sint32 FSFlushQuota(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSFlushQuotaAsync(fsClient, fsCmdBlock, path, errorMask, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSFlushQuotaAsync(fsClient, fsCmdBlock, path, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1821,8 +1821,8 @@ namespace coreinit
sint32 FSGetStat(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSStat_t* statOut, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSGetStatAsync(fsClient, fsCmdBlock, path, statOut, errorMask, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSGetStatAsync(fsClient, fsCmdBlock, path, statOut, errorMask, &asyncParams);
sint32 ret = __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
return ret;
}
@ -1858,8 +1858,8 @@ namespace coreinit
sint32 FSGetStatFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, FSStat_t* statOut, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSGetStatFileAsync(fsClient, fsCmdBlock, fileHandle, statOut, errorMask, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSGetStatFileAsync(fsClient, fsCmdBlock, fileHandle, statOut, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1873,8 +1873,8 @@ namespace coreinit
sint32 FSGetFreeSpaceSize(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const char* path, FSLargeSize* returnedFreeSize, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSGetFreeSpaceSizeAsync(fsClient, fsCmdBlock, path, returnedFreeSize, errorMask, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSGetFreeSpaceSizeAsync(fsClient, fsCmdBlock, path, returnedFreeSize, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}
@ -1908,8 +1908,8 @@ namespace coreinit
sint32 FSIsEof(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask)
{
StackAllocator<FSAsyncParamsNew_t, 1> asyncParams;
__FSAsyncToSyncInit(fsClient, fsCmdBlock, asyncParams);
sint32 fsAsyncRet = FSIsEofAsync(fsClient, fsCmdBlock, fileHandle, errorMask, asyncParams);
__FSAsyncToSyncInit(fsClient, fsCmdBlock, &asyncParams);
sint32 fsAsyncRet = FSIsEofAsync(fsClient, fsCmdBlock, fileHandle, errorMask, &asyncParams);
return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask);
}

View File

@ -355,23 +355,6 @@ namespace coreinit
IOS_ERROR _IPCDriver_SetupCmd_IOSIoctlv(IPCDriver& ipcDriver, IPCResourceBufferDescriptor* requestDescriptor, uint32 requestId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec)
{
IPCCommandBody& cmdBody = requestDescriptor->resourcePtr->commandBody;
// verify input and output vectors
IPCIoctlVector* vecIn = vec;
IPCIoctlVector* vecOut = vec + numIn;
for (uint32 i = 0; i < numIn; i++)
{
if (vecIn[i].baseVirt == nullptr && vecIn[i].size != 0)
return IOS_ERROR_INVALID_ARG;
vecIn[i].basePhys = vecIn[i].baseVirt;
vecIn[i].baseVirt = nullptr;
}
for (uint32 i = 0; i < numOut; i++)
{
if (vecOut[i].baseVirt == nullptr && vecOut[i].size != 0)
return IOS_ERROR_INVALID_ARG;
vecOut[i].basePhys = vecOut[i].baseVirt;
vecOut[i].baseVirt = nullptr;
}
// set args
cmdBody.ppcVirt0 = MEMPTR<void>(vec).GetMPTR();
cmdBody.args[0] = requestId;

View File

@ -195,7 +195,28 @@ namespace coreinit
else if ((formatStr[0] == 'l' && formatStr[1] == 'l' && (formatStr[2] == 'x' || formatStr[2] == 'X')))
{
formatStr += 3;
// number (64bit)
// double (64bit)
strncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));
if ((formatStr - formatStart) < sizeof(tempFormat))
tempFormat[(formatStr - formatStart)] = '\0';
else
tempFormat[sizeof(tempFormat) - 1] = '\0';
if (integerParamIndex & 1)
integerParamIndex++;
sint32 tempLen = sprintf(tempStr, tempFormat, PPCInterpreter_getCallParamU64(hCPU, integerParamIndex));
integerParamIndex += 2;
for (sint32 i = 0; i < tempLen; i++)
{
if (writeIndex >= maxLength)
break;
strOut[writeIndex] = tempStr[i];
writeIndex++;
}
}
else if ((formatStr[0] == 'l' && formatStr[1] == 'l' && formatStr[2] == 'd'))
{
formatStr += 3;
// signed integer (64bit)
strncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));
if ((formatStr - formatStart) < sizeof(tempFormat))
tempFormat[(formatStr - formatStart)] = '\0';

View File

@ -859,10 +859,10 @@ namespace H264
return H264DEC_STATUS::SUCCESS;
}
StackAllocator<coreinit::OSEvent> executeDoneEvent;
coreinit::OSInitEvent(executeDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
coreinit::OSInitEvent(&executeDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
std::vector<H264AVCDecoder::DecodeResult> results;
auto asyncTask = std::async(std::launch::async, _async_H264DECEnd, executeDoneEvent.GetPointer(), session, ctx, &results);
coreinit::OSWaitEvent(executeDoneEvent);
coreinit::OSWaitEvent(&executeDoneEvent);
_ReleaseDecoderSession(session);
if (!results.empty())
{
@ -977,9 +977,9 @@ namespace H264
StackAllocator<H264DECFrameOutput, 8> stack_decodedFrameResult;
for (sint32 i = 0; i < outputFrameCount; i++)
stack_resultPtrArray[i] = stack_decodedFrameResult + i;
stack_resultPtrArray[i] = &stack_decodedFrameResult + i;
H264DECFrameOutput* frameOutput = stack_decodedFrameResult + 0;
H264DECFrameOutput* frameOutput = &stack_decodedFrameResult + 0;
memset(frameOutput, 0x00, sizeof(H264DECFrameOutput));
frameOutput->imagePtr = (uint8*)decodeResult.imageOutput;
frameOutput->result = 100;
@ -1022,10 +1022,10 @@ namespace H264
return 0;
}
StackAllocator<coreinit::OSEvent> executeDoneEvent;
coreinit::OSInitEvent(executeDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
coreinit::OSInitEvent(&executeDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
H264AVCDecoder::DecodeResult decodeResult;
auto asyncTask = std::async(std::launch::async, _async_H264DECExecute, executeDoneEvent.GetPointer(), session, ctx, imageOutput , &decodeResult);
coreinit::OSWaitEvent(executeDoneEvent);
auto asyncTask = std::async(std::launch::async, _async_H264DECExecute, &executeDoneEvent, session, ctx, imageOutput , &decodeResult);
coreinit::OSWaitEvent(&executeDoneEvent);
_ReleaseDecoderSession(session);
if(decodeResult.frameReady)
H264DoFrameOutputCallback(ctx, decodeResult);

View File

@ -391,7 +391,7 @@ void nnActExport_GetMiiName(PPCInterpreter_t* hCPU)
StackAllocator<FFLData_t> miiData;
uint32 r = nn::act::GetMiiEx(miiData, iosu::act::ACT_SLOT_CURRENT);
uint32 r = nn::act::GetMiiEx(&miiData, iosu::act::ACT_SLOT_CURRENT);
// extract name
sint32 miiNameLength = 0;
for (sint32 i = 0; i < MII_FFL_NAME_LENGTH; i++)
@ -414,7 +414,7 @@ void nnActExport_GetMiiNameEx(PPCInterpreter_t* hCPU)
StackAllocator<FFLData_t> miiData;
uint32 r = nn::act::GetMiiEx(miiData, slot);
uint32 r = nn::act::GetMiiEx(&miiData, slot);
// extract name
sint32 miiNameLength = 0;
for (sint32 i = 0; i < MII_FFL_NAME_LENGTH; i++)

File diff suppressed because it is too large Load Diff

View File

@ -47,10 +47,10 @@ namespace nn
InitializeOliveRequest(req);
StackAllocator<coreinit::OSEvent> requestDoneEvent;
coreinit::OSInitEvent(requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
coreinit::OSInitEvent(&requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
std::future<sint32> requestRes = std::async(std::launch::async, DownloadCommunityDataList_AsyncRequest,
std::ref(req), reqUrl, requestDoneEvent.GetPointer(), pOutList, pOutNum, numMaxList, pParam);
coreinit::OSWaitEvent(requestDoneEvent);
coreinit::OSWaitEvent(&requestDoneEvent);
return requestRes.get();
}

View File

@ -199,9 +199,9 @@ namespace nn
InitializeOliveRequest(req);
StackAllocator<coreinit::OSEvent> requestDoneEvent;
coreinit::OSInitEvent(requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
coreinit::OSInitEvent(&requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
std::future<sint32> requestRes = std::async(std::launch::async, MakeDiscoveryRequest_AsyncRequest, std::ref(req), requestUrl.c_str(), requestDoneEvent.GetPointer());
coreinit::OSWaitEvent(requestDoneEvent);
coreinit::OSWaitEvent(&requestDoneEvent);
return requestRes.get();
}

View File

@ -25,7 +25,7 @@ namespace nn
// open archive
g_offlineDBArchive = ZArchiveReader::OpenFromFile(ActiveSettings::GetUserDataPath("resources/miiverse/OfflineDB.zar"));
if(!g_offlineDBArchive)
cemuLog_log(LogType::Force, "Failed to open resources/miiverse/OfflineDB.zar. Miiverse posts will not be available");
cemuLog_log(LogType::Force, "Offline miiverse posts are not available");
g_offlineDBInitialized = true;
}
@ -175,9 +175,9 @@ namespace nn
return OLV_RESULT_SUCCESS; // the offlineDB doesn't contain any self posts
StackAllocator<coreinit::OSEvent> doneEvent;
coreinit::OSInitEvent(doneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
coreinit::OSInitEvent(&doneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
auto asyncTask = std::async(std::launch::async, _Async_OfflineDB_DownloadPostDataListParam_DownloadPostDataList, doneEvent.GetPointer(), downloadedTopicData, downloadedPostData, postCountOut, maxCount, param);
coreinit::OSWaitEvent(doneEvent);
coreinit::OSWaitEvent(&doneEvent);
nnResult r = asyncTask.get();
return r;
}
@ -204,9 +204,9 @@ namespace nn
nnResult OfflineDB_DownloadPostDataListParam_DownloadExternalImageData(DownloadedDataBase* _this, void* imageDataOut, uint32be* imageSizeOut, uint32 maxSize)
{
StackAllocator<coreinit::OSEvent> doneEvent;
coreinit::OSInitEvent(doneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
coreinit::OSInitEvent(&doneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
auto asyncTask = std::async(std::launch::async, _Async_OfflineDB_DownloadPostDataListParam_DownloadExternalImageData, doneEvent.GetPointer(), _this, imageDataOut, imageSizeOut, maxSize);
coreinit::OSWaitEvent(doneEvent);
coreinit::OSWaitEvent(&doneEvent);
nnResult r = asyncTask.get();
return r;
}

View File

@ -54,9 +54,9 @@ namespace nn
InitializeOliveRequest(req);
StackAllocator<coreinit::OSEvent> requestDoneEvent;
coreinit::OSInitEvent(requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
coreinit::OSInitEvent(&requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
std::future<sint32> requestRes = std::async(std::launch::async, UploadCommunityData_AsyncRequest, std::ref(req), requestUrl, requestDoneEvent.GetPointer(), pOutData, pParam);
coreinit::OSWaitEvent(requestDoneEvent);
coreinit::OSWaitEvent(&requestDoneEvent);
return requestRes.get();
}

View File

@ -44,9 +44,9 @@ namespace nn
InitializeOliveRequest(req);
StackAllocator<coreinit::OSEvent> requestDoneEvent;
coreinit::OSInitEvent(requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
coreinit::OSInitEvent(&requestDoneEvent, coreinit::OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, coreinit::OSEvent::EVENT_MODE::MODE_MANUAL);
std::future<sint32> requestRes = std::async(std::launch::async, UploadFavoriteToCommunityData_AsyncRequest, std::ref(req), requestUrl, requestDoneEvent.GetPointer(), pOutData, pParam);
coreinit::OSWaitEvent(requestDoneEvent);
coreinit::OSWaitEvent(&requestDoneEvent);
return requestRes.get();
}

View File

@ -43,6 +43,7 @@ const std::map<LogType, std::string> g_logging_window_mapping
{LogType::CoreinitMP, "Coreinit MP"},
{LogType::CoreinitThread, "Coreinit Thread"},
{LogType::NN_NFP, "nn::nfp"},
{LogType::NN_FP, "nn::fp"},
{LogType::GX2, "GX2"},
{LogType::SoundAPI, "Audio"},
{LogType::InputAPI, "Input"},

View File

@ -34,6 +34,7 @@ enum class LogType : sint32
NN_PDM = 21,
NN_OLV = 23,
NN_NFP = 13,
NN_FP = 24,
TextureReadback = 29,

View File

@ -358,7 +358,7 @@ namespace NAPI
std::string_view port = tokenNode.child_value("port");
std::string_view token = tokenNode.child_value("token");
std::memset(&result.nexToken, 0, sizeof(result.nexToken));
memset(&result.nexToken, 0, sizeof(ACTNexToken));
if (host.size() > 15)
cemuLog_log(LogType::Force, "NexToken response: host field too long");
if (nex_password.size() > 64)

View File

@ -160,11 +160,10 @@ bool nexService::isMarkedForDestruction()
void nexService::callMethod(uint8 protocolId, uint32 methodId, nexPacketBuffer* parameter, void(*nexServiceResponse)(nexService* nex, nexServiceResponse_t* serviceResponse), void* custom, bool callHandlerIfError)
{
// add to queue
queuedRequest_t queueRequest = { 0 };
queueRequest.protocolId = protocolId;
queueRequest.methodId = methodId;
queueRequest.parameterData = std::vector<uint8>(parameter->getDataPtr(), parameter->getDataPtr() + parameter->getWriteIndex());
queueRequest.parameterData.assign(parameter->getDataPtr(), parameter->getDataPtr() + parameter->getWriteIndex());
queueRequest.nexServiceResponse = nexServiceResponse;
queueRequest.custom = custom;
queueRequest.callHandlerIfError = callHandlerIfError;
@ -175,11 +174,10 @@ void nexService::callMethod(uint8 protocolId, uint32 methodId, nexPacketBuffer*
void nexService::callMethod(uint8 protocolId, uint32 methodId, nexPacketBuffer* parameter, std::function<void(nexServiceResponse_t*)> cb, bool callHandlerIfError)
{
// add to queue
queuedRequest_t queueRequest = { 0 };
queueRequest.protocolId = protocolId;
queueRequest.methodId = methodId;
queueRequest.parameterData = std::vector<uint8>(parameter->getDataPtr(), parameter->getDataPtr() + parameter->getWriteIndex());
queueRequest.parameterData.assign(parameter->getDataPtr(), parameter->getDataPtr() + parameter->getWriteIndex());
queueRequest.nexServiceResponse = nullptr;
queueRequest.cb2 = cb;
queueRequest.callHandlerIfError = callHandlerIfError;

View File

@ -274,8 +274,7 @@ void NexFriends::handleResponse_getAllInformation(nexServiceResponse_t* response
return;
}
NexFriends* session = (NexFriends*)nexFriends;
nexPrincipalPreference preference(&response->data);
session->myPreference = nexPrincipalPreference(&response->data);
nexComment comment(&response->data);
if (response->data.hasReadOutOfBounds())
return;
@ -290,29 +289,21 @@ void NexFriends::handleResponse_getAllInformation(nexServiceResponse_t* response
uint32 friendCount = response->data.readU32();
session->list_friends.resize(friendCount);
for (uint32 i = 0; i < friendCount; i++)
{
session->list_friends[i].readData(&response->data);
}
// friend requests (outgoing)
uint32 friendRequestsOutCount = response->data.readU32();
if (response->data.hasReadOutOfBounds())
{
return;
}
session->list_friendReqOutgoing.resize(friendRequestsOutCount);
for (uint32 i = 0; i < friendRequestsOutCount; i++)
{
session->list_friendReqOutgoing[i].readData(&response->data);
}
// friend requests (incoming)
uint32 friendRequestsInCount = response->data.readU32();
if (response->data.hasReadOutOfBounds())
return;
session->list_friendReqIncoming.resize(friendRequestsInCount);
for (uint32 i = 0; i < friendRequestsInCount; i++)
{
session->list_friendReqIncoming[i].readData(&response->data);
}
if (response->data.hasReadOutOfBounds())
return;
// blacklist
@ -336,7 +327,7 @@ void NexFriends::handleResponse_getAllInformation(nexServiceResponse_t* response
if (isPreferenceInvalid)
{
cemuLog_log(LogType::Force, "NEX: First time login into friend account, setting up default preferences");
session->updatePreferences(nexPrincipalPreference(1, 1, 0));
session->updatePreferencesAsync(nexPrincipalPreference(1, 1, 0), [](RpcErrorCode err){});
}
if (session->firstInformationRequest == false)
@ -377,20 +368,27 @@ bool NexFriends::requestGetAllInformation(std::function<void(uint32)> cb)
return true;
}
void NexFriends::handleResponse_updatePreferences(nexServiceResponse_t* response, NexFriends* nexFriends, std::function<void(uint32)> cb)
{
// todo
}
bool NexFriends::updatePreferences(const nexPrincipalPreference& newPreferences)
bool NexFriends::updatePreferencesAsync(nexPrincipalPreference newPreferences, std::function<void(RpcErrorCode)> cb)
{
uint8 tempNexBufferArray[1024];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
newPreferences.writeData(&packetBuffer);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 16, &packetBuffer, std::bind(handleResponse_updatePreferences, std::placeholders::_1, this, nullptr), true);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 16, &packetBuffer, [this, cb, newPreferences](nexServiceResponse_t* response) -> void
{
if (!response->isSuccessful)
return cb(NexFriends::ERR_RPC_FAILED);
this->myPreference = newPreferences;
return cb(NexFriends::ERR_NONE);
}, true);
// TEST
return true;
}
void NexFriends::getMyPreference(nexPrincipalPreference& preference)
{
preference = myPreference;
}
bool NexFriends::addProvisionalFriendByPidGuessed(uint32 principalId)
{
uint8 tempNexBufferArray[512];
@ -401,6 +399,7 @@ bool NexFriends::addProvisionalFriendByPidGuessed(uint32 principalId)
return true;
}
// returns true once connection is established and friend list data is available
bool NexFriends::isOnline()
{
return isCurrentlyConnected && hasData;
@ -731,7 +730,7 @@ void addProvisionalFriendHandler(nexServiceResponse_t* nexResponse, std::functio
}
}
bool NexFriends::addProvisionalFriend(char* name, std::function<void(uint32)> cb)
bool NexFriends::addProvisionalFriend(char* name, std::function<void(RpcErrorCode)> cb)
{
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
{
@ -754,12 +753,11 @@ void addFriendRequestHandler(nexServiceResponse_t* nexResponse, NexFriends* nexF
{
// todo: Properly handle returned error code
cb(NexFriends::ERR_RPC_FAILED);
// refresh the list
nexFriends->requestGetAllInformation();
nexFriends->requestGetAllInformation(); // refresh friend list and send add/remove notifications
}
}
void NexFriends::addFriendRequest(uint32 pid, const char* comment, std::function<void(uint32)> cb)
void NexFriends::addFriendRequest(uint32 pid, const char* comment, std::function<void(RpcErrorCode)> cb)
{
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
{
@ -779,72 +777,31 @@ void NexFriends::addFriendRequest(uint32 pid, const char* comment, std::function
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 5, &packetBuffer, std::bind(addFriendRequestHandler, std::placeholders::_1, this, cb), true);
}
typedef struct
{
NEXFRIENDS_CALLBACK cb;
void* customParam;
NexFriends* nexFriends;
// command specific
struct
{
nexPrincipalBasicInfo* basicInfo;
sint32 count;
}principalBaseInfo;
}nexFriendsCallInfo_t;
void NexFriends_handleResponse_requestPrincipleBaseInfoByPID(nexService* nex, nexServiceResponse_t* response)
{
nexFriendsCallInfo_t* callInfo = (nexFriendsCallInfo_t*)response->custom;
if (response->isSuccessful == false)
{
// handle error case
callInfo->cb(callInfo->nexFriends, NexFriends::ERR_RPC_FAILED, callInfo->customParam);
free(callInfo);
return;
}
// process result
uint32 count = response->data.readU32();
if (count != callInfo->principalBaseInfo.count)
{
callInfo->cb(callInfo->nexFriends, NexFriends::ERR_UNEXPECTED_RESULT, callInfo->customParam);
free(callInfo);
return;
}
for (uint32 i = 0; i < count; i++)
{
callInfo->principalBaseInfo.basicInfo[i].readData(&response->data);
}
if (response->data.hasReadOutOfBounds())
{
callInfo->cb(callInfo->nexFriends, NexFriends::ERR_UNEXPECTED_RESULT, callInfo->customParam);
free(callInfo);
return;
}
// callback
callInfo->cb(callInfo->nexFriends, NexFriends::ERR_NONE, callInfo->customParam);
free(callInfo);
}
void NexFriends::requestPrincipleBaseInfoByPID(nexPrincipalBasicInfo* basicInfo, uint32* pidList, sint32 count, NEXFRIENDS_CALLBACK cb, void* customParam)
void NexFriends::requestPrincipleBaseInfoByPID(uint32* pidList, sint32 count, const std::function<void(RpcErrorCode result, std::span<nexPrincipalBasicInfo> basicInfo)>& cb)
{
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
{
// not connected
cb(this, ERR_NOT_CONNECTED, customParam);
return;
}
return cb(ERR_NOT_CONNECTED, {});
uint8 tempNexBufferArray[512];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
packetBuffer.writeU32(count);
for(sint32 i=0; i<count; i++)
packetBuffer.writeU32(pidList[i]);
nexFriendsCallInfo_t* callInfo = (nexFriendsCallInfo_t*)malloc(sizeof(nexFriendsCallInfo_t));
callInfo->principalBaseInfo.basicInfo = basicInfo;
callInfo->principalBaseInfo.count = count;
callInfo->cb = cb;
callInfo->customParam = customParam;
callInfo->nexFriends = this;
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 17, &packetBuffer, NexFriends_handleResponse_requestPrincipleBaseInfoByPID, callInfo, true);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 17, &packetBuffer, [cb, count](nexServiceResponse_t* response)
{
if (!response->isSuccessful)
return cb(NexFriends::ERR_RPC_FAILED, {});
// process result
uint32 resultCount = response->data.readU32();
if (resultCount != count)
return cb(NexFriends::ERR_UNEXPECTED_RESULT, {});
std::vector<nexPrincipalBasicInfo> nexBasicInfo;
nexBasicInfo.resize(count);
for (uint32 i = 0; i < resultCount; i++)
nexBasicInfo[i].readData(&response->data);
if (response->data.hasReadOutOfBounds())
return cb(NexFriends::ERR_UNEXPECTED_RESULT, {});
return cb(NexFriends::ERR_NONE, nexBasicInfo);
}, true);
}
void genericFriendServiceNoResponseHandler(nexServiceResponse_t* nexResponse, std::function<void(uint32)> cb)
@ -858,7 +815,7 @@ void genericFriendServiceNoResponseHandler(nexServiceResponse_t* nexResponse, st
}
}
void NexFriends::removeFriend(uint32 pid, std::function<void(uint32)> cb)
void NexFriends::removeFriend(uint32 pid, std::function<void(RpcErrorCode)> cb)
{
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
{
@ -869,10 +826,20 @@ void NexFriends::removeFriend(uint32 pid, std::function<void(uint32)> cb)
uint8 tempNexBufferArray[512];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
packetBuffer.writeU32(pid);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 4, &packetBuffer, std::bind(genericFriendServiceNoResponseHandler, std::placeholders::_1, cb), true);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 4, &packetBuffer, [this, cb](nexServiceResponse_t* response) -> void
{
if (!response->isSuccessful)
return cb(NexFriends::ERR_RPC_FAILED);
else
{
cb(NexFriends::ERR_NONE);
this->requestGetAllInformation(); // refresh friend list and send add/remove notifications
return;
}
}, true);
}
void NexFriends::cancelOutgoingProvisionalFriendRequest(uint32 pid, std::function<void(uint32)> cb)
void NexFriends::cancelOutgoingProvisionalFriendRequest(uint32 pid, std::function<void(RpcErrorCode)> cb)
{
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
{
@ -883,53 +850,63 @@ void NexFriends::cancelOutgoingProvisionalFriendRequest(uint32 pid, std::functio
uint8 tempNexBufferArray[512];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
packetBuffer.writeU32(pid);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 4, &packetBuffer, std::bind(genericFriendServiceNoResponseHandler, std::placeholders::_1, cb), true);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 4, &packetBuffer, [cb](nexServiceResponse_t* response) -> void
{
if (!response->isSuccessful)
return cb(NexFriends::ERR_RPC_FAILED);
else
return cb(NexFriends::ERR_NONE);
}, true);
}
void NexFriends::acceptFriendRequest(uint64 messageId, std::function<void(uint32)> cb)
void NexFriends::acceptFriendRequest(uint64 messageId, std::function<void(RpcErrorCode)> cb)
{
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
{
// not connected
cb(ERR_NOT_CONNECTED);
return;
}
return cb(ERR_NOT_CONNECTED);
uint8 tempNexBufferArray[128];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
packetBuffer.writeU64(messageId);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 7, &packetBuffer, std::bind(genericFriendServiceNoResponseHandler, std::placeholders::_1, cb), true);
}
void markFriendRequestsAsReceivedHandler(nexServiceResponse_t* nexResponse, std::function<void(uint32)> cb)
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 7, &packetBuffer, [cb](nexServiceResponse_t* response) -> void
{
if (nexResponse->isSuccessful)
cb(0);
if (!response->isSuccessful)
return cb(NexFriends::ERR_RPC_FAILED);
else
{
// todo: Properly handle returned error code
cb(NexFriends::ERR_RPC_FAILED);
}
return cb(NexFriends::ERR_NONE);
}, true);
}
void NexFriends::markFriendRequestsAsReceived(uint64* messageIdList, sint32 count, std::function<void(uint32)> cb)
void NexFriends::deleteFriendRequest(uint64 messageId, std::function<void(RpcErrorCode)> cb)
{
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
return cb(ERR_NOT_CONNECTED);
uint8 tempNexBufferArray[128];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
packetBuffer.writeU64(messageId);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 8, &packetBuffer, [this, cb](nexServiceResponse_t* response) -> void
{
// not connected
cb(ERR_NOT_CONNECTED);
return;
if (!response->isSuccessful)
return cb(NexFriends::ERR_RPC_FAILED);
cb(NexFriends::ERR_NONE);
this->requestGetAllInformation(); // refresh friend list and send add/remove notifications
}, true);
}
void NexFriends::markFriendRequestsAsReceived(uint64* messageIdList, sint32 count, std::function<void(RpcErrorCode)> cb)
{
if (nexCon == nullptr || nexCon->getState() != nexService::STATE_CONNECTED)
return cb(ERR_NOT_CONNECTED);
uint8 tempNexBufferArray[1024];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
packetBuffer.writeU32(count);
for(sint32 i=0; i<count; i++)
packetBuffer.writeU64(messageIdList[i]);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 10, &packetBuffer, std::bind(markFriendRequestsAsReceivedHandler, std::placeholders::_1, cb), true);
}
void genericFriendServiceNoResponseHandlerWithoutCB(nexServiceResponse_t* nexResponse)
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 10, &packetBuffer, [cb](nexServiceResponse_t* response) -> void
{
if (!response->isSuccessful)
return cb(NexFriends::ERR_RPC_FAILED);
else
return cb(NexFriends::ERR_NONE);
}, true);
}
void NexFriends::updateMyPresence(nexPresenceV2& myPresence)
@ -943,7 +920,7 @@ void NexFriends::updateMyPresence(nexPresenceV2& myPresence)
uint8 tempNexBufferArray[1024];
nexPacketBuffer packetBuffer(tempNexBufferArray, sizeof(tempNexBufferArray), true);
myPresence.writeData(&packetBuffer);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 13, &packetBuffer, std::bind(genericFriendServiceNoResponseHandlerWithoutCB, std::placeholders::_1), false);
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 13, &packetBuffer, +[](nexServiceResponse_t* nexResponse){}, false);
}
void NexFriends::update()

View File

@ -248,9 +248,9 @@ public:
nexPrincipalPreference(uint8 ukn0, uint8 ukn1, uint8 ukn2)
{
this->ukn0 = ukn0;
this->ukn1 = ukn1;
this->ukn2 = ukn2;
this->showOnline = ukn0;
this->showGame = ukn1;
this->blockFriendRequests = ukn2;
}
nexPrincipalPreference(nexPacketBuffer* pb)
@ -260,21 +260,21 @@ public:
void writeData(nexPacketBuffer* pb) const override
{
pb->writeU8(ukn0);
pb->writeU8(ukn1);
pb->writeU8(ukn2);
pb->writeU8(showOnline);
pb->writeU8(showGame);
pb->writeU8(blockFriendRequests);
}
void readData(nexPacketBuffer* pb) override
{
ukn0 = pb->readU8();
ukn1 = pb->readU8();
ukn2 = pb->readU8();
showOnline = pb->readU8();
showGame = pb->readU8();
blockFriendRequests = pb->readU8();
}
public:
uint8 ukn0;
uint8 ukn1;
uint8 ukn2;
uint8 showOnline;
uint8 showGame;
uint8 blockFriendRequests;
};
class nexComment : public nexType
@ -505,13 +505,12 @@ public:
uint32 type;
std::string msg;
};
class NexFriends;
typedef void (*NEXFRIENDS_CALLBACK)(NexFriends* nexFriends, uint32 result, void* custom);
class NexFriends
{
public:
using RpcErrorCode = int; // replace with enum class later
static const int ERR_NONE = 0;
static const int ERR_RPC_FAILED = 1;
static const int ERR_UNEXPECTED_RESULT = 2;
@ -544,27 +543,29 @@ public:
int getPendingFriendRequestCount();
bool requestGetAllInformation();
bool requestGetAllInformation(std::function<void(uint32)> cb);
bool addProvisionalFriendByPidGuessed(uint32 principalId);
void acceptFriendRequest(uint64 messageId, std::function<void(uint32)> cb);
bool isOnline();
// synchronous API (returns immediately)
bool requestGetAllInformation(std::function<void(uint32)> cb);
void getFriendPIDs(uint32* pidList, uint32* pidCount, sint32 offset, sint32 count, bool includeFriendRequests);
void getFriendRequestPIDs(uint32* pidList, uint32* pidCount, sint32 offset, sint32 count, bool includeIncoming, bool includeOutgoing);
bool getFriendByPID(nexFriend& friendData, uint32 pid);
bool getFriendRequestByPID(nexFriendRequest& friendRequestData, bool* isIncoming, uint32 searchedPid);
bool getFriendRequestByMessageId(nexFriendRequest& friendRequestData, bool* isIncoming, uint64 messageId);
bool isOnline();
void getMyPreference(nexPrincipalPreference& preference);
bool addProvisionalFriend(char* name, std::function<void(uint32)> cb);
void addFriendRequest(uint32 pid, const char* comment, std::function<void(uint32)> cb);
void requestPrincipleBaseInfoByPID(nexPrincipalBasicInfo* basicInfo, uint32* pidList, sint32 count, NEXFRIENDS_CALLBACK cb, void* customParam);
void removeFriend(uint32 pid, std::function<void(uint32)> cb);
void cancelOutgoingProvisionalFriendRequest(uint32 pid, std::function<void(uint32)> cb);
void markFriendRequestsAsReceived(uint64* messageIdList, sint32 count, std::function<void(uint32)> cb);
// asynchronous API (data has to be requested)
bool addProvisionalFriend(char* name, std::function<void(RpcErrorCode)> cb);
void addFriendRequest(uint32 pid, const char* comment, std::function<void(RpcErrorCode)> cb);
void requestPrincipleBaseInfoByPID(uint32* pidList, sint32 count, const std::function<void(RpcErrorCode result, std::span<nexPrincipalBasicInfo> basicInfo)>& cb);
void removeFriend(uint32 pid, std::function<void(RpcErrorCode)> cb);
void cancelOutgoingProvisionalFriendRequest(uint32 pid, std::function<void(RpcErrorCode)> cb);
void markFriendRequestsAsReceived(uint64* messageIdList, sint32 count, std::function<void(RpcErrorCode)> cb);
void acceptFriendRequest(uint64 messageId, std::function<void(RpcErrorCode)> cb);
void deleteFriendRequest(uint64 messageId, std::function<void(RpcErrorCode)> cb); // rejecting incoming friend request (differs from blocking friend requests)
bool updatePreferencesAsync(const nexPrincipalPreference newPreferences, std::function<void(RpcErrorCode)> cb);
void updateMyPresence(nexPresenceV2& myPresence);
bool updatePreferences(const nexPrincipalPreference& newPreferences);
void setNotificationHandler(void(*notificationHandler)(NOTIFICATION_TYPE notificationType, uint32 pid));
@ -578,7 +579,6 @@ private:
static void handleResponse_acceptFriendRequest(nexService* nex, nexServiceResponse_t* response);
static void handleResponse_getAllInformation(nexServiceResponse_t* response, NexFriends* nexFriends, std::function<void(uint32)> cb);
static void handleResponse_updatePreferences(nexServiceResponse_t* response, NexFriends* nexFriends, std::function<void(uint32)> cb);
void generateNotification(NOTIFICATION_TYPE notificationType, uint32 pid);
void trackNotifications();
@ -618,6 +618,7 @@ private:
}auth;
// local friend state
nexPresenceV2 myPresence;
nexPrincipalPreference myPreference;
std::recursive_mutex mtx_lists;
std::vector<nexFriend> list_friends;

View File

@ -20,6 +20,7 @@ add_library(CemuCommon
StackAllocator.h
SysAllocator.cpp
SysAllocator.h
CafeString.h
version.h
)

73
src/Common/CafeString.h Normal file
View File

@ -0,0 +1,73 @@
#pragma once
#include "betype.h"
#include "util/helpers/StringHelpers.h"
/* Helper classes to represent CafeOS strings in emulated memory */
template <size_t N>
class CafeString // fixed buffer size, null-terminated, PPC char
{
public:
bool assign(std::string_view sv)
{
if (sv.size()+1 >= N)
{
memcpy(data, sv.data(), sv.size()-1);
data[sv.size()-1] = '\0';
return false;
}
memcpy(data, sv.data(), sv.size());
data[sv.size()] = '\0';
return true;
}
uint8be data[N];
};
template <size_t N>
class CafeWideString // fixed buffer size, null-terminated, PPC wchar_t (16bit big-endian)
{
public:
bool assign(const uint16be* input)
{
size_t i = 0;
while(input[i])
{
if(i >= N-1)
{
data[N-1] = 0;
return false;
}
data[i] = input[i];
i++;
}
data[i] = 0;
return true;
}
bool assignFromUTF8(std::string_view sv)
{
std::basic_string<uint16be> beStr = StringHelpers::FromUtf8(sv);
if(beStr.length() > N-1)
{
memcpy(data, beStr.data(), (N-1)*sizeof(uint16be));
data[N-1] = 0;
return false;
}
memcpy(data, beStr.data(), beStr.length()*sizeof(uint16be));
data[beStr.length()] = '\0';
return true;
}
uint16be data[N];
};
namespace CafeStringHelpers
{
static uint32 Length(const uint16be* input, uint32 maxLength)
{
uint32 i = 0;
while(input[i] && i < maxLength)
i++;
return i;
}
};

View File

@ -30,8 +30,35 @@ public:
uint32 GetMPTR() const { return MEMPTR<T>(m_ptr).GetMPTR(); }
uint32 GetMPTRBE() const { return MEMPTR<T>(m_ptr).GetMPTRBE(); }
operator T*() const { return GetPointer(); }
T* operator&() { return GetPointer(); }
explicit operator T*() const { return GetPointer(); }
explicit operator uint32() const { return GetMPTR(); }
explicit operator bool() const { return *m_ptr != 0; }
// for arrays (count > 1) allow direct access via [] operator
template<int c = count>
requires (c > 1)
T& operator[](const uint32 index)
{
return m_ptr[index];
}
// if count is 1, then allow direct value assignment via = operator
template<int c = count>
requires (c == 1)
T& operator=(const T& rhs)
{
*m_ptr = rhs;
return *m_ptr;
}
// if count is 1, then allow == and != operators
template<int c = count>
requires (c == 1)
bool operator==(const T& rhs) const
{
return *m_ptr == rhs;
}
private:
static const uint32 kStaticMemOffset = 64;

View File

@ -2198,6 +2198,7 @@ void MainWindow::RecreateMenu()
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitMP), _("&Coreinit MP API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitMP));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitThread), _("&Coreinit Thread API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitThread));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NN_NFP), _("&NN NFP"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::NN_NFP));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::NN_FP), _("&NN FP"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::NN_FP));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::GX2), _("&GX2 API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::GX2));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::SoundAPI), _("&Audio API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::SoundAPI));
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::InputAPI), _("&Input API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::InputAPI));

View File

@ -2,6 +2,7 @@
#include "boost/nowide/convert.hpp"
#include <charconv>
// todo - move the Cafe/PPC specific parts to CafeString.h eventually
namespace StringHelpers
{
// convert Wii U big-endian wchar_t string to utf8 string

View File

@ -36,6 +36,16 @@ public:
static HighResolutionTimer now();
static HRTick getFrequency();
static HRTick microsecondsToTicks(uint64 microseconds)
{
return microseconds * m_freq / 1000000;
}
static uint64 ticksToMicroseconds(HRTick ticks)
{
return ticks * 1000000 / m_freq;
}
private:
HighResolutionTimer(uint64 timePoint) : m_timePoint(timePoint) {};