diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index 8a6a8123d..730a07c02 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -1548,13 +1548,15 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, table = tabulate::Table(); 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 : properties_list) { std::string label = string_util::remove_eol(string_util::trim(entry.description)); + table.add_row({fmt::format("{:08X}", entry.id), label, + entry.is_matchmaking ? "True" : "False", fmt::format("{}", entry.data_size)}); } XELOGI("\n-------------------- PROPERTIES --------------------\n{}", @@ -1565,13 +1567,16 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path, table = tabulate::Table(); 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 : contexts_list) { std::string label = string_util::remove_eol(string_util::trim(entry.description)); + table.add_row({fmt::format("{:08X}", entry.id), label, + entry.is_matchmaking ? "True" : "False", fmt::format("{}", entry.default_value), fmt::format("{}", entry.max_value)}); } diff --git a/src/xenia/kernel/util/game_info_database.cc b/src/xenia/kernel/util/game_info_database.cc index b04bbc754..8c3293dcb 100644 --- a/src/xenia/kernel/util/game_info_database.cc +++ b/src/xenia/kernel/util/game_info_database.cc @@ -103,6 +103,8 @@ GameInfoDatabase::Context GameInfoDatabase::GetContext( context.max_value = xdbf_context->max_value; context.is_system = xam::UserData::is_system_property(xdbf_context->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); return context; } @@ -124,6 +126,8 @@ GameInfoDatabase::Property GameInfoDatabase::GetProperty( property.data_size = xdbf_property->data_size; property.is_system = xam::UserData::is_system_property(xdbf_property->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); return property; } @@ -350,6 +354,11 @@ GameInfoDatabase::ProductInformation GameInfoDatabase::GetProductInformation() return info; } +GameInfoDatabase::PropertyBag GameInfoDatabase::GetMatchmakingCollection() + const { + return GetPropertyBag(*spa_gamedata_->GetMatchCollection()); +} + // Aggregators std::vector GameInfoDatabase::GetContexts() const { std::vector contexts; diff --git a/src/xenia/kernel/util/game_info_database.h b/src/xenia/kernel/util/game_info_database.h index e08b1488e..bccef285d 100644 --- a/src/xenia/kernel/util/game_info_database.h +++ b/src/xenia/kernel/util/game_info_database.h @@ -34,6 +34,7 @@ class GameInfoDatabase { uint32_t default_value; bool is_system; bool is_presence; + bool is_matchmaking; std::string description; }; @@ -42,6 +43,7 @@ class GameInfoDatabase { uint32_t data_size; bool is_system; bool is_presence; + bool is_matchmaking; std::string description; }; @@ -160,6 +162,7 @@ class GameInfoDatabase { Query GetQueryData(const uint32_t id) const; std::vector GetSupportedLanguages() const; ProductInformation GetProductInformation() const; + PropertyBag GetMatchmakingCollection() const; // Aggregators for specific usecases std::vector GetContexts() const; diff --git a/src/xenia/kernel/xam/xdbf/spa_info.cc b/src/xenia/kernel/xam/xdbf/spa_info.cc index 52a4a67ae..ce0d4799a 100644 --- a/src/xenia/kernel/xam/xdbf/spa_info.cc +++ b/src/xenia/kernel/xam/xdbf/spa_info.cc @@ -25,6 +25,7 @@ void SpaInfo::Load() { LoadProperties(); LoadContexts(); LoadPresenceModes(); + LoadMatchmaking(); LoadStatsViews(); } @@ -329,6 +330,41 @@ void SpaInfo::LoadPresenceModes() { } } +void SpaInfo::LoadMatchmaking() { + auto matchmaking_schema = + GetEntry(static_cast(SpaSection::kMetadata), kXdbfIdXmat); + if (!matchmaking_schema) { + return; + } + + auto xrpt_head = reinterpret_cast( + matchmaking_schema->data.data()); + assert_true(xrpt_head->magic == kXdbfSignatureXmat); + assert_true(xrpt_head->version == 1); + + auto xpbm_head = reinterpret_cast(xrpt_head + 1); + + assert_true(xpbm_head->magic == kXdbfSignatureXpbm); + assert_true(xpbm_head->version == 1); + + const PropertyBagEntry* property_bag_header_ptr = + reinterpret_cast(xpbm_head + 1); + + auto contexts_ptr = + reinterpret_cast*>(property_bag_header_ptr + 1); + + auto properties_ptr = reinterpret_cast*>( + 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, uint32_t& decompressed_size) { auto xlast_table = diff --git a/src/xenia/kernel/xam/xdbf/spa_info.h b/src/xenia/kernel/xam/xdbf/spa_info.h index cfffe6126..b7f44a451 100644 --- a/src/xenia/kernel/xam/xdbf/spa_info.h +++ b/src/xenia/kernel/xam/xdbf/spa_info.h @@ -297,6 +297,8 @@ class SpaInfo : public XdbfFile { const PresenceTableEntry* GetPresence() const { return &presence_; } + const PropertyBag* GetMatchCollection() const { return &matchmaking_; } + const XdbfContextTableEntry* GetContext(uint32_t id); const XdbfPropertyTableEntry* GetProperty(uint32_t id); const std::optional GetStatsView(uint32_t id); @@ -328,6 +330,7 @@ class SpaInfo : public XdbfFile { std::vector properties_; std::vector stats_views_; PresenceTableEntry presence_; + PropertyBag matchmaking_; using XdbfLanguageStrings = std::map; @@ -342,8 +345,8 @@ class SpaInfo : public XdbfFile { void LoadProperties(); void LoadStatsViews(); - void LoadPresenceModes(); + void LoadMatchmaking(); template static T GetSpaEntry(std::vector& container, uint32_t id);