Skip to content

Commit

Permalink
move non-hardcore warning to account for async load (#1041)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamiras authored Dec 9, 2023
1 parent c19a893 commit ba588c6
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 210 deletions.
34 changes: 34 additions & 0 deletions src/data/context/GameContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "data\models\RichPresenceModel.hh"

#include "services\AchievementRuntime.hh"
#include "services\FrameEventQueue.hh"
#include "services\IAudioSystem.hh"
#include "services\IConfiguration.hh"
#include "services\ILocalStorage.hh"
Expand Down Expand Up @@ -290,6 +291,39 @@ void GameContext::FinishLoadGame(int nResult, const char* sErrorMessage, bool bW
pRuntime.SyncAssets();

EndLoad();

// non-hardcore warning
auto& pConfiguration = ra::services::ServiceLocator::Get<ra::services::IConfiguration>();
if (!pConfiguration.IsFeatureEnabled(ra::services::Feature::Hardcore))
{
bool bShowHardcorePrompt = false;
if (pConfiguration.IsFeatureEnabled(ra::services::Feature::NonHardcoreWarning))
bShowHardcorePrompt = Assets().HasCoreAssets();

if (bShowHardcorePrompt)
{
ra::services::ServiceLocator::GetMutable<ra::services::FrameEventQueue>().QueueFunction([]() {
ra::ui::viewmodels::MessageBoxViewModel vmWarning;
vmWarning.SetHeader(L"Enable Hardcore mode?");
vmWarning.SetMessage(L"You are loading a game with achievements and do not currently have hardcore mode enabled.");
vmWarning.SetIcon(ra::ui::viewmodels::MessageBoxViewModel::Icon::Warning);
vmWarning.SetButtons(ra::ui::viewmodels::MessageBoxViewModel::Buttons::YesNo);

if (vmWarning.ShowModal() == ra::ui::DialogResult::Yes)
ra::services::ServiceLocator::GetMutable<ra::data::context::EmulatorContext>().EnableHardcoreMode(false);
});
}
else
{
const bool bLeaderboardsEnabled = pConfiguration.IsFeatureEnabled(ra::services::Feature::Leaderboards);

ra::services::ServiceLocator::Get<ra::services::IAudioSystem>().PlayAudioFile(L"Overlay\\info.wav");
ra::services::ServiceLocator::GetMutable<ra::ui::viewmodels::OverlayManager>().QueueMessage(
L"Playing in Softcore Mode",
bLeaderboardsEnabled ? L"Leaderboard entries will not be submitted." : L"");
}
}

OnActiveGameChanged();
}

Expand Down
8 changes: 8 additions & 0 deletions src/services/FrameEventQueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ void FrameEventQueue::DoFrame()
{
std::wstring sPauseMessage;

if (!m_vFunctions.empty())
{
for (auto& fFunction : m_vFunctions)
fFunction();

m_vFunctions.clear();
}

if (!m_vTriggeredTriggers.empty())
{
sPauseMessage.append(L"The following triggers have triggered:");
Expand Down
6 changes: 6 additions & 0 deletions src/services/FrameEventQueue.hh
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,18 @@ public:
m_vTriggeredTriggers.push_back(sTriggerName);
}

void QueueFunction(std::function<void(void)> fAction)
{
m_vFunctions.push_back(fAction);
}

void DoFrame();

protected:
std::set<std::wstring> m_vMemChanges;
std::vector<std::wstring> m_vResetTriggers;
std::vector<std::wstring> m_vTriggeredTriggers;
std::vector<std::function<void(void)>> m_vFunctions;
};

} // namespace services
Expand Down
29 changes: 0 additions & 29 deletions src/services/GameIdentifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,35 +184,6 @@ void GameIdentifier::ActivateGame(unsigned int nGameId)
pGameContext.SetGameHash((nGameId == m_nPendingGameId) ? m_sPendingHash : "");

ra::services::ServiceLocator::GetMutable<ra::data::context::SessionTracker>().BeginSession(nGameId);

