From 4072c8cd61cca4a40b5021b4df0f112bef6c2d9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Jan 2025 12:57:54 +0100 Subject: [PATCH 1/2] Hide the pause/play button on the pause screen if any network connected. --- UI/EmuScreen.cpp | 3 ++- UI/PauseScreen.cpp | 38 +++++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index cc8f3a8b77a1..df8d6fe81a04 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -67,6 +67,7 @@ using namespace std::placeholders; #include "Core/MIPS/MIPS.h" #include "Core/HLE/sceCtrl.h" #include "Core/HLE/sceSas.h" +#include "Core/HLE/sceNet.h" #include "Core/HLE/sceNetAdhoc.h" #include "Core/Debugger/SymbolMap.h" #include "Core/RetroAchievements.h" @@ -1841,7 +1842,7 @@ void EmuScreen::resized() { } bool MustRunBehind() { - return __NetAdhocConnected(); + return netInited || __NetAdhocConnected(); } bool ShouldRunBehind() { diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 56128b2d58d7..b266d9b87a9a 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -266,6 +266,9 @@ void GamePauseScreen::update() { finishNextFrame_ = false; } + bool mustRunBehind = MustRunBehind(); + playButton_->SetVisibility(mustRunBehind ? UI::V_GONE : UI::V_VISIBLE); + SetVRAppMode(VRAppMode::VR_MENU_MODE); } @@ -448,23 +451,29 @@ void GamePauseScreen::CreateViews() { rightColumnItems->Add(new Choice(pa->T("Exit to menu")))->OnClick.Handle(this, &GamePauseScreen::OnExitToMenu); } - if (!MustRunBehind()) { - playButton_ = middleColumn->Add(new Button("", g_Config.bRunBehindPauseMenu ? ImageID("I_PAUSE") : ImageID("I_PLAY"), new LinearLayoutParams(64, 64))); - playButton_->OnClick.Add([=](UI::EventParams &e) { - g_Config.bRunBehindPauseMenu = !g_Config.bRunBehindPauseMenu; - playButton_->SetImageID(g_Config.bRunBehindPauseMenu ? ImageID("I_PAUSE") : ImageID("I_PLAY")); - return UI::EVENT_DONE; - }); - middleColumn->Add(new Spacer(20.0)); - Button *infoButton = middleColumn->Add(new Button("", ImageID("I_INFO"), new LinearLayoutParams(64, 64))); - infoButton->OnClick.Add([=](UI::EventParams &e) { - screenManager()->push(new GameScreen(gamePath_, true)); - return UI::EVENT_DONE; - }); - } else { + middleColumn->SetSpacing(20.0f); + playButton_ = middleColumn->Add(new Button("", g_Config.bRunBehindPauseMenu ? ImageID("I_PAUSE") : ImageID("I_PLAY"), new LinearLayoutParams(64, 64))); + playButton_->OnClick.Add([=](UI::EventParams &e) { + g_Config.bRunBehindPauseMenu = !g_Config.bRunBehindPauseMenu; + playButton_->SetImageID(g_Config.bRunBehindPauseMenu ? ImageID("I_PAUSE") : ImageID("I_PLAY")); + return UI::EVENT_DONE; + }); + + bool mustRunBehind = MustRunBehind(); + playButton_->SetVisibility(mustRunBehind ? UI::V_GONE : UI::V_VISIBLE); + + if (mustRunBehind) { auto nw = GetI18NCategory(I18NCat::NETWORKING); rightColumnHolder->Add(new TextView(nw->T("Network connected"))); } + + Button *infoButton = middleColumn->Add(new Button("", ImageID("I_INFO"), new LinearLayoutParams(64, 64))); + infoButton->OnClick.Add([=](UI::EventParams &e) { + screenManager()->push(new GameScreen(gamePath_, true)); + return UI::EVENT_DONE; + }); + + // What's this for? rightColumnHolder->Add(new Spacer(10.0f)); } @@ -591,6 +600,5 @@ UI::EventReturn GamePauseScreen::OnDeleteConfig(UI::EventParams &e) screenManager()->push( new PromptScreen(gamePath_, di->T("DeleteConfirmGameConfig", "Do you really want to delete the settings for this game?"), ga->T("ConfirmDelete"), di->T("Cancel"), std::bind(&GamePauseScreen::CallbackDeleteConfig, this, std::placeholders::_1))); - return UI::EVENT_DONE; } From f66ea2f63e66cc34f4d1fab0f9829222a821375e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Jan 2025 19:33:06 +0100 Subject: [PATCH 2/2] Add a bunch of restrictions when online (no savestate, no speed control) --- Core/Config.cpp | 1 + Core/Config.h | 1 + Core/FrameTiming.cpp | 11 ++++- Core/HLE/sceDisplay.cpp | 5 +++ Core/HLE/sceNet.cpp | 28 ++++++++++++ Core/HLE/sceNet.h | 7 +++ Core/SaveState.cpp | 37 +++++++++++++++- UI/EmuScreen.cpp | 23 +++++----- UI/GamepadEmu.h | 1 - UI/PauseScreen.cpp | 88 +++++++++++++++++++++++--------------- UI/PauseScreen.h | 1 + Windows/MainWindowMenu.cpp | 29 ++++++++----- 12 files changed, 173 insertions(+), 59 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 0f4be8e9af15..8bcbf54edeeb 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -908,6 +908,7 @@ static const ConfigSetting networkSettings[] = { ConfigSetting("UPnPUseOriginalPort", &g_Config.bUPnPUseOriginalPort, false, CfgFlag::PER_GAME), ConfigSetting("InfrastructureUsername", &g_Config.sInfrastructureUsername, &DefaultInfrastructureUsername, CfgFlag::PER_GAME), ConfigSetting("InfrastructureAutoDNS", &g_Config.bInfrastructureAutoDNS, true, CfgFlag::PER_GAME), + ConfigSetting("AllowSavestateWhileConnected", &g_Config.bAllowSavestateWhileConnected, false, CfgFlag::DONT_SAVE), ConfigSetting("EnableNetworkChat", &g_Config.bEnableNetworkChat, false, CfgFlag::PER_GAME), ConfigSetting("ChatButtonPosition", &g_Config.iChatButtonPosition, (int)ScreenEdgePosition::BOTTOM_LEFT, CfgFlag::PER_GAME), diff --git a/Core/Config.h b/Core/Config.h index 3a87cef41917..7ad0c8faabb9 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -462,6 +462,7 @@ struct Config { std::string sInfrastructureDNSServer; std::string sInfrastructureUsername; // Username used for Infrastructure play. Different restrictions. bool bInfrastructureAutoDNS; + bool bAllowSavestateWhileConnected; // Developer option, ini-only. No normal users need this, it's always wrong to save/load state when online. bool bEnableWlan; std::map mHostToAlias; // Local DNS database stored in ini file diff --git a/Core/FrameTiming.cpp b/Core/FrameTiming.cpp index 0c75f41c629b..1d1d84c8edee 100644 --- a/Core/FrameTiming.cpp +++ b/Core/FrameTiming.cpp @@ -29,6 +29,7 @@ #include "Core/System.h" #include "Core/Config.h" #include "Core/HW/Display.h" +#include "Core/HLE/sceNet.h" #include "Core/FrameTiming.h" FrameTiming g_frameTiming; @@ -93,10 +94,16 @@ Draw::PresentMode ComputePresentMode(Draw::DrawContext *draw, int *interval) { wantInstant = true; } - if (PSP_CoreParameter().fastForward) { + if (PSP_CoreParameter().fastForward && NetworkAllowSpeedControl()) { wantInstant = true; } - if (PSP_CoreParameter().fpsLimit != FPSLimit::NORMAL) { + + FPSLimit limit = PSP_CoreParameter().fpsLimit; + if (!NetworkAllowSpeedControl()) { + limit = FPSLimit::NORMAL; + } + + if (limit != FPSLimit::NORMAL) { int limit; if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1) limit = g_Config.iFpsLimit1; diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index a0ba14ca133f..b790a109bf05 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -46,6 +46,7 @@ #include "Core/HLE/FunctionWrappers.h" #include "Core/HLE/sceDisplay.h" #include "Core/HLE/sceKernel.h" +#include "Core/HLE/sceNet.h" #include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceKernelInterrupt.h" #include "Core/HW/Display.h" @@ -353,6 +354,10 @@ void __DisplaySetWasPaused() { // TOOD: Should return 59.997? static int FrameTimingLimit() { + if (!NetworkAllowSpeedControl()) { + return 60; + } + bool challenge = Achievements::HardcoreModeActive(); auto fixRate = [=](int limit) { diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 83b1f341147e..2c97a2f7d10a 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -95,6 +95,34 @@ int NetApctl_Term(); void NetApctl_InitDefaultInfo(); void NetApctl_InitInfo(int confId); +bool NetworkWarnUserIfOnlineAndCantSavestate() { + if (netInited && !g_Config.bAllowSavestateWhileConnected) { + auto nw = GetI18NCategory(I18NCat::NETWORKING); + g_OSD.Show(OSDType::MESSAGE_INFO, nw->T("Save states are not available when online"), 3.0f, "saveonline"); + return true; + } else { + return false; + } +} + +bool NetworkWarnUserIfOnlineAndCantSpeed() { + if (netInited) { + auto nw = GetI18NCategory(I18NCat::NETWORKING); + g_OSD.Show(OSDType::MESSAGE_INFO, nw->T("Speed controls are not available when online"), 3.0f, "speedonline"); + return true; + } else { + return false; + } +} + +bool NetworkAllowSpeedControl() { + return !netInited; +} + +bool NetworkAllowSaveState() { + return !netInited || g_Config.bAllowSavestateWhileConnected; +} + void AfterApctlMipsCall::DoState(PointerWrap & p) { auto s = p.Section("AfterApctlMipsCall", 1, 1); if (!s) diff --git a/Core/HLE/sceNet.h b/Core/HLE/sceNet.h index 533d32a40aa8..a1969b470568 100644 --- a/Core/HLE/sceNet.h +++ b/Core/HLE/sceNet.h @@ -130,6 +130,13 @@ int NetApctl_GetState(); int sceNetApctlConnect(int connIndex); int sceNetApctlTerm(); +// These return false if allowed to be consistent with the similar function for achievements. +bool NetworkWarnUserIfOnlineAndCantSavestate(); +bool NetworkWarnUserIfOnlineAndCantSpeed(); + +bool NetworkAllowSaveState(); +bool NetworkAllowSpeedControl(); + enum class InfraGameState { Unknown, Working, diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index 78107463cad5..b4649264abcd 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -40,6 +40,7 @@ #include "Core/FileSystems/MetaFileSystem.h" #include "Core/ELF/ParamSFO.h" #include "Core/HLE/HLE.h" +#include "Core/HLE/sceNet.h" #include "Core/HLE/ReplaceTables.h" #include "Core/HLE/sceDisplay.h" #include "Core/HLE/sceKernel.h" @@ -404,6 +405,9 @@ namespace SaveState void Enqueue(const SaveState::Operation &op) { + if (!NetworkAllowSaveState()) { + return; + } if (Achievements::HardcoreModeActive()) { if (g_Config.bAchievementsSaveStateInHardcoreMode && ((op.type == SaveState::SAVESTATE_SAVE) || (op.type == SAVESTATE_SAVE_SCREENSHOT))) { // We allow saving in hardcore mode if this setting is on. @@ -423,6 +427,10 @@ namespace SaveState void Load(const Path &filename, int slot, Callback callback, void *cbUserData) { + if (!NetworkAllowSaveState()) { + return; + } + rewindStates.NotifyState(); if (coreState == CoreState::CORE_RUNTIME_ERROR) Core_Break("savestate.load", 0); @@ -431,6 +439,10 @@ namespace SaveState void Save(const Path &filename, int slot, Callback callback, void *cbUserData) { + if (!NetworkAllowSaveState()) { + return; + } + rewindStates.NotifyState(); if (coreState == CoreState::CORE_RUNTIME_ERROR) Core_Break("savestate.save", 0); @@ -444,6 +456,9 @@ namespace SaveState void Rewind(Callback callback, void *cbUserData) { + if (netInited) { + return; + } if (coreState == CoreState::CORE_RUNTIME_ERROR) Core_Break("savestate.rewind", 0); Enqueue(Operation(SAVESTATE_REWIND, Path(), -1, callback, cbUserData)); @@ -574,6 +589,10 @@ namespace SaveState void LoadSlot(const Path &gameFilename, int slot, Callback callback, void *cbUserData) { + if (!NetworkAllowSaveState()) { + return; + } + Path fn = GenerateSaveSlotFilename(gameFilename, slot, STATE_EXTENSION); if (!fn.empty()) { // This add only 1 extra state, should we just always enable it? @@ -611,6 +630,10 @@ namespace SaveState bool UndoLoad(const Path &gameFilename, Callback callback, void *cbUserData) { + if (!NetworkAllowSaveState()) { + return false; + } + if (g_Config.sStateLoadUndoGame != GenerateFullDiscId(gameFilename)) { if (callback) { auto sy = GetI18NCategory(I18NCat::SYSTEM); @@ -634,6 +657,10 @@ namespace SaveState void SaveSlot(const Path &gameFilename, int slot, Callback callback, void *cbUserData) { + if (!NetworkAllowSaveState()) { + return; + } + Path fn = GenerateSaveSlotFilename(gameFilename, slot, STATE_EXTENSION); Path fnUndo = GenerateSaveSlotFilename(gameFilename, slot, UNDO_STATE_EXTENSION); if (!fn.empty()) { @@ -671,7 +698,11 @@ namespace SaveState } } - bool UndoSaveSlot(const Path &gameFilename, int slot) { + bool UndoSaveSlot(const Path &gameFilename, int slot) { + if (!NetworkAllowSaveState()) { + return false; + } + Path fnUndo = GenerateSaveSlotFilename(gameFilename, slot, UNDO_STATE_EXTENSION); // Do nothing if there's no undo. @@ -690,6 +721,10 @@ namespace SaveState bool UndoLastSave(const Path &gameFilename) { + if (!NetworkAllowSaveState()) { + return false; + } + if (g_Config.sStateUndoLastSaveGame != GenerateFullDiscId(gameFilename)) return false; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index df8d6fe81a04..cf61f04e27c9 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -679,7 +679,7 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) { } break; case VIRTKEY_FASTFORWARD: - if (down) { + if (down && !NetworkWarnUserIfOnlineAndCantSpeed()) { if (coreState == CORE_STEPPING_CPU) { Core_Resume(); } @@ -690,7 +690,7 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) { break; case VIRTKEY_SPEED_TOGGLE: - if (down) { + if (down && !NetworkWarnUserIfOnlineAndCantSpeed()) { // Cycle through enabled speeds. if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL && g_Config.iFpsLimit1 >= 0) { PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM1; @@ -706,7 +706,7 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) { break; case VIRTKEY_SPEED_CUSTOM1: - if (down) { + if (down && !NetworkWarnUserIfOnlineAndCantSpeed()) { if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL) { PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM1; g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("fixed", "Speed: alternate"), 1.0, "altspeed"); @@ -719,7 +719,7 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) { } break; case VIRTKEY_SPEED_CUSTOM2: - if (down) { + if (down && !NetworkWarnUserIfOnlineAndCantSpeed()) { if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL) { PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM2; g_OSD.Show(OSDType::MESSAGE_INFO, sc->T("SpeedCustom2", "Speed: alternate 2"), 1.0, "altspeed"); @@ -744,7 +744,7 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) { case VIRTKEY_FRAME_ADVANCE: // Can't do this reliably in an async fashion, so we just set a variable. - if (down) { + if (down && !NetworkWarnUserIfOnlineAndCantSpeed()) { doFrameAdvance_.store(true); } break; @@ -798,7 +798,7 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) { #endif case VIRTKEY_REWIND: - if (down && !Achievements::WarnUserIfHardcoreModeActive(false)) { + if (down && !Achievements::WarnUserIfHardcoreModeActive(false) && !NetworkWarnUserIfOnlineAndCantSavestate()) { if (SaveState::CanRewind()) { SaveState::Rewind(&AfterSaveStateAction); } else { @@ -807,23 +807,23 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) { } break; case VIRTKEY_SAVE_STATE: - if (down && !Achievements::WarnUserIfHardcoreModeActive(true)) { + if (down && !Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) { SaveState::SaveSlot(gamePath_, g_Config.iCurrentStateSlot, &AfterSaveStateAction); } break; case VIRTKEY_LOAD_STATE: - if (down && !Achievements::WarnUserIfHardcoreModeActive(false)) { + if (down && !Achievements::WarnUserIfHardcoreModeActive(false) && !NetworkWarnUserIfOnlineAndCantSavestate()) { SaveState::LoadSlot(gamePath_, g_Config.iCurrentStateSlot, &AfterSaveStateAction); } break; case VIRTKEY_PREVIOUS_SLOT: - if (down && !Achievements::WarnUserIfHardcoreModeActive(true)) { + if (down && !Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) { SaveState::PrevSlot(); System_PostUIMessage(UIMessage::SAVESTATE_DISPLAY_SLOT); } break; case VIRTKEY_NEXT_SLOT: - if (down && !Achievements::WarnUserIfHardcoreModeActive(true)) { + if (down && !Achievements::WarnUserIfHardcoreModeActive(true) && NetworkWarnUserIfOnlineAndCantSavestate()) { SaveState::NextSlot(); System_PostUIMessage(UIMessage::SAVESTATE_DISPLAY_SLOT); } @@ -905,7 +905,8 @@ void EmuScreen::onVKey(int virtualKeyCode, bool down) { g_Config.iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL180; break; case VIRTKEY_TOGGLE_WLAN: - if (down) { + // Let's not allow the user to toggle wlan while connected, could get confusing. + if (down && !netInited) { auto n = GetI18NCategory(I18NCat::NETWORKING); auto di = GetI18NCategory(I18NCat::DIALOG); g_Config.bEnableWlan = !g_Config.bEnableWlan; diff --git a/UI/GamepadEmu.h b/UI/GamepadEmu.h index dfe551b54b83..b4ad53c81c11 100644 --- a/UI/GamepadEmu.h +++ b/UI/GamepadEmu.h @@ -71,7 +71,6 @@ class BoolButton : public MultiTouchButton { public: BoolButton(bool *value, const char *key, ImageID bgImg, ImageID bgDownImg, ImageID img, float scale, UI::LayoutParams *layoutParams) : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams), value_(value) { - } bool Touch(const TouchInput &input) override; bool IsDown() override { return *value_; } diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index b266d9b87a9a..2a717378994f 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -121,22 +121,28 @@ class ScreenshotViewScreen : public PopupScreen { }; UI::EventReturn ScreenshotViewScreen::OnSaveState(UI::EventParams &e) { - g_Config.iCurrentStateSlot = slot_; - SaveState::SaveSlot(gamePath_, slot_, &AfterSaveStateAction); - TriggerFinish(DR_OK); //OK will close the pause screen as well + if (!NetworkWarnUserIfOnlineAndCantSavestate()) { + g_Config.iCurrentStateSlot = slot_; + SaveState::SaveSlot(gamePath_, slot_, &AfterSaveStateAction); + TriggerFinish(DR_OK); //OK will close the pause screen as well + } return UI::EVENT_DONE; } UI::EventReturn ScreenshotViewScreen::OnLoadState(UI::EventParams &e) { - g_Config.iCurrentStateSlot = slot_; - SaveState::LoadSlot(gamePath_, slot_, &AfterSaveStateAction); - TriggerFinish(DR_OK); + if (!NetworkWarnUserIfOnlineAndCantSavestate()) { + g_Config.iCurrentStateSlot = slot_; + SaveState::LoadSlot(gamePath_, slot_, &AfterSaveStateAction); + TriggerFinish(DR_OK); + } return UI::EVENT_DONE; } UI::EventReturn ScreenshotViewScreen::OnUndoState(UI::EventParams &e) { - SaveState::UndoSaveSlot(gamePath_, slot_); - TriggerFinish(DR_CANCEL); + if (!NetworkWarnUserIfOnlineAndCantSavestate()) { + SaveState::UndoSaveSlot(gamePath_, slot_); + TriggerFinish(DR_CANCEL); + } return UI::EVENT_DONE; } @@ -233,20 +239,24 @@ void SaveSlotView::Draw(UIContext &dc) { } UI::EventReturn SaveSlotView::OnLoadState(UI::EventParams &e) { - g_Config.iCurrentStateSlot = slot_; - SaveState::LoadSlot(gamePath_, slot_, &AfterSaveStateAction); - UI::EventParams e2{}; - e2.v = this; - OnStateLoaded.Trigger(e2); + if (!NetworkWarnUserIfOnlineAndCantSavestate()) { + g_Config.iCurrentStateSlot = slot_; + SaveState::LoadSlot(gamePath_, slot_, &AfterSaveStateAction); + UI::EventParams e2{}; + e2.v = this; + OnStateLoaded.Trigger(e2); + } return UI::EVENT_DONE; } UI::EventReturn SaveSlotView::OnSaveState(UI::EventParams &e) { - g_Config.iCurrentStateSlot = slot_; - SaveState::SaveSlot(gamePath_, slot_, &AfterSaveStateAction); - UI::EventParams e2{}; - e2.v = this; - OnStateSaved.Trigger(e2); + if (!NetworkWarnUserIfOnlineAndCantSavestate()) { + g_Config.iCurrentStateSlot = slot_; + SaveState::SaveSlot(gamePath_, slot_, &AfterSaveStateAction); + UI::EventParams e2{}; + e2.v = this; + OnStateSaved.Trigger(e2); + } return UI::EVENT_DONE; } @@ -266,6 +276,12 @@ void GamePauseScreen::update() { finishNextFrame_ = false; } + if (netInited != lastNetInited_) { + INFO_LOG(Log::sceNet, "Network status changed, recreating views"); + RecreateViews(); + lastNetInited_ = netInited; + } + bool mustRunBehind = MustRunBehind(); playButton_->SetVisibility(mustRunBehind ? UI::V_GONE : UI::V_VISIBLE); @@ -318,7 +334,7 @@ void GamePauseScreen::CreateSavestateControls(UI::LinearLayout *leftColumnItems, leftColumnItems->Add(new Spacer(0.0)); LinearLayout *buttonRow = leftColumnItems->Add(new LinearLayout(ORIENT_HORIZONTAL)); - if (g_Config.bEnableStateUndo && !Achievements::HardcoreModeActive()) { + if (g_Config.bEnableStateUndo && !Achievements::HardcoreModeActive() && NetworkAllowSaveState()) { UI::Choice *loadUndoButton = buttonRow->Add(new Choice(pa->T("Undo last load"))); loadUndoButton->SetEnabled(SaveState::HasUndoLoad(gamePath_)); loadUndoButton->OnClick.Handle(this, &GamePauseScreen::OnLoadUndo); @@ -328,7 +344,7 @@ void GamePauseScreen::CreateSavestateControls(UI::LinearLayout *leftColumnItems, saveUndoButton->OnClick.Handle(this, &GamePauseScreen::OnLastSaveUndo); } - if (g_Config.iRewindSnapshotInterval > 0 && !Achievements::HardcoreModeActive()) { + if (g_Config.iRewindSnapshotInterval > 0 && !Achievements::HardcoreModeActive() && NetworkAllowSaveState()) { UI::Choice *rewindButton = buttonRow->Add(new Choice(pa->T("Rewind"))); rewindButton->SetEnabled(SaveState::CanRewind()); rewindButton->OnClick.Handle(this, &GamePauseScreen::OnRewind); @@ -345,6 +361,7 @@ void GamePauseScreen::CreateViews() { auto gr = GetI18NCategory(I18NCat::GRAPHICS); auto pa = GetI18NCategory(I18NCat::PAUSE); auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS); + auto nw = GetI18NCategory(I18NCat::NETWORKING); root_ = new LinearLayout(ORIENT_HORIZONTAL); @@ -365,7 +382,17 @@ void GamePauseScreen::CreateViews() { } } - if (!Achievements::HardcoreModeActive() || g_Config.bAchievementsSaveStateInHardcoreMode) { + if (netInited) { + leftColumnItems->Add(new NoticeView(NoticeLevel::INFO, nw->T("Network connected"), "")); + } + + bool achievementsAllowSavestates = !Achievements::HardcoreModeActive() || g_Config.bAchievementsSaveStateInHardcoreMode; + bool showSavestateControls = achievementsAllowSavestates; + if (netInited && !g_Config.bAllowSavestateWhileConnected) { + showSavestateControls = false; + } + + if (showSavestateControls) { CreateSavestateControls(leftColumnItems, vertical); } else { // Let's show the active challenges. @@ -381,8 +408,9 @@ void GamePauseScreen::CreateViews() { } // And tack on an explanation for why savestate options are not available. - std::string_view notAvailable = ac->T("Save states not available in Hardcore Mode"); - leftColumnItems->Add(new NoticeView(NoticeLevel::INFO, notAvailable, "")); + if (!achievementsAllowSavestates) { + leftColumnItems->Add(new NoticeView(NoticeLevel::INFO, ac->T("Save states not available in Hardcore Mode"), "")); + } } LinearLayout *middleColumn = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(64, FILL_PARENT, Margins(0, 10, 0, 15))); @@ -462,11 +490,6 @@ void GamePauseScreen::CreateViews() { bool mustRunBehind = MustRunBehind(); playButton_->SetVisibility(mustRunBehind ? UI::V_GONE : UI::V_VISIBLE); - if (mustRunBehind) { - auto nw = GetI18NCategory(I18NCat::NETWORKING); - rightColumnHolder->Add(new TextView(nw->T("Network connected"))); - } - Button *infoButton = middleColumn->Add(new Button("", ImageID("I_INFO"), new LinearLayoutParams(64, 64))); infoButton->OnClick.Add([=](UI::EventParams &e) { screenManager()->push(new GameScreen(gamePath_, true)); @@ -564,8 +587,7 @@ UI::EventReturn GamePauseScreen::OnLastSaveUndo(UI::EventParams &e) { return UI::EVENT_DONE; } -void GamePauseScreen::CallbackDeleteConfig(bool yes) -{ +void GamePauseScreen::CallbackDeleteConfig(bool yes) { if (yes) { std::shared_ptr info = g_gameInfoCache->GetInfo(NULL, gamePath_, GameInfoFlags::PARAM_SFO); if (info->Ready(GameInfoFlags::PARAM_SFO)) { @@ -577,8 +599,7 @@ void GamePauseScreen::CallbackDeleteConfig(bool yes) } } -UI::EventReturn GamePauseScreen::OnCreateConfig(UI::EventParams &e) -{ +UI::EventReturn GamePauseScreen::OnCreateConfig(UI::EventParams &e) { std::shared_ptr info = g_gameInfoCache->GetInfo(NULL, gamePath_, GameInfoFlags::PARAM_SFO); if (info->Ready(GameInfoFlags::PARAM_SFO)) { std::string gameId = g_paramSFO.GetDiscID(); @@ -593,8 +614,7 @@ UI::EventReturn GamePauseScreen::OnCreateConfig(UI::EventParams &e) return UI::EVENT_DONE; } -UI::EventReturn GamePauseScreen::OnDeleteConfig(UI::EventParams &e) -{ +UI::EventReturn GamePauseScreen::OnDeleteConfig(UI::EventParams &e) { auto di = GetI18NCategory(I18NCat::DIALOG); auto ga = GetI18NCategory(I18NCat::GAME); screenManager()->push( diff --git a/UI/PauseScreen.h b/UI/PauseScreen.h index f177b33f2c12..8dcdfeab87a9 100644 --- a/UI/PauseScreen.h +++ b/UI/PauseScreen.h @@ -64,4 +64,5 @@ class GamePauseScreen : public UIDialogScreenWithGameBackground { DialogResult finishNextFrameResult_ = DR_CANCEL; UI::Button *playButton_ = nullptr; + bool lastNetInited_ = false; }; diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index a78fae1ed4fa..0f46a99019a5 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -49,6 +49,7 @@ #include "Windows/W32Util/DarkMode.h" #include "Core/HLE/sceUmd.h" +#include "Core/HLE/sceNet.h" #include "Core/SaveState.h" #include "Core/Core.h" #include "Core/RetroAchievements.h" @@ -85,6 +86,11 @@ namespace MainWindow { } } + if (!NetworkAllowSaveState()) { + loadStateEnableBool = false; + saveStateEnableBool = false; + } + const UINT menuEnable = menuEnableBool ? MF_ENABLED : MF_GRAYED; const UINT loadStateEnable = loadStateEnableBool ? MF_ENABLED : MF_GRAYED; const UINT saveStateEnable = saveStateEnableBool ? MF_ENABLED : MF_GRAYED; @@ -491,7 +497,9 @@ namespace MainWindow { break; case ID_EMULATION_PAUSE: - System_PostUIMessage(UIMessage::REQUEST_GAME_PAUSE); + if (!NetworkWarnUserIfOnlineAndCantSpeed()) { + System_PostUIMessage(UIMessage::REQUEST_GAME_PAUSE); + } break; case ID_EMULATION_STOP: @@ -527,8 +535,9 @@ namespace MainWindow { System_PostUIMessage(UIMessage::SHOW_CHAT_SCREEN); } break; + case ID_FILE_LOADSTATEFILE: - if (!Achievements::WarnUserIfHardcoreModeActive(false)) { + if (!Achievements::WarnUserIfHardcoreModeActive(false) && !NetworkWarnUserIfOnlineAndCantSavestate()) { if (W32Util::BrowseForFileName(true, hWnd, L"Load state", 0, L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) { SetCursor(LoadCursor(0, IDC_WAIT)); SaveState::Load(Path(fn), -1, SaveStateActionFinished); @@ -536,7 +545,7 @@ namespace MainWindow { } break; case ID_FILE_SAVESTATEFILE: - if (!Achievements::WarnUserIfHardcoreModeActive(true)) { + if (!Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) { if (W32Util::BrowseForFileName(false, hWnd, L"Save state", 0, L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) { SetCursor(LoadCursor(0, IDC_WAIT)); SaveState::Save(Path(fn), -1, SaveStateActionFinished); @@ -546,7 +555,7 @@ namespace MainWindow { case ID_FILE_SAVESTATE_NEXT_SLOT: { - if (!Achievements::WarnUserIfHardcoreModeActive(true)) { + if (!Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) { SaveState::NextSlot(); System_PostUIMessage(UIMessage::SAVESTATE_DISPLAY_SLOT); } @@ -555,7 +564,7 @@ namespace MainWindow { case ID_FILE_SAVESTATE_NEXT_SLOT_HC: { - if (!Achievements::WarnUserIfHardcoreModeActive(true)) { + if (!Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) { // We let F3 (search next) in the imdebugger take priority, if active. if (!KeyMap::PspButtonHasMappings(VIRTKEY_NEXT_SLOT) && !g_Config.bShowImDebugger) { SaveState::NextSlot(); @@ -570,13 +579,13 @@ namespace MainWindow { case ID_FILE_SAVESTATE_SLOT_3: case ID_FILE_SAVESTATE_SLOT_4: case ID_FILE_SAVESTATE_SLOT_5: - if (!Achievements::WarnUserIfHardcoreModeActive(true)) { + if (!Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) { g_Config.iCurrentStateSlot = wmId - ID_FILE_SAVESTATE_SLOT_1; } break; case ID_FILE_QUICKLOADSTATE: - if (!Achievements::WarnUserIfHardcoreModeActive(false)) { + if (!Achievements::WarnUserIfHardcoreModeActive(false) && !NetworkWarnUserIfOnlineAndCantSavestate()) { SetCursor(LoadCursor(0, IDC_WAIT)); SaveState::LoadSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished); } @@ -584,7 +593,7 @@ namespace MainWindow { case ID_FILE_QUICKLOADSTATE_HC: { - if (!Achievements::WarnUserIfHardcoreModeActive(false)) { + if (!Achievements::WarnUserIfHardcoreModeActive(false) && !NetworkWarnUserIfOnlineAndCantSavestate()) { if (!KeyMap::PspButtonHasMappings(VIRTKEY_LOAD_STATE)) { SetCursor(LoadCursor(0, IDC_WAIT)); SaveState::LoadSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished); @@ -594,7 +603,7 @@ namespace MainWindow { } case ID_FILE_QUICKSAVESTATE: { - if (!Achievements::WarnUserIfHardcoreModeActive(true)) { + if (!Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) { SetCursor(LoadCursor(0, IDC_WAIT)); SaveState::SaveSlot(PSP_CoreParameter().fileToStart, g_Config.iCurrentStateSlot, SaveStateActionFinished); } @@ -603,7 +612,7 @@ namespace MainWindow { case ID_FILE_QUICKSAVESTATE_HC: { - if (!Achievements::WarnUserIfHardcoreModeActive(true)) { + if (!Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) { if (!KeyMap::PspButtonHasMappings(VIRTKEY_SAVE_STATE)) { SetCursor(LoadCursor(0, IDC_WAIT));