From 10bfc92d9a6ec1ee89ad7d8c3b54ca6934d747a7 Mon Sep 17 00:00:00 2001 From: Adrian <78108584+AdrianCassar@users.noreply.github.com> Date: Fri, 28 Nov 2025 14:35:36 +0000 Subject: [PATCH] [XAM] Stubbed XMPCreateUserPlaylistEnumerator Fixed 545408C0 freezing at main menu. --- src/xenia/kernel/xam/xam.h | 11 ++++++ src/xenia/kernel/xam/xam_enum.cc | 57 ++++++++++++++++++++++++++++---- src/xenia/kernel/xenumerator.cc | 28 ++++++++++++++++ src/xenia/kernel/xenumerator.h | 23 +++++++++++++ 4 files changed, 112 insertions(+), 7 deletions(-) diff --git a/src/xenia/kernel/xam/xam.h b/src/xenia/kernel/xam/xam.h index 8991965fc..ca7a59206 100644 --- a/src/xenia/kernel/xam/xam.h +++ b/src/xenia/kernel/xam/xam.h @@ -329,6 +329,17 @@ enum class UserContextDevice : uint32_t { Microphone = 4, }; +constexpr uint32_t XMP_MAX_METADATA_STRING = 40; +constexpr uint32_t XMP_MAX_USER_PLAYLIST_ID = 572; +constexpr uint32_t XMP_USER_PLAYLIST_RESERVED_FIELD_SIZE = 168; + +struct XMP_USER_PLAYLIST_INFO { + uint8_t id[XMP_MAX_USER_PLAYLIST_ID]; + xe::be title[XMP_MAX_METADATA_STRING]; + uint8_t reserved[XMP_USER_PLAYLIST_RESERVED_FIELD_SIZE]; +}; +static_assert_size(XMP_USER_PLAYLIST_INFO, 0x334); + } // namespace xam } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xam/xam_enum.cc b/src/xenia/kernel/xam/xam_enum.cc index 15ca58bcc..bcf4fd8d8 100644 --- a/src/xenia/kernel/xam/xam_enum.cc +++ b/src/xenia/kernel/xam/xam_enum.cc @@ -79,20 +79,63 @@ dword_result_t XamEnumerate_entry(dword_t handle, dword_t flags, } DECLARE_XAM_EXPORT1(XamEnumerate, kNone, kImplemented); -dword_result_t XamCreateEnumeratorHandle_entry( - dword_t user_index, dword_t app_id, dword_t open_message, - dword_t close_message, dword_t extra_size, dword_t item_count, - dword_t flags, lpdword_t out_handle) { - auto e = object_ref( - new XStaticUntypedEnumerator(kernel_state(), item_count, extra_size)); +static uint32_t XMPCreateUserPlaylistEnumeratorHandle( + uint32_t user_index, uint32_t app_id, uint32_t open_message, + uint32_t close_message, uint32_t extra_size, uint32_t item_count, + uint32_t flags, uint32_t& out_enum_handle) { + auto e = object_ref( + new XMPCreateUserPlaylistEnumerator(kernel_state(), item_count)); auto result = e->Initialize(user_index, app_id, open_message, close_message, flags, extra_size, nullptr); + if (XFAILED(result)) { return result; } - *out_handle = e->handle(); + std::vector user_playlist_info = {}; + + for (const auto& playlist_info : user_playlist_info) { + e->AppendItem(playlist_info); + } + + XELOGI("{}: added {} items to enumerator", __func__, e->item_count()); + + out_enum_handle = e->handle(); + return X_ERROR_SUCCESS; +} + +constexpr uint32_t XMPCreateUserPlaylistEnumeratorMessage = 0x70026; + +dword_result_t XamCreateEnumeratorHandle_entry( + dword_t user_index, dword_t app_id, dword_t open_message, + dword_t close_message, dword_t extra_size, dword_t item_count, + dword_t flags, lpdword_t out_handle) { + uint32_t enum_handle = 0; + X_STATUS result = 0; + + switch (open_message) { + case XMPCreateUserPlaylistEnumeratorMessage: { + result = XMPCreateUserPlaylistEnumeratorHandle( + user_index, app_id, open_message, close_message, extra_size, + item_count, flags, enum_handle); + } break; + default: { + auto e = object_ref( + new XStaticUntypedEnumerator(kernel_state(), item_count, extra_size)); + + result = e->Initialize(user_index, app_id, open_message, close_message, + flags, extra_size, nullptr); + enum_handle = e->handle(); + } break; + } + + if (XFAILED(result)) { + return result; + } + + *out_handle = enum_handle; + return X_ERROR_SUCCESS; } DECLARE_XAM_EXPORT1(XamCreateEnumeratorHandle, kNone, kImplemented); diff --git a/src/xenia/kernel/xenumerator.cc b/src/xenia/kernel/xenumerator.cc index 8fd83ae06..811f7f1ff 100644 --- a/src/xenia/kernel/xenumerator.cc +++ b/src/xenia/kernel/xenumerator.cc @@ -40,6 +40,8 @@ X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id, *extra_buffer = !extra_buffer ? nullptr : &native_object[sizeof(X_KENUMERATOR)]; } + + extra_size_ = extra_size; return X_STATUS_SUCCESS; } @@ -175,5 +177,31 @@ uint32_t XUserStatsEnumerator::WriteItems(uint32_t buffer_ptr, return X_ERROR_SUCCESS; } +uint32_t XMPCreateUserPlaylistEnumerator::WriteItems(uint32_t buffer_ptr, + uint8_t* buffer_data, + uint32_t* written_count) { + // Fixed 545408C0 freezing at main menu. + std::memset(buffer_data, 0, extra_size()); + + size_t count = std::min(items_.size() - current_item_, items_per_enumerate()); + if (!count) { + return X_ERROR_NO_MORE_FILES; + } + + xam::XMP_USER_PLAYLIST_INFO* results = + reinterpret_cast(buffer_data); + + for (size_t i = 0, o = current_item_; i < count; ++i, ++current_item_) { + const auto& item = items_[current_item_]; + results[i] = item; + } + + if (written_count) { + *written_count = static_cast(count); + } + + return X_ERROR_SUCCESS; +} + } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xenumerator.h b/src/xenia/kernel/xenumerator.h index e90007c8a..6d78d9fa0 100644 --- a/src/xenia/kernel/xenumerator.h +++ b/src/xenia/kernel/xenumerator.h @@ -14,6 +14,7 @@ #include "xenia/kernel/xam/achievement_manager.h" #include "xenia/kernel/xam/user_tracker.h" +#include "xenia/kernel/xam/xam.h" #include "xenia/kernel/xobject.h" namespace xe { @@ -89,10 +90,12 @@ class XEnumerator : public XObject { size_t item_size() const { return item_size_; } size_t items_per_enumerate() const { return items_per_enumerate_; } + size_t extra_size() const { return extra_size_; } private: size_t items_per_enumerate_; size_t item_size_; + size_t extra_size_; }; class XStaticUntypedEnumerator : public XEnumerator { @@ -219,6 +222,26 @@ class XUserStatsEnumerator : public XEnumerator { size_t current_item_ = 0; }; +class XMPCreateUserPlaylistEnumerator : public XEnumerator { + public: + XMPCreateUserPlaylistEnumerator(KernelState* kernel_state, + size_t items_per_enumerate) + : XEnumerator(kernel_state, items_per_enumerate, 0) {} + + size_t item_count() const { return items_.size(); } + + void AppendItem(const xam::XMP_USER_PLAYLIST_INFO& item) { + items_.push_back(item); + } + + uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, + uint32_t* written_count) override; + + private: + std::vector items_; + size_t current_item_ = 0; +}; + } // namespace kernel } // namespace xe