diff --git a/src/core/libraries/error_codes.h b/src/core/libraries/error_codes.h index 321a9fba..c7732ad5 100644 --- a/src/core/libraries/error_codes.h +++ b/src/core/libraries/error_codes.h @@ -446,3 +446,10 @@ constexpr int ORBIS_USER_SERVICE_ERROR_BUFFER_TOO_SHORT = 0x8096000A; // SystemService library constexpr int ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER = 0x80A10003; + +// NpTrophy library +constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT = 0x80551604; +constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE = 0x80551608; +constexpr int ORBIS_NP_TROPHY_ERROR_HANDLE_EXCEEDS_MAX = 0x80551624; +constexpr int ORBIS_NP_TROPHY_ERROR_CONTEXT_ALREADY_EXISTS = 0x80551613; +constexpr int ORBIS_NP_TROPHY_ERROR_CONTEXT_EXCEEDS_MAX = 0x80551622; diff --git a/src/core/libraries/np_trophy/np_trophy.cpp b/src/core/libraries/np_trophy/np_trophy.cpp index f7fb6e09..9a18d4a6 100644 --- a/src/core/libraries/np_trophy/np_trophy.cpp +++ b/src/core/libraries/np_trophy/np_trophy.cpp @@ -2,14 +2,34 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Generated By moduleGenerator +#include + #include "common/logging/log.h" +#include "common/slot_vector.h" #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" #include "np_trophy.h" namespace Libraries::NpTrophy { -int PS4_SYSV_ABI sceNpTrophyAbortHandle() { +static constexpr auto MaxTrophyHandles = 4u; +static constexpr auto MaxTrophyContexts = 8u; + +using ContextKey = std::pair; // +struct ContextKeyHash { + size_t operator()(const ContextKey& key) const { + return key.first + (u64(key.second) << 32u); + } +}; + +struct TrophyContext { + u32 context_id; +}; +static Common::SlotVector trophy_handles{}; +static Common::SlotVector trophy_contexts{}; +static std::unordered_map contexts_internal{}; + +static int PS4_SYSV_ABI sceNpTrophyAbortHandle() { LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); return ORBIS_OK; } @@ -64,14 +84,43 @@ int PS4_SYSV_ABI sceNpTrophyConfigHasGroupFeature() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNpTrophyCreateContext() { - LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTrophyCreateContext(u32* context, u32 user_id, u32 service_label, + u64 options) { + ASSERT(options == 0ull); + if (!context) { + return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT; + } + + if (trophy_contexts.size() >= MaxTrophyContexts) { + return ORBIS_NP_TROPHY_ERROR_CONTEXT_EXCEEDS_MAX; + } + + const auto& key = ContextKey{service_label, user_id}; + if (contexts_internal.contains(key)) { + return ORBIS_NP_TROPHY_ERROR_CONTEXT_ALREADY_EXISTS; + } + + const auto ctx_id = trophy_contexts.insert(user_id, service_label); + contexts_internal[key].context_id = ctx_id.index; + LOG_INFO(Lib_NpTrophy, "New context = {}, service label = {} user_id = {}", ctx_id.index, + service_label, user_id); + *context = ctx_id.index; return ORBIS_OK; } -int PS4_SYSV_ABI sceNpTrophyCreateHandle() { - LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); - return -1; +s32 PS4_SYSV_ABI sceNpTrophyCreateHandle(u32* handle) { + if (!handle) { + return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT; + } + + if (trophy_handles.size() >= MaxTrophyHandles) { + return ORBIS_NP_TROPHY_ERROR_HANDLE_EXCEEDS_MAX; + } + const auto handle_id = trophy_handles.insert(); + LOG_INFO(Lib_NpTrophy, "New handle = {}", handle_id.index); + + *handle = handle_id.index; + return ORBIS_OK; } int PS4_SYSV_ABI sceNpTrophyDestroyContext() { @@ -79,8 +128,13 @@ int PS4_SYSV_ABI sceNpTrophyDestroyContext() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNpTrophyDestroyHandle() { - LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); +s32 PS4_SYSV_ABI sceNpTrophyDestroyHandle(u32 handle) { + if (!trophy_handles.IsAllocated({handle})) { + return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE; + } + + trophy_handles.erase({handle}); + LOG_INFO(Lib_NpTrophy, "Handle {} destroyed", handle); return ORBIS_OK; } @@ -114,8 +168,10 @@ int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo() { return ORBIS_OK; } -int PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState() { +s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, u32* flags, u32* count) { LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); + *flags = 0u; + *count = 0; return ORBIS_OK; } diff --git a/src/core/libraries/np_trophy/np_trophy.h b/src/core/libraries/np_trophy/np_trophy.h index 91b9351b..d05d353f 100644 --- a/src/core/libraries/np_trophy/np_trophy.h +++ b/src/core/libraries/np_trophy/np_trophy.h @@ -22,17 +22,18 @@ int PS4_SYSV_ABI sceNpTrophyConfigGetTrophySetInfoInGroup(); int PS4_SYSV_ABI sceNpTrophyConfigGetTrophySetVersion(); int PS4_SYSV_ABI sceNpTrophyConfigGetTrophyTitleDetails(); int PS4_SYSV_ABI sceNpTrophyConfigHasGroupFeature(); -int PS4_SYSV_ABI sceNpTrophyCreateContext(); -int PS4_SYSV_ABI sceNpTrophyCreateHandle(); +s32 PS4_SYSV_ABI sceNpTrophyCreateContext(u32* context, u32 user_id, u32 service_label, + u64 options); +s32 PS4_SYSV_ABI sceNpTrophyCreateHandle(u32* handle); int PS4_SYSV_ABI sceNpTrophyDestroyContext(); -int PS4_SYSV_ABI sceNpTrophyDestroyHandle(); +s32 PS4_SYSV_ABI sceNpTrophyDestroyHandle(u32 handle); int PS4_SYSV_ABI sceNpTrophyGetGameIcon(); int PS4_SYSV_ABI sceNpTrophyGetGameInfo(); int PS4_SYSV_ABI sceNpTrophyGetGroupIcon(); int PS4_SYSV_ABI sceNpTrophyGetGroupInfo(); int PS4_SYSV_ABI sceNpTrophyGetTrophyIcon(); int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo(); -int PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(); +s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, u32* flags, u32* count); int PS4_SYSV_ABI sceNpTrophyGroupArrayGetNum(); int PS4_SYSV_ABI sceNpTrophyIntAbortHandle(); int PS4_SYSV_ABI sceNpTrophyIntCheckNetSyncTitles();