[XAM] Implemented SPA XMAT
This commit is contained in:
@@ -1548,13 +1548,15 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
|
|||||||
|
|
||||||
table = tabulate::Table();
|
table = tabulate::Table();
|
||||||
table.format().multi_byte_characters(true);
|
table.format().multi_byte_characters(true);
|
||||||
table.add_row({"ID", "Name", "Data Size"});
|
table.add_row({"ID", "Name", "Matchmaking", "Data Size"});
|
||||||
|
|
||||||
for (const kernel::util::GameInfoDatabase::Property& entry :
|
for (const kernel::util::GameInfoDatabase::Property& entry :
|
||||||
properties_list) {
|
properties_list) {
|
||||||
std::string label =
|
std::string label =
|
||||||
string_util::remove_eol(string_util::trim(entry.description));
|
string_util::remove_eol(string_util::trim(entry.description));
|
||||||
|
|
||||||
table.add_row({fmt::format("{:08X}", entry.id), label,
|
table.add_row({fmt::format("{:08X}", entry.id), label,
|
||||||
|
entry.is_matchmaking ? "True" : "False",
|
||||||
fmt::format("{}", entry.data_size)});
|
fmt::format("{}", entry.data_size)});
|
||||||
}
|
}
|
||||||
XELOGI("\n-------------------- PROPERTIES --------------------\n{}",
|
XELOGI("\n-------------------- PROPERTIES --------------------\n{}",
|
||||||
@@ -1565,13 +1567,16 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
|
|||||||
|
|
||||||
table = tabulate::Table();
|
table = tabulate::Table();
|
||||||
table.format().multi_byte_characters(true);
|
table.format().multi_byte_characters(true);
|
||||||
table.add_row({"ID", "Name", "Default Value", "Max Value"});
|
table.add_row(
|
||||||
|
{"ID", "Name", "Matchmaking", "Default Value", "Max Value"});
|
||||||
|
|
||||||
for (const kernel::util::GameInfoDatabase::Context& entry :
|
for (const kernel::util::GameInfoDatabase::Context& entry :
|
||||||
contexts_list) {
|
contexts_list) {
|
||||||
std::string label =
|
std::string label =
|
||||||
string_util::remove_eol(string_util::trim(entry.description));
|
string_util::remove_eol(string_util::trim(entry.description));
|
||||||
|
|
||||||
table.add_row({fmt::format("{:08X}", entry.id), label,
|
table.add_row({fmt::format("{:08X}", entry.id), label,
|
||||||
|
entry.is_matchmaking ? "True" : "False",
|
||||||
fmt::format("{}", entry.default_value),
|
fmt::format("{}", entry.default_value),
|
||||||
fmt::format("{}", entry.max_value)});
|
fmt::format("{}", entry.max_value)});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,8 @@ GameInfoDatabase::Context GameInfoDatabase::GetContext(
|
|||||||
context.max_value = xdbf_context->max_value;
|
context.max_value = xdbf_context->max_value;
|
||||||
context.is_system = xam::UserData::is_system_property(xdbf_context->id);
|
context.is_system = xam::UserData::is_system_property(xdbf_context->id);
|
||||||
context.is_presence = GetPresence().property_bag.contexts.contains(id);
|
context.is_presence = GetPresence().property_bag.contexts.contains(id);
|
||||||
|
context.is_matchmaking =
|
||||||
|
GetMatchmakingCollection().contexts.contains(xdbf_context->id);
|
||||||
context.description = GetLocalizedString(xdbf_context->string_id);
|
context.description = GetLocalizedString(xdbf_context->string_id);
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
@@ -124,6 +126,8 @@ GameInfoDatabase::Property GameInfoDatabase::GetProperty(
|
|||||||
property.data_size = xdbf_property->data_size;
|
property.data_size = xdbf_property->data_size;
|
||||||
property.is_system = xam::UserData::is_system_property(xdbf_property->id);
|
property.is_system = xam::UserData::is_system_property(xdbf_property->id);
|
||||||
property.is_presence = GetPresence().property_bag.properties.contains(id);
|
property.is_presence = GetPresence().property_bag.properties.contains(id);
|
||||||
|
property.is_matchmaking =
|
||||||
|
GetMatchmakingCollection().properties.contains(xdbf_property->id);
|
||||||
property.description = GetLocalizedString(xdbf_property->string_id);
|
property.description = GetLocalizedString(xdbf_property->string_id);
|
||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
@@ -350,6 +354,11 @@ GameInfoDatabase::ProductInformation GameInfoDatabase::GetProductInformation()
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GameInfoDatabase::PropertyBag GameInfoDatabase::GetMatchmakingCollection()
|
||||||
|
const {
|
||||||
|
return GetPropertyBag(*spa_gamedata_->GetMatchCollection());
|
||||||
|
}
|
||||||
|
|
||||||
// Aggregators
|
// Aggregators
|
||||||
std::vector<GameInfoDatabase::Context> GameInfoDatabase::GetContexts() const {
|
std::vector<GameInfoDatabase::Context> GameInfoDatabase::GetContexts() const {
|
||||||
std::vector<Context> contexts;
|
std::vector<Context> contexts;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ class GameInfoDatabase {
|
|||||||
uint32_t default_value;
|
uint32_t default_value;
|
||||||
bool is_system;
|
bool is_system;
|
||||||
bool is_presence;
|
bool is_presence;
|
||||||
|
bool is_matchmaking;
|
||||||
std::string description;
|
std::string description;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,6 +43,7 @@ class GameInfoDatabase {
|
|||||||
uint32_t data_size;
|
uint32_t data_size;
|
||||||
bool is_system;
|
bool is_system;
|
||||||
bool is_presence;
|
bool is_presence;
|
||||||
|
bool is_matchmaking;
|
||||||
std::string description;
|
std::string description;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -160,6 +162,7 @@ class GameInfoDatabase {
|
|||||||
Query GetQueryData(const uint32_t id) const;
|
Query GetQueryData(const uint32_t id) const;
|
||||||
std::vector<XLanguage> GetSupportedLanguages() const;
|
std::vector<XLanguage> GetSupportedLanguages() const;
|
||||||
ProductInformation GetProductInformation() const;
|
ProductInformation GetProductInformation() const;
|
||||||
|
PropertyBag GetMatchmakingCollection() const;
|
||||||
|
|
||||||
// Aggregators for specific usecases
|
// Aggregators for specific usecases
|
||||||
std::vector<Context> GetContexts() const;
|
std::vector<Context> GetContexts() const;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ void SpaInfo::Load() {
|
|||||||
LoadProperties();
|
LoadProperties();
|
||||||
LoadContexts();
|
LoadContexts();
|
||||||
LoadPresenceModes();
|
LoadPresenceModes();
|
||||||
|
LoadMatchmaking();
|
||||||
LoadStatsViews();
|
LoadStatsViews();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,6 +330,41 @@ void SpaInfo::LoadPresenceModes() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpaInfo::LoadMatchmaking() {
|
||||||
|
auto matchmaking_schema =
|
||||||
|
GetEntry(static_cast<uint16_t>(SpaSection::kMetadata), kXdbfIdXmat);
|
||||||
|
if (!matchmaking_schema) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto xrpt_head = reinterpret_cast<const XdbfSectionHeader*>(
|
||||||
|
matchmaking_schema->data.data());
|
||||||
|
assert_true(xrpt_head->magic == kXdbfSignatureXmat);
|
||||||
|
assert_true(xrpt_head->version == 1);
|
||||||
|
|
||||||
|
auto xpbm_head = reinterpret_cast<const XdbfSectionHeader*>(xrpt_head + 1);
|
||||||
|
|
||||||
|
assert_true(xpbm_head->magic == kXdbfSignatureXpbm);
|
||||||
|
assert_true(xpbm_head->version == 1);
|
||||||
|
|
||||||
|
const PropertyBagEntry* property_bag_header_ptr =
|
||||||
|
reinterpret_cast<const PropertyBagEntry*>(xpbm_head + 1);
|
||||||
|
|
||||||
|
auto contexts_ptr =
|
||||||
|
reinterpret_cast<const xe::be<uint32_t>*>(property_bag_header_ptr + 1);
|
||||||
|
|
||||||
|
auto properties_ptr = reinterpret_cast<const xe::be<uint32_t>*>(
|
||||||
|
contexts_ptr + property_bag_header_ptr->contexts_count);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < property_bag_header_ptr->contexts_count; i++) {
|
||||||
|
matchmaking_.contexts.insert(contexts_ptr[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < property_bag_header_ptr->properties_count; i++) {
|
||||||
|
matchmaking_.properties.insert(properties_ptr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const uint8_t* SpaInfo::ReadXLast(uint32_t& compressed_size,
|
const uint8_t* SpaInfo::ReadXLast(uint32_t& compressed_size,
|
||||||
uint32_t& decompressed_size) {
|
uint32_t& decompressed_size) {
|
||||||
auto xlast_table =
|
auto xlast_table =
|
||||||
|
|||||||
@@ -297,6 +297,8 @@ class SpaInfo : public XdbfFile {
|
|||||||
|
|
||||||
const PresenceTableEntry* GetPresence() const { return &presence_; }
|
const PresenceTableEntry* GetPresence() const { return &presence_; }
|
||||||
|
|
||||||
|
const PropertyBag* GetMatchCollection() const { return &matchmaking_; }
|
||||||
|
|
||||||
const XdbfContextTableEntry* GetContext(uint32_t id);
|
const XdbfContextTableEntry* GetContext(uint32_t id);
|
||||||
const XdbfPropertyTableEntry* GetProperty(uint32_t id);
|
const XdbfPropertyTableEntry* GetProperty(uint32_t id);
|
||||||
const std::optional<ViewTable> GetStatsView(uint32_t id);
|
const std::optional<ViewTable> GetStatsView(uint32_t id);
|
||||||
@@ -328,6 +330,7 @@ class SpaInfo : public XdbfFile {
|
|||||||
std::vector<const XdbfPropertyTableEntry*> properties_;
|
std::vector<const XdbfPropertyTableEntry*> properties_;
|
||||||
std::vector<ViewTable> stats_views_;
|
std::vector<ViewTable> stats_views_;
|
||||||
PresenceTableEntry presence_;
|
PresenceTableEntry presence_;
|
||||||
|
PropertyBag matchmaking_;
|
||||||
|
|
||||||
using XdbfLanguageStrings = std::map<uint16_t, std::string>;
|
using XdbfLanguageStrings = std::map<uint16_t, std::string>;
|
||||||
|
|
||||||
@@ -342,8 +345,8 @@ class SpaInfo : public XdbfFile {
|
|||||||
void LoadProperties();
|
void LoadProperties();
|
||||||
|
|
||||||
void LoadStatsViews();
|
void LoadStatsViews();
|
||||||
|
|
||||||
void LoadPresenceModes();
|
void LoadPresenceModes();
|
||||||
|
void LoadMatchmaking();
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static T GetSpaEntry(std::vector<T>& container, uint32_t id);
|
static T GetSpaEntry(std::vector<T>& container, uint32_t id);
|
||||||
|
|||||||
Reference in New Issue
Block a user