mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-12-25 01:01:52 +01:00
nn_fp: Full rework of friend service
This commit is contained in:
parent
13a50a915e
commit
0d71885c88
@ -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
|
||||
|
@ -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)>();
|
||||
|
@ -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
|
||||
|
@ -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?
|
||||
@ -19,4 +22,13 @@ enum IOS_ERROR : sint32
|
||||
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
|
||||
};
|
||||
|
@ -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,7 +686,11 @@ namespace iosu
|
||||
r = _IPCHandlerIn_IOS_Ioctl(dispatchCmd);
|
||||
break;
|
||||
case IPCCommandId::IOS_IOCTLV:
|
||||
r = _IPCHandlerIn_IOS_Ioctlv(dispatchCmd);
|
||||
r = _IPCHandlerIn_TranslateVectorAddresses(dispatchCmd);
|
||||
if(r < 0)
|
||||
cemuLog_log(LogType::Force, "Ioctlv error");
|
||||
else
|
||||
r = _IPCHandlerIn_IOS_Ioctlv(dispatchCmd);
|
||||
break;
|
||||
default:
|
||||
cemuLog_log(LogType::Force, "Invalid IPC command {}", (uint32)(IPCCommandId)cmd->cmdId);
|
||||
@ -547,10 +743,34 @@ namespace iosu
|
||||
return IOS_ERROR_OK;
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
class : public ::IOSUModule
|
||||
{
|
||||
_IPCInitDispatchablePool();
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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
@ -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,13 +15,61 @@ 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
|
||||
{
|
||||
/* +0x000 */ uint8 type; // type(Non-Zero -> Friend, 0 -> Friend request ? )
|
||||
/* +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];
|
||||
/* +0x008 */ uint32be pid;
|
||||
/* +0x00C */ char nnid[0x10 + 1];
|
||||
@ -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_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(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(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, "");
|
||||
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);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
// output
|
||||
uint32 returnCode; // return value
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 numReturnedCount;
|
||||
}resultGetFriendList;
|
||||
struct
|
||||
{
|
||||
uint32 u32;
|
||||
}resultU32;
|
||||
};
|
||||
}iosuFpdCemuRequest_t;
|
||||
|
||||
// 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,
|
||||
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,
|
||||
};
|
||||
|
||||
void Initialize();
|
||||
using FriendPID = uint32;
|
||||
|
||||
IOSUModule* GetModule();
|
||||
}
|
||||
}
|
@ -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))
|
||||
@ -83,4 +210,4 @@ namespace iosu
|
||||
m_threadInitialized = false;
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
};
|
||||
};
|
@ -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);
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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';
|
||||
|
@ -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);
|
||||
|
@ -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
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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"},
|
||||
|
@ -34,6 +34,7 @@ enum class LogType : sint32
|
||||
NN_PDM = 21,
|
||||
NN_OLV = 23,
|
||||
NN_NFP = 13,
|
||||
NN_FP = 24,
|
||||
|
||||
TextureReadback = 29,
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
@ -683,7 +682,7 @@ bool NexFriends::getFriendRequestByPID(nexFriendRequest& friendRequestData, bool
|
||||
{
|
||||
friendRequestData = it;
|
||||
if (isIncoming)
|
||||
*isIncoming = false;
|
||||
*isIncoming = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
nexCon->callMethod(NEX_PROTOCOL_FRIENDS_WIIU, 7, &packetBuffer, [cb](nexServiceResponse_t* response) -> void
|
||||
{
|
||||
if (!response->isSuccessful)
|
||||
return cb(NexFriends::ERR_RPC_FAILED);
|
||||
else
|
||||
return cb(NexFriends::ERR_NONE);
|
||||
}, true);
|
||||
}
|
||||
|
||||
void markFriendRequestsAsReceivedHandler(nexServiceResponse_t* nexResponse, std::function<void(uint32)> cb)
|
||||
{
|
||||
if (nexResponse->isSuccessful)
|
||||
cb(0);
|
||||
else
|
||||
{
|
||||
// todo: Properly handle returned error code
|
||||
cb(NexFriends::ERR_RPC_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// 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, 8, &packetBuffer, [this, cb](nexServiceResponse_t* response) -> void
|
||||
{
|
||||
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()
|
||||
|
@ -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;
|
||||
|
@ -20,6 +20,7 @@ add_library(CemuCommon
|
||||
StackAllocator.h
|
||||
SysAllocator.cpp
|
||||
SysAllocator.h
|
||||
CafeString.h
|
||||
version.h
|
||||
)
|
||||
|
||||
|
73
src/Common/CafeString.h
Normal file
73
src/Common/CafeString.h
Normal 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;
|
||||
}
|
||||
};
|
@ -29,9 +29,36 @@ public:
|
||||
T* GetPointer() const { return m_ptr; }
|
||||
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;
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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) {};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user