feat: run the common-dialog state machine in the Facebook and game custom data dialogs

This commit is contained in:
Felipe Arce committed 2026-10-23 01:18:59 -03:00
1 parent 9d6adeb550
commit 6f401fe667
8 files changed
+297 -38

No files matched your search

@@ -0,0 +1,14 @@
add_library(libSceGameCustomDataDialog SHARED EXCLUDE_FROM_ALL Export.cpp)
target_include_directories(libSceGameCustomDataDialog PRIVATE ${LIBS_INCLUDE_DIR})
configure_windows_unwind(libSceGameCustomDataDialog)
if(BUILD_TESTING)
add_test_executable(guest_game_custom_data_dialog_tests ${LIBS_INCLUDE_DIR}/tests/GuestGameCustomDataDialog.cpp)
target_include_directories(guest_game_custom_data_dialog_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_game_custom_data_dialog_tests PRIVATE libSceGameCustomDataDialog)
add_test(NAME guest_game_custom_data_dialog COMMAND guest_game_custom_data_dialog_tests)
if(WIN32)
set_tests_properties(guest_game_custom_data_dialog PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceGameCustomDataDialog>")
endif()
endif()
@@ -1,14 +1,74 @@
#include <atomic>
#include <cstdint>
#include <cstddef>
#include <cstring>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
namespace {
constexpr int COMMON_DIALOG_STATUS_NONE = 0;
constexpr int COMMON_DIALOG_STATUS_INITIALIZED = 1;
constexpr int COMMON_DIALOG_STATUS_RUNNING = 2;
constexpr int COMMON_DIALOG_STATUS_FINISHED = 3;
constexpr int COMMON_DIALOG_ERROR_NOT_INITIALIZED = static_cast<int>(0x80B80003u);
constexpr int COMMON_DIALOG_ERROR_ALREADY_INITIALIZED = static_cast<int>(0x80B80004u);
constexpr int COMMON_DIALOG_ERROR_NOT_FINISHED = static_cast<int>(0x80B80005u);
constexpr int COMMON_DIALOG_ERROR_BUSY = static_cast<int>(0x80B80007u);
constexpr int COMMON_DIALOG_ERROR_ARG_NULL = static_cast<int>(0x80B8000Du);
constexpr int COMMON_DIALOG_RESULT_USER_CANCELED = 1;
std::atomic<int> g_status{COMMON_DIALOG_STATUS_NONE};
}
extern "C" {
int APS5_VABI sceGameCustomDataDialogGetResult() {
NotImplemented_nid_no_patch(__func__);
int APS5_VABI sceGameCustomDataDialogInitialize(void) {
int expected = COMMON_DIALOG_STATUS_NONE;
if (!g_status.compare_exchange_strong(expected, COMMON_DIALOG_STATUS_INITIALIZED)) return COMMON_DIALOG_ERROR_ALREADY_INITIALIZED;
return 0;
}
int APS5_VABI sceGameCustomDataDialogInitialize() {
int APS5_VABI sceGameCustomDataDialogOpenA(const void* param) {
const int status = g_status.load();
if (status == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
if (status == COMMON_DIALOG_STATUS_RUNNING) return COMMON_DIALOG_ERROR_BUSY;
if (param == nullptr) return COMMON_DIALOG_ERROR_ARG_NULL;
g_status = COMMON_DIALOG_STATUS_FINISHED;
return 0;
}
int APS5_VABI sceGameCustomDataDialogUpdateStatus(void) {
return g_status.load();
}
int APS5_VABI sceGameCustomDataDialogGetStatus(void) {
return g_status.load();
}
int APS5_VABI sceGameCustomDataDialogGetResultA(void* result) {
const int status = g_status.load();
if (status == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
if (result == nullptr) return COMMON_DIALOG_ERROR_ARG_NULL;
if (status != COMMON_DIALOG_STATUS_FINISHED) return COMMON_DIALOG_ERROR_NOT_FINISHED;
const std::int32_t canceled = COMMON_DIALOG_RESULT_USER_CANCELED;
std::memcpy(result, &canceled, sizeof(canceled));
return 0;
}
int APS5_VABI sceGameCustomDataDialogClose(void) {
if (g_status.load() == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
g_status = COMMON_DIALOG_STATUS_FINISHED;
return 0;
}
int APS5_VABI sceGameCustomDataDialogTerminate(void) {
if (g_status.exchange(COMMON_DIALOG_STATUS_NONE) == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
return 0;
}
int APS5_VABI sceGameCustomDataDialogGetResult() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
@@ -18,14 +78,4 @@ int APS5_VABI sceGameCustomDataDialogOpen() {
return 0;
}
int APS5_VABI sceGameCustomDataDialogTerminate() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceGameCustomDataDialogUpdateStatus() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
}
@@ -0,0 +1,14 @@
add_library(libSceNpSnsFacebookDialog SHARED EXCLUDE_FROM_ALL Export.cpp)
target_include_directories(libSceNpSnsFacebookDialog PRIVATE ${LIBS_INCLUDE_DIR})
configure_windows_unwind(libSceNpSnsFacebookDialog)
if(BUILD_TESTING)
add_test_executable(guest_np_sns_facebook_dialog_tests ${LIBS_INCLUDE_DIR}/tests/GuestNpSnsFacebookDialog.cpp)
target_include_directories(guest_np_sns_facebook_dialog_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_np_sns_facebook_dialog_tests PRIVATE libSceNpSnsFacebookDialog)
add_test(NAME guest_np_sns_facebook_dialog COMMAND guest_np_sns_facebook_dialog_tests)
if(WIN32)
set_tests_properties(guest_np_sns_facebook_dialog PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpSnsFacebookDialog>")
endif()
endif()
@@ -1,42 +1,70 @@
#include <cstddef>
#include <atomic>
#include <cstdint>
#include <cstddef>
#include <cstring>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
namespace {
constexpr int COMMON_DIALOG_STATUS_NONE = 0;
constexpr int COMMON_DIALOG_STATUS_INITIALIZED = 1;
constexpr int COMMON_DIALOG_STATUS_RUNNING = 2;
constexpr int COMMON_DIALOG_STATUS_FINISHED = 3;
constexpr int COMMON_DIALOG_ERROR_NOT_INITIALIZED = static_cast<int>(0x80B80003u);
constexpr int COMMON_DIALOG_ERROR_ALREADY_INITIALIZED = static_cast<int>(0x80B80004u);
constexpr int COMMON_DIALOG_ERROR_NOT_FINISHED = static_cast<int>(0x80B80005u);
constexpr int COMMON_DIALOG_ERROR_BUSY = static_cast<int>(0x80B80007u);
constexpr int COMMON_DIALOG_ERROR_ARG_NULL = static_cast<int>(0x80B8000Du);
constexpr int COMMON_DIALOG_RESULT_USER_CANCELED = 1;
std::atomic<int> g_status{COMMON_DIALOG_STATUS_NONE};
}
extern "C" {
int APS5_VABI sceNpSnsFacebookDialogClose(void) {
NotImplemented_nid_no_patch(__func__);
int APS5_VABI sceNpSnsFacebookDialogInitialize(void) {
int expected = COMMON_DIALOG_STATUS_NONE;
if (!g_status.compare_exchange_strong(expected, COMMON_DIALOG_STATUS_INITIALIZED)) return COMMON_DIALOG_ERROR_ALREADY_INITIALIZED;
return 0;
}
int APS5_VABI sceNpSnsFacebookDialogOpen(const void* param) {
const int status = g_status.load();
if (status == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
if (status == COMMON_DIALOG_STATUS_RUNNING) return COMMON_DIALOG_ERROR_BUSY;
if (param == nullptr) return COMMON_DIALOG_ERROR_ARG_NULL;
g_status = COMMON_DIALOG_STATUS_FINISHED;
return 0;
}
int APS5_VABI sceNpSnsFacebookDialogUpdateStatus(void) {
return g_status.load();
}
int APS5_VABI sceNpSnsFacebookDialogGetStatus(void) {
NotImplemented_nid_no_patch(__func__);
return g_status.load();
}
int APS5_VABI sceNpSnsFacebookDialogGetResult(void* result) {
const int status = g_status.load();
if (status == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
if (result == nullptr) return COMMON_DIALOG_ERROR_ARG_NULL;
if (status != COMMON_DIALOG_STATUS_FINISHED) return COMMON_DIALOG_ERROR_NOT_FINISHED;
const std::int32_t canceled = COMMON_DIALOG_RESULT_USER_CANCELED;
std::memcpy(result, &canceled, sizeof(canceled));
return 0;
}
int APS5_VABI sceNpSnsFacebookDialogGetResult() {
NotImplemented_nid_no_patch(__func__);
int APS5_VABI sceNpSnsFacebookDialogClose(void) {
if (g_status.load() == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
g_status = COMMON_DIALOG_STATUS_FINISHED;
return 0;
}
int APS5_VABI sceNpSnsFacebookDialogInitialize() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceNpSnsFacebookDialogOpen() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceNpSnsFacebookDialogTerminate() {
NotImplemented_nid_no_patch(__func__);
return 0;
}
int APS5_VABI sceNpSnsFacebookDialogUpdateStatus() {
NotImplemented_nid_no_patch(__func__);
int APS5_VABI sceNpSnsFacebookDialogTerminate(void) {
if (g_status.exchange(COMMON_DIALOG_STATUS_NONE) == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
return 0;
}
@@ -0,0 +1,72 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdint>
#include <cstdlib>
extern "C" {
int APS5_VABI sceGameCustomDataDialogInitialize(void);
int APS5_VABI sceGameCustomDataDialogOpenA(const void* param);
int APS5_VABI sceGameCustomDataDialogUpdateStatus(void);
int APS5_VABI sceGameCustomDataDialogGetStatus(void);
int APS5_VABI sceGameCustomDataDialogGetResultA(void* result);
int APS5_VABI sceGameCustomDataDialogClose(void);
int APS5_VABI sceGameCustomDataDialogTerminate(void);
}
namespace {
void Require(bool value) { if (!value) std::abort(); }
constexpr int kStatusNone = 0;
constexpr int kStatusInitialized = 1;
constexpr int kStatusFinished = 3;
constexpr int kErrNotInitialized = static_cast<int>(0x80B80003);
constexpr int kErrAlreadyInitialized = static_cast<int>(0x80B80004);
constexpr int kErrNotFinished = static_cast<int>(0x80B80005);
constexpr int kErrArgNull = static_cast<int>(0x80B8000D);
constexpr int kResultUserCanceled = 1;
}
int main() {
std::int64_t param = 0;
std::int32_t result[2] = {-1, -1};
Require(sceGameCustomDataDialogTerminate() == kErrNotInitialized);
Require(sceGameCustomDataDialogOpenA(&param) == kErrNotInitialized);
Require(sceGameCustomDataDialogClose() == kErrNotInitialized);
Require(sceGameCustomDataDialogGetResultA(result) == kErrNotInitialized);
Require(sceGameCustomDataDialogGetStatus() == kStatusNone);
Require(sceGameCustomDataDialogUpdateStatus() == kStatusNone);
Require(sceGameCustomDataDialogInitialize() == 0);
Require(sceGameCustomDataDialogInitialize() == kErrAlreadyInitialized);
Require(sceGameCustomDataDialogGetStatus() == kStatusInitialized);
Require(sceGameCustomDataDialogUpdateStatus() == kStatusInitialized);
Require(sceGameCustomDataDialogOpenA(nullptr) == kErrArgNull);
Require(sceGameCustomDataDialogGetResultA(result) == kErrNotFinished);
Require(sceGameCustomDataDialogOpenA(&param) == 0);
Require(sceGameCustomDataDialogGetStatus() == kStatusFinished);
Require(sceGameCustomDataDialogUpdateStatus() == kStatusFinished);
Require(sceGameCustomDataDialogGetResultA(nullptr) == kErrArgNull);
Require(sceGameCustomDataDialogGetResultA(result) == 0);
Require(result[0] == kResultUserCanceled);
Require(result[1] == -1);
Require(sceGameCustomDataDialogClose() == 0);
Require(sceGameCustomDataDialogTerminate() == 0);
Require(sceGameCustomDataDialogTerminate() == kErrNotInitialized);
Require(sceGameCustomDataDialogGetStatus() == kStatusNone);
Require(sceGameCustomDataDialogUpdateStatus() == kStatusNone);
Require(sceGameCustomDataDialogInitialize() == 0);
Require(sceGameCustomDataDialogUpdateStatus() == kStatusInitialized);
Require(sceGameCustomDataDialogClose() == 0);
Require(sceGameCustomDataDialogUpdateStatus() == kStatusFinished);
result[0] = -1;
Require(sceGameCustomDataDialogGetResultA(result) == 0);
Require(result[0] == kResultUserCanceled);
Require(sceGameCustomDataDialogTerminate() == 0);
}
@@ -0,0 +1,72 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdint>
#include <cstdlib>
extern "C" {
int APS5_VABI sceNpSnsFacebookDialogInitialize(void);
int APS5_VABI sceNpSnsFacebookDialogOpen(const void* param);
int APS5_VABI sceNpSnsFacebookDialogUpdateStatus(void);
int APS5_VABI sceNpSnsFacebookDialogGetStatus(void);
int APS5_VABI sceNpSnsFacebookDialogGetResult(void* result);
int APS5_VABI sceNpSnsFacebookDialogClose(void);
int APS5_VABI sceNpSnsFacebookDialogTerminate(void);
}
namespace {
void Require(bool value) { if (!value) std::abort(); }
constexpr int kStatusNone = 0;
constexpr int kStatusInitialized = 1;
constexpr int kStatusFinished = 3;
constexpr int kErrNotInitialized = static_cast<int>(0x80B80003);
constexpr int kErrAlreadyInitialized = static_cast<int>(0x80B80004);
constexpr int kErrNotFinished = static_cast<int>(0x80B80005);
constexpr int kErrArgNull = static_cast<int>(0x80B8000D);
constexpr int kResultUserCanceled = 1;
}
int main() {
std::int64_t param = 0;
std::int32_t result[2] = {-1, -1};
Require(sceNpSnsFacebookDialogTerminate() == kErrNotInitialized);
Require(sceNpSnsFacebookDialogOpen(&param) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogClose() == kErrNotInitialized);
Require(sceNpSnsFacebookDialogGetResult(result) == kErrNotInitialized);
Require(sceNpSnsFacebookDialogGetStatus() == kStatusNone);
Require(sceNpSnsFacebookDialogUpdateStatus() == kStatusNone);
Require(sceNpSnsFacebookDialogInitialize() == 0);
Require(sceNpSnsFacebookDialogInitialize() == kErrAlreadyInitialized);
Require(sceNpSnsFacebookDialogGetStatus() == kStatusInitialized);
Require(sceNpSnsFacebookDialogUpdateStatus() == kStatusInitialized);
Require(sceNpSnsFacebookDialogOpen(nullptr) == kErrArgNull);
Require(sceNpSnsFacebookDialogGetResult(result) == kErrNotFinished);
Require(sceNpSnsFacebookDialogOpen(&param) == 0);
Require(sceNpSnsFacebookDialogGetStatus() == kStatusFinished);
Require(sceNpSnsFacebookDialogUpdateStatus() == kStatusFinished);
Require(sceNpSnsFacebookDialogGetResult(nullptr) == kErrArgNull);
Require(sceNpSnsFacebookDialogGetResult(result) == 0);
Require(result[0] == kResultUserCanceled);
Require(result[1] == -1);
Require(sceNpSnsFacebookDialogClose() == 0);
Require(sceNpSnsFacebookDialogTerminate() == 0);
Require(sceNpSnsFacebookDialogTerminate() == kErrNotInitialized);
Require(sceNpSnsFacebookDialogGetStatus() == kStatusNone);
Require(sceNpSnsFacebookDialogUpdateStatus() == kStatusNone);
Require(sceNpSnsFacebookDialogInitialize() == 0);
Require(sceNpSnsFacebookDialogUpdateStatus() == kStatusInitialized);
Require(sceNpSnsFacebookDialogClose() == 0);
Require(sceNpSnsFacebookDialogUpdateStatus() == kStatusFinished);
result[0] = -1;
Require(sceNpSnsFacebookDialogGetResult(result) == 0);
Require(result[0] == kResultUserCanceled);
Require(sceNpSnsFacebookDialogTerminate() == 0);
}
@@ -0,0 +1,9 @@
# libSceGameCustomDataDialog technical debt
### Silent stubs
- [libSceGameCustomDataDialog](../../../core/libs/prx/libSceGameCustomDataDialog/Export.cpp) - the game custom data dialog (`sceGameCustomDataDialogOpenA` and `sceGameCustomDataDialogGetResultA`) runs the common-dialog state machine but shows nothing and reports the user as having cancelled, as there is no PSN game custom data. The signatures are from [Orbital's type database](https://github.com/AlexAltea/orbital/blob/b321fcdbd700cc02da1cb1ad25412781d5ec73c6/tools/ida/db_types.json); the result layout beyond the leading `int32_t` result code is not known, so nothing else is written.
### Unknown function info
- [sceGameCustomDataDialogGetResult and sceGameCustomDataDialogOpen](../../../core/libs/prx/libSceGameCustomDataDialog/Export.cpp) (libSceGameCustomDataDialog) - names and NIDs are present in the [PS5 3.20 export inventory](https://github.com/DNNDHH/PS5-3.20_Libs/blob/b2a77c09cd71c01f34c790cfbe98c751a13262ad/libSceGameCustomDataDialog.c), but Orbital has prototypes only for the `A` variants and no credible prototypes were found for these. The declarations have no parameters solely to resolve known imports; this is not an ABI claim and callers must not call them until signatures are verified
+2 -2
View File
@@ -1,5 +1,5 @@
# libSceNpSnsFacebookDialog technical debt
### Unknown function info
### Silent stubs
- The following pending declarations have unverified signatures and behavior; they are parameterless import-resolution declarations and throw through `NotImplemented_nid_no_patch`: [`sceNpSnsFacebookDialogClose`](../../../core/libs/prx/libSceNpSnsFacebookDialog/Export.cpp), [`sceNpSnsFacebookDialogGetStatus`](../../../core/libs/prx/libSceNpSnsFacebookDialog/Export.cpp).
- [libSceNpSnsFacebookDialog](../../../core/libs/prx/libSceNpSnsFacebookDialog/Export.cpp) - the Facebook dialog runs the common-dialog state machine but shows nothing and reports the user as having cancelled, as there is no Facebook account link. The signatures are from [Orbital's type database](https://github.com/AlexAltea/orbital/blob/b321fcdbd700cc02da1cb1ad25412781d5ec73c6/tools/ida/db_types.json); the result layout beyond the leading `int32_t` result code is not known, so nothing else is written.