auto& pConfiguration = ra::services::ServiceLocator::Get<ra::services::IConfiguration>();
if (!pConfiguration.IsFeatureEnabled(ra::services::Feature::Hardcore))
{
bool bShowHardcorePrompt = false;
if (pConfiguration.IsFeatureEnabled(ra::services::Feature::NonHardcoreWarning))
bShowHardcorePrompt = pGameContext.Assets().HasCoreAssets();

if (bShowHardcorePrompt)
{
ra::ui::viewmodels::MessageBoxViewModel vmWarning;
vmWarning.SetHeader(L"Enable Hardcore mode?");
vmWarning.SetMessage(L"You are loading a game with achievements and do not currently have hardcore mode enabled.");
vmWarning.SetIcon(ra::ui::viewmodels::MessageBoxViewModel::Icon::Warning);
vmWarning.SetButtons(ra::ui::viewmodels::MessageBoxViewModel::Buttons::YesNo);

if (vmWarning.ShowModal() == ra::ui::DialogResult::Yes)
ra::services::ServiceLocator::GetMutable<ra::data::context::EmulatorContext>().EnableHardcoreMode(false);
}
else
{
const bool bLeaderboardsEnabled = pConfiguration.IsFeatureEnabled(ra::services::Feature::Leaderboards);

ra::services::ServiceLocator::Get<ra::services::IAudioSystem>().PlayAudioFile(L"Overlay\\info.wav");
ra::services::ServiceLocator::GetMutable<ra::ui::viewmodels::OverlayManager>().QueueMessage(
L"Playing in Softcore Mode",
bLeaderboardsEnabled ? L"Leaderboard entries will not be submitted." : L"");
}
}
}
else
{
Expand Down
177 changes: 177 additions & 0 deletions tests/data/context/GameContext_Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "tests\RA_UnitTestHelpers.h"
#include "tests\data\DataAsserts.hh"
#include "tests\ui\UIAsserts.hh"

#include "tests\mocks\MockAchievementRuntime.hh"
#include "tests\mocks\MockAudioSystem.hh"
Expand All @@ -20,6 +21,7 @@
#include "tests\mocks\MockClock.hh"
#include "tests\mocks\MockConfiguration.hh"
#include "tests\mocks\MockDesktop.hh"
#include "tests\mocks\MockFrameEventQueue.hh"
#include "tests\mocks\MockLocalStorage.hh"
#include "tests\mocks\MockOverlayManager.hh"
#include "tests\mocks\MockServer.hh"
Expand Down Expand Up @@ -65,6 +67,7 @@ TEST_CLASS(GameContext_Tests)
ra::services::mocks::MockThreadPool mockThreadPool;
ra::services::mocks::MockAudioSystem mockAudioSystem;
ra::services::mocks::MockAchievementRuntime mockAchievementRuntime;
ra::services::mocks::MockFrameEventQueue mockFrameEventQueue;
ra::ui::viewmodels::mocks::MockOverlayManager mockOverlayManager;
ra::data::context::mocks::MockConsoleContext mockConsoleContext;
ra::data::context::mocks::MockEmulatorContext mockEmulator;
Expand Down Expand Up @@ -1235,6 +1238,180 @@ TEST_CLASS(GameContext_Tests)
Assert::AreEqual(GameContext::Mode::Normal, game.GetMode());
Assert::IsFalse(notifyHarness.m_bNotified);
}


TEST_METHOD(TestLoadGameNonHardcoreWarningHardcore)
{
GameContextHarness game;
game.MockLoadGameAPIs(1U, "0123456789abcdeffedcba987654321", "",
"{\"ID\":5,\"Title\":\"Ach1\",\"Description\":\"Desc1\",\"Flags\":3,"
"\"Points\":5,\"MemAddr\":\"1=1\",\"Author\":\"Auth1\",\"BadgeName\":\"12345\","
"\"Created\":1234567890,\"Modified\":123459999},"
"{\"ID\":7,\"Title\":\"Ach2\",\"Description\":\"Desc2\",\"Flags\":3,"
"\"Points\":10,\"MemAddr\":\"1=1\",\"Author\":\"Auth2\",\"BadgeName\":\"12345\","
"\"Created\":1234567890,\"Modified\":123459999}"
);

game.mockConfiguration.SetFeatureEnabled(ra::services::Feature::NonHardcoreWarning, true);
game.mockConfiguration.SetFeatureEnabled(ra::services::Feature::Hardcore, true);
game.LoadGame(1U, "0123456789abcdeffedcba987654321");

// no dialogs when game with achievements loaded in hardcore mode
game.mockFrameEventQueue.DoFrame(); // hardcore warning gets queued for the UI thread
Assert::IsFalse(game.mockDesktop.WasDialogShown());
Assert::IsNull(game.mockOverlayManager.GetMessage(2U)); // message 1 will be game placard
}

