From e8a92c1073ce54269457c0ebd2a22ed390027979 Mon Sep 17 00:00:00 2001 From: Gliniak Date: Sat, 14 Dec 2024 18:32:53 +0100 Subject: [PATCH] [Kernel] Split achievements backends from manager and interface --- .../gpd_achievement_backend.cc | 131 ++++++++++++++++++ .../gpd_achievement_backend.h | 60 ++++++++ src/xenia/kernel/xam/achievement_manager.cc | 110 +-------------- src/xenia/kernel/xam/achievement_manager.h | 30 ---- 4 files changed, 192 insertions(+), 139 deletions(-) create mode 100644 src/xenia/kernel/xam/achievement_backends/gpd_achievement_backend.cc create mode 100644 src/xenia/kernel/xam/achievement_backends/gpd_achievement_backend.h diff --git a/src/xenia/kernel/xam/achievement_backends/gpd_achievement_backend.cc b/src/xenia/kernel/xam/achievement_backends/gpd_achievement_backend.cc new file mode 100644 index 000000000..8cbc1a37e --- /dev/null +++ b/src/xenia/kernel/xam/achievement_backends/gpd_achievement_backend.cc @@ -0,0 +1,131 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2024 Xenia Canary. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/kernel/xam/achievement_backends/gpd_achievement_backend.h" +#include "xenia/kernel/kernel_state.h" +#include "xenia/kernel/util/shim_utils.h" + +DECLARE_int32(user_language); + +namespace xe { +namespace kernel { +namespace xam { + +GpdAchievementBackend::GpdAchievementBackend() {} +GpdAchievementBackend::~GpdAchievementBackend() {} + +void GpdAchievementBackend::EarnAchievement(const uint64_t xuid, + const uint32_t title_id, + const uint32_t achievement_id) { + const auto user = kernel_state()->xam_state()->GetUserProfile(xuid); + if (!user) { + return; + } + + auto achievement = GetAchievementInfoInternal(xuid, title_id, achievement_id); + if (!achievement) { + return; + } + + XELOGI("Player: {} Unlocked Achievement: {}", user->name(), + xe::to_utf8(xe::load_and_swap( + achievement->achievement_name.c_str()))); + + const uint64_t unlock_time = Clock::QueryHostSystemTime(); + // We're adding achieved online flag because on console locally achieved + // entries don't have valid unlock time. + achievement->flags = achievement->flags | + static_cast(AchievementFlags::kAchieved) | + static_cast(AchievementFlags::kAchievedOnline); + achievement->unlock_time.high_part = static_cast(unlock_time >> 32); + achievement->unlock_time.low_part = static_cast(unlock_time); + + SaveAchievementData(xuid, title_id, achievement_id); +} + +AchievementGpdStructure* GpdAchievementBackend::GetAchievementInfoInternal( + const uint64_t xuid, const uint32_t title_id, + const uint32_t achievement_id) const { + const auto user = kernel_state()->xam_state()->GetUserProfile(xuid); + if (!user) { + return nullptr; + } + + return user->GetAchievement(title_id, achievement_id); +} + +const AchievementGpdStructure* GpdAchievementBackend::GetAchievementInfo( + const uint64_t xuid, const uint32_t title_id, + const uint32_t achievement_id) const { + return GetAchievementInfoInternal(xuid, title_id, achievement_id); +} + +bool GpdAchievementBackend::IsAchievementUnlocked( + const uint64_t xuid, const uint32_t title_id, + const uint32_t achievement_id) const { + const auto achievement = + GetAchievementInfoInternal(xuid, title_id, achievement_id); + + return (achievement->flags & + static_cast(AchievementFlags::kAchieved)) != 0; +} + +const std::vector* +GpdAchievementBackend::GetTitleAchievements(const uint64_t xuid, + const uint32_t title_id) const { + const auto user = kernel_state()->xam_state()->GetUserProfile(xuid); + if (!user) { + return {}; + } + + return user->GetTitleAchievements(title_id); +} + +bool GpdAchievementBackend::LoadAchievementsData( + const uint64_t xuid, const util::XdbfGameData title_data) { + auto user = kernel_state()->xam_state()->GetUserProfile(xuid); + if (!user) { + return false; + } + + // Question. Should loading for GPD for profile be directly done by profile or + // here? + if (!title_data.is_valid()) { + return false; + } + + const auto achievements = title_data.GetAchievements(); + if (achievements.empty()) { + return true; + } + + const auto title_id = title_data.GetTitleInformation().title_id; + + const XLanguage title_language = title_data.GetExistingLanguage( + static_cast(cvars::user_language)); + for (const auto& achievement : achievements) { + AchievementGpdStructure achievementData(title_language, title_data, + achievement); + user->achievements_[title_id].push_back(achievementData); + } + + // TODO(Gliniak): Here should be loader of GPD file for loaded title. That way + // we can load flags and unlock_time from specific user. + return true; +} + +bool GpdAchievementBackend::SaveAchievementData(const uint64_t xuid, + const uint32_t title_id, + const uint32_t achievement_id) { + return true; +} + +} // namespace xam +} // namespace kernel +} // namespace xe diff --git a/src/xenia/kernel/xam/achievement_backends/gpd_achievement_backend.h b/src/xenia/kernel/xam/achievement_backends/gpd_achievement_backend.h new file mode 100644 index 000000000..6c572f121 --- /dev/null +++ b/src/xenia/kernel/xam/achievement_backends/gpd_achievement_backend.h @@ -0,0 +1,60 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2024 Xenia Canary. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_XAM_ACHIEVEMENT_BACKENDS_GPD_ACHIEVEMENT_BACKEND_H_ +#define XENIA_KERNEL_XAM_ACHIEVEMENT_BACKENDS_GPD_ACHIEVEMENT_BACKEND_H_ + +#include +#include +#include +#include + +#include "xenia/kernel/util/xdbf_utils.h" +#include "xenia/kernel/xam/achievement_manager.h" +#include "xenia/xbox.h" + +namespace xe { +namespace kernel { +namespace xam { + +class GpdAchievementBackend : public AchievementBackendInterface { + public: + GpdAchievementBackend(); + ~GpdAchievementBackend(); + + void EarnAchievement(const uint64_t xuid, const uint32_t title_id, + const uint32_t achievement_id) override; + bool IsAchievementUnlocked(const uint64_t xuid, const uint32_t title_id, + const uint32_t achievement_id) const override; + const AchievementGpdStructure* GetAchievementInfo( + const uint64_t xuid, const uint32_t title_id, + const uint32_t achievement_id) const override; + const std::vector* GetTitleAchievements( + const uint64_t xuid, const uint32_t title_id) const override; + bool LoadAchievementsData(const uint64_t xuid, + const util::XdbfGameData title_data) override; + + private: + AchievementGpdStructure* GetAchievementInfoInternal( + const uint64_t xuid, const uint32_t title_id, + const uint32_t achievement_id) const; + + bool SaveAchievementsData(const uint64_t xuid, + const uint32_t title_id) override { + return 0; + }; + bool SaveAchievementData(const uint64_t xuid, const uint32_t title_id, + const uint32_t achievement_id) override; +}; + +} // namespace xam +} // namespace kernel +} // namespace xe + +#endif // XENIA_KERNEL_XAM_ACHIEVEMENT_BACKENDS_GPD_ACHIEVEMENT_BACKEND_H_ diff --git a/src/xenia/kernel/xam/achievement_manager.cc b/src/xenia/kernel/xam/achievement_manager.cc index 07ce9b54d..79b807e68 100644 --- a/src/xenia/kernel/xam/achievement_manager.cc +++ b/src/xenia/kernel/xam/achievement_manager.cc @@ -12,6 +12,7 @@ #include "xenia/gpu/graphics_system.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" +#include "xenia/kernel/xam/achievement_backends/gpd_achievement_backend.h" #include "xenia/ui/imgui_guest_notification.h" DEFINE_bool(show_achievement_notification, false, @@ -29,115 +30,6 @@ namespace xe { namespace kernel { namespace xam { -GpdAchievementBackend::GpdAchievementBackend() {} -GpdAchievementBackend::~GpdAchievementBackend() {} - -void GpdAchievementBackend::EarnAchievement(const uint64_t xuid, - const uint32_t title_id, - const uint32_t achievement_id) { - const auto user = kernel_state()->xam_state()->GetUserProfile(xuid); - if (!user) { - return; - } - - auto achievement = GetAchievementInfoInternal(xuid, title_id, achievement_id); - if (!achievement) { - return; - } - - XELOGI("Player: {} Unlocked Achievement: {}", user->name(), - xe::to_utf8(xe::load_and_swap( - achievement->achievement_name.c_str()))); - - const uint64_t unlock_time = Clock::QueryHostSystemTime(); - // We're adding achieved online flag because on console locally achieved - // entries don't have valid unlock time. - achievement->flags = achievement->flags | - static_cast(AchievementFlags::kAchieved) | - static_cast(AchievementFlags::kAchievedOnline); - achievement->unlock_time.high_part = static_cast(unlock_time >> 32); - achievement->unlock_time.low_part = static_cast(unlock_time); - - SaveAchievementData(xuid, title_id, achievement_id); -} - -AchievementGpdStructure* GpdAchievementBackend::GetAchievementInfoInternal( - const uint64_t xuid, const uint32_t title_id, - const uint32_t achievement_id) const { - const auto user = kernel_state()->xam_state()->GetUserProfile(xuid); - if (!user) { - return nullptr; - } - - return user->GetAchievement(title_id, achievement_id); -} - -const AchievementGpdStructure* GpdAchievementBackend::GetAchievementInfo( - const uint64_t xuid, const uint32_t title_id, - const uint32_t achievement_id) const { - return GetAchievementInfoInternal(xuid, title_id, achievement_id); -} - -bool GpdAchievementBackend::IsAchievementUnlocked( - const uint64_t xuid, const uint32_t title_id, - const uint32_t achievement_id) const { - const auto achievement = - GetAchievementInfoInternal(xuid, title_id, achievement_id); - - return (achievement->flags & - static_cast(AchievementFlags::kAchieved)) != 0; -} - -const std::vector* -GpdAchievementBackend::GetTitleAchievements(const uint64_t xuid, - const uint32_t title_id) const { - const auto user = kernel_state()->xam_state()->GetUserProfile(xuid); - if (!user) { - return {}; - } - - return user->GetTitleAchievements(title_id); -} - -bool GpdAchievementBackend::LoadAchievementsData( - const uint64_t xuid, const util::XdbfGameData title_data) { - auto user = kernel_state()->xam_state()->GetUserProfile(xuid); - if (!user) { - return false; - } - - // Question. Should loading for GPD for profile be directly done by profile or - // here? - if (!title_data.is_valid()) { - return false; - } - - const auto achievements = title_data.GetAchievements(); - if (achievements.empty()) { - return true; - } - - const auto title_id = title_data.GetTitleInformation().title_id; - - const XLanguage title_language = title_data.GetExistingLanguage( - static_cast(cvars::user_language)); - for (const auto& achievement : achievements) { - AchievementGpdStructure achievementData(title_language, title_data, - achievement); - user->achievements_[title_id].push_back(achievementData); - } - - // TODO(Gliniak): Here should be loader of GPD file for loaded title. That way - // we can load flags and unlock_time from specific user. - return true; -} - -bool GpdAchievementBackend::SaveAchievementData(const uint64_t xuid, - const uint32_t title_id, - const uint32_t achievement_id) { - return true; -} - AchievementManager::AchievementManager() { default_achievements_backend_ = std::make_unique(); diff --git a/src/xenia/kernel/xam/achievement_manager.h b/src/xenia/kernel/xam/achievement_manager.h index 037b9c879..5790870a0 100644 --- a/src/xenia/kernel/xam/achievement_manager.h +++ b/src/xenia/kernel/xam/achievement_manager.h @@ -149,36 +149,6 @@ class AchievementBackendInterface { const uint32_t achievement_id) = 0; }; -class GpdAchievementBackend : public AchievementBackendInterface { - public: - GpdAchievementBackend(); - ~GpdAchievementBackend(); - - void EarnAchievement(const uint64_t xuid, const uint32_t title_id, - const uint32_t achievement_id) override; - bool IsAchievementUnlocked(const uint64_t xuid, const uint32_t title_id, - const uint32_t achievement_id) const override; - const AchievementGpdStructure* GetAchievementInfo( - const uint64_t xuid, const uint32_t title_id, - const uint32_t achievement_id) const override; - const std::vector* GetTitleAchievements( - const uint64_t xuid, const uint32_t title_id) const override; - bool LoadAchievementsData(const uint64_t xuid, - const util::XdbfGameData title_data) override; - - private: - AchievementGpdStructure* GetAchievementInfoInternal( - const uint64_t xuid, const uint32_t title_id, - const uint32_t achievement_id) const; - - bool SaveAchievementsData(const uint64_t xuid, - const uint32_t title_id) override { - return 0; - }; - bool SaveAchievementData(const uint64_t xuid, const uint32_t title_id, - const uint32_t achievement_id) override; -}; - class AchievementManager { public: AchievementManager();