diff --git a/src/xenia/kernel/achievement_manager.cc b/src/xenia/kernel/achievement_manager.cc index e58965b84..e16571e06 100644 --- a/src/xenia/kernel/achievement_manager.cc +++ b/src/xenia/kernel/achievement_manager.cc @@ -22,10 +22,14 @@ DECLARE_int32(user_language); namespace xe { namespace kernel { -AchievementManager::AchievementManager(){}; +AchievementManager::AchievementManager() { unlocked_achievements.clear(); }; void AchievementManager::EarnAchievement(uint64_t xuid, uint32_t title_id, uint32_t achievement_id) { + if (IsAchievementUnlocked(achievement_id)) { + return; + } + const Emulator* emulator = kernel_state()->emulator(); ui::WindowedAppContext& app_context = kernel_state()->emulator()->display_window()->app_context(); @@ -48,6 +52,7 @@ void AchievementManager::EarnAchievement(uint64_t xuid, uint32_t title_id, const std::string description = fmt::format("{}G - {}", entry.gamerscore, label); + unlocked_achievements[achievement_id] = Clock::QueryHostSystemTime(); // Even if we disable popup we still should store info that this // achievement was earned. if (!cvars::show_achievement_notification) { @@ -63,5 +68,20 @@ void AchievementManager::EarnAchievement(uint64_t xuid, uint32_t title_id, } } +bool AchievementManager::IsAchievementUnlocked(uint32_t achievement_id) { + auto itr = unlocked_achievements.find(achievement_id); + + return itr != unlocked_achievements.cend(); +} + +uint64_t AchievementManager::GetAchievementUnlockTime(uint32_t achievement_id) { + auto itr = unlocked_achievements.find(achievement_id); + if (itr == unlocked_achievements.cend()) { + return 0; + } + + return itr->second; +} + } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/achievement_manager.h b/src/xenia/kernel/achievement_manager.h index 43ee5b59c..b425558cb 100644 --- a/src/xenia/kernel/achievement_manager.h +++ b/src/xenia/kernel/achievement_manager.h @@ -10,6 +10,7 @@ #ifndef XENIA_KERNEL_ACHIEVEMENT_MANAGER_H_ #define XENIA_KERNEL_ACHIEVEMENT_MANAGER_H_ +#include #include #include @@ -25,7 +26,11 @@ class AchievementManager { void EarnAchievement(uint64_t xuid, uint32_t title_id, uint32_t achievement_id); + bool IsAchievementUnlocked(uint32_t achievement_id); + uint64_t GetAchievementUnlockTime(uint32_t achievement_id); + private: + std::map unlocked_achievements; // void Load(); // void Save(); }; diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index 3dd5a5d82..60795787f 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -728,6 +728,13 @@ dword_result_t XamUserCreateAchievementEnumerator_entry( db.GetAchievements(); for (const util::XdbfAchievementTableEntry& entry : achievement_list) { + auto is_unlocked = + kernel_state()->achievement_manager()->IsAchievementUnlocked( + entry.id); + auto unlock_time = + kernel_state()->achievement_manager()->GetAchievementUnlockTime( + entry.id); + auto item = XStaticAchievementEnumerator::AchievementDetails{ entry.id, xe::to_utf16(db.GetStringTableEntry(language, entry.label_id)), @@ -735,8 +742,9 @@ dword_result_t XamUserCreateAchievementEnumerator_entry( xe::to_utf16(db.GetStringTableEntry(language, entry.unachieved_id)), entry.image_id, entry.gamerscore, - {0, 0}, - entry.flags}; + (uint32_t)(unlock_time << 31), + (uint32_t)unlock_time, + is_unlocked ? entry.flags | 0x20000 : entry.flags}; e->AppendItem(item); }