[Kernel] Added Extracting Properties and Contexts out of SPA file
+ Did a bit of a cleanup in achievement earning code
This commit is contained in:
parent
2de1b8ad4b
commit
d6dc4dc556
|
@ -1042,6 +1042,26 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
|
|||
}
|
||||
XELOGI("----------------- END OF ACHIEVEMENTS ----------------");
|
||||
|
||||
XELOGI("-------------------- PROPERTIES --------------------");
|
||||
const std::vector<kernel::util::XdbfPropertyTableEntry> properties_list =
|
||||
db.GetProperties();
|
||||
|
||||
for (const kernel::util::XdbfPropertyTableEntry& entry :
|
||||
properties_list) {
|
||||
std::string label = db.GetStringTableEntry(language, entry.string_id);
|
||||
XELOGI("{:08X} - {} - {}", entry.id, label, entry.data_size);
|
||||
}
|
||||
XELOGI("----------------- END OF PROPERTIES ----------------");
|
||||
|
||||
XELOGI("-------------------- CONTEXTS --------------------");
|
||||
const std::vector<kernel::util::XdbfContextTableEntry> contexts_list =
|
||||
db.GetContexts();
|
||||
|
||||
for (const kernel::util::XdbfContextTableEntry& entry : contexts_list) {
|
||||
std::string label = db.GetStringTableEntry(language, entry.string_id);
|
||||
XELOGI("{:08X} - {} - {}", entry.id, label, entry.unk2);
|
||||
}
|
||||
XELOGI("----------------- END OF CONTEXTS ----------------");
|
||||
auto icon_block = db.icon();
|
||||
if (icon_block) {
|
||||
display_window_->SetIcon(icon_block.buffer, icon_block.size);
|
||||
|
|
|
@ -36,36 +36,38 @@ void AchievementManager::EarnAchievement(uint64_t xuid, uint32_t title_id,
|
|||
ui::ImGuiDrawer* imgui_drawer = emulator->imgui_drawer();
|
||||
|
||||
const util::XdbfGameData title_xdbf = kernel_state()->title_xdbf();
|
||||
const std::vector<util::XdbfAchievementTableEntry> achievements =
|
||||
title_xdbf.GetAchievements();
|
||||
const util::XdbfAchievementTableEntry achievement =
|
||||
title_xdbf.GetAchievement(achievement_id);
|
||||
|
||||
if (!achievement.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const XLanguage title_language = title_xdbf.GetExistingLanguage(
|
||||
static_cast<XLanguage>(cvars::user_language));
|
||||
|
||||
for (const util::XdbfAchievementTableEntry& entry : achievements) {
|
||||
if (entry.id == achievement_id) {
|
||||
const std::string label =
|
||||
title_xdbf.GetStringTableEntry(title_language, entry.label_id);
|
||||
const std::string desc =
|
||||
title_xdbf.GetStringTableEntry(title_language, entry.description_id);
|
||||
const std::string label =
|
||||
title_xdbf.GetStringTableEntry(title_language, achievement.label_id);
|
||||
const std::string desc = title_xdbf.GetStringTableEntry(
|
||||
title_language, achievement.description_id);
|
||||
|
||||
XELOGI("Achievement unlocked: {}", label);
|
||||
const std::string description =
|
||||
fmt::format("{}G - {}", entry.gamerscore, label);
|
||||
XELOGI("Achievement unlocked: {}", label);
|
||||
|
||||
unlocked_achievements[achievement_id] = Clock::QueryHostSystemTime();
|
||||
// Even if we disable popup we still should store info that this
|
||||
// achievement was earned.
|
||||
if (!cvars::show_achievement_notification) {
|
||||
continue;
|
||||
}
|
||||
|
||||
app_context.CallInUIThread([imgui_drawer, description]() {
|
||||
new xe::ui::AchievementNotificationWindow(
|
||||
imgui_drawer, "Achievement unlocked", description, 0,
|
||||
kernel_state()->notification_position_);
|
||||
});
|
||||
}
|
||||
unlocked_achievements[achievement_id] = Clock::QueryHostSystemTime();
|
||||
// Even if we disable popup we still should store info that this
|
||||
// achievement was earned.
|
||||
if (!cvars::show_achievement_notification) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string description =
|
||||
fmt::format("{}G - {}", achievement.gamerscore, label);
|
||||
|
||||
app_context.CallInUIThread([imgui_drawer, description]() {
|
||||
new xe::ui::AchievementNotificationWindow(
|
||||
imgui_drawer, "Achievement unlocked", description, 0,
|
||||
kernel_state()->notification_position_);
|
||||
});
|
||||
}
|
||||
|
||||
bool AchievementManager::IsAchievementUnlocked(uint32_t achievement_id) {
|
||||
|
|
|
@ -17,10 +17,14 @@ constexpr fourcc_t kXdbfSignatureXdbf = make_fourcc("XDBF");
|
|||
constexpr fourcc_t kXdbfSignatureXstc = make_fourcc("XSTC");
|
||||
constexpr fourcc_t kXdbfSignatureXstr = make_fourcc("XSTR");
|
||||
constexpr fourcc_t kXdbfSignatureXach = make_fourcc("XACH");
|
||||
constexpr fourcc_t kXdbfSignatureXprp = make_fourcc("XPRP");
|
||||
constexpr fourcc_t kXdbfSignatureXcxt = make_fourcc("XCXT");
|
||||
|
||||
constexpr uint64_t kXdbfIdTitle = 0x8000;
|
||||
constexpr uint64_t kXdbfIdXstc = 0x58535443;
|
||||
constexpr uint64_t kXdbfIdXach = 0x58414348;
|
||||
constexpr uint64_t kXdbfIdXprp = 0x58505250;
|
||||
constexpr uint64_t kXdbfIdXctx = 0x58435854;
|
||||
|
||||
XdbfWrapper::XdbfWrapper(const uint8_t* data, size_t data_size)
|
||||
: data_(data), data_size_(data_size) {
|
||||
|
@ -69,11 +73,11 @@ std::string XdbfWrapper::GetStringTableEntry(XLanguage language,
|
|||
}
|
||||
|
||||
auto xstr_head =
|
||||
reinterpret_cast<const XdbfSectionHeader*>(language_block.buffer);
|
||||
reinterpret_cast<const XdbfXstrSectionHeader*>(language_block.buffer);
|
||||
assert_true(xstr_head->magic == kXdbfSignatureXstr);
|
||||
assert_true(xstr_head->version == 1);
|
||||
|
||||
const uint8_t* ptr = language_block.buffer + sizeof(XdbfSectionHeader);
|
||||
const uint8_t* ptr = language_block.buffer + sizeof(XdbfXstrSectionHeader);
|
||||
for (uint16_t i = 0; i < xstr_head->count; ++i) {
|
||||
auto entry = reinterpret_cast<const XdbfStringTableEntry*>(ptr);
|
||||
ptr += sizeof(XdbfStringTableEntry);
|
||||
|
@ -95,11 +99,11 @@ std::vector<XdbfAchievementTableEntry> XdbfWrapper::GetAchievements() const {
|
|||
}
|
||||
|
||||
auto xach_head =
|
||||
reinterpret_cast<const XdbfSectionHeader*>(achievement_table.buffer);
|
||||
reinterpret_cast<const XdbfXachSectionHeader*>(achievement_table.buffer);
|
||||
assert_true(xach_head->magic == kXdbfSignatureXach);
|
||||
assert_true(xach_head->version == 1);
|
||||
|
||||
const uint8_t* ptr = achievement_table.buffer + sizeof(XdbfSectionHeader);
|
||||
const uint8_t* ptr = achievement_table.buffer + sizeof(XdbfXachSectionHeader);
|
||||
for (uint16_t i = 0; i < xach_head->count; ++i) {
|
||||
auto entry = reinterpret_cast<const XdbfAchievementTableEntry*>(ptr);
|
||||
ptr += sizeof(XdbfAchievementTableEntry);
|
||||
|
@ -108,6 +112,86 @@ std::vector<XdbfAchievementTableEntry> XdbfWrapper::GetAchievements() const {
|
|||
return achievements;
|
||||
}
|
||||
|
||||
std::vector<XdbfPropertyTableEntry> XdbfWrapper::GetProperties() const {
|
||||
std::vector<XdbfPropertyTableEntry> properties;
|
||||
|
||||
auto property_table = GetEntry(XdbfSection::kMetadata, kXdbfIdXprp);
|
||||
if (!property_table) {
|
||||
return properties;
|
||||
}
|
||||
|
||||
auto xprp_head =
|
||||
reinterpret_cast<const XdbfXprpSectionHeader*>(property_table.buffer);
|
||||
assert_true(xprp_head->magic == kXdbfSignatureXprp);
|
||||
assert_true(xprp_head->version == 1);
|
||||
|
||||
const uint8_t* ptr = property_table.buffer + sizeof(XdbfXprpSectionHeader);
|
||||
for (uint16_t i = 0; i < xprp_head->count; ++i) {
|
||||
auto entry = reinterpret_cast<const XdbfPropertyTableEntry*>(ptr);
|
||||
ptr += sizeof(XdbfPropertyTableEntry);
|
||||
properties.push_back(*entry);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::vector<XdbfContextTableEntry> XdbfWrapper::GetContexts() const {
|
||||
std::vector<XdbfContextTableEntry> contexts;
|
||||
|
||||
auto contexts_table = GetEntry(XdbfSection::kMetadata, kXdbfIdXctx);
|
||||
if (!contexts_table) {
|
||||
return contexts;
|
||||
}
|
||||
|
||||
auto xcxt_head =
|
||||
reinterpret_cast<const XdbfXcxtSectionHeader*>(contexts_table.buffer);
|
||||
assert_true(xcxt_head->magic == kXdbfSignatureXcxt);
|
||||
assert_true(xcxt_head->version == 1);
|
||||
|
||||
const uint8_t* ptr = contexts_table.buffer + sizeof(XdbfXcxtSectionHeader);
|
||||
for (uint16_t i = 0; i < xcxt_head->count; ++i) {
|
||||
auto entry = reinterpret_cast<const XdbfContextTableEntry*>(ptr);
|
||||
ptr += sizeof(XdbfContextTableEntry);
|
||||
contexts.push_back(*entry);
|
||||
}
|
||||
return contexts;
|
||||
}
|
||||
|
||||
XdbfAchievementTableEntry XdbfWrapper::GetAchievement(const uint32_t id) const {
|
||||
const auto achievements = GetAchievements();
|
||||
|
||||
for (const auto& entry : achievements) {
|
||||
if (entry.id != id) {
|
||||
continue;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
XdbfPropertyTableEntry XdbfWrapper::GetProperty(const uint32_t id) const {
|
||||
const auto properties = GetProperties();
|
||||
|
||||
for (const auto& entry : properties) {
|
||||
if (entry.id != id) {
|
||||
continue;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
XdbfContextTableEntry XdbfWrapper::GetContext(const uint32_t id) const {
|
||||
const auto contexts = GetContexts();
|
||||
|
||||
for (const auto& entry : contexts) {
|
||||
if (entry.id != id) {
|
||||
continue;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
XLanguage XdbfGameData::GetExistingLanguage(XLanguage language_to_check) const {
|
||||
// A bit of a hack. Check if title in specific language exist.
|
||||
// If it doesn't then for sure language is not supported.
|
||||
|
|
|
@ -62,13 +62,37 @@ struct XdbfXstc {
|
|||
};
|
||||
static_assert_size(XdbfXstc, 16);
|
||||
|
||||
struct XdbfSectionHeader {
|
||||
struct XdbfXstrSectionHeader {
|
||||
xe::be<uint32_t> magic;
|
||||
xe::be<uint32_t> version;
|
||||
xe::be<uint32_t> size;
|
||||
xe::be<uint16_t> count;
|
||||
};
|
||||
static_assert_size(XdbfSectionHeader, 14);
|
||||
static_assert_size(XdbfXstrSectionHeader, 14);
|
||||
|
||||
struct XdbfXprpSectionHeader {
|
||||
xe::be<uint32_t> magic;
|
||||
xe::be<uint32_t> version;
|
||||
xe::be<uint32_t> size;
|
||||
xe::be<uint16_t> count;
|
||||
};
|
||||
static_assert_size(XdbfXprpSectionHeader, 14);
|
||||
|
||||
struct XdbfXachSectionHeader {
|
||||
xe::be<uint32_t> magic;
|
||||
xe::be<uint32_t> version;
|
||||
xe::be<uint32_t> size;
|
||||
xe::be<uint16_t> count;
|
||||
};
|
||||
static_assert_size(XdbfXachSectionHeader, 14);
|
||||
|
||||
struct XdbfXcxtSectionHeader {
|
||||
xe::be<uint32_t> magic;
|
||||
xe::be<uint32_t> version;
|
||||
xe::be<uint32_t> size;
|
||||
xe::be<uint32_t> count;
|
||||
};
|
||||
static_assert_size(XdbfXcxtSectionHeader, 16);
|
||||
|
||||
struct XdbfStringTableEntry {
|
||||
xe::be<uint16_t> id;
|
||||
|
@ -76,6 +100,22 @@ struct XdbfStringTableEntry {
|
|||
};
|
||||
static_assert_size(XdbfStringTableEntry, 4);
|
||||
|
||||
struct XdbfContextTableEntry {
|
||||
xe::be<uint32_t> id;
|
||||
xe::be<uint16_t> unk1;
|
||||
xe::be<uint16_t> string_id;
|
||||
xe::be<uint32_t> unk2;
|
||||
xe::be<uint32_t> unk3;
|
||||
};
|
||||
static_assert_size(XdbfContextTableEntry, 16);
|
||||
|
||||
struct XdbfPropertyTableEntry {
|
||||
xe::be<uint32_t> id;
|
||||
xe::be<uint16_t> string_id;
|
||||
xe::be<uint16_t> data_size;
|
||||
};
|
||||
static_assert_size(XdbfPropertyTableEntry, 8);
|
||||
|
||||
struct XdbfAchievementTableEntry {
|
||||
xe::be<uint16_t> id;
|
||||
xe::be<uint16_t> label_id;
|
||||
|
@ -117,6 +157,12 @@ class XdbfWrapper {
|
|||
// Returns the empty string if the entry is not found.
|
||||
std::string GetStringTableEntry(XLanguage language, uint16_t string_id) const;
|
||||
std::vector<XdbfAchievementTableEntry> GetAchievements() const;
|
||||
std::vector<XdbfPropertyTableEntry> GetProperties() const;
|
||||
std::vector<XdbfContextTableEntry> GetContexts() const;
|
||||
|
||||
XdbfAchievementTableEntry GetAchievement(const uint32_t id) const;
|
||||
XdbfPropertyTableEntry GetProperty(const uint32_t id) const;
|
||||
XdbfContextTableEntry GetContext(const uint32_t id) const;
|
||||
|
||||
private:
|
||||
const uint8_t* data_ = nullptr;
|
||||
|
|
|
@ -43,6 +43,17 @@ X_HRESULT XgiApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
|
|||
uint32_t context_value = xe::load_and_swap<uint32_t>(buffer + 20);
|
||||
XELOGD("XGIUserSetContextEx({:08X}, {:08X}, {:08X})", user_index,
|
||||
context_id, context_value);
|
||||
|
||||
const util::XdbfGameData title_xdbf = kernel_state_->title_xdbf();
|
||||
if (title_xdbf.is_valid()) {
|
||||
const auto context = title_xdbf.GetContext(context_id);
|
||||
const XLanguage title_language = title_xdbf.GetExistingLanguage(
|
||||
static_cast<XLanguage>(XLanguage::kEnglish));
|
||||
const std::string desc =
|
||||
title_xdbf.GetStringTableEntry(title_language, context.string_id);
|
||||
XELOGD("XGIUserSetContextEx: {} - Set to value: {}", desc,
|
||||
context_value);
|
||||
}
|
||||
return X_E_SUCCESS;
|
||||
}
|
||||
case 0x000B0007: {
|
||||
|
@ -52,6 +63,17 @@ X_HRESULT XgiApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
|
|||
uint32_t value_ptr = xe::load_and_swap<uint32_t>(buffer + 24);
|
||||
XELOGD("XGIUserSetPropertyEx({:08X}, {:08X}, {}, {:08X})", user_index,
|
||||
property_id, value_size, value_ptr);
|
||||
|
||||
const util::XdbfGameData title_xdbf = kernel_state_->title_xdbf();
|
||||
if (title_xdbf.is_valid()) {
|
||||
const auto property = title_xdbf.GetContext(property_id);
|
||||
const XLanguage title_language = title_xdbf.GetExistingLanguage(
|
||||
static_cast<XLanguage>(XLanguage::kEnglish));
|
||||
const std::string desc =
|
||||
title_xdbf.GetStringTableEntry(title_language, property.string_id);
|
||||
XELOGD("XGIUserSetPropertyEx: Setting property: {}", desc);
|
||||
}
|
||||
|
||||
return X_E_SUCCESS;
|
||||
}
|
||||
case 0x000B0008: {
|
||||
|
|
Loading…
Reference in New Issue