TEST_METHOD(TestLoadGameNonHardcoreWarningLeaderboards)
{
GameContextHarness game;
game.MockLoadGameAPIs(1U, "0123456789abcdeffedcba987654321", "",
"{\"ID\":5,\"Title\":\"Ach1\",\"Description\":\"Desc1\",\"Flags\":3,"
"\"Points\":5,\"MemAddr\":\"1=1\",\"Author\":\"Auth1\",\"BadgeName\":\"12345\","
"\"Created\":1234567890,\"Modified\":123459999},"
"{\"ID\":7,\"Title\":\"Ach2\",\"Description\":\"Desc2\",\"Flags\":3,"
"\"Points\":10,\"MemAddr\":\"1=1\",\"Author\":\"Auth2\",\"BadgeName\":\"12345\","
"\"Created\":1234567890,\"Modified\":123459999}"
);

game.mockConfiguration.SetFeatureEnabled(ra::services::Feature::NonHardcoreWarning, false);
game.mockConfiguration.SetFeatureEnabled(ra::services::Feature::Hardcore, false);
game.mockConfiguration.SetFeatureEnabled(ra::services::Feature::Leaderboards, true);
game.LoadGame(1U, "0123456789abcdeffedcba987654321");

// should get popup message indicating leaderboards not supported in softcore
game.mockFrameEventQueue.DoFrame(); // hardcore warning gets queued for the UI thread
Assert::IsFalse(game.mockDesktop.WasDialogShown());

const auto* pPopup = game.mockOverlayManager.GetMessage(2U);
Expects(pPopup != nullptr);
Assert::AreEqual(std::wstring(L"Playing in Softcore Mode"), pPopup->GetTitle());
Assert::AreEqual(std::wstring(L"Leaderboard entries will not be submitted."), pPopup->GetDescription());
}

TEST_METHOD(TestLoadGameNonHardcoreWarningLeaderboardsOff)
{
GameContextHarness game;
game.MockLoadGameAPIs(1U, "0123456789abcdeffedcba987654321", "",
"{\"ID\":5,\"Title\":\"Ach1\",\"Description\":\"Desc1\",\"Flags\":3,"
"\"Points\":5,\"MemAddr\":\"1=1\",\"Author\":\"Auth1\",\"BadgeName\":\"12345\","
"\"Created\":1234567890,\"Modified\":123459999},"
"{\"ID\":7,\"Title\":\"Ach2\",\"Description\":\"Desc2\",\"Flags\":3,"
"\"Points\":10,\"MemAddr\":\"1=1\",\"Author\":\"Auth2\",\"BadgeName\":\"12345\","
"\"Created\":1234567890,\"Modified\":123459999}"
);

game.mockConfiguration.SetFeatureEnabled(ra::services::Feature::NonHardcoreWarning, false);
game.mockConfiguration.SetFeatureEnabled(ra::services::Feature::Hardcore, false);
game.mockConfiguration.SetFeatureEnabled(ra::services::Feature::Leaderboards, false);
game.LoadGame(1U, "0123456789abcdeffedcba987654321");

// should get popup message indicating playing in softcore
game.mockFrameEventQueue.DoFrame(); // hardcore warning gets queued for the UI thread
Assert::IsFalse(game.mockDesktop.WasDialogShown());

const auto* pPopup = game.mockOverlayManager.GetMessage(2U);
Expects(pPopup != nullptr);
Assert::AreEqual(std::wstring(L"Playing in Softcore Mode"), pPopup->GetTitle());
Assert::AreEqual(std::wstring(L""), pPopup->GetDescription());
}

TEST_METHOD(TestLoadGameNonHardcoreWarningCancel)
{
GameContextHarness game;
game.MockLoadGameAPIs(1U, "0123456789abcdeffedcba987654321", "",
"{\"ID\":5,\"Title\":\"Ach1\",\"Description\":\"Desc1\",\"Flags\":3,"
"\"Points\":5,\"MemAddr\":\"1=1\",\"Author\":\"Auth1\",\"BadgeName\":\"12345\","
"\"Created\":1234567890,\"Modified\":123459999},"
"{\"ID\":7,\"Title\":\"Ach2\",\"Description\":\"Desc2\",\"Flags\":3,"
"\"Points\":10,\"MemAddr\":\"1=1\",\"Author\":\"Auth2\",\"BadgeName\":\"12345\","
"\"Created\":1234567890,\"Modified\":123459999}"
);

game.mockConfiguration.SetFeatureEnabled(ra::services::Feature::NonHardcoreWarning, true);
game.mockConfiguration.SetFeatureEnabled(ra::services::Feature::Hardcore, false);
game.mockDesktop.ExpectWindow<ra::ui::viewmodels::MessageBoxViewModel>(
[](ra::ui::viewmodels::MessageBoxViewModel& vmMessageBox) {
Assert::AreEqual(std::wstring(L"Enable Hardcore mode?"), vmMessageBox.GetHeader());
Assert::AreEqual(std::wstring(L"You are loading a game with achievements and do not currently have hardcore mode enabled."), vmMessageBox.GetMessage());
Assert::AreEqual(ra::ui::viewmodels::MessageBoxViewModel::Icon::Warning, vmMessageBox.GetIcon());
Assert::AreEqual(ra::ui::viewmodels::MessageBoxViewModel::Buttons::YesNo, vmMessageBox.GetButtons());
return ra::ui::DialogResult::No;
});

game.LoadGame(1U, "0123456789abcdeffedcba987654321");

// should get confirmation dialog about hardcore and no popups
game.mockFrameEventQueue.DoFrame(); // hardcore warning gets queued for the UI thread
Assert::IsTrue(game.mockDesktop.WasDialogShown());
Assert::IsNull(game.mockOverlayManager.GetMessage(2U));

// hardcore should remain disabled
Assert::IsFalse(game.mockConfiguration.IsFeatureEnabled(ra::services::Feature::Hardcore));
}

