From 520353e95a4c517b6e3867b3f8c5365ece63da58 Mon Sep 17 00:00:00 2001 From: Gliniak Date: Sun, 23 Nov 2025 17:26:55 +0100 Subject: [PATCH 1/4] [SDL] Fixed spam caused by infinitely increasing packet count It was incremented with each GetState instead of controller state update --- src/xenia/hid/sdl/sdl_input_driver.cc | 6 ++---- src/xenia/hid/sdl/sdl_input_driver.h | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/xenia/hid/sdl/sdl_input_driver.cc b/src/xenia/hid/sdl/sdl_input_driver.cc index 051dc7210..50341a7ad 100644 --- a/src/xenia/hid/sdl/sdl_input_driver.cc +++ b/src/xenia/hid/sdl/sdl_input_driver.cc @@ -226,11 +226,9 @@ X_RESULT SDLInputDriver::GetState(uint32_t user_index, return X_ERROR_DEVICE_NOT_CONNECTED; } - // Make sure packet_number is only incremented by 1, even if there have been - // multiple updates between GetState calls. Also track `is_active` to - // increment the packet number if it changed. - if (controller->is_active || controller->state_changed) { + if (controller->state_changed) { controller->state.packet_number++; + controller->state_changed = false; } std::memcpy(out_state, &controller->state, sizeof(*out_state)); return X_ERROR_SUCCESS; diff --git a/src/xenia/hid/sdl/sdl_input_driver.h b/src/xenia/hid/sdl/sdl_input_driver.h index 462374d82..db1dc3bc1 100644 --- a/src/xenia/hid/sdl/sdl_input_driver.h +++ b/src/xenia/hid/sdl/sdl_input_driver.h @@ -52,7 +52,6 @@ class SDLInputDriver final : public InputDriver { X_INPUT_CAPABILITIES caps; X_INPUT_STATE state; bool state_changed; - bool is_active; }; enum class RepeatState { From 6783bea223b89d0099b7e4976fe027b2f12076a3 Mon Sep 17 00:00:00 2001 From: Adrian <78108584+AdrianCassar@users.noreply.github.com> Date: Sat, 8 Nov 2025 15:28:18 +0000 Subject: [PATCH 2/4] [XAM] Implemented SPA XMAT --- src/xenia/emulator.cc | 9 ++++-- src/xenia/kernel/util/game_info_database.cc | 9 ++++++ src/xenia/kernel/util/game_info_database.h | 3 ++ src/xenia/kernel/xam/xdbf/spa_info.cc | 36 +++++++++++++++++++++ src/xenia/kernel/xam/xdbf/spa_info.h | 5 ++- 5 files changed, 59 insertions(+), 3 deletions(-) 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); From e7d08b8e8e5dea412b57af0ac7839aec0812d0f6 Mon Sep 17 00:00:00 2001 From: Adrian <78108584+AdrianCassar@users.noreply.github.com> Date: Sun, 23 Nov 2025 15:55:22 +0000 Subject: [PATCH 3/4] [XAM] Improved writing struct for XEnumerateCrossTitle --- src/xenia/kernel/xam/apps/xam_app.cc | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/xenia/kernel/xam/apps/xam_app.cc b/src/xenia/kernel/xam/apps/xam_app.cc index 0a3b86371..a5ccb2cdd 100644 --- a/src/xenia/kernel/xam/apps/xam_app.cc +++ b/src/xenia/kernel/xam/apps/xam_app.cc @@ -64,16 +64,32 @@ X_HRESULT XamApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, assert_true(enum_struct->magic == kXObjSignature); - // This is a struct of XCONTENT_DATA_INTERNAL - uint8_t* content_data_ptr = - memory_->TranslateVirtual(data_ptr->buffer_ptr); + XCONTENT_CROSS_TITLE_DATA cross_title_data = {}; + uint8_t* cross_title_data_ptr = + reinterpret_cast(&cross_title_data); + + uint32_t item_count = 0; + X_RESULT result = e->WriteItems(0, cross_title_data_ptr, &item_count); + + XCONTENT_DATA_INTERNAL* content_data_ptr = + memory_->TranslateVirtual( + data_ptr->buffer_ptr); assert_true(data_ptr->buffer_size == sizeof(XCONTENT_DATA_INTERNAL)); std::memset(content_data_ptr, 0, data_ptr->buffer_size); - uint32_t item_count = 0; - X_RESULT result = e->WriteItems(0, content_data_ptr, &item_count); + if (!result) { + content_data_ptr->device_id = cross_title_data.content_data.device_id; + content_data_ptr->content_type = + cross_title_data.content_data.content_type; + content_data_ptr->set_display_name( + cross_title_data.content_data.display_name()); + content_data_ptr->set_file_name( + cross_title_data.content_data.file_name()); + content_data_ptr->padding[0] = content_data_ptr->padding[1] = 0; + content_data_ptr->title_id = cross_title_data.title_id; + } result = X_HRESULT_FROM_WIN32(result); From 481ab595ceaf66a59d510b97b5ad84fdaee9dc73 Mon Sep 17 00:00:00 2001 From: Adrian <78108584+AdrianCassar@users.noreply.github.com> Date: Mon, 10 Nov 2025 19:04:04 +0000 Subject: [PATCH 4/4] [Kernel] ObReferenceObjectByHandle Cleanup --- src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc | 26 +++++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc index 356c9b2f1..467501b9f 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc @@ -254,25 +254,31 @@ dword_result_t ObReferenceObjectByHandle_entry(dword_t handle, } uint32_t native_ptr = object->guest_object(); - auto& object_types = - kernel_state()->host_object_type_enum_to_guest_object_type_ptr_; - auto object_type = object_types.find(object->type()); - if (object_type != object_types.end()) { - if (object_type_ptr && object_type_ptr != object_type->second) { - return X_STATUS_OBJECT_TYPE_MISMATCH; + + if (object_type_ptr) { + auto& object_types = + kernel_state()->host_object_type_enum_to_guest_object_type_ptr_; + + if (object_types.contains(object->type())) { + if (object_type_ptr != object_types[object->type()]) { + return X_STATUS_OBJECT_TYPE_MISMATCH; + } + } else { + assert_unhandled_case(object->type()); + native_ptr = 0xDEADF00D; } - } else { - assert_unhandled_case(object->type()); - native_ptr = 0xDEADF00D; } + // Caller takes the reference. // It's released in ObDereferenceObject. object->RetainHandle(); - xenia_assert(native_ptr != 0); + assert_not_zero(native_ptr); + if (out_object_ptr.guest_address()) { *out_object_ptr = native_ptr; } + return X_STATUS_SUCCESS; } DECLARE_XBOXKRNL_EXPORT1(ObReferenceObjectByHandle, kNone, kImplemented);