From 2a0f2523965ba20b8504b07899b0612216da59db Mon Sep 17 00:00:00 2001 From: orezraey Date: Tue, 20 Oct 2026 10:39:56 -0300 Subject: [PATCH] feat(libSceNpManager): accept game presence callbacks while signed out Co-Authored-By: Claude Opus 5.5 --- core/libs/prx/libSceNpManager/Export.cpp | 5 ++--- core/libs/tests/GuestNpManager.cpp | 7 +++++++ docs/dev/debt/libSceNpManager.md | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/core/libs/prx/libSceNpManager/Export.cpp b/core/libs/prx/libSceNpManager/Export.cpp index 6458a32373..877e2c6af7 100644 --- a/core/libs/prx/libSceNpManager/Export.cpp +++ b/core/libs/prx/libSceNpManager/Export.cpp @@ -175,9 +175,8 @@ int APS5_VABI sceNpPollAsync(int req_id, int* result) { } void APS5_VABI sceNpRegisterGamePresenceCallback(void* callback, void* userdata) { - (void)callback; - (void)userdata; - NotImplemented_nid_no_patch(__func__); + (void)callback; + (void)userdata; } int APS5_VABI sceNpRegisterNpReachabilityStateCallback(void* callback, void* userdata) { diff --git a/core/libs/tests/GuestNpManager.cpp b/core/libs/tests/GuestNpManager.cpp index a12312255b..ca4daa5da4 100644 --- a/core/libs/tests/GuestNpManager.cpp +++ b/core/libs/tests/GuestNpManager.cpp @@ -31,6 +31,7 @@ int APS5_VABI sceNpUnregisterStateCallback(void); int APS5_VABI sceNpRegisterStateCallbackA(void* callback, void* userdata); int APS5_VABI sceNpUnregisterStateCallbackA(int callbackId); int APS5_VABI sceNpRegisterNpReachabilityStateCallback(void* callback, void* userdata); +void APS5_VABI sceNpRegisterGamePresenceCallback(void* callback, void* userdata); int APS5_VABI sceNpUnregisterNpReachabilityStateCallback(void); } @@ -76,6 +77,10 @@ bool SignedOutOnce(const StateCall& call, void* userdata) { call.npId == nullptr && call.userdata == userdata; } +void APS5_VABI AbortingGamePresenceCallback(const void*, const void*, void*) { + std::abort(); +} + void APS5_VABI AbortingReachabilityCallback(int, std::uint32_t, void*) { std::fprintf(stderr, "NpManager: the reachability callback was called\n"); std::abort(); @@ -111,6 +116,8 @@ void CheckStateCallbacksA() { Require(stateCallsA[0].calls == 0, "registering calls the state callback"); Require(sceNpRegisterNpReachabilityStateCallback(reinterpret_cast(&AbortingReachabilityCallback), nullptr) == 0, "registering the reachability callback"); + sceNpRegisterGamePresenceCallback(nullptr, nullptr); + sceNpRegisterGamePresenceCallback(reinterpret_cast(&AbortingGamePresenceCallback), &userdata[0]); Require(sceNpCheckCallback() == 0, "sceNpCheckCallback failed"); Require(SignedOutOnce(stateCallsA[0], &userdata[0]), "sceNpCheckCallback must deliver SIGNED_OUT once"); Require(sceNpUnregisterNpReachabilityStateCallback() == 0, "unregistering the reachability callback"); diff --git a/docs/dev/debt/libSceNpManager.md b/docs/dev/debt/libSceNpManager.md index e9f15ca299..4d8d182956 100644 --- a/docs/dev/debt/libSceNpManager.md +++ b/docs/dev/debt/libSceNpManager.md @@ -13,3 +13,4 @@ - [NP reachability callbacks](../../../core/libs/prx/libSceNpManager/Export.cpp) retain one callback and its user data; duplicate registration and unregistering an absent callback return the errors used by [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/945dbc3cc3eee80ac3e053b438502ed936fa6bb2/src/core/libraries/np/np_manager.cpp). No callback is delivered because the existing NP model remains signed out with reachability unavailable. - [sceNpCheckNpAvailability](../../../core/libs/prx/libSceNpManager/Export.cpp) (libSceNpManager) - the `(req_id, online_id)` signature and the errors follow [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/0fe263a4760dfbfa973366890061749b4af0de97/src/core/libraries/np/np_manager.cpp) with no user signed in to PSN: a null online id is `SCE_NP_ERROR_INVALID_ARGUMENT`, and any other online id matches no user, `SCE_NP_ERROR_USER_NOT_FOUND`; the request id is not checked, as in the other NpManager requests - [NP state callbacks](../../../core/libs/prx/libSceNpManager/Export.cpp) (libSceNpManager) - the registration rules are [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/15abf68c9b52c4b04d094f2837719fdb871021f3/src/core/libraries/np/np_manager.cpp#L857-L901)'s: `sceNpRegisterStateCallbackA` keeps up to 8 callbacks and returns the slot plus 1, a null callback returns `INVALID_ARGUMENT`, a callback already registered `CALLBACK_ALREADY_REGISTERED` and a ninth one `CALLBACK_MAX` (0x8055001D, [np_error.h](https://github.com/shadps4-emu/shadPS4/blob/15abf68c9b52c4b04d094f2837719fdb871021f3/src/core/libraries/np/np_error.h#L38)); `sceNpUnregisterStateCallbackA` returns `INVALID_ARGUMENT` for an id outside 1..8 and `CALLBACK_NOT_REGISTERED` for an empty slot; the legacy [sceNpRegisterStateCallback](https://github.com/shadps4-emu/shadPS4/blob/15abf68c9b52c4b04d094f2837719fdb871021f3/src/core/libraries/np/np_manager.cpp#L981-L1005) keeps one callback with the same errors. Each registration gets `SIGNED_OUT` for the initial user (0x10000000) once, from the next `sceNpCheckCallback` on the calling thread. For the A form this follows [KytyPS5](https://github.com/KytyPS5/KytyPS5/blob/9e41d8320a2774b303fbad344c2347e8d0292e83/src/libs/network.cpp#L3959-L3974), whose [sceNpRegisterStateCallbackA](https://github.com/KytyPS5/KytyPS5/blob/9e41d8320a2774b303fbad344c2347e8d0292e83/src/libs/network.cpp#L4021-L4034) marks the registration pending. KytyPS5 never calls the legacy callback ([sceNpRegisterStateCallback](https://github.com/KytyPS5/KytyPS5/blob/9e41d8320a2774b303fbad344c2347e8d0292e83/src/libs/network.cpp#L4009-L4019) stores nothing); it is called as `(user, SIGNED_OUT, nullptr, userdata)`, as in shadPS4, which passes an NpId only for `SIGNED_IN` ([L823](https://github.com/shadps4-emu/shadPS4/blob/15abf68c9b52c4b04d094f2837719fdb871021f3/src/core/libraries/np/np_manager.cpp#L823), [L938-L940](https://github.com/shadps4-emu/shadPS4/blob/15abf68c9b52c4b04d094f2837719fdb871021f3/src/core/libraries/np/np_manager.cpp#L938-L940)). shadPS4 instead queues `SIGNED_OUT` from the user service login event and delivers it from `sceNpCheckCallback` ([DispatchPendingNpStateCallbacks](https://github.com/shadps4-emu/shadPS4/blob/15abf68c9b52c4b04d094f2837719fdb871021f3/src/core/libraries/np/np_manager.cpp#L903-L962)); the reachability callback is not given an initial `UNAVAILABLE`, unlike that function ([L922-L961](https://github.com/shadps4-emu/shadPS4/blob/15abf68c9b52c4b04d094f2837719fdb871021f3/src/core/libraries/np/np_manager.cpp#L922-L961)). A callback being delivered when another thread unregisters it is still called once. When and how often the console calls the state callbacks, and the errors, are not measured +- [sceNpRegisterGamePresenceCallback](../../../core/libs/prx/libSceNpManager/Export.cpp) (libSceNpManager) - accepts any callback, null included, and returns nothing; no game presence event is delivered because the NP model remains signed out. [Kyty](https://github.com/InoriRus/Kyty/blob/4733b7e1c91b10554a52007903d74dc76c39a230/source/emulator/src/Network.cpp#L1549-L1552) ignores the callback the same way, and [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/8d50471b7dc141dd700b51276b8edd1f293bce26/src/core/libraries/np/np_manager.cpp#L1121-L1126) keeps the last one without calling it. Not measured on a PS5