diff --git a/src/xenia/kernel/achievement_manager.h b/src/xenia/kernel/achievement_manager.h index b425558cb..6b935a1c1 100644 --- a/src/xenia/kernel/achievement_manager.h +++ b/src/xenia/kernel/achievement_manager.h @@ -19,6 +19,26 @@ namespace xe { namespace kernel { +// TODO(gibbed): probably a FILETIME/LARGE_INTEGER, unknown currently +struct X_ACHIEVEMENT_UNLOCK_TIME { + xe::be unk_0; + xe::be unk_4; +}; + +struct X_ACHIEVEMENT_DETAILS { + xe::be id; + xe::be label_ptr; + xe::be description_ptr; + xe::be unachieved_ptr; + xe::be image_id; + xe::be gamerscore; + X_ACHIEVEMENT_UNLOCK_TIME unlock_time; + xe::be flags; + + static const size_t kStringBufferSize = 464; +}; +static_assert_size(X_ACHIEVEMENT_DETAILS, 36); + class AchievementManager { public: AchievementManager(); diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index 60795787f..1b6239495 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -574,123 +574,6 @@ dword_result_t XamShowSigninUI_entry(dword_t unk, dword_t unk_mask) { } DECLARE_XAM_EXPORT1(XamShowSigninUI, kUserProfiles, kStub); -// TODO(gibbed): probably a FILETIME/LARGE_INTEGER, unknown currently -struct X_ACHIEVEMENT_UNLOCK_TIME { - xe::be unk_0; - xe::be unk_4; -}; - -struct X_ACHIEVEMENT_DETAILS { - xe::be id; - xe::be label_ptr; - xe::be description_ptr; - xe::be unachieved_ptr; - xe::be image_id; - xe::be gamerscore; - X_ACHIEVEMENT_UNLOCK_TIME unlock_time; - xe::be flags; - - static const size_t kStringBufferSize = 464; -}; -static_assert_size(X_ACHIEVEMENT_DETAILS, 36); - -class XStaticAchievementEnumerator : public XEnumerator { - public: - struct AchievementDetails { - uint32_t id; - std::u16string label; - std::u16string description; - std::u16string unachieved; - uint32_t image_id; - uint32_t gamerscore; - struct { - uint32_t unk_0; - uint32_t unk_4; - } unlock_time; - uint32_t flags; - }; - - XStaticAchievementEnumerator(KernelState* kernel_state, - size_t items_per_enumerate, uint32_t flags) - : XEnumerator( - kernel_state, items_per_enumerate, - sizeof(X_ACHIEVEMENT_DETAILS) + - (!!(flags & 7) ? X_ACHIEVEMENT_DETAILS::kStringBufferSize : 0)), - flags_(flags) {} - - void AppendItem(AchievementDetails item) { - items_.push_back(std::move(item)); - } - - uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, - uint32_t* written_count) override { - size_t count = - std::min(items_.size() - current_item_, items_per_enumerate()); - if (!count) { - return X_ERROR_NO_MORE_FILES; - } - - size_t size = count * item_size(); - - auto details = reinterpret_cast(buffer_data); - size_t string_offset = - items_per_enumerate() * sizeof(X_ACHIEVEMENT_DETAILS); - auto string_buffer = - StringBuffer{buffer_ptr + static_cast(string_offset), - &buffer_data[string_offset], - count * X_ACHIEVEMENT_DETAILS::kStringBufferSize}; - for (size_t i = 0, o = current_item_; i < count; ++i, ++current_item_) { - const auto& item = items_[current_item_]; - details[i].id = item.id; - details[i].label_ptr = - !!(flags_ & 1) ? AppendString(string_buffer, item.label) : 0; - details[i].description_ptr = - !!(flags_ & 2) ? AppendString(string_buffer, item.description) : 0; - details[i].unachieved_ptr = - !!(flags_ & 4) ? AppendString(string_buffer, item.unachieved) : 0; - details[i].image_id = item.image_id; - details[i].gamerscore = item.gamerscore; - details[i].unlock_time.unk_0 = item.unlock_time.unk_0; - details[i].unlock_time.unk_4 = item.unlock_time.unk_4; - details[i].flags = item.flags; - } - - if (written_count) { - *written_count = static_cast(count); - } - - return X_ERROR_SUCCESS; - } - - private: - struct StringBuffer { - uint32_t ptr; - uint8_t* data; - size_t remaining_bytes; - }; - - uint32_t AppendString(StringBuffer& sb, const std::u16string_view string) { - size_t count = string.length() + 1; - size_t size = count * sizeof(char16_t); - if (size > sb.remaining_bytes) { - assert_always(); - return 0; - } - auto ptr = sb.ptr; - string_util::copy_and_swap_truncating(reinterpret_cast(sb.data), - string, count); - sb.ptr += static_cast(size); - sb.data += size; - sb.remaining_bytes -= size; - return ptr; - } - - private: - uint32_t flags_; - std::vector items_; - size_t current_item_ = 0; -}; - dword_result_t XamUserCreateAchievementEnumerator_entry( dword_t title_id, dword_t user_index, dword_t xuid, dword_t flags, dword_t offset, dword_t count, lpdword_t buffer_size_ptr, @@ -712,8 +595,8 @@ dword_result_t XamUserCreateAchievementEnumerator_entry( *buffer_size_ptr = static_cast(entry_size) * count; } - auto e = object_ref( - new XStaticAchievementEnumerator(kernel_state(), count, flags)); + auto e = object_ref( + new XAchievementEnumerator(kernel_state(), count, flags)); auto result = e->Initialize(user_index, 0xFB, 0xB000A, 0xB000B, 0); if (XFAILED(result)) { return result; @@ -735,7 +618,7 @@ dword_result_t XamUserCreateAchievementEnumerator_entry( kernel_state()->achievement_manager()->GetAchievementUnlockTime( entry.id); - auto item = XStaticAchievementEnumerator::AchievementDetails{ + auto item = XAchievementEnumerator::AchievementDetails{ entry.id, xe::to_utf16(db.GetStringTableEntry(language, entry.label_id)), xe::to_utf16(db.GetStringTableEntry(language, entry.description_id)), diff --git a/src/xenia/kernel/xenumerator.cc b/src/xenia/kernel/xenumerator.cc index dcaa6a07a..44f6169f2 100644 --- a/src/xenia/kernel/xenumerator.cc +++ b/src/xenia/kernel/xenumerator.cc @@ -78,5 +78,44 @@ uint32_t XStaticUntypedEnumerator::WriteItems(uint32_t buffer_ptr, return X_ERROR_SUCCESS; } +uint32_t XAchievementEnumerator::WriteItems(uint32_t buffer_ptr, + uint8_t* buffer_data, + uint32_t* written_count) { + size_t count = std::min(items_.size() - current_item_, items_per_enumerate()); + if (!count) { + return X_ERROR_NO_MORE_FILES; + } + + size_t size = count * item_size(); + + auto details = reinterpret_cast(buffer_data); + size_t string_offset = items_per_enumerate() * sizeof(X_ACHIEVEMENT_DETAILS); + auto string_buffer = + StringBuffer{buffer_ptr + static_cast(string_offset), + &buffer_data[string_offset], + count * X_ACHIEVEMENT_DETAILS::kStringBufferSize}; + for (size_t i = 0, o = current_item_; i < count; ++i, ++current_item_) { + const auto& item = items_[current_item_]; + details[i].id = item.id; + details[i].label_ptr = + !!(flags_ & 1) ? AppendString(string_buffer, item.label) : 0; + details[i].description_ptr = + !!(flags_ & 2) ? AppendString(string_buffer, item.description) : 0; + details[i].unachieved_ptr = + !!(flags_ & 4) ? AppendString(string_buffer, item.unachieved) : 0; + details[i].image_id = item.image_id; + details[i].gamerscore = item.gamerscore; + details[i].unlock_time.unk_0 = item.unlock_time.unk_0; + details[i].unlock_time.unk_4 = item.unlock_time.unk_4; + details[i].flags = item.flags; + } + + 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 7b2218e97..d89c08461 100644 --- a/src/xenia/kernel/xenumerator.h +++ b/src/xenia/kernel/xenumerator.h @@ -14,6 +14,7 @@ #include #include +#include "xenia/kernel/achievement_manager.h" #include "xenia/kernel/xobject.h" #include "xenia/xbox.h" @@ -113,6 +114,66 @@ class XStaticEnumerator : public XStaticUntypedEnumerator { } }; +class XAchievementEnumerator : public XEnumerator { + public: + struct AchievementDetails { + uint32_t id; + std::u16string label; + std::u16string description; + std::u16string unachieved; + uint32_t image_id; + uint32_t gamerscore; + struct { + uint32_t unk_0; + uint32_t unk_4; + } unlock_time; + uint32_t flags; + }; + + XAchievementEnumerator(KernelState* kernel_state, size_t items_per_enumerate, + uint32_t flags) + : XEnumerator( + kernel_state, items_per_enumerate, + sizeof(X_ACHIEVEMENT_DETAILS) + + (!!(flags & 7) ? X_ACHIEVEMENT_DETAILS::kStringBufferSize : 0)), + flags_(flags) {} + + void AppendItem(AchievementDetails item) { + items_.push_back(std::move(item)); + } + + uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, + uint32_t* written_count) override; + + private: + struct StringBuffer { + uint32_t ptr; + uint8_t* data; + size_t remaining_bytes; + }; + + uint32_t AppendString(StringBuffer& sb, const std::u16string_view string) { + size_t count = string.length() + 1; + size_t size = count * sizeof(char16_t); + if (size > sb.remaining_bytes) { + assert_always(); + return 0; + } + auto ptr = sb.ptr; + string_util::copy_and_swap_truncating(reinterpret_cast(sb.data), + string, count); + sb.ptr += static_cast(size); + sb.data += size; + sb.remaining_bytes -= size; + return ptr; + } + + private: + uint32_t flags_; + std::vector items_; + size_t current_item_ = 0; +}; + } // namespace kernel } // namespace xe