diff --git a/src/xenia/kernel/xam/user_profile.cc b/src/xenia/kernel/xam/user_profile.cc index c3e56d70f..d73ff0b9d 100644 --- a/src/xenia/kernel/xam/user_profile.cc +++ b/src/xenia/kernel/xam/user_profile.cc @@ -104,6 +104,9 @@ UserProfile::UserProfile() : dash_gpd_(kDashboardID) { account_.xuid_online = 0xE000BABEBABEBABE; wcscpy(account_.gamertag, L"XeniaUser"); + // Try loading profile GPD files... + LoadProfile(); + // https://cs.rin.ru/forum/viewtopic.php?f=38&t=60668&hilit=gfwl+live&start=195 // https://github.com/arkem/py360/blob/master/py360/constants.py // XPROFILE_GAMER_YAXIS_INVERSION @@ -168,9 +171,6 @@ UserProfile::UserProfile() : dash_gpd_(kDashboardID) { AddSetting(std::make_unique(0x63E83FFE)); // XPROFILE_TITLE_SPECIFIC3 AddSetting(std::make_unique(0x63E83FFD)); - - // Try loading profile GPD files... - LoadProfile(); } void UserProfile::LoadProfile() { @@ -597,6 +597,23 @@ xdbf::GpdFile* UserProfile::GetDashboardGpd() { return &dash_gpd_; } +xdbf::SpaFile* UserProfile::GetTitleSpa(uint32_t title_id) { + std::wstring file_location = xe::to_wstring(cvars::profile_directory) + + format_string(L"%X", title_id) + L".gpd"; + + auto mmap_ = MappedMemory::Open(file_location, MappedMemory::Mode::kRead); + + if (!mmap_) { + return (nullptr); + } + + xdbf::SpaFile* game_entry = new xdbf::SpaFile(); + game_entry->Read(mmap_->data(), mmap_->size()); + mmap_->Close(); + + return (game_entry); +} + } // namespace xam } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xam/user_profile.h b/src/xenia/kernel/xam/user_profile.h index f253436d3..d0071bcb1 100644 --- a/src/xenia/kernel/xam/user_profile.h +++ b/src/xenia/kernel/xam/user_profile.h @@ -18,6 +18,7 @@ #include "xenia/kernel/xam/xdbf/xdbf.h" #include "xenia/xbox.h" + namespace xe { namespace kernel { namespace xam { @@ -323,6 +324,7 @@ class UserProfile { xdbf::GpdFile* SetTitleSpaData(const xdbf::SpaFile& spa_data); xdbf::GpdFile* GetTitleGpd(uint32_t title_id = -1); xdbf::GpdFile* GetDashboardGpd(); + xdbf::SpaFile* GetTitleSpa(uint32_t title_id); void GetTitles(std::vector& titles); diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index 072c9058e..bf66a1724 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -720,7 +720,30 @@ dword_result_t XamUserCreateTitlesPlayedEnumerator( return X_ERROR_SUCCESS; } -DECLARE_XAM_EXPORT1(XamUserCreateTitlesPlayedEnumerator, kUserProfiles, kStub); +DECLARE_XAM_EXPORT1(XamUserCreateTitlesPlayedEnumerator, kUserProfiles, kImplemented); + +dword_result_t XamReadTile(dword_t section_id, dword_t game_id, dword_t item_id, + dword_t offset, lpdword_t output_ptr, + lpdword_t buffer_size_ptr, + lpdword_t overlapped_ptr) { + if (!output_ptr) { + return X_ERROR_FILE_NOT_FOUND; + } + + SpaFile* game_spa = + kernel_state()->user_profile()->GetTitleSpa(game_id.value()); + + if (!game_spa) { + return X_ERROR_FILE_NOT_FOUND; + } + + // Section 2 == images + Entry* entry = game_spa->GetEntry(2, item_id.value()); + memcpy_s(output_ptr, *buffer_size_ptr, entry->data.data(), entry->info.size); + + return X_ERROR_SUCCESS; +} +DECLARE_XAM_EXPORT1(XamReadTile, kUserProfiles, kSketchy); } // namespace xdbf } // namespace xam