Skip to content

Commit

Permalink
use published achievement trigger when reverting (#1106)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamiras authored Jul 27, 2024
1 parent 809f1b6 commit d720bed
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/data/models/AchievementModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,15 @@ void AchievementModel::SyncTrigger()
m_pAchievement->trigger = nullptr;
}

const auto* pPublishedAchievementInfo = pRuntime.GetPublishedAchievementInfo(m_pAchievement->public_.id);
if (pPublishedAchievementInfo && memcmp(pPublishedAchievementInfo->md5, md5, sizeof(md5)) == 0)
{
Expects(pPublishedAchievementInfo->trigger != nullptr);
m_pAchievement->trigger = pPublishedAchievementInfo->trigger;
rc_reset_trigger(m_pAchievement->trigger);
return;
}

const auto nSize = rc_trigger_size(sTrigger.c_str());
if (nSize > 0)
{
Expand Down
9 changes: 9 additions & 0 deletions src/data/models/LeaderboardModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,15 @@ void LeaderboardModel::SyncDefinition()
m_pLeaderboard->lboard = nullptr;
}

const auto* pPublishedLeaderboardInfo = pRuntime.GetPublishedLeaderboardInfo(m_pLeaderboard->public_.id);
if (pPublishedLeaderboardInfo && memcmp(pPublishedLeaderboardInfo->md5, md5, sizeof(md5)) == 0)
{
Expects(pPublishedLeaderboardInfo->lboard != nullptr);
m_pLeaderboard->lboard = pPublishedLeaderboardInfo->lboard;
rc_reset_lboard(m_pLeaderboard->lboard);
return;
}

const auto nSize = rc_lboard_size(sMemAddr.c_str());
if (nSize > 0)
{
Expand Down
39 changes: 39 additions & 0 deletions src/services/AchievementRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,29 @@ class AchievementRuntime::ClientSynchronizer
return DetachMemory(m_pSubsetWrapper->vAllocatedMemory, pMemory);
}

const rc_client_achievement_info_t* GetPublishedAchievementInfo(ra::AchievementID nId) const
{
for (auto* pSubset = m_pPublishedSubset; pSubset; pSubset = pSubset->next)
{
const auto* pAchievement = FindAchievement(pSubset, nId);
if (pAchievement != nullptr)
return pAchievement;
}

return nullptr;
}

const rc_client_leaderboard_info_t* GetPublishedLeaderboardInfo(ra::LeaderboardID nId) const
{
for (auto* pSubset = m_pPublishedSubset; pSubset; pSubset = pSubset->next)
{
const auto* pLeaderboard = FindLeaderboard(pSubset, nId);
if (pLeaderboard != nullptr)
return pLeaderboard;
}

return nullptr;
}
};

void AchievementRuntime::SyncAssets()
Expand Down Expand Up @@ -850,6 +873,22 @@ rc_trigger_t* AchievementRuntime::GetAchievementTrigger(ra::AchievementID nId) c
return (achievement != nullptr) ? achievement->trigger : nullptr;
}

const rc_client_achievement_info_t* AchievementRuntime::GetPublishedAchievementInfo(ra::AchievementID nId) const
{
if (m_pClientSynchronizer != nullptr)
return m_pClientSynchronizer->GetPublishedAchievementInfo(nId);

return nullptr;
}

const rc_client_leaderboard_info_t* AchievementRuntime::GetPublishedLeaderboardInfo(ra::LeaderboardID nId) const
{
if (m_pClientSynchronizer != nullptr)
return m_pClientSynchronizer->GetPublishedLeaderboardInfo(nId);

return nullptr;
}

