diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index c42305224a..da9aa50757 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -361,6 +361,8 @@ add_library(Core STATIC Dialog/PSPOskDialog.h Dialog/PSPOskConstants.cpp Dialog/PSPOskConstants.h + Dialog/PSPPlaceholderDialog.cpp + Dialog/PSPPlaceholderDialog.h Dialog/PSPSaveDialog.cpp Dialog/PSPSaveDialog.h Dialog/PSPScreenshotDialog.cpp diff --git a/Core/Dialog/PSPPlaceholderDialog.cpp b/Core/Dialog/PSPPlaceholderDialog.cpp index e320449bd3..85c9415b0c 100644 --- a/Core/Dialog/PSPPlaceholderDialog.cpp +++ b/Core/Dialog/PSPPlaceholderDialog.cpp @@ -15,31 +15,75 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "PSPPlaceholderDialog.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeFuncs.h" +#include "Core/Dialog/PSPPlaceholderDialog.h" +#include "Core/HLE/ErrorCodes.h" + +// Rough guesses, like the other dialogs'. +static const int PLACEHOLDER_INIT_DELAY_US = 200000; +static const int PLACEHOLDER_SHUTDOWN_DELAY_US = 2000; PSPPlaceholderDialog::PSPPlaceholderDialog(UtilityDialogType type) : PSPDialog(type) { - } -PSPPlaceholderDialog::~PSPPlaceholderDialog() { -} +int PSPPlaceholderDialog::Init(u32 paramAddr) { + if (ReadStatus() != SCE_UTILITY_STATUS_NONE) { + return SCE_ERROR_UTILITY_INVALID_STATUS; + } + if (!Memory::IsValidRange(paramAddr, sizeof(pspUtilityDialogCommon))) { + return SCE_KERNEL_ERROR_BAD_ARGUMENT; + } + params_ = paramAddr; + // The request sizes a PSP accepts for GameSharing. + const u32 size = params_->size; + if (DialogType() == UtilityDialogType::GAMESHARING && size != 0x50 && size != 0x54 && size != 0x64) { + params_ = 0; + return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE; + } - -int PSPPlaceholderDialog::Init() { - ChangeStatus(SCE_UTILITY_STATUS_INITIALIZE, 0); + ChangeStatusInit(PLACEHOLDER_INIT_DELAY_US); InitCommon(); return 0; } int PSPPlaceholderDialog::Update(int animSpeed) { - if (ReadStatus() == SCE_UTILITY_STATUS_INITIALIZE) { - ChangeStatus(SCE_UTILITY_STATUS_RUNNING, 0); - } else if (ReadStatus() == SCE_UTILITY_STATUS_RUNNING) { - ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0); - } else if (ReadStatus() == SCE_UTILITY_STATUS_FINISHED) { - ChangeStatus(SCE_UTILITY_STATUS_SHUTDOWN, 0); + if (ReadStatus() != SCE_UTILITY_STATUS_RUNNING) { + return SCE_ERROR_UTILITY_INVALID_STATUS; } - UpdateCommon(); + if (params_.IsValid()) { + params_->result = SCE_UTILITY_DIALOG_RESULT_CANCEL; + params_.NotifyWrite("DialogResult"); + } + ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0); return 0; } + +int PSPPlaceholderDialog::Shutdown(bool force) { + if (ReadStatus() != SCE_UTILITY_STATUS_FINISHED && !force) { + return SCE_ERROR_UTILITY_INVALID_STATUS; + } + + PSPDialog::Shutdown(force); + if (!force) { + ChangeStatusShutdown(PLACEHOLDER_SHUTDOWN_DELAY_US); + } + return 0; +} + +void PSPPlaceholderDialog::DoState(PointerWrap &p) { + PSPDialog::DoState(p); + + auto s = p.Section("PSPPlaceholderDialog", 1, 1); + if (!s) + return; + + Do(p, params_); +} + +pspUtilityDialogCommon *PSPPlaceholderDialog::GetCommonParam() { + if (params_.IsValid()) + return params_; + return nullptr; +} diff --git a/Core/Dialog/PSPPlaceholderDialog.h b/Core/Dialog/PSPPlaceholderDialog.h index b494d92944..92e4d8649b 100644 --- a/Core/Dialog/PSPPlaceholderDialog.h +++ b/Core/Dialog/PSPPlaceholderDialog.h @@ -18,13 +18,26 @@ #pragma once #include "Core/Dialog/PSPDialog.h" +#include "Core/MemMap.h" -class PSPPlaceholderDialog: public PSPDialog { +// Stands in for a utility dialog we don't implement (currently GameSharing). It goes through the +// real lifecycle - INIT, RUNNING, FINISHED, SHUTDOWN, NONE - and on the first frame reports that +// the user backed out, so a game takes its "cancelled" path instead of waiting forever. +class PSPPlaceholderDialog : public PSPDialog { public: PSPPlaceholderDialog(UtilityDialogType type); - ~PSPPlaceholderDialog(); - int Init(); + int Init(u32 paramAddr); int Update(int animSpeed) override; -}; + int Shutdown(bool force = false) override; + void DoState(PointerWrap &p) override; + pspUtilityDialogCommon *GetCommonParam() override; +protected: + bool UseAutoStatus() override { + return false; + } + +private: + PSPPointer params_; +}; diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index 0538cfaadb..3fbf1aedde 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -326,6 +326,7 @@ static PSPNetconfDialog *netDialog; static PSPScreenshotDialog *screenshotDialog; static PSPGamedataInstallDialog *gamedataInstallDialog; static PSPNpSigninDialog *npSigninDialog; +static PSPPlaceholderDialog *gameSharingDialog; // A lot of state seems to be shared between the various dialog types. static int oldStatus = -1; @@ -389,7 +390,7 @@ static PSPDialog *CurrentDialog(UtilityDialogType type) { case UtilityDialogType::SCREENSHOT: return screenshotDialog; case UtilityDialogType::GAMESHARING: - break; + return gameSharingDialog; case UtilityDialogType::GAMEDATAINSTALL: return gamedataInstallDialog; case UtilityDialogType::NPSIGNIN: @@ -481,6 +482,7 @@ void __UtilityInit() { screenshotDialog = new PSPScreenshotDialog(UtilityDialogType::SCREENSHOT); gamedataInstallDialog = new PSPGamedataInstallDialog(UtilityDialogType::GAMEDATAINSTALL); npSigninDialog = new PSPNpSigninDialog(UtilityDialogType::NPSIGNIN); + gameSharingDialog = new PSPPlaceholderDialog(UtilityDialogType::GAMESHARING); currentDialogType = UtilityDialogType::NONE; DeactivateDialog(); @@ -493,7 +495,7 @@ void __UtilityInit() { } void __UtilityDoState(PointerWrap &p) { - auto s = p.Section("sceUtility", 1, 7); + auto s = p.Section("sceUtility", 1, 8); if (!s) { return; } @@ -564,6 +566,10 @@ void __UtilityDoState(PointerWrap &p) { lastSaveStateVersion = s.Version(); } + if (s >= 8) { + gameSharingDialog->DoState(p); + } + if (!hasAccessThread && accessThread) { accessThread->Forget(); delete accessThread; @@ -580,6 +586,7 @@ void __UtilityShutdown() { screenshotDialog->Shutdown(true); gamedataInstallDialog->Shutdown(true); npSigninDialog->Shutdown(true); + gameSharingDialog->Shutdown(true); if (accessThread) { // Don't need to free it during shutdown, may have already been freed. @@ -598,6 +605,7 @@ void __UtilityShutdown() { delete screenshotDialog; delete gamedataInstallDialog; delete npSigninDialog; + delete gameSharingDialog; } // On a PSP, dialog init and shutdown happen partly at the accessThread priority and partly at the @@ -1632,40 +1640,47 @@ static int sceUtilityStoreCheckoutGetStatus() { return hleLogError(Log::sceUtility, 0, "UNIMPL"); } +// We don't implement game sharing: a placeholder dialog runs the normal lifecycle and reports that +// the user cancelled. Outside it, WRONG_TYPE is the normal answer (a PSP gives it for any type +// other than the last one started), and games like Sega Rally poll GetStatus every frame. static int sceUtilityGameSharingShutdownStart() { if (currentDialogType != UtilityDialogType::GAMESHARING) { - return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogDebug(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } DeactivateDialog(); - return hleLogError(Log::sceUtility, 0, "UNIMPL"); + return hleLogDebug(Log::sceUtility, gameSharingDialog->Shutdown()); } static int sceUtilityGameSharingInitStart(u32 paramsPtr) { if (currentDialogActive && currentDialogType != UtilityDialogType::GAMESHARING) { - return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE); + return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } ActivateDialog(UtilityDialogType::GAMESHARING); - ERROR_LOG_REPORT(Log::sceUtility, "UNIMPL sceUtilityGameSharingInitStart(%08x)", paramsPtr); - return hleNoLog(0); + return hleLogWarning(Log::sceUtility, gameSharingDialog->Init(paramsPtr), "not implemented, will report cancelled"); } static int sceUtilityGameSharingUpdate(int animSpeed) { if (currentDialogType != UtilityDialogType::GAMESHARING) { - return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogDebug(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } - return hleLogError(Log::sceUtility, 0, "UNIMPL"); + return hleLogDebug(Log::sceUtility, gameSharingDialog->Update(animSpeed)); } static int sceUtilityGameSharingGetStatus() { if (currentDialogType != UtilityDialogType::GAMESHARING) { - return hleLogWarning(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + return hleLogDebug(Log::sceUtility, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } + const PSPDialog::DialogStatus status = gameSharingDialog->GetStatus(); CleanupDialogThreads(); - return hleLogError(Log::sceUtility, 0, "UNIMPL"); + if (oldStatus != status) { + oldStatus = status; + return hleLogDebug(Log::sceUtility, status, "status changed: %s", UtilityDialogStatusToString(status)); + } + return hleLogVerbose(Log::sceUtility, status, "status: %s", UtilityDialogStatusToString(status)); } static u32 sceUtilityLoadUsbModule(u32 module) {