Files
AnyPS5/core/libs/prx/libSceSaveDataDialog.native/Export.cpp
T
TibixDev 97f16be342 fix(savedata): keep progress dialogs running until closed
Opening a save progress dialog immediately reported FINISHED. Skyrim
waited for RUNNING before writing SAVEDATA.DAT and never resumed. Keep
progress-bar mode running through polling and progress updates until
Close, retaining the existing automatic responses for other dialog modes.

Add lifecycle regression coverage for repeated polling, completion,
reopening, result metadata and ordinary selection dialogs. The test
failed on the previous implementation and passes with the fix on Fedora
44 Release. Correcting the live dialog state recovered a blocked Skyrim
save without restarting its session.

Written with AI assistance.
2026-10-08 01:37:34 +03:00

108 lines
2.9 KiB
C++

#include <cstdint>
#include <cstddef>
#include <cstring>
#include <cstdio>
#include "SceTypes.hpp"
#include "prx/libSceSaveDataDialog.native/SaveDataDialog.hpp"
#include "prx/libc/include/General.hpp"
static int g_status = SAVE_DATA_DIALOG_STATUS_NONE;
static int g_mode = 0;
static void* g_user_data = nullptr;
static char g_dir_name[32] = {};
extern "C" {
int APS5_VABI sceSaveDataDialogInitialize(void) {
if (g_status != SAVE_DATA_DIALOG_STATUS_NONE) {
return SAVE_DATA_DIALOG_ERROR_ALREADY_INITIALIZED;
}
g_status = SAVE_DATA_DIALOG_STATUS_INITIALIZED;
g_mode = 0;
g_user_data = nullptr;
g_dir_name[0] = '\0';
return SAVE_DATA_DIALOG_OK;
}
int APS5_VABI sceSaveDataDialogGetStatus(void) {
return g_status;
}
int APS5_VABI sceSaveDataDialogUpdateStatus(void) {
return g_status;
}
int APS5_VABI sceSaveDataDialogGetResult(void* result) {
if (result == nullptr) {
return SAVE_DATA_DIALOG_ERROR_ARG_NULL;
}
auto* r = static_cast<SaveDataDialogResult*>(result);
r->mode = g_mode;
r->result = SAVE_DATA_DIALOG_RESULT_OK;
r->button_id = SAVE_DATA_DIALOG_BUTTON_ID_OK;
r->user_data = g_user_data;
if (r->dir_name != nullptr && g_dir_name[0] != '\0') {
std::snprintf(static_cast<SaveDataDirName*>(r->dir_name)->data,
sizeof(SaveDataDirName::data), "%s", g_dir_name);
}
return SAVE_DATA_DIALOG_OK;
}
int APS5_VABI sceSaveDataDialogOpen(const void* param) {
if (g_status != SAVE_DATA_DIALOG_STATUS_INITIALIZED && g_status != SAVE_DATA_DIALOG_STATUS_FINISHED) {
return SAVE_DATA_DIALOG_ERROR_INVALID_STATE;
}
if (param == nullptr) {
return SAVE_DATA_DIALOG_ERROR_ARG_NULL;
}
const auto* p = static_cast<const SaveDataDialogParam*>(param);
g_mode = p->mode;
g_user_data = p->user_data;
g_dir_name[0] = '\0';
const auto* items = static_cast<const SaveDataDialogItems*>(p->items);
if (items != nullptr && items->dir_names != nullptr) {
for (std::uint32_t i = 0; i < items->dir_names_num; i++) {
const char* name = items->dir_names[i].data;
if (name[0] != '\0') {
std::snprintf(g_dir_name, sizeof(g_dir_name), "%s", name);
break;
}
}
}
g_status = g_mode == SAVE_DATA_DIALOG_MODE_PROGRESS_BAR
? SAVE_DATA_DIALOG_STATUS_RUNNING : SAVE_DATA_DIALOG_STATUS_FINISHED;
return SAVE_DATA_DIALOG_OK;
}
int APS5_VABI sceSaveDataDialogClose(const void* closeParam) {
(void)closeParam;
g_status = SAVE_DATA_DIALOG_STATUS_FINISHED;
return SAVE_DATA_DIALOG_OK;
}
int APS5_VABI sceSaveDataDialogIsReadyToDisplay(void) {
return 1;
}
int APS5_VABI sceSaveDataDialogTerminate(void) {
g_status = SAVE_DATA_DIALOG_STATUS_NONE;
g_mode = 0;
g_user_data = nullptr;
g_dir_name[0] = '\0';
return SAVE_DATA_DIALOG_OK;
}
int APS5_VABI sceSaveDataDialogProgressBarInc(int target, std::uint32_t delta) {
(void)target;
(void)delta;
return SAVE_DATA_DIALOG_OK;
}
int APS5_VABI sceSaveDataDialogProgressBarSetValue(int target, std::uint32_t rate) {
(void)target;
(void)rate;
return SAVE_DATA_DIALOG_OK;
}
}