[Kernel] Put achievement enumerator in xenumerator file
This commit is contained in:
parent
57a23cf192
commit
a5596332c9
|
@ -19,6 +19,26 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
|
// TODO(gibbed): probably a FILETIME/LARGE_INTEGER, unknown currently
|
||||||
|
struct X_ACHIEVEMENT_UNLOCK_TIME {
|
||||||
|
xe::be<uint32_t> unk_0;
|
||||||
|
xe::be<uint32_t> unk_4;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct X_ACHIEVEMENT_DETAILS {
|
||||||
|
xe::be<uint32_t> id;
|
||||||
|
xe::be<uint32_t> label_ptr;
|
||||||
|
xe::be<uint32_t> description_ptr;
|
||||||
|
xe::be<uint32_t> unachieved_ptr;
|
||||||
|
xe::be<uint32_t> image_id;
|
||||||
|
xe::be<uint32_t> gamerscore;
|
||||||
|
X_ACHIEVEMENT_UNLOCK_TIME unlock_time;
|
||||||
|
xe::be<uint32_t> flags;
|
||||||
|
|
||||||
|
static const size_t kStringBufferSize = 464;
|
||||||
|
};
|
||||||
|
static_assert_size(X_ACHIEVEMENT_DETAILS, 36);
|
||||||
|
|
||||||
class AchievementManager {
|
class AchievementManager {
|
||||||
public:
|
public:
|
||||||
AchievementManager();
|
AchievementManager();
|
||||||
|
|
|
@ -574,123 +574,6 @@ dword_result_t XamShowSigninUI_entry(dword_t unk, dword_t unk_mask) {
|
||||||
}
|
}
|
||||||
DECLARE_XAM_EXPORT1(XamShowSigninUI, kUserProfiles, kStub);
|
DECLARE_XAM_EXPORT1(XamShowSigninUI, kUserProfiles, kStub);
|
||||||
|
|
||||||
// TODO(gibbed): probably a FILETIME/LARGE_INTEGER, unknown currently
|
|
||||||
struct X_ACHIEVEMENT_UNLOCK_TIME {
|
|
||||||
xe::be<uint32_t> unk_0;
|
|
||||||
xe::be<uint32_t> unk_4;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct X_ACHIEVEMENT_DETAILS {
|
|
||||||
xe::be<uint32_t> id;
|
|
||||||
xe::be<uint32_t> label_ptr;
|
|
||||||
xe::be<uint32_t> description_ptr;
|
|
||||||
xe::be<uint32_t> unachieved_ptr;
|
|
||||||
xe::be<uint32_t> image_id;
|
|
||||||
xe::be<uint32_t> gamerscore;
|
|
||||||
X_ACHIEVEMENT_UNLOCK_TIME unlock_time;
|
|
||||||
xe::be<uint32_t> 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<X_ACHIEVEMENT_DETAILS*>(buffer_data);
|
|
||||||
size_t string_offset =
|
|
||||||
items_per_enumerate() * sizeof(X_ACHIEVEMENT_DETAILS);
|
|
||||||
auto string_buffer =
|
|
||||||
StringBuffer{buffer_ptr + static_cast<uint32_t>(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<uint32_t>(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<char16_t*>(sb.data),
|
|
||||||
string, count);
|
|
||||||
sb.ptr += static_cast<uint32_t>(size);
|
|
||||||
sb.data += size;
|
|
||||||
sb.remaining_bytes -= size;
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t flags_;
|
|
||||||
std::vector<AchievementDetails> items_;
|
|
||||||
size_t current_item_ = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
dword_result_t XamUserCreateAchievementEnumerator_entry(
|
dword_result_t XamUserCreateAchievementEnumerator_entry(
|
||||||
dword_t title_id, dword_t user_index, dword_t xuid, dword_t flags,
|
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,
|
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<uint32_t>(entry_size) * count;
|
*buffer_size_ptr = static_cast<uint32_t>(entry_size) * count;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto e = object_ref<XStaticAchievementEnumerator>(
|
auto e = object_ref<XAchievementEnumerator>(
|
||||||
new XStaticAchievementEnumerator(kernel_state(), count, flags));
|
new XAchievementEnumerator(kernel_state(), count, flags));
|
||||||
auto result = e->Initialize(user_index, 0xFB, 0xB000A, 0xB000B, 0);
|
auto result = e->Initialize(user_index, 0xFB, 0xB000A, 0xB000B, 0);
|
||||||
if (XFAILED(result)) {
|
if (XFAILED(result)) {
|
||||||
return result;
|
return result;
|
||||||
|
@ -735,7 +618,7 @@ dword_result_t XamUserCreateAchievementEnumerator_entry(
|
||||||
kernel_state()->achievement_manager()->GetAchievementUnlockTime(
|
kernel_state()->achievement_manager()->GetAchievementUnlockTime(
|
||||||
entry.id);
|
entry.id);
|
||||||
|
|
||||||
auto item = XStaticAchievementEnumerator::AchievementDetails{
|
auto item = XAchievementEnumerator::AchievementDetails{
|
||||||
entry.id,
|
entry.id,
|
||||||
xe::to_utf16(db.GetStringTableEntry(language, entry.label_id)),
|
xe::to_utf16(db.GetStringTableEntry(language, entry.label_id)),
|
||||||
xe::to_utf16(db.GetStringTableEntry(language, entry.description_id)),
|
xe::to_utf16(db.GetStringTableEntry(language, entry.description_id)),
|
||||||
|
|
|
@ -78,5 +78,44 @@ uint32_t XStaticUntypedEnumerator::WriteItems(uint32_t buffer_ptr,
|
||||||
return X_ERROR_SUCCESS;
|
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<X_ACHIEVEMENT_DETAILS*>(buffer_data);
|
||||||
|
size_t string_offset = items_per_enumerate() * sizeof(X_ACHIEVEMENT_DETAILS);
|
||||||
|
auto string_buffer =
|
||||||
|
StringBuffer{buffer_ptr + static_cast<uint32_t>(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<uint32_t>(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return X_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "xenia/kernel/achievement_manager.h"
|
||||||
#include "xenia/kernel/xobject.h"
|
#include "xenia/kernel/xobject.h"
|
||||||
#include "xenia/xbox.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<char16_t*>(sb.data),
|
||||||
|
string, count);
|
||||||
|
sb.ptr += static_cast<uint32_t>(size);
|
||||||
|
sb.data += size;
|
||||||
|
sb.remaining_bytes -= size;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t flags_;
|
||||||
|
std::vector<AchievementDetails> items_;
|
||||||
|
size_t current_item_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue