[Kernel] Split achievements backends from manager and interface
This commit is contained in:
parent
45332299b2
commit
e8a92c1073
|
@ -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<std::u16string>(
|
||||||
|
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<uint32_t>(AchievementFlags::kAchieved) |
|
||||||
|
static_cast<uint32_t>(AchievementFlags::kAchievedOnline);
|
||||||
|
achievement->unlock_time.high_part = static_cast<uint32_t>(unlock_time >> 32);
|
||||||
|
achievement->unlock_time.low_part = static_cast<uint32_t>(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<uint32_t>(AchievementFlags::kAchieved)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<AchievementGpdStructure>*
|
||||||
|
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<XLanguage>(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
|
|
@ -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 <map>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#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<AchievementGpdStructure>* 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_
|
|
@ -12,6 +12,7 @@
|
||||||
#include "xenia/gpu/graphics_system.h"
|
#include "xenia/gpu/graphics_system.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
#include "xenia/kernel/util/shim_utils.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"
|
#include "xenia/ui/imgui_guest_notification.h"
|
||||||
|
|
||||||
DEFINE_bool(show_achievement_notification, false,
|
DEFINE_bool(show_achievement_notification, false,
|
||||||
|
@ -29,115 +30,6 @@ namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace xam {
|
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<std::u16string>(
|
|
||||||
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<uint32_t>(AchievementFlags::kAchieved) |
|
|
||||||
static_cast<uint32_t>(AchievementFlags::kAchievedOnline);
|
|
||||||
achievement->unlock_time.high_part = static_cast<uint32_t>(unlock_time >> 32);
|
|
||||||
achievement->unlock_time.low_part = static_cast<uint32_t>(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<uint32_t>(AchievementFlags::kAchieved)) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<AchievementGpdStructure>*
|
|
||||||
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<XLanguage>(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() {
|
AchievementManager::AchievementManager() {
|
||||||
default_achievements_backend_ = std::make_unique<GpdAchievementBackend>();
|
default_achievements_backend_ = std::make_unique<GpdAchievementBackend>();
|
||||||
|
|
||||||
|
|
|
@ -149,36 +149,6 @@ class AchievementBackendInterface {
|
||||||
const uint32_t achievement_id) = 0;
|
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<AchievementGpdStructure>* 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 {
|
class AchievementManager {
|
||||||
public:
|
public:
|
||||||
AchievementManager();
|
AchievementManager();
|
||||||
|
|
Loading…
Reference in New Issue