From 99661aa6b3ba7da57eec720d41bca55ae631f8c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Tue, 10 Feb 2026 22:59:07 +0100 Subject: [PATCH] RE encountered NpTus functions (#4018) --- CMakeLists.txt | 1 + src/core/libraries/np/np_error.h | 10 +- src/core/libraries/np/np_manager.h | 2 + src/core/libraries/np/np_tus.cpp | 573 ++++++++++++++++++++++--- src/core/libraries/np/np_tus.h | 213 +++------ src/core/libraries/np/object_manager.h | 56 +++ 6 files changed, 647 insertions(+), 208 deletions(-) create mode 100644 src/core/libraries/np/object_manager.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cef2df24..ba16732ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -613,6 +613,7 @@ set(NP_LIBS src/core/libraries/np/np_error.h src/core/libraries/np/np_sns_facebook_dialog.h src/core/libraries/np/np_partner.cpp src/core/libraries/np/np_partner.h + src/core/libraries/np/object_manager.h ) set(ZLIB_LIB src/core/libraries/zlib/zlib.cpp diff --git a/src/core/libraries/np/np_error.h b/src/core/libraries/np/np_error.h index cf2014148..518344ba3 100644 --- a/src/core/libraries/np/np_error.h +++ b/src/core/libraries/np/np_error.h @@ -13,4 +13,12 @@ constexpr int ORBIS_NP_ERROR_INVALID_SIZE = 0x80550011; constexpr int ORBIS_NP_ERROR_ABORTED = 0x80550012; constexpr int ORBIS_NP_ERROR_REQUEST_MAX = 0x80550013; constexpr int ORBIS_NP_ERROR_REQUEST_NOT_FOUND = 0x80550014; -constexpr int ORBIS_NP_ERROR_INVALID_ID = 0x80550015; \ No newline at end of file +constexpr int ORBIS_NP_ERROR_INVALID_ID = 0x80550015; + +constexpr int ORBIS_NP_COMMUNITY_ERROR_INVALID_ARGUMENT = 0x80550704; +constexpr int ORBIS_NP_COMMUNITY_ERROR_TOO_MANY_OBJECTS = 0x80550706; +constexpr int ORBIS_NP_COMMUNITY_ERROR_INSUFFICIENT_ARGUMENT = 0x8055070c; +constexpr int ORBIS_NP_COMMUNITY_ERROR_INVALID_ID = 0x8055070e; +constexpr int ORBIS_NP_COMMUNITY_ERROR_INVALID_ALIGNMENT = 0x80550714; +constexpr int ORBIS_NP_COMMUNITY_ERROR_TOO_MANY_SLOTID = 0x80550718; +constexpr int ORBIS_NP_COMMUNITY_ERROR_TOO_MANY_NPID = 0x80550719; \ No newline at end of file diff --git a/src/core/libraries/np/np_manager.h b/src/core/libraries/np/np_manager.h index 078fa804a..49250db03 100644 --- a/src/core/libraries/np/np_manager.h +++ b/src/core/libraries/np/np_manager.h @@ -93,6 +93,8 @@ struct OrbisNpCreateAsyncRequestParameter { void RegisterNpCallback(std::string key, std::function cb); void DeregisterNpCallback(std::string key); +s32 PS4_SYSV_ABI sceNpGetNpId(Libraries::UserService::OrbisUserServiceUserId user_id, + OrbisNpId* np_id); s32 PS4_SYSV_ABI sceNpGetOnlineId(Libraries::UserService::OrbisUserServiceUserId user_id, OrbisNpOnlineId* online_id); diff --git a/src/core/libraries/np/np_tus.cpp b/src/core/libraries/np/np_tus.cpp index e0d0aaad1..d18cf4ec0 100644 --- a/src/core/libraries/np/np_tus.cpp +++ b/src/core/libraries/np/np_tus.cpp @@ -1,15 +1,87 @@ // SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include +#include + #include "common/logging/log.h" #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" +#include "core/libraries/np/np_error.h" +#include "core/libraries/np/np_manager.h" #include "core/libraries/np/np_tus.h" +#include "core/libraries/np/np_types.h" +#include "core/libraries/np/object_manager.h" +#include "core/libraries/system/userservice.h" namespace Libraries::Np::NpTus { -s32 PS4_SYSV_ABI sceNpTssCreateNpTitleCtx() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); +int PackReqId(int libCtxId, int reqId) { + return ((libCtxId & 0xFFFF) << 16) | (reqId & 0xFFFF); +} + +std::pair UnpackReqId(int reqId) { + return {reqId >> 16, reqId & 0xFFFF}; +} + +bool IsReqId(int id) { + return id > (1 << 16); +} + +struct NpTusRequest { + std::future task; + + void Start(auto lambda) { + this->task = std::async(std::launch::async, lambda); + } +}; + +using NpTusRequestsManager = + ObjectManager; + +struct NpTusTitleContext { + u32 serviceLabel; + OrbisNpId npId; + NpTusRequestsManager requestsManager; + + s32 GetRequest(int reqId, NpTusRequest** out) { + NpTusRequest* req = nullptr; + if (auto ret = requestsManager.GetObject(reqId, &req); ret < 0) { + return ret; + } + + *out = req; + + return ORBIS_OK; + } + + s32 DeleteRequest(int reqId) { + return requestsManager.DeleteObject(reqId); + } +}; + +using NpTusContextManager = + ObjectManager; + +static NpTusContextManager ctxManager; + +s32 GetRequest(int requestId, NpTusRequest** out) { + auto [ctxId, reqId] = UnpackReqId(requestId); + + NpTusTitleContext* ctx = nullptr; + if (auto ret = ctxManager.GetObject(ctxId, &ctx); ret < 0) { + return ret; + } + + NpTusRequest* req = nullptr; + if (auto ret = ctx->GetRequest(reqId, &req); ret < 0) { + return ret; + } + + *out = req; + return ORBIS_OK; } @@ -33,9 +105,34 @@ s32 PS4_SYSV_ABI sceNpTusAddAndGetVariableVUserAsync() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusCreateNpTitleCtx() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); - return ORBIS_OK; +s32 PS4_SYSV_ABI sceNpTusCreateNpTitleCtx(OrbisNpServiceLabel serviceLabel, OrbisNpId* npId) { + if (!npId) { + return ORBIS_NP_COMMUNITY_ERROR_INSUFFICIENT_ARGUMENT; + } + if (serviceLabel == ORBIS_NP_INVALID_SERVICE_LABEL) { + return ORBIS_NP_COMMUNITY_ERROR_INVALID_ARGUMENT; + } + LOG_ERROR(Lib_NpTus, "serviceLabel = {}, npId->data = {}", serviceLabel, npId->handle.data); + + return ctxManager.CreateObject(serviceLabel, *npId); +} + +s32 PS4_SYSV_ABI sceNpTusCreateNpTitleCtxA(OrbisNpServiceLabel serviceLabel, + Libraries::UserService::OrbisUserServiceUserId userId) { + LOG_ERROR(Lib_NpTus, "serviceLabel = {}, userId = {}", serviceLabel, userId); + OrbisNpId npId; + auto ret = NpManager::sceNpGetNpId(userId, &npId); + + if (ret < 0) { + return ret; + } + + return sceNpTusCreateNpTitleCtx(serviceLabel, &npId); +} + +s32 PS4_SYSV_ABI sceNpTssCreateNpTitleCtx(OrbisNpServiceLabel serviceLabel, OrbisNpId* npId) { + LOG_INFO(Lib_NpTus, "redirecting"); + return sceNpTusCreateNpTitleCtx(serviceLabel, npId); } s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotData() { @@ -58,14 +155,33 @@ s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotVariableAsync() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusGetData() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTusGetDataAsync(int reqId, OrbisNpId* npId, OrbisNpTusSlotId slotId, + OrbisNpTusDataStatus* dataStatus, u64 dataStatusSize, + void* data, u64 dataSize, void* option) { + LOG_INFO( + Lib_NpTus, + "reqId = {:#x}, slotId = {}, dataStatusSize = {}, data = {}, dataSize = {}, option = {}", + reqId, slotId, dataStatusSize, data, dataSize, fmt::ptr(option)); return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusGetDataAsync() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); - return ORBIS_OK; +s32 PS4_SYSV_ABI sceNpTusGetData(int reqId, OrbisNpId* npId, OrbisNpTusSlotId slotId, + OrbisNpTusDataStatus* dataStatus, u64 dataStatusSize, void* data, + u64 dataSize, void* option) { + LOG_ERROR( + Lib_NpTus, + "reqId = {:#x}, slotId = {}, dataStatusSize = {}, data = {}, dataSize = {}, option = {}", + reqId, slotId, dataStatusSize, data, dataSize, fmt::ptr(option)); + + auto ret = sceNpTusGetDataAsync(reqId, npId, slotId, dataStatus, dataStatusSize, data, dataSize, + option); + if (ret < 0) { + return ret; + } + + sceNpTusWaitAsync(reqId, &ret); + + return ret; } s32 PS4_SYSV_ABI sceNpTusGetDataVUser() { @@ -118,13 +234,45 @@ s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusVUserAsync() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariable() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariableAsync(int reqId, OrbisNpId* npId, + OrbisNpTusSlotId* slotIds, s64* variables, + u64 variablesSize, int arrayLen, void* option) { + LOG_INFO(Lib_NpTus, + "reqId = {}, npId = {}, slotIds = {}, variables = {}, variablesSize = {}, arrayLen = " + "{}, option = {}", + reqId, npId ? npId->handle.data : "", fmt::ptr(slotIds), fmt::ptr(variables), + variablesSize, arrayLen, fmt::ptr(option)); + + NpTusRequest* req = nullptr; + if (auto ret = GetRequest(reqId, &req); ret < 0) { + return ret; + } + + req->Start([=]() { + // + return 0; + }); + return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariableAsync() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariable(int reqId, OrbisNpId* npId, OrbisNpTusSlotId* slotIds, + s64* variables, u64 variablesSize, int arrayLen, + void* option) { + LOG_INFO(Lib_NpTus, + "reqId = {}, npId = {}, slotIds = {}, variables = {}, variablesSize = {}, arrayLen = " + "{}, option = {}", + reqId, npId ? npId->handle.data : "", fmt::ptr(slotIds), fmt::ptr(variables), + variablesSize, arrayLen, fmt::ptr(option)); + + auto ret = sceNpTusGetMultiSlotVariableAsync(reqId, npId, slotIds, variables, variablesSize, + arrayLen, option); + if (ret < 0) { + return ret; + } + + sceNpTusWaitAsync(reqId, &ret); + return ORBIS_OK; } @@ -143,8 +291,24 @@ s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatus() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatusAsync() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatusAsync(int reqId, OrbisNpId* npIds, + OrbisNpTusSlotId slotId, + OrbisNpTusDataStatus* statuses, + u64 statusesBytes, int arrayLen, + void* option) { + LOG_ERROR(Lib_NpTus, "(STUBBED) reqId = {:#x}, slotId = {}, arrayLen = {}, option = {}", reqId, + slotId, arrayLen, fmt::ptr(option)); + + NpTusRequest* req = nullptr; + if (auto ret = GetRequest(reqId, &req); ret < 0) { + return ret; + } + + req->Start([=]() { + // + return 0; + }); + return ORBIS_OK; } @@ -178,13 +342,49 @@ s32 PS4_SYSV_ABI sceNpTusGetMultiUserVariableVUserAsync() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusSetData() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTusSetDataAsync(int reqId, OrbisNpId* npId, OrbisNpTusSlotId slotId, + u64 totalSize, u64 sendSize, const void* data, + const OrbisNpTusDataInfo* info, u64 infoSize, + const OrbisNpId* lastChangedAuthor, + Libraries::Rtc::OrbisRtcTick lastChanged, void* option) { + LOG_INFO(Lib_NpTus, + "reqId = {:#x}, npId = {}, slotId = {}, totalSize = {}, sendSize = {}, " + "info->size = {}, infoSize = {}, lastChangedAuthor = {}", + reqId, npId ? npId->handle.data : "", slotId, totalSize, sendSize, + info ? info->size : 0, infoSize, + lastChangedAuthor ? lastChangedAuthor->handle.data : ""); + + NpTusRequest* req = nullptr; + if (auto ret = GetRequest(reqId, &req); ret < 0) { + return ret; + } + req->Start([=]() { + // + return 0; + }); + return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusSetDataAsync() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTusSetData(int reqId, OrbisNpId* npId, OrbisNpTusSlotId slotId, u64 totalSize, + u64 sendSize, const void* data, const OrbisNpTusDataInfo* info, + u64 infoSize, const OrbisNpId* lastChangedAuthor, + Libraries::Rtc::OrbisRtcTick lastChanged, void* option) { + LOG_INFO(Lib_NpTus, + "reqId = {:#x}, npId = {}, slotId = {}, totalSize = {}, sendSize = {}, " + "info->size = {}, infoSize = {}, lastChangedAuthor = {}", + reqId, npId ? npId->handle.data : "", slotId, totalSize, sendSize, + info ? info->size : 0, infoSize, + lastChangedAuthor ? lastChangedAuthor->handle.data : ""); + + auto ret = sceNpTusSetDataAsync(reqId, npId, slotId, totalSize, sendSize, data, info, infoSize, + lastChangedAuthor, lastChanged, option); + if (ret < 0) { + return ret; + } + + sceNpTusWaitAsync(reqId, &ret); + return ORBIS_OK; } @@ -203,8 +403,39 @@ s32 PS4_SYSV_ABI sceNpTusSetMultiSlotVariable() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusSetMultiSlotVariableAsync() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTusSetMultiSlotVariableAsync(int reqId, OrbisNpId* npId, + OrbisNpTusSlotId* slotIds, s64* variables, + int arrayLen, void* option) { + LOG_INFO(Lib_NpTus, + "reqId = {}, npId = {}, slotIds = {}, variables = {}, arrayLen = {}, option = {}", + reqId, npId ? npId->handle.data : "", fmt::ptr(slotIds), fmt::ptr(variables), arrayLen, + fmt::ptr(option)); + + if (!slotIds || !variables) { + return ORBIS_NP_COMMUNITY_ERROR_INSUFFICIENT_ARGUMENT; + } + if (arrayLen < 1 || option) { + return ORBIS_NP_COMMUNITY_ERROR_INVALID_ARGUMENT; + } + if (arrayLen > 64) { + return ORBIS_NP_COMMUNITY_ERROR_TOO_MANY_SLOTID; + } + if (std::ranges::any_of( + std::vector>(slotIds, slotIds + arrayLen), + [](auto id) { return id < 0; })) { + return ORBIS_NP_COMMUNITY_ERROR_INVALID_ARGUMENT; + } + + NpTusRequest* req = nullptr; + if (auto ret = GetRequest(reqId, &req); ret < 0) { + return ret; + } + + req->Start([=]() { + // + return 0; + }); + return ORBIS_OK; } @@ -228,19 +459,59 @@ s32 PS4_SYSV_ABI sceNpTusTryAndSetVariableVUserAsync() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTssCreateNpTitleCtxA() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTssCreateNpTitleCtxA(OrbisNpServiceLabel serviceLabel, + Libraries::UserService::OrbisUserServiceUserId userId) { + LOG_DEBUG(Lib_NpTus, "redirecting"); + return sceNpTusCreateNpTitleCtxA(serviceLabel, userId); +} + +s32 PS4_SYSV_ABI sceNpTssGetDataAsync(int reqId, OrbisNpTssSlotId slotId, + OrbisNpTssDataStatus* dataStatus, u64 dataStatusSize, + void* data, u64 dataSize, OrbisNpTssGetDataOptParam* option) { + LOG_INFO(Lib_NpTus, "reqId = {:#x}, slotId = {}, dataStatusSize = {}, dataSize = {}", reqId, + slotId, dataStatusSize, dataSize); + + if (option && option->size != 0x20) { + return ORBIS_NP_COMMUNITY_ERROR_INVALID_ALIGNMENT; + } + if (dataStatus && dataStatusSize != 0x18) { + return ORBIS_NP_COMMUNITY_ERROR_INVALID_ALIGNMENT; + } + if (slotId < 0 || slotId > 15) { + return ORBIS_NP_COMMUNITY_ERROR_INVALID_ARGUMENT; + } + + NpTusRequest* req = nullptr; + if (auto ret = GetRequest(reqId, &req); ret < 0) { + return ret; + } + + req->Start([=]() { + if (dataStatus) { + dataStatus->status = OrbisNpTssStatus::Ok; + dataStatus->contentLength = 0; + } + return 0; + }); + return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTssGetData() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); - return ORBIS_OK; -} +s32 PS4_SYSV_ABI sceNpTssGetData(int reqId, OrbisNpTssSlotId slotId, + OrbisNpTssDataStatus* dataStatus, u64 dataStatusSize, void* data, + u64 dataSize, OrbisNpTssGetDataOptParam* option) { + LOG_INFO(Lib_NpTus, "reqId = {:#x}, slotId = {}, dataStatusSize = {}, dataSize = {}", reqId, + slotId, dataStatusSize, dataSize); -s32 PS4_SYSV_ABI sceNpTssGetDataAsync() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); - return ORBIS_OK; + auto ret = + sceNpTssGetDataAsync(reqId, slotId, dataStatus, dataStatusSize, data, dataSize, option); + if (ret < 0) { + return ret; + } + + sceNpTusWaitAsync(reqId, &ret); + + return ret; } s32 PS4_SYSV_ABI sceNpTssGetSmallStorage() { @@ -313,14 +584,20 @@ s32 PS4_SYSV_ABI sceNpTusChangeModeForOtherSaveDataOwners() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusCreateNpTitleCtxA() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); - return ORBIS_OK; -} +s32 PS4_SYSV_ABI sceNpTusCreateRequest(int libCtxId) { + LOG_INFO(Lib_NpTus, "libCtxId = {}", libCtxId); -s32 PS4_SYSV_ABI sceNpTusCreateRequest() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); - return ORBIS_OK; + NpTusTitleContext* ctx = nullptr; + if (auto ret = ctxManager.GetObject(libCtxId, &ctx); ret < 0) { + return ret; + } + + auto req = ctx->requestsManager.CreateObject(); + if (req < 0) { + return req; + } + + return PackReqId(libCtxId, req); } s32 PS4_SYSV_ABI sceNpTusCreateTitleCtx() { @@ -368,24 +645,70 @@ s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotVariableVUserAsync() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusDeleteNpTitleCtx() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTusDeleteNpTitleCtx(int ctxId) { + LOG_INFO(Lib_NpTus, "ctxId = {}", ctxId); + + return ctxManager.DeleteObject(ctxId); +} + +s32 PS4_SYSV_ABI sceNpTusDeleteRequest(int requestId) { + LOG_INFO(Lib_NpTus, "requestId = {:#x}", requestId); + + auto [ctxId, reqId] = UnpackReqId(requestId); + + NpTusTitleContext* ctx = nullptr; + if (auto ret = ctxManager.GetObject(ctxId, &ctx); ret < 0) { + return ret; + } + + return ctx->DeleteRequest(reqId); +} + +s32 PS4_SYSV_ABI sceNpTusGetDataAAsync(int reqId, OrbisNpAccountId accountId, + OrbisNpTusSlotId slotId, OrbisNpTusDataStatusA* dataStatus, + u64 dataStatusSize, void* data, u64 dataSize, void* option) { + LOG_INFO(Lib_NpTus, + "reqId = {:#x}, accountId = {:#x}, slotId = {}, dataStatus = {}, dataStatusSize = {}, " + "dataSize = {}", + reqId, accountId, slotId, fmt::ptr(dataStatus), dataStatusSize, dataSize); + + if (slotId < 0 || option) { + return ORBIS_NP_COMMUNITY_ERROR_INVALID_ARGUMENT; + } + if (dataStatusSize != sizeof(OrbisNpTusDataStatusA)) { + return ORBIS_NP_COMMUNITY_ERROR_INVALID_ARGUMENT; + } + + NpTusRequest* req = nullptr; + if (auto ret = GetRequest(reqId, &req); ret < 0) { + return ret; + } + + req->Start([=]() { + // + return 0; + }); + return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusDeleteRequest() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); - return ORBIS_OK; -} +s32 PS4_SYSV_ABI sceNpTusGetDataA(int reqId, OrbisNpAccountId accountId, OrbisNpTusSlotId slotId, + OrbisNpTusDataStatusA* dataStatus, u64 dataStatusSize, void* data, + u64 dataSize, void* option) { + LOG_INFO(Lib_NpTus, + "reqId = {:#x}, accountId = {:#x}, slotId = {}, dataStatus = {}, dataStatusSize = {}, " + "dataSize = {}", + reqId, accountId, slotId, fmt::ptr(dataStatus), dataStatusSize, dataSize); -s32 PS4_SYSV_ABI sceNpTusGetDataA() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); - return ORBIS_OK; -} + auto ret = sceNpTusGetDataAAsync(reqId, accountId, slotId, dataStatus, dataStatusSize, data, + dataSize, option); + if (ret < 0) { + return ret; + } -s32 PS4_SYSV_ABI sceNpTusGetDataAAsync() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); - return ORBIS_OK; + sceNpTusWaitAsync(reqId, &ret); + + return ret; } s32 PS4_SYSV_ABI sceNpTusGetDataAVUser() { @@ -458,13 +781,62 @@ s32 PS4_SYSV_ABI sceNpTusGetFriendsVariableForCrossSaveAsync() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusA() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusAAsync(int reqId, OrbisNpAccountId accountId, + OrbisNpTusSlotId* slotIds, + OrbisNpTusDataStatusA* statuses, + u64 statusesSize, int arrayLen, + void* option) { + LOG_ERROR(Lib_NpTus, "reqId = {:#x}, accountId = {}, arrayLen = {}, option = {}", reqId, + accountId, arrayLen, fmt::ptr(option)); + + if (!slotIds || !statuses) { + return ORBIS_NP_COMMUNITY_ERROR_INSUFFICIENT_ARGUMENT; + } + if (arrayLen < 1 || option) { + return ORBIS_NP_COMMUNITY_ERROR_INVALID_ARGUMENT; + } + if (arrayLen * sizeof(OrbisNpTusDataStatusA) != statusesSize) { + return ORBIS_NP_COMMUNITY_ERROR_INVALID_ALIGNMENT; + } + if (arrayLen > 64) { + return ORBIS_NP_COMMUNITY_ERROR_TOO_MANY_SLOTID; + } + if (std::ranges::any_of( + std::vector>(slotIds, slotIds + arrayLen), + [](auto id) { return id < 0; })) { + return ORBIS_NP_COMMUNITY_ERROR_INVALID_ARGUMENT; + } + + // if sdk_ver >= 5.50 clear the statuses array + + NpTusRequest* req = nullptr; + if (auto ret = GetRequest(reqId, &req); ret < 0) { + return ret; + } + + req->Start([=]() { + // + return 0; + }); + return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusAAsync() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusA(int reqId, OrbisNpAccountId accountId, + OrbisNpTusSlotId* slotIds, + OrbisNpTusDataStatusA* statuses, u64 statusesSize, + int arrayLen, void* option) { + LOG_ERROR(Lib_NpTus, "reqId = {:#x}, accountId = {}, arrayLen = {}, option = {}", reqId, + accountId, arrayLen, fmt::ptr(option)); + + auto ret = sceNpTusGetMultiSlotDataStatusAAsync(reqId, accountId, slotIds, statuses, + statusesSize, arrayLen, option); + if (ret < 0) { + return ret; + } + + sceNpTusWaitAsync(reqId, &ret); + return ORBIS_OK; } @@ -618,18 +990,72 @@ s32 PS4_SYSV_ABI sceNpTusGetMultiUserVariableForCrossSaveVUserAsync() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusPollAsync() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTusPollAsync(int reqId, int* result) { + LOG_INFO(Lib_NpTus, "reqId = {:#x}", reqId); + + NpTusRequest* req = nullptr; + if (auto ret = GetRequest(reqId, &req); ret < 0) { + return ret; + } + + if (!req->task.valid()) { + LOG_ERROR(Lib_NpTus, "request not started"); + return 1; + } + if (req->task.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { + LOG_DEBUG(Lib_NpTus, "request finished"); + if (result) { + *result = req->task.get(); + } + return 0; + } + + return 1; +} + +s32 PS4_SYSV_ABI sceNpTusSetDataAAsync(int reqId, OrbisNpAccountId accountId, + OrbisNpTusSlotId slotId, u64 totalSize, u64 sendSize, + const void* data, const OrbisNpTusDataInfo* info, + u64 infoSize, const OrbisNpAccountId* lastChangedAuthor, + Libraries::Rtc::OrbisRtcTick* lastChanged, void* option) { + LOG_INFO(Lib_NpTus, + "reqId = {:#x}, accountId = {}, slotId = {}, totalSize = {}, sendSize = {}, " + "info->size = {}, infoSize = {}, lastChangedAuthor = {}", + reqId, accountId, slotId, totalSize, sendSize, info ? info->size : 0, infoSize, + lastChangedAuthor ? *lastChangedAuthor : 0); + + NpTusRequest* req = nullptr; + if (auto ret = GetRequest(reqId, &req); ret < 0) { + return ret; + } + + req->Start([=]() { + // + return 0; + }); + return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusSetDataA() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); - return ORBIS_OK; -} +s32 PS4_SYSV_ABI sceNpTusSetDataA(int reqId, OrbisNpAccountId accountId, OrbisNpTusSlotId slotId, + u64 totalSize, u64 sendSize, const void* data, + const OrbisNpTusDataInfo* info, u64 infoSize, + const OrbisNpAccountId* lastChangedAuthor, + Libraries::Rtc::OrbisRtcTick* lastChanged, void* option) { + LOG_INFO(Lib_NpTus, + "reqId = {:#x}, accountId = {}, slotId = {}, totalSize = {}, sendSize = {}, " + "info->size = {}, infoSize = {}, lastChangedAuthor = {}", + reqId, accountId, slotId, totalSize, sendSize, info ? info->size : 0, infoSize, + lastChangedAuthor ? *lastChangedAuthor : 0); + + auto ret = sceNpTusSetDataAAsync(reqId, accountId, slotId, totalSize, sendSize, data, info, + infoSize, lastChangedAuthor, lastChanged, option); + if (ret < 0) { + return ret; + } + + sceNpTusWaitAsync(reqId, &ret); -s32 PS4_SYSV_ABI sceNpTusSetDataAAsync() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); return ORBIS_OK; } @@ -713,8 +1139,25 @@ s32 PS4_SYSV_ABI sceNpTusTryAndSetVariableForCrossSaveVUserAsync() { return ORBIS_OK; } -s32 PS4_SYSV_ABI sceNpTusWaitAsync() { - LOG_ERROR(Lib_NpTus, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTusWaitAsync(int reqId, int* result) { + LOG_INFO(Lib_NpTus, "reqId = {:#x}", reqId); + + NpTusRequest* req = nullptr; + if (auto ret = GetRequest(reqId, &req); ret < 0) { + return ret; + } + + if (!req->task.valid()) { + LOG_ERROR(Lib_NpTus, "request not started"); + return 1; + } + + req->task.wait(); + + LOG_DEBUG(Lib_NpTus, "request finished"); + if (result) { + *result = req->task.get(); + } return ORBIS_OK; } diff --git a/src/core/libraries/np/np_tus.h b/src/core/libraries/np/np_tus.h index 3c18099b2..ef4554ec3 100644 --- a/src/core/libraries/np/np_tus.h +++ b/src/core/libraries/np/np_tus.h @@ -4,6 +4,7 @@ #pragma once #include "common/types.h" +#include "core/libraries/rtc/rtc.h" namespace Core::Loader { class SymbolsResolver; @@ -11,148 +12,76 @@ class SymbolsResolver; namespace Libraries::Np::NpTus { -s32 PS4_SYSV_ABI sceNpTssCreateNpTitleCtx(); -s32 PS4_SYSV_ABI sceNpTusAddAndGetVariable(); -s32 PS4_SYSV_ABI sceNpTusAddAndGetVariableAsync(); -s32 PS4_SYSV_ABI sceNpTusAddAndGetVariableVUser(); -s32 PS4_SYSV_ABI sceNpTusAddAndGetVariableVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusCreateNpTitleCtx(); -s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotData(); -s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotDataAsync(); -s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotVariable(); -s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotVariableAsync(); -s32 PS4_SYSV_ABI sceNpTusGetData(); -s32 PS4_SYSV_ABI sceNpTusGetDataAsync(); -s32 PS4_SYSV_ABI sceNpTusGetDataVUser(); -s32 PS4_SYSV_ABI sceNpTusGetDataVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusGetFriendsDataStatus(); -s32 PS4_SYSV_ABI sceNpTusGetFriendsDataStatusAsync(); -s32 PS4_SYSV_ABI sceNpTusGetFriendsVariable(); -s32 PS4_SYSV_ABI sceNpTusGetFriendsVariableAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatus(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusVUser(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariable(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariableAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariableVUser(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariableVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatus(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatusAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatusVUser(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatusVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserVariable(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserVariableAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserVariableVUser(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserVariableVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusSetData(); -s32 PS4_SYSV_ABI sceNpTusSetDataAsync(); -s32 PS4_SYSV_ABI sceNpTusSetDataVUser(); -s32 PS4_SYSV_ABI sceNpTusSetDataVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusSetMultiSlotVariable(); -s32 PS4_SYSV_ABI sceNpTusSetMultiSlotVariableAsync(); -s32 PS4_SYSV_ABI sceNpTusTryAndSetVariable(); -s32 PS4_SYSV_ABI sceNpTusTryAndSetVariableAsync(); -s32 PS4_SYSV_ABI sceNpTusTryAndSetVariableVUser(); -s32 PS4_SYSV_ABI sceNpTusTryAndSetVariableVUserAsync(); -s32 PS4_SYSV_ABI sceNpTssCreateNpTitleCtxA(); -s32 PS4_SYSV_ABI sceNpTssGetData(); -s32 PS4_SYSV_ABI sceNpTssGetDataAsync(); -s32 PS4_SYSV_ABI sceNpTssGetSmallStorage(); -s32 PS4_SYSV_ABI sceNpTssGetSmallStorageAsync(); -s32 PS4_SYSV_ABI sceNpTssGetStorage(); -s32 PS4_SYSV_ABI sceNpTssGetStorageAsync(); -s32 PS4_SYSV_ABI sceNpTusAbortRequest(); -s32 PS4_SYSV_ABI sceNpTusAddAndGetVariableA(); -s32 PS4_SYSV_ABI sceNpTusAddAndGetVariableAAsync(); -s32 PS4_SYSV_ABI sceNpTusAddAndGetVariableAVUser(); -s32 PS4_SYSV_ABI sceNpTusAddAndGetVariableAVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusAddAndGetVariableForCrossSave(); -s32 PS4_SYSV_ABI sceNpTusAddAndGetVariableForCrossSaveAsync(); -s32 PS4_SYSV_ABI sceNpTusAddAndGetVariableForCrossSaveVUser(); -s32 PS4_SYSV_ABI sceNpTusAddAndGetVariableForCrossSaveVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusChangeModeForOtherSaveDataOwners(); -s32 PS4_SYSV_ABI sceNpTusCreateNpTitleCtxA(); -s32 PS4_SYSV_ABI sceNpTusCreateRequest(); -s32 PS4_SYSV_ABI sceNpTusCreateTitleCtx(); -s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotDataA(); -s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotDataAAsync(); -s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotDataVUser(); -s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotDataVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotVariableA(); -s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotVariableAAsync(); -s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotVariableVUser(); -s32 PS4_SYSV_ABI sceNpTusDeleteMultiSlotVariableVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusDeleteNpTitleCtx(); -s32 PS4_SYSV_ABI sceNpTusDeleteRequest(); -s32 PS4_SYSV_ABI sceNpTusGetDataA(); -s32 PS4_SYSV_ABI sceNpTusGetDataAAsync(); -s32 PS4_SYSV_ABI sceNpTusGetDataAVUser(); -s32 PS4_SYSV_ABI sceNpTusGetDataAVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusGetDataForCrossSave(); -s32 PS4_SYSV_ABI sceNpTusGetDataForCrossSaveAsync(); -s32 PS4_SYSV_ABI sceNpTusGetDataForCrossSaveVUser(); -s32 PS4_SYSV_ABI sceNpTusGetDataForCrossSaveVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusGetFriendsDataStatusA(); -s32 PS4_SYSV_ABI sceNpTusGetFriendsDataStatusAAsync(); -s32 PS4_SYSV_ABI sceNpTusGetFriendsDataStatusForCrossSave(); -s32 PS4_SYSV_ABI sceNpTusGetFriendsDataStatusForCrossSaveAsync(); -s32 PS4_SYSV_ABI sceNpTusGetFriendsVariableA(); -s32 PS4_SYSV_ABI sceNpTusGetFriendsVariableAAsync(); -s32 PS4_SYSV_ABI sceNpTusGetFriendsVariableForCrossSave(); -s32 PS4_SYSV_ABI sceNpTusGetFriendsVariableForCrossSaveAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusA(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusAAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusAVUser(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusAVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusForCrossSave(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusForCrossSaveAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusForCrossSaveVUser(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotDataStatusForCrossSaveVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariableA(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariableAAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariableAVUser(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariableAVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariableForCrossSave(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariableForCrossSaveAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariableForCrossSaveVUser(); -s32 PS4_SYSV_ABI sceNpTusGetMultiSlotVariableForCrossSaveVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatusA(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatusAAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatusAVUser(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatusAVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatusForCrossSave(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatusForCrossSaveAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatusForCrossSaveVUser(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserDataStatusForCrossSaveVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserVariableA(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserVariableAAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserVariableAVUser(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserVariableAVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserVariableForCrossSave(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserVariableForCrossSaveAsync(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserVariableForCrossSaveVUser(); -s32 PS4_SYSV_ABI sceNpTusGetMultiUserVariableForCrossSaveVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusPollAsync(); -s32 PS4_SYSV_ABI sceNpTusSetDataA(); -s32 PS4_SYSV_ABI sceNpTusSetDataAAsync(); -s32 PS4_SYSV_ABI sceNpTusSetDataAVUser(); -s32 PS4_SYSV_ABI sceNpTusSetDataAVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusSetMultiSlotVariableA(); -s32 PS4_SYSV_ABI sceNpTusSetMultiSlotVariableAAsync(); -s32 PS4_SYSV_ABI sceNpTusSetMultiSlotVariableVUser(); -s32 PS4_SYSV_ABI sceNpTusSetMultiSlotVariableVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusSetThreadParam(); -s32 PS4_SYSV_ABI sceNpTusSetTimeout(); -s32 PS4_SYSV_ABI sceNpTusTryAndSetVariableA(); -s32 PS4_SYSV_ABI sceNpTusTryAndSetVariableAAsync(); -s32 PS4_SYSV_ABI sceNpTusTryAndSetVariableAVUser(); -s32 PS4_SYSV_ABI sceNpTusTryAndSetVariableAVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusTryAndSetVariableForCrossSave(); -s32 PS4_SYSV_ABI sceNpTusTryAndSetVariableForCrossSaveAsync(); -s32 PS4_SYSV_ABI sceNpTusTryAndSetVariableForCrossSaveVUser(); -s32 PS4_SYSV_ABI sceNpTusTryAndSetVariableForCrossSaveVUserAsync(); -s32 PS4_SYSV_ABI sceNpTusWaitAsync(); +using OrbisNpTssSlotId = s32; +using OrbisNpTusSlotId = s32; + +struct OrbisNpTusVariable { + OrbisNpId npId; + int set; + Libraries::Rtc::OrbisRtcTick lastChanged; + u8 pad1[4]; + OrbisNpId lastChangedAuthor; + s64 variable; + s64 oldVariable; + OrbisNpAccountId owner; + OrbisNpAccountId lastChangedAuthorId; +}; + +struct OrbisNpTusDataInfo { + u64 size; + u8 data[384]; +}; + +struct OrbisNpTusDataStatus { + OrbisNpId npId; + int set; + Libraries::Rtc::OrbisRtcTick lastChanged; + OrbisNpId lastChangedAuthor; + u8 pad2[4]; + void* data; + u64 dataSize; + OrbisNpTusDataInfo info; +}; + +static_assert(sizeof(OrbisNpTusDataStatus) == 0x1F0); + +struct OrbisNpTusDataStatusA { + OrbisNpOnlineId onlineId; + u8 pad[16]; + int set; + Libraries::Rtc::OrbisRtcTick lastChanged; + OrbisNpOnlineId lastChangedAuthor; + u8 pad2[20]; + void* data; + u64 dataSize; + OrbisNpTusDataInfo info; + OrbisNpAccountId owner; + OrbisNpAccountId lastChangedAuthorId; + u8 pad3[16]; +}; + +static_assert(sizeof(OrbisNpTusDataStatusA) == 0x210); + +enum class OrbisNpTssStatus : int { + Ok = 0, + Partial = 1, + NotModified = 2, +}; + +struct OrbisNpTssDataStatus { + Libraries::Rtc::OrbisRtcTick modified; + OrbisNpTssStatus status; + u64 contentLength; +}; + +struct OrbisNpTssGetDataOptParam { + u64 size; + u64* offset; + u64* last; + void* param; +}; + +s32 PS4_SYSV_ABI sceNpTusWaitAsync(int reqId, int* result); void RegisterLib(Core::Loader::SymbolsResolver* sym); } // namespace Libraries::Np::NpTus \ No newline at end of file diff --git a/src/core/libraries/np/object_manager.h b/src/core/libraries/np/object_manager.h new file mode 100644 index 000000000..5f6ed9663 --- /dev/null +++ b/src/core/libraries/np/object_manager.h @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include + +template +struct ObjectManager { + s32 GetObject(int objectId, T** out) { + std::scoped_lock lk{mutex}; + if (objectId < 1 || objectId > N) { + return INVALID_OBJECT_ID_ERROR; + } + auto obj = objects[objectId - 1]; + if (!obj) { + return OBJECT_NOT_FOUND_ERROR; + } + *out = obj; + return ORBIS_OK; + } + + template + s32 CreateObject(Args&&... args) { + std::scoped_lock lk{mutex}; + + if (auto slot = std::ranges::find(objects, nullptr); slot != objects.end()) { + *slot = new T{args...}; + + return std::ranges::distance(objects.begin(), slot) + 1; + } + + return MAX_OBJECTS_ERROR; + } + + s32 DeleteObject(int objectId) { + std::scoped_lock lk{mutex}; + + if (objectId < 1 || objectId > N) { + return INVALID_OBJECT_ID_ERROR; + } + auto obj = objects[objectId - 1]; + if (!obj) { + return OBJECT_NOT_FOUND_ERROR; + } + + delete obj; + objects[objectId - 1] = nullptr; + + return ORBIS_OK; + } + +private: + std::mutex mutex; + std::array objects = {nullptr}; +}; \ No newline at end of file