std::string AchievementRuntime::GetAchievementBadge(const rc_client_achievement_t& pAchievement)
{
std::string sBadgeName = pAchievement.badge_name;
Expand Down
2 changes: 2 additions & 0 deletions src/services/AchievementRuntime.hh
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public:
/// Gets the raw trigger for the achievement.
/// </summary>
rc_trigger_t* GetAchievementTrigger(ra::AchievementID nId) const noexcept;
const rc_client_achievement_info_t* GetPublishedAchievementInfo(ra::AchievementID nId) const;

static std::string GetAchievementBadge(const rc_client_achievement_t& pAchievement);

Expand All @@ -75,6 +76,7 @@ public:
/// Gets the raw definition for the leaderboard.
/// </summary>
rc_lboard_t* GetLeaderboardDefinition(ra::LeaderboardID nId) const noexcept;
const rc_client_leaderboard_info_t* GetPublishedLeaderboardInfo(ra::LeaderboardID nId) const;

void ReleaseLeaderboardTracker(ra::LeaderboardID nId) noexcept;

Expand Down
59 changes: 59 additions & 0 deletions tests/services/AchievementRuntime_Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,65 @@ TEST_CLASS(AchievementRuntime_Tests)
Assert::AreNotEqual(static_cast<const void*>(pNewerTrigger), static_cast<const void*>(pNewestTrigger));
}

TEST_METHOD(TestSyncAssetsModifiedCoreAchievement)
{
AchievementRuntimeHarness runtime;
runtime.MockGame();

auto* pAchievement = runtime.MockAchievement(12345U, "0xH0000=1");
pAchievement->public_.category = gsl::narrow_cast<uint8_t>(ra::etoi(ra::data::models::AssetCategory::Core));
pAchievement->public_.title = "Achievement Name";
pAchievement->public_.description = "Do something cool";
pAchievement->public_.points = 25;

auto vmNewAchievement = std::make_unique<ra::data::models::AchievementModel>();
vmNewAchievement->Attach(*pAchievement, ra::data::models::AssetCategory::Core, "0xH0000=1");
auto& vmAchievement = reinterpret_cast<ra::data::models::AchievementModel&>(runtime.mockGameContext.Assets().Append(std::move(vmNewAchievement)));

// SyncAssets should generate the core subset
runtime.SyncAssets();

auto* pSubset = runtime.GetClient()->game->subsets;
Expects(pSubset != nullptr);
Assert::AreEqual("Game Title", pSubset->public_.title);
Assert::AreEqual(1U, pSubset->public_.id);
Assert::AreEqual("012345", pSubset->public_.badge_name);
Assert::AreEqual(1U, pSubset->public_.num_achievements);
Assert::IsTrue(pSubset->active);
Assert::IsNull(pSubset->next);
const auto* pOriginalTrigger = pSubset->achievements->trigger;

Assert::AreEqual(std::wstring(L"Achievement Name"), vmAchievement.GetName());
Assert::AreEqual(std::wstring(L"Do something cool"), vmAchievement.GetDescription());
Assert::AreEqual(25, vmAchievement.GetPoints());
Assert::AreEqual(12345U, vmAchievement.GetID());
Assert::IsNotNull(pAchievement->trigger);

// directly modifying the achievement trigger should rebuild the underlying trigger
runtime.mockGameContext.Assets().FindAchievement(12345U)->SetTrigger("0xH0000=99"); // force memref allocation
runtime.mockGameContext.Assets().FindAchievement(12345U)->SetTrigger("0xH0000=2"); // no memref allocation, can be freed
Assert::IsNotNull(pAchievement->trigger);
const auto* pNewTrigger = pSubset->achievements->trigger;
Assert::AreNotEqual(static_cast<const void*>(pOriginalTrigger), static_cast<const void*>(pNewTrigger));

runtime.SyncAssets();

pSubset = runtime.GetClient()->game->subsets;
const auto* pNewerTrigger = pSubset->achievements->trigger;
Assert::AreEqual(static_cast<const void*>(pNewerTrigger), static_cast<const void*>(pNewTrigger));
Assert::IsNull(pNewerTrigger->alternative); // simple check to make sure memory is valid - debug build will fill freed memory with 0xDD

// revert to the original definition - original trigger should be used
runtime.mockGameContext.Assets().FindAchievement(12345U)->RestoreServerCheckpoint();

runtime.SyncAssets();

pSubset = runtime.GetClient()->game->subsets;
const auto* pNewestTrigger = pSubset->achievements->trigger;
Assert::AreNotEqual(static_cast<const void*>(pNewerTrigger), static_cast<const void*>(pNewestTrigger));
Assert::AreEqual(static_cast<const void*>(pOriginalTrigger), static_cast<const void*>(pNewestTrigger));
}

TEST_METHOD(TestDoFrameTriggerAchievement)
{
std::array<unsigned char, 1> memory{ 0x00 };
Expand Down

0 comments on commit d720bed

Please sign in to comment.