[XAM/User] GetTitleId -> GetTitleData, check flags/titletype before adding to profile
This commit is contained in:
parent
e6172cdc28
commit
b48c03ab32
|
@ -258,31 +258,46 @@ xdbf::GpdFile* UserProfile::SetTitleSpaData(const xdbf::SpaFile& spa_data) {
|
||||||
curr_title_id_ = 0;
|
curr_title_id_ = 0;
|
||||||
curr_gpd_ = nullptr;
|
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;
|
std::vector<xdbf::Achievement> spa_achievements;
|
||||||
// TODO: let user choose locale?
|
// TODO: let user choose locale?
|
||||||
spa_data.GetAchievements(spa_data.GetDefaultLocale(), &spa_achievements);
|
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()) {
|
if (gpd != title_gpds_.end()) {
|
||||||
auto& title_gpd = (*gpd).second;
|
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;
|
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();
|
assert_always();
|
||||||
XELOGE(
|
XELOGE(
|
||||||
"GPD exists but is missing XbdfTitlePlayed entry? (this shouldn't be "
|
"GPD exists but is missing XbdfTitlePlayed entry? (this shouldn't be "
|
||||||
"happening!)");
|
"happening!)");
|
||||||
// Try to work around it...
|
// Try to work around it...
|
||||||
title_info.title_name = xe::to_wstring(spa_data.GetTitleName());
|
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_possible = 0;
|
||||||
title_info.achievements_earned = 0;
|
title_info.achievements_earned = 0;
|
||||||
title_info.gamerscore_total = 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
|
// Update dash with new title_info
|
||||||
dash_gpd_.UpdateTitle(title_info);
|
if (title_included) {
|
||||||
|
dash_gpd_.UpdateTitle(title_info);
|
||||||
|
}
|
||||||
|
|
||||||
// Only write game GPD if achievements were updated
|
// Only write game GPD if achievements were updated
|
||||||
if (ach_updated) {
|
if (ach_updated) {
|
||||||
UpdateGpd(spa_title, title_gpd);
|
UpdateGpd(title_data.title_id, title_gpd);
|
||||||
}
|
}
|
||||||
UpdateGpd(kDashboardID, dash_gpd_);
|
UpdateGpd(kDashboardID, dash_gpd_);
|
||||||
} else {
|
} else {
|
||||||
// GPD not found... have to create it!
|
// 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_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();
|
title_info.last_played = Clock::QueryHostSystemTime();
|
||||||
|
|
||||||
// Copy cheevos from SPA -> GPD
|
// Copy cheevos from SPA -> GPD
|
||||||
auto& title_gpd = dash_gpd_;
|
auto& title_gpd = dash_gpd_;
|
||||||
if (spa_title != kDashboardID) {
|
if (title_data.title_id != kDashboardID) {
|
||||||
title_gpd = xdbf::GpdFile(spa_title);
|
title_gpd = xdbf::GpdFile(title_data.title_id);
|
||||||
for (auto ach : spa_achievements) {
|
for (auto ach : spa_achievements) {
|
||||||
title_gpd.UpdateAchievement(ach);
|
title_gpd.UpdateAchievement(ach);
|
||||||
|
|
||||||
|
@ -373,20 +390,22 @@ xdbf::GpdFile* UserProfile::SetTitleSpaData(const xdbf::SpaFile& spa_data) {
|
||||||
title_gpd.UpdateEntry(title_name_ent);
|
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
|
// Update dash GPD with title and write updated GPDs
|
||||||
if (spa_title != kDashboardID) {
|
if (title_data.title_id != kDashboardID) {
|
||||||
title_gpds_[spa_title] = title_gpd;
|
title_gpds_[title_data.title_id] = title_gpd;
|
||||||
dash_gpd_.UpdateTitle(title_info);
|
if (title_included) {
|
||||||
UpdateGpd(spa_title, title_gpds_[spa_title]);
|
dash_gpd_.UpdateTitle(title_info);
|
||||||
|
}
|
||||||
|
UpdateGpd(title_data.title_id, title_gpds_[title_data.title_id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateGpd(kDashboardID, dash_gpd_);
|
UpdateGpd(kDashboardID, dash_gpd_);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spa_title != kDashboardID) {
|
if (title_data.title_id != kDashboardID) {
|
||||||
curr_gpd_ = &title_gpds_[spa_title];
|
curr_gpd_ = &title_gpds_[title_data.title_id];
|
||||||
} else {
|
} else {
|
||||||
curr_gpd_ = &dash_gpd_;
|
curr_gpd_ = &dash_gpd_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -258,17 +258,20 @@ std::string SpaFile::GetTitleName() const {
|
||||||
static_cast<uint16_t>(SpaID::Title));
|
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),
|
auto block = GetEntry(static_cast<uint16_t>(SpaSection::kMetadata),
|
||||||
static_cast<uint64_t>(SpaID::Xthd));
|
static_cast<uint64_t>(SpaID::Xthd));
|
||||||
if (!block) {
|
if (!block) {
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto xthd = reinterpret_cast<const X_XDBF_XTHD_DATA*>(block->data.data());
|
auto xthd = reinterpret_cast<const X_XDBF_XTHD_DATA*>(block->data.data());
|
||||||
assert_true(xthd->header.magic == static_cast<uint32_t>(SpaID::Xthd));
|
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) {
|
bool GpdFile::GetAchievement(uint16_t id, Achievement* dest) {
|
||||||
|
|
|
@ -359,7 +359,7 @@ class SpaFile : public XdbfFile {
|
||||||
Entry* GetIcon() const;
|
Entry* GetIcon() const;
|
||||||
Locale GetDefaultLocale() const;
|
Locale GetDefaultLocale() const;
|
||||||
std::string GetTitleName() const;
|
std::string GetTitleName() const;
|
||||||
uint32_t GetTitleId() const;
|
bool GetTitleData(X_XDBF_XTHD_DATA* title_data) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GpdFile : public XdbfFile {
|
class GpdFile : public XdbfFile {
|
||||||
|
|
|
@ -62,13 +62,19 @@ struct X_XDBF_XSTC_DATA {
|
||||||
static_assert_size(X_XDBF_XSTC_DATA, 16);
|
static_assert_size(X_XDBF_XSTC_DATA, 16);
|
||||||
|
|
||||||
struct X_XDBF_XTHD_DATA {
|
struct X_XDBF_XTHD_DATA {
|
||||||
|
enum class TitleType : uint32_t {
|
||||||
|
kSystem = 0,
|
||||||
|
kFull = 1,
|
||||||
|
kDemo = 2,
|
||||||
|
kDownload = 3,
|
||||||
|
};
|
||||||
enum class Flags {
|
enum class Flags {
|
||||||
kAlwaysIncludeInProfile = 1,
|
kAlwaysIncludeInProfile = 1,
|
||||||
kNeverIncludeInProfile = 2,
|
kNeverIncludeInProfile = 2,
|
||||||
};
|
};
|
||||||
X_XDBF_SECTION_HEADER header;
|
X_XDBF_SECTION_HEADER header;
|
||||||
xe::be<uint32_t> title_id;
|
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_major;
|
||||||
xe::be<uint16_t> title_version_minor;
|
xe::be<uint16_t> title_version_minor;
|
||||||
xe::be<uint16_t> title_version_build;
|
xe::be<uint16_t> title_version_build;
|
||||||
|
|
Loading…
Reference in New Issue