TEST_METHOD(TestLoadGameNonHardcoreWarningAccept)
{
GameContextHarness game;
game.MockLoadGameAPIs(1U, "0123456789abcdeffedcba987654321", "",
"{\"ID\":5,\"Title\":\"Ach1\",\"Description\":\"Desc1\",\"Flags\":3,"
"\"Points\":5,\"MemAddr\":\"1=1\",\"Author\":\"Auth1\",\"BadgeName\":\"12345\","
"\"Created\":1234567890,\"Modified\":123459999},"
"{\"ID\":7,\"Title\":\"Ach2\",\"Description\":\"Desc2\",\"Flags\":3,"
"\"Points\":10,\"MemAddr\":\"1=1\",\"Author\":\"Auth2\",\"BadgeName\":\"12345\","
"\"Created\":1234567890,\"Modified\":123459999}"
);

game.mockConfiguration.SetFeatureEnabled(ra::services::Feature::NonHardcoreWarning, true);
game.mockConfiguration.SetFeatureEnabled(ra::services::Feature::Hardcore, false);
game.mockDesktop.ExpectWindow<ra::ui::viewmodels::MessageBoxViewModel>(
[](ra::ui::viewmodels::MessageBoxViewModel& vmMessageBox) {
Assert::AreEqual(std::wstring(L"Enable Hardcore mode?"), vmMessageBox.GetHeader());
Assert::AreEqual(std::wstring(L"You are loading a game with achievements and do not currently have hardcore mode enabled."), vmMessageBox.GetMessage());
Assert::AreEqual(ra::ui::viewmodels::MessageBoxViewModel::Icon::Warning, vmMessageBox.GetIcon());
Assert::AreEqual(ra::ui::viewmodels::MessageBoxViewModel::Buttons::YesNo, vmMessageBox.GetButtons());
return ra::ui::DialogResult::Yes;
});

game.LoadGame(1U, "0123456789abcdeffedcba987654321");

// should get confirmation dialog about hardcore and no popups
game.mockFrameEventQueue.DoFrame(); // hardcore warning gets queued for the UI thread
Assert::IsTrue(game.mockDesktop.WasDialogShown());
Assert::IsNull(game.mockOverlayManager.GetMessage(2U));

// hardcore should remain disabled
Assert::IsTrue(game.mockConfiguration.IsFeatureEnabled(ra::services::Feature::Hardcore));
}

TEST_METHOD(TestLoadGameNonHardcoreWarningNoCoreAchievements)
{
GameContextHarness game;
game.MockLoadGameAPIs(1U, "0123456789abcdeffedcba987654321", "",
"{\"ID\":5,\"Title\":\"Ach1\",\"Description\":\"Desc1\",\"Flags\":5,"
"\"Points\":5,\"MemAddr\":\"1=1\",\"Author\":\"Auth1\",\"BadgeName\":\"12345\","
"\"Created\":1234567890,\"Modified\":123459999},"
"{\"ID\":7,\"Title\":\"Ach2\",\"Description\":\"Desc2\",\"Flags\":5,"
"\"Points\":10,\"MemAddr\":\"1=1\",\"Author\":\"Auth2\",\"BadgeName\":\"12345\","
"\"Created\":1234567890,\"Modified\":123459999}");

game.mockConfiguration.SetFeatureEnabled(ra::services::Feature::NonHardcoreWarning, true);
game.mockConfiguration.SetFeatureEnabled(ra::services::Feature::Hardcore, false);

game.LoadGame(1U, "0123456789abcdeffedcba987654321");

// should only get softcore popup
game.mockFrameEventQueue.DoFrame(); // hardcore warning gets queued for the UI thread
Assert::IsFalse(game.mockDesktop.WasDialogShown());

const auto* pPopup = game.mockOverlayManager.GetMessage(2U);
Expects(pPopup != nullptr);
Assert::AreEqual(std::wstring(L"Playing in Softcore Mode"), pPopup->GetTitle());
Assert::AreEqual(std::wstring(L""), pPopup->GetDescription());

// hardcore should remain disabled
Assert::IsFalse(game.mockConfiguration.IsFeatureEnabled(ra::services::Feature::Hardcore));
}
};

} // namespace tests
Expand Down
Loading

0 comments on commit ba588c6

Please sign in to comment.