Files
Xenia-Canary/src/xenia/kernel/xam/achievement_manager.cc

164 lines
5.4 KiB
C++

/**
******************************************************************************
* 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_manager.h"
#include "xenia/emulator.h"
#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,
"Show achievement notification on screen.", "UI");
DEFINE_string(
default_achievements_backend, "GPD",
"Defines which achievements backend should be used as an default. "
"Possible options: GPD.",
"Kernel");
DECLARE_int32(user_language);
namespace xe {
namespace kernel {
namespace xam {
AchievementManager::AchievementManager() {
default_achievements_backend_ = std::make_unique<GpdAchievementBackend>();
// Add any optional backend here.
};
void AchievementManager::EarnAchievement(const uint32_t user_index,
const uint32_t title_id,
const uint32_t achievement_id) const {
const auto user = kernel_state()->xam_state()->GetUserProfile(user_index);
if (!user) {
return;
}
EarnAchievement(user->xuid(), title_id, achievement_id);
};
void AchievementManager::EarnAchievement(const uint64_t xuid,
const uint32_t title_id,
const uint32_t achievement_id) const {
if (!DoesAchievementExist(achievement_id)) {
XELOGW(
"{}: Achievement with ID: {} for title: {:08X} doesn't exist in "
"database!",
__func__, achievement_id, title_id);
return;
}
// Always send request to unlock in 3PP backends. It's up to them to check if
// achievement was unlocked
for (auto& backend : achievement_backends_) {
backend->EarnAchievement(xuid, title_id, achievement_id);
}
if (default_achievements_backend_->IsAchievementUnlocked(xuid, title_id,
achievement_id)) {
return;
}
default_achievements_backend_->EarnAchievement(xuid, title_id,
achievement_id);
if (!cvars::show_achievement_notification) {
return;
}
const auto achievement = default_achievements_backend_->GetAchievementInfo(
xuid, title_id, achievement_id);
if (!achievement) {
// Something went really wrong!
return;
}
ShowAchievementEarnedNotification(achievement);
}
void AchievementManager::LoadTitleAchievements(
const uint64_t xuid, const util::XdbfGameData title_data) const {
default_achievements_backend_->LoadAchievementsData(xuid, title_data);
}
const AchievementGpdStructure* AchievementManager::GetAchievementInfo(
const uint64_t xuid, const uint32_t title_id,
const uint32_t achievement_id) const {
return default_achievements_backend_->GetAchievementInfo(xuid, title_id,
achievement_id);
}
const std::vector<AchievementGpdStructure>*
AchievementManager::GetTitleAchievements(const uint64_t xuid,
const uint32_t title_id) const {
return default_achievements_backend_->GetTitleAchievements(xuid, title_id);
}
const std::optional<TitleAchievementsProfileInfo>
AchievementManager::GetTitleAchievementsInfo(const uint64_t xuid,
const uint32_t title_id) const {
TitleAchievementsProfileInfo info = {};
const auto achievements = GetTitleAchievements(xuid, title_id);
if (!achievements) {
return std::nullopt;
}
info.achievements_count = static_cast<uint32_t>(achievements->size());
for (const auto& entry : *achievements) {
if (!entry.IsUnlocked()) {
continue;
}
info.unlocked_achievements_count++;
info.gamerscore += entry.gamerscore;
}
return info;
}
bool AchievementManager::DoesAchievementExist(
const uint32_t achievement_id) const {
const util::XdbfGameData title_xdbf = kernel_state()->title_xdbf();
const util::XdbfAchievementTableEntry achievement =
title_xdbf.GetAchievement(achievement_id);
if (!achievement.id) {
return false;
}
return true;
}
void AchievementManager::ShowAchievementEarnedNotification(
const AchievementGpdStructure* achievement) const {
const std::string description =
fmt::format("{}G - {}", achievement->gamerscore.get(),
xe::to_utf8(xe::load_and_swap<std::u16string>(
achievement->achievement_name.c_str())));
const Emulator* emulator = kernel_state()->emulator();
ui::WindowedAppContext& app_context =
emulator->display_window()->app_context();
ui::ImGuiDrawer* imgui_drawer = emulator->imgui_drawer();
app_context.CallInUIThread([imgui_drawer, description]() {
new xe::ui::AchievementNotificationWindow(
imgui_drawer, "Achievement unlocked", description, 0,
kernel_state()->notification_position_);
});
}
} // namespace xam
} // namespace kernel
} // namespace xe