RE encountered NpTus functions (#4018)

This commit is contained in:
Marcin Mikołajczyk 2026-02-10 22:59:07 +01:00 committed by GitHub
parent a706b325f4
commit 99661aa6b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 647 additions and 208 deletions

View File

@ -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

View File

@ -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;
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;

View File

@ -93,6 +93,8 @@ struct OrbisNpCreateAsyncRequestParameter {
void RegisterNpCallback(std::string key, std::function<void()> 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);

View File

@ -1,15 +1,87 @@
// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <fstream>
#include <future>
#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<int, int> UnpackReqId(int reqId) {
return {reqId >> 16, reqId & 0xFFFF};
}
bool IsReqId(int id) {
return id > (1 << 16);
}
struct NpTusRequest {
std::future<int> task;
void Start(auto lambda) {
this->task = std::async(std::launch::async, lambda);
}
};
using NpTusRequestsManager =
ObjectManager<NpTusRequest, 32, ORBIS_NP_COMMUNITY_ERROR_INVALID_ID,
ORBIS_NP_COMMUNITY_ERROR_INVALID_ID, ORBIS_NP_COMMUNITY_ERROR_TOO_MANY_OBJECTS>;
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<NpTusTitleContext, 32, ORBIS_NP_COMMUNITY_ERROR_INVALID_ID,
ORBIS_NP_COMMUNITY_ERROR_INVALID_ID, ORBIS_NP_COMMUNITY_ERROR_TOO_MANY_OBJECTS>;
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<std::reference_wrapper<OrbisNpTusSlotId>>(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<std::reference_wrapper<OrbisNpTusSlotId>>(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;
}

View File

@ -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

View File

@ -0,0 +1,56 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include <mutex>
template <typename T, size_t N, int INVALID_OBJECT_ID_ERROR, int OBJECT_NOT_FOUND_ERROR,
int MAX_OBJECTS_ERROR>
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 <typename... Args>
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<T*, N> objects = {nullptr};
};