[XAM/User] GetTitleId -> GetTitleData, check flags/titletype before adding to profile

This commit is contained in:
emoose 2019-12-26 01:35:38 +00:00 committed by illusion
parent e6172cdc28
commit b48c03ab32
4 changed files with 53 additions and 25 deletions

View File

@ -258,31 +258,46 @@ xdbf::GpdFile* UserProfile::SetTitleSpaData(const xdbf::SpaFile& spa_data) {
curr_title_id_ = 0;
curr_gpd_ = nullptr;
uint32_t spa_title = spa_data.GetTitleId();
xdbf::X_XDBF_XTHD_DATA title_data;
spa_data.GetTitleData(&title_data);
curr_title_id_ = spa_title;
curr_title_id_ = title_data.title_id;
std::vector<xdbf::Achievement> spa_achievements;
// TODO: let user choose locale?
spa_data.GetAchievements(spa_data.GetDefaultLocale(), &spa_achievements);
xdbf::TitlePlayed title_info;
bool title_included =
title_data.title_type == xdbf::X_XDBF_XTHD_DATA::TitleType::kFull ||
title_data.title_type == xdbf::X_XDBF_XTHD_DATA::TitleType::kDownload;
auto gpd = title_gpds_.find(spa_title);
if (title_data.flags &
(uint32_t)xdbf::X_XDBF_XTHD_DATA::Flags::kAlwaysIncludeInProfile) {
title_included = true;
}
if (title_data.flags &
(uint32_t)xdbf::X_XDBF_XTHD_DATA::Flags::kNeverIncludeInProfile) {
title_included = false;
}
// TODO: set title_included if 'owned' (license_mask check?)
xdbf::TitlePlayed title_info;
auto gpd = title_gpds_.find(title_data.title_id);
if (gpd != title_gpds_.end()) {
auto& title_gpd = (*gpd).second;
XELOGI("Loaded existing GPD for title %X", spa_title);
XELOGI("Loaded existing GPD for title %X", title_data.title_id);
bool always_update_title = false;
if (!dash_gpd_.GetTitle(spa_title, &title_info)) {
if (!dash_gpd_.GetTitle(title_data.title_id, &title_info)) {
assert_always();
XELOGE(
"GPD exists but is missing XbdfTitlePlayed entry? (this shouldn't be "
"happening!)");
// Try to work around it...
title_info.title_name = xe::to_wstring(spa_data.GetTitleName());
title_info.title_id = spa_title;
title_info.title_id = title_data.title_id;
title_info.achievements_possible = 0;
title_info.achievements_earned = 0;
title_info.gamerscore_total = 0;
@ -317,25 +332,27 @@ xdbf::GpdFile* UserProfile::SetTitleSpaData(const xdbf::SpaFile& spa_data) {
}
// Update dash with new title_info
if (title_included) {
dash_gpd_.UpdateTitle(title_info);
}
// Only write game GPD if achievements were updated
if (ach_updated) {
UpdateGpd(spa_title, title_gpd);
UpdateGpd(title_data.title_id, title_gpd);
}
UpdateGpd(kDashboardID, dash_gpd_);
} else {
// GPD not found... have to create it!
XELOGI("Creating new GPD for title %X", spa_title);
XELOGI("Creating new GPD for title %X", title_data.title_id);
title_info.title_name = xe::to_wstring(spa_data.GetTitleName());
title_info.title_id = spa_title;
title_info.title_id = title_data.title_id;
title_info.last_played = Clock::QueryHostSystemTime();
// Copy cheevos from SPA -> GPD
auto& title_gpd = dash_gpd_;
if (spa_title != kDashboardID) {
title_gpd = xdbf::GpdFile(spa_title);
if (title_data.title_id != kDashboardID) {
title_gpd = xdbf::GpdFile(title_data.title_id);
for (auto ach : spa_achievements) {
title_gpd.UpdateAchievement(ach);
@ -373,20 +390,22 @@ xdbf::GpdFile* UserProfile::SetTitleSpaData(const xdbf::SpaFile& spa_data) {
title_gpd.UpdateEntry(title_name_ent);
}
title_gpds_[spa_title] = title_gpd;
title_gpds_[title_data.title_id] = title_gpd;
// Update dash GPD with title and write updated GPDs
if (spa_title != kDashboardID) {
title_gpds_[spa_title] = title_gpd;
if (title_data.title_id != kDashboardID) {
title_gpds_[title_data.title_id] = title_gpd;
if (title_included) {
dash_gpd_.UpdateTitle(title_info);
UpdateGpd(spa_title, title_gpds_[spa_title]);
}
UpdateGpd(title_data.title_id, title_gpds_[title_data.title_id]);
}
UpdateGpd(kDashboardID, dash_gpd_);
}
if (spa_title != kDashboardID) {
curr_gpd_ = &title_gpds_[spa_title];
if (title_data.title_id != kDashboardID) {
curr_gpd_ = &title_gpds_[title_data.title_id];
} else {
curr_gpd_ = &dash_gpd_;
}

View File

@ -258,17 +258,20 @@ std::string SpaFile::GetTitleName() const {
static_cast<uint16_t>(SpaID::Title));
}
uint32_t SpaFile::GetTitleId() const {
bool SpaFile::GetTitleData(X_XDBF_XTHD_DATA* title_data) const {
auto block = GetEntry(static_cast<uint16_t>(SpaSection::kMetadata),
static_cast<uint64_t>(SpaID::Xthd));
if (!block) {
return -1;
return false;
}
auto xthd = reinterpret_cast<const X_XDBF_XTHD_DATA*>(block->data.data());
assert_true(xthd->header.magic == static_cast<uint32_t>(SpaID::Xthd));
return xthd->title_id;
if (title_data) {
*title_data = *xthd;
}
return true;
}
bool GpdFile::GetAchievement(uint16_t id, Achievement* dest) {

View File

@ -359,7 +359,7 @@ class SpaFile : public XdbfFile {
Entry* GetIcon() const;
Locale GetDefaultLocale() const;
std::string GetTitleName() const;
uint32_t GetTitleId() const;
bool GetTitleData(X_XDBF_XTHD_DATA* title_data) const;
};
class GpdFile : public XdbfFile {

View File

@ -62,13 +62,19 @@ struct X_XDBF_XSTC_DATA {
static_assert_size(X_XDBF_XSTC_DATA, 16);
struct X_XDBF_XTHD_DATA {
enum class TitleType : uint32_t {
kSystem = 0,
kFull = 1,
kDemo = 2,
kDownload = 3,
};
enum class Flags {
kAlwaysIncludeInProfile = 1,
kNeverIncludeInProfile = 2,
};
X_XDBF_SECTION_HEADER header;
xe::be<uint32_t> title_id;
xe::be<uint32_t> title_type;
xe::be<TitleType> title_type;
xe::be<uint16_t> title_version_major;
xe::be<uint16_t> title_version_minor;
xe::be<uint16_t> title_version_build;