diff --git a/src/services/AchievementRuntimeExports.cpp b/src/services/AchievementRuntimeExports.cpp index d6cc3614..adb39745 100644 --- a/src/services/AchievementRuntimeExports.cpp +++ b/src/services/AchievementRuntimeExports.cpp @@ -283,6 +283,12 @@ class AchievementRuntimeExports : private AchievementRuntime { auto& pClient = ra::services::ServiceLocator::GetMutable(); rc_client_load_unknown_game(pClient.GetClient(), hash); + + auto& pGameContext = ra::services::ServiceLocator::GetMutable(); + pGameContext.SetGameHash(hash); + + const auto& pConsoleContext = ra::services::ServiceLocator::Get(); + pClient.GetClient()->game->public_.console_id = ra::etoi(pConsoleContext.Id()); } static void unload_game() diff --git a/src/ui/viewmodels/IntegrationMenuViewModel.cpp b/src/ui/viewmodels/IntegrationMenuViewModel.cpp index df20024a..e6d31b03 100644 --- a/src/ui/viewmodels/IntegrationMenuViewModel.cpp +++ b/src/ui/viewmodels/IntegrationMenuViewModel.cpp @@ -7,6 +7,8 @@ #include "data/context/GameContext.hh" #include "data/context/UserContext.hh" +#include "services/AchievementRuntime.hh" +#include "services/AchievementRuntimeExports.hh" #include "services/IConfiguration.hh" #include "services/ServiceLocator.hh" @@ -21,6 +23,8 @@ #include "ui/viewmodels/UnknownGameViewModel.hh" #include "ui/viewmodels/WindowManager.hh" +#include "rcheevos/src/rc_client_external.h" + namespace ra { namespace ui { namespace viewmodels { @@ -388,6 +392,39 @@ void IntegrationMenuViewModel::ShowGameHash() } else { + if (pGameContext.GameId() == 0 && !pGameContext.GameHash().empty()) + { + const auto& pConsoleContext = ra::services::ServiceLocator::Get(); + const auto nConsoleId = pConsoleContext.Id(); + if (nConsoleId != ConsoleID::UnknownConsoleID) + { + const auto& pEmulatorContext = ra::services::ServiceLocator::Get(); + auto sEstimatedGameTitle = ra::Widen(pEmulatorContext.GetGameTitle()); + + ra::ui::viewmodels::UnknownGameViewModel vmUnknownGame; + vmUnknownGame.InitializeGameTitles(nConsoleId); + vmUnknownGame.SetSystemName(pConsoleContext.Name()); + vmUnknownGame.SetChecksum(ra::Widen(pGameContext.GameHash())); + vmUnknownGame.SetEstimatedGameName(sEstimatedGameTitle); + vmUnknownGame.SetNewGameName(sEstimatedGameTitle); + + if (vmUnknownGame.ShowModal() == ra::ui::DialogResult::OK) + { + // register the hash so the dialog doesn't immediately reappear + auto* pClient = ra::services::ServiceLocator::GetMutable().GetClient(); + rc_client_add_game_hash(pClient, pGameContext.GameHash().c_str(), vmUnknownGame.GetSelectedGameId()); + + // attempt to load the newly associated game + pGameContext.LoadGame(vmUnknownGame.GetSelectedGameId(), pGameContext.GameHash(), + vmUnknownGame.GetTestMode() + ? ra::data::context::GameContext::Mode::CompatibilityTest + : ra::data::context::GameContext::Mode::Normal); + } + + return; + } + } + ra::ui::viewmodels::GameChecksumViewModel vmGameChecksum; vmGameChecksum.ShowModal(); } diff --git a/tests/services/AchievementRuntimeExports_Tests.cpp b/tests/services/AchievementRuntimeExports_Tests.cpp index d8425476..8c5a1ac9 100644 --- a/tests/services/AchievementRuntimeExports_Tests.cpp +++ b/tests/services/AchievementRuntimeExports_Tests.cpp @@ -8,6 +8,7 @@ #include "tests\mocks\MockConsoleContext.hh" #include "tests\mocks\MockDesktop.hh" #include "tests\mocks\MockEmulatorContext.hh" +#include "tests\mocks\MockGameContext.hh" #include "tests\mocks\MockUserContext.hh" #include @@ -464,6 +465,51 @@ TEST_CLASS(AchievementRuntimeExports_Tests) *ptr = '\0'; Assert::AreEqual("Integration/" RA_INTEGRATION_VERSION, buffer); } + + TEST_METHOD(TestLoadUnknownGame) + { + AchievementRuntimeExportsHarness runtime; + ra::data::context::mocks::MockGameContext mockGameContext; + ra::data::context::mocks::MockConsoleContext mockConsoleContext; + + rc_client_external_t pClient; + memset(&pClient, 0, sizeof(pClient)); + _Rcheevos_GetExternalClient(&pClient, 2); + + pClient.load_unknown_game("ABCDEF0123456789"); + + const auto* pGame = rc_client_get_game_info(runtime.GetClient()); + Assert::IsNotNull(pGame); + Ensures(pGame != nullptr); + Assert::AreEqual(0U, pGame->id); + Assert::AreEqual("Unknown Game", pGame->title); + Assert::AreEqual(0U, pGame->console_id); + + Assert::AreEqual(std::string("ABCDEF0123456789"), mockGameContext.GameHash()); + } + + TEST_METHOD(TestLoadUnknownGameWithConsole) + { + AchievementRuntimeExportsHarness runtime; + ra::data::context::mocks::MockGameContext mockGameContext; + ra::data::context::mocks::MockConsoleContext mockConsoleContext; + + rc_client_external_t pClient; + memset(&pClient, 0, sizeof(pClient)); + _Rcheevos_GetExternalClient(&pClient, 2); + + mockConsoleContext.SetId(ConsoleID::GBC); + pClient.load_unknown_game("ABCDEF0123456789"); + + const auto* pGame = rc_client_get_game_info(runtime.GetClient()); + Assert::IsNotNull(pGame); + Ensures(pGame != nullptr); + Assert::AreEqual(0U, pGame->id); + Assert::AreEqual("Unknown Game", pGame->title); + Assert::AreEqual({ RC_CONSOLE_GAMEBOY_COLOR }, pGame->console_id); + + Assert::AreEqual(std::string("ABCDEF0123456789"), mockGameContext.GameHash()); + } }; } // namespace tests diff --git a/tests/ui/viewmodels/IntegrationMenuViewModel_Tests.cpp b/tests/ui/viewmodels/IntegrationMenuViewModel_Tests.cpp index 4a1f60c8..49be1bc6 100644 --- a/tests/ui/viewmodels/IntegrationMenuViewModel_Tests.cpp +++ b/tests/ui/viewmodels/IntegrationMenuViewModel_Tests.cpp @@ -834,6 +834,83 @@ TEST_CLASS(IntegrationMenuViewModel_Tests) Assert::IsTrue(bDialogShown); Assert::AreEqual(ra::data::context::GameContext::Mode::Normal, menu.mockGameContext.GetMode()); } + + TEST_METHOD(TestShowGameHashUnknownHashCancel) + { + IntegrationMenuViewModelHarness menu; + + menu.mockConsoleContext.SetId(ConsoleID::Arcade); + menu.mockGameContext.SetGameHash("ABCDEF0123456789"); + + bool bDialogShown = false; + menu.mockDesktop.ExpectWindow( + [&bDialogShown](ra::ui::viewmodels::UnknownGameViewModel& vmUnknown) { + bDialogShown = true; + + Assert::IsTrue(vmUnknown.IsSelectedGameEnabled()); + + return DialogResult::Cancel; + }); + + menu.ActivateMenuItem(IDM_RA_GETROMCHECKSUM); + + Assert::IsTrue(bDialogShown); + Assert::AreEqual(ra::data::context::GameContext::Mode::Normal, menu.mockGameContext.GetMode()); + Assert::AreEqual({ 0U }, menu.mockGameContext.GameId()); + } + + TEST_METHOD(TestShowGameHashUnknownHashAssociate) + { + IntegrationMenuViewModelHarness menu; + + menu.mockConsoleContext.SetId(ConsoleID::Arcade); + menu.mockGameContext.SetGameHash("ABCDEF0123456789"); + + bool bDialogShown = false; + menu.mockDesktop.ExpectWindow( + [&bDialogShown](ra::ui::viewmodels::UnknownGameViewModel& vmUnknown) { + bDialogShown = true; + + Assert::IsTrue(vmUnknown.IsSelectedGameEnabled()); + vmUnknown.SetSelectedGameId(523); + + return DialogResult::OK; + }); + + menu.ActivateMenuItem(IDM_RA_GETROMCHECKSUM); + + Assert::IsTrue(bDialogShown); + Assert::AreEqual(ra::data::context::GameContext::Mode::Normal, menu.mockGameContext.GetMode()); + Assert::AreEqual({ 523U }, menu.mockGameContext.GameId()); + Assert::IsTrue(menu.mockGameContext.WasLoaded()); + } + + TEST_METHOD(TestShowGameHashUnknownHashTestCompatibility) + { + IntegrationMenuViewModelHarness menu; + + menu.mockConsoleContext.SetId(ConsoleID::Arcade); + menu.mockGameContext.SetGameHash("ABCDEF0123456789"); + + bool bDialogShown = false; + menu.mockDesktop.ExpectWindow( + [&bDialogShown](ra::ui::viewmodels::UnknownGameViewModel& vmUnknown) { + bDialogShown = true; + + Assert::IsTrue(vmUnknown.IsSelectedGameEnabled()); + vmUnknown.SetSelectedGameId(523); + vmUnknown.SetTestMode(true); + + return DialogResult::OK; + }); + + menu.ActivateMenuItem(IDM_RA_GETROMCHECKSUM); + + Assert::IsTrue(bDialogShown); + Assert::AreEqual(ra::data::context::GameContext::Mode::CompatibilityTest, menu.mockGameContext.GetMode()); + Assert::AreEqual({ 523U }, menu.mockGameContext.GameId()); + Assert::IsTrue(menu.mockGameContext.WasLoaded()); + } }; } // namespace tests