From 4865dd92ca6b6bb907748f125883093af038f53b Mon Sep 17 00:00:00 2001 From: Dimitar Vagalinski Date: Thu, 8 Oct 2026 08:48:01 -0400 Subject: [PATCH] libNet: answer sceNpGetAccountLanguage2 as a signed-out user (#1186) * libNet: answer sceNpGetAccountLanguage2 as a signed-out user sceNpGetAccountLanguage2 was not registered, so games that call it hit the unresolved-import stub. The stub returns 0, which tells the game the request succeeded and that the language code buffer now holds the account's language, but nothing was written to it. Saros (#1053) calls it from its analytics thread right after sceNpGetAccountAge, each on its own request. sceNpGetAccountAge already reports SCE_NP_ERROR_SIGNED_OUT there, so the game is told the user is signed out for one query and signed in for the next. Demon's Souls (#890), Ghost of Yotei (#1095) and NHL 27 (#1101) import it as well. Register it next to the other NpManager account queries and answer the way they do: SCE_NP_ERROR_INVALID_ARGUMENT for a request id <= 0 or a null output pointer, SCE_NP_ERROR_SIGNED_OUT otherwise. The output is left untouched because nothing was looked up. * libNet: reject missing account language requests --------- Co-authored-by: overlordxrz-source Co-authored-by: nmzik --- src/libs/libNet.cpp | 1 + src/libs/network.cpp | 20 ++++++++++++++++++++ src/libs/network.h | 1 + 3 files changed, 22 insertions(+) diff --git a/src/libs/libNet.cpp b/src/libs/libNet.cpp index 3e1be3f3c..d540a4d0f 100644 --- a/src/libs/libNet.cpp +++ b/src/libs/libNet.cpp @@ -1559,6 +1559,7 @@ LIB_DEFINE(InitNet_1_NpManager) { LIB_FUNC("rbknaUjpqWo", NpManager::NpGetAccountIdA); LIB_FUNC("JT+t00a3TxA", NpManager::NpGetAccountCountryA); LIB_FUNC("+4DegjBqV1g", NpManager::NpGetAccountAge); + LIB_FUNC("3Tcz5bNCfZQ", NpManager::NpGetAccountLanguage2); LIB_FUNC("GpLQDNKICac", NpManager::NpCreateRequest); LIB_FUNC("eiqMCt9UshI", NpManager::NpCreateAsyncRequest); LIB_FUNC("S7QTn72PrDw", NpManager::NpDeleteRequest); diff --git a/src/libs/network.cpp b/src/libs/network.cpp index a4aac332f..847f53f2d 100644 --- a/src/libs/network.cpp +++ b/src/libs/network.cpp @@ -4106,6 +4106,26 @@ int KYTY_SYSV_ABI NpGetAccountAge(int req_id, int user_id, uint8_t* age) { return np_error_signed_out; } +int KYTY_SYSV_ABI NpGetAccountLanguage2(int req_id, int user_id, void* language_code) { + PRINT_NAME(); + + LOGF("\t req_id = %d\n", req_id); + LOGF("\t user_id = %d\n", user_id); + LOGF("\t language_code = 0x%016" PRIx64 "\n", reinterpret_cast(language_code)); + + if (req_id <= 0 || language_code == nullptr) { + return np_error_invalid_argument; + } + + std::lock_guard lock(g_np_request_mutex); + + if (np_get_request_locked(req_id) == nullptr) { + return np_error_request_not_found; + } + + return np_error_signed_out; +} + int KYTY_SYSV_ABI NpCreateRequest() { PRINT_NAME(); diff --git a/src/libs/network.h b/src/libs/network.h index c00046e1c..b8f0bdc1c 100644 --- a/src/libs/network.h +++ b/src/libs/network.h @@ -187,6 +187,7 @@ int KYTY_SYSV_ABI NpGetOnlineId(int user_id, NpOnlineId* online_id); int KYTY_SYSV_ABI NpGetAccountIdA(int user_id, uint64_t* account_id); int KYTY_SYSV_ABI NpGetAccountCountryA(int user_id, void* country_code); int KYTY_SYSV_ABI NpGetAccountAge(int req_id, int user_id, uint8_t* age); +int KYTY_SYSV_ABI NpGetAccountLanguage2(int req_id, int user_id, void* language_code); int KYTY_SYSV_ABI NpCreateRequest(); int KYTY_SYSV_ABI NpCreateAsyncRequest(const NpCreateAsyncRequestParameter* param); int KYTY_SYSV_ABI NpDeleteRequest(int req_id);