diff --git a/src/xenia/kernel/xam/profile_manager.cc b/src/xenia/kernel/xam/profile_manager.cc index cfc0502b0..d6c1a1ab1 100644 --- a/src/xenia/kernel/xam/profile_manager.cc +++ b/src/xenia/kernel/xam/profile_manager.cc @@ -489,6 +489,23 @@ bool ProfileManager::CreateProfile(const std::string gamertag, bool autologin, return is_account_created; } +bool ProfileManager::CreateProfile(const X_XAMACCOUNTINFO* account_info, + uint64_t xuid) { + if (!xuid) { + xuid = GenerateXuid(); + } + + if (!std::filesystem::create_directories(GetProfilePath(xuid))) { + return false; + } + + if (!MountProfile(xuid)) { + return false; + } + + return CreateAccount(xuid, account_info); +} + const X_XAMACCOUNTINFO* ProfileManager::GetAccount(const uint64_t xuid) { if (!accounts_.count(xuid)) { return nullptr; @@ -505,15 +522,26 @@ bool ProfileManager::CreateAccount(const uint64_t xuid, string_util::copy_truncating(account.gamertag, gamertag_u16, sizeof(account.gamertag)); - UpdateAccount(xuid, &account); + const bool result = UpdateAccount(xuid, &account); DismountProfile(xuid); - accounts_.insert({xuid, account}); - return true; + if (result) { + accounts_.insert({xuid, account}); + } + return result; +} + +bool ProfileManager::CreateAccount(const uint64_t xuid, + const X_XAMACCOUNTINFO* account) { + const bool result = UpdateAccount(xuid, account); + if (result) { + accounts_.insert({xuid, *account}); + } + return result; } bool ProfileManager::UpdateAccount(const uint64_t xuid, - X_XAMACCOUNTINFO* account) { + const X_XAMACCOUNTINFO* account) { const std::string guest_path = fmt::format(kDefaultMountFormat, xuid) + ":\\Account"; diff --git a/src/xenia/kernel/xam/profile_manager.h b/src/xenia/kernel/xam/profile_manager.h index e6ef40aa0..d5d618bf6 100644 --- a/src/xenia/kernel/xam/profile_manager.h +++ b/src/xenia/kernel/xam/profile_manager.h @@ -64,7 +64,8 @@ class ProfileManager { bool CreateProfile(const std::string gamertag, bool autologin, bool default_xuid = false); - // bool CreateProfile(const X_XAMACCOUNTINFO* account_info); + bool CreateProfile(const X_XAMACCOUNTINFO* account_info, uint64_t xuid); + bool DeleteProfile(const uint64_t xuid); void ModifyGamertag(const uint64_t xuid, std::string gamertag); @@ -105,7 +106,8 @@ class ProfileManager { private: void UpdateConfig(const uint64_t xuid, const uint8_t slot); bool CreateAccount(const uint64_t xuid, const std::string gamertag); - bool UpdateAccount(const uint64_t xuid, X_XAMACCOUNTINFO* account); + bool CreateAccount(const uint64_t xuid, const X_XAMACCOUNTINFO* account); + bool UpdateAccount(const uint64_t xuid, const X_XAMACCOUNTINFO* account); std::filesystem::path GetProfilePath(const uint64_t xuid) const; std::filesystem::path GetProfilePath(const std::string xuid) const; diff --git a/src/xenia/kernel/xam/user_profile.h b/src/xenia/kernel/xam/user_profile.h index dd4c387b9..771ab1781 100644 --- a/src/xenia/kernel/xam/user_profile.h +++ b/src/xenia/kernel/xam/user_profile.h @@ -91,11 +91,13 @@ class UserProfile { std::span GetProfileIcon(XTileType icon_type) { // Overwrite same types? - if (icon_type == XTileType::kPersonalGamerTile) { + if (icon_type == XTileType::kPersonalGamerTile || + icon_type == XTileType::kLocalGamerTile) { icon_type = XTileType::kGamerTile; } - if (icon_type == XTileType::kPersonalGamerTileSmall) { + if (icon_type == XTileType::kPersonalGamerTileSmall || + icon_type == XTileType::kLocalGamerTileSmall) { icon_type = XTileType::kGamerTileSmall; } diff --git a/src/xenia/kernel/xam/user_tracker.cc b/src/xenia/kernel/xam/user_tracker.cc index 458fa2307..05aa98f3f 100644 --- a/src/xenia/kernel/xam/user_tracker.cc +++ b/src/xenia/kernel/xam/user_tracker.cc @@ -770,6 +770,8 @@ std::span UserTracker::GetIcon(uint64_t xuid, uint32_t title_id, } case XTileType::kGamerTile: case XTileType::kGamerTileSmall: + case XTileType::kLocalGamerTile: + case XTileType::kLocalGamerTileSmall: case XTileType::kPersonalGamerTile: case XTileType::kPersonalGamerTileSmall: return user->GetProfileIcon(tile_type); diff --git a/src/xenia/kernel/xam/xam_content_device.cc b/src/xenia/kernel/xam/xam_content_device.cc index 0102f9b7c..52988bed1 100644 --- a/src/xenia/kernel/xam/xam_content_device.cc +++ b/src/xenia/kernel/xam/xam_content_device.cc @@ -15,6 +15,7 @@ #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xam/xam_private.h" #include "xenia/kernel/xenumerator.h" +#include "xenia/vfs/devices/stfs_xbox.h" #include "xenia/xbox.h" namespace xe { @@ -171,6 +172,11 @@ dword_result_t XamContentCreateDeviceEnumerator_entry(dword_t content_type, } for (const auto& device_info : dummy_device_infos_) { + if (device_info->device_type == DeviceType::ODD && + (content_flags & vfs::XContentFlag::kExcludeReadOnlyDevices)) { + continue; + } + // Copy our dummy device into the enumerator auto device_data = e->AppendItem(); assert_not_null(device_data); diff --git a/src/xenia/kernel/xam/xam_content_device.h b/src/xenia/kernel/xam/xam_content_device.h index c4bb57982..088bcf983 100644 --- a/src/xenia/kernel/xam/xam_content_device.h +++ b/src/xenia/kernel/xam/xam_content_device.h @@ -19,6 +19,7 @@ namespace xam { enum class DeviceType : uint32_t { Invalid = 0, HDD = 1, + MU = 2, ODD = 4, }; diff --git a/src/xenia/kernel/xam/xam_profile.cc b/src/xenia/kernel/xam/xam_profile.cc index 12afb909c..3cc511140 100644 --- a/src/xenia/kernel/xam/xam_profile.cc +++ b/src/xenia/kernel/xam/xam_profile.cc @@ -62,11 +62,40 @@ dword_result_t XamProfileCreate_entry(dword_t flags, lpdword_t device_id, pointer_t account, dword_t unk1, dword_t unk2, dword_t unk3, dword_t unk4) { - // **unk4 + if (device_id) { + *device_id = 0x1; + } + if (xuid != 0) { + assert_always(); + return X_E_INVALIDARG; + } + + X_XAMACCOUNTINFO account_info_data; + memcpy(&account_info_data, account, sizeof(X_XAMACCOUNTINFO)); + xe::copy_and_swap(account_info_data.gamertag, + account_info_data.gamertag, 16); + + bool result = kernel_state()->xam_state()->profile_manager()->CreateProfile( + &account_info_data, xuid); + + return result ? X_ERROR_SUCCESS : X_ERROR_INVALID_PARAMETER; +} +DECLARE_XAM_EXPORT1(XamProfileCreate, kNone, kSketchy); + +dword_result_t XamProfileClose_entry(lpstring_t mount_name) { + std::string guest_name = mount_name.value(); + const bool result = + kernel_state()->file_system()->UnregisterDevice(guest_name + ':'); + + return result ? X_ERROR_SUCCESS : X_ERROR_FUNCTION_FAILED; +} +DECLARE_XAM_EXPORT1(XamProfileClose, kNone, kStub); + +dword_result_t XamProfileGetCreationStatus_entry(lpdword_t r3, lpdword_t r4) { return X_ERROR_SUCCESS; } -DECLARE_XAM_EXPORT1(XamProfileCreate, kNone, kStub); +DECLARE_XAM_EXPORT1(XamProfileGetCreationStatus, kNone, kStub); } // namespace xam } // namespace kernel diff --git a/src/xenia/kernel/xam/xam_ui.cc b/src/xenia/kernel/xam/xam_ui.cc index 9f2cb0ae5..1fd79fca4 100644 --- a/src/xenia/kernel/xam/xam_ui.cc +++ b/src/xenia/kernel/xam/xam_ui.cc @@ -2086,15 +2086,19 @@ dword_result_t XamShowCreateProfileUI_entry(dword_t user_index, dword_t unkn) { DECLARE_XAM_EXPORT1(XamShowCreateProfileUI, kUserProfiles, kImplemented); dword_result_t XamShowAchievementsUI_entry(dword_t user_index, - dword_t unk_mask) { + dword_t title_id) { auto user = kernel_state()->xam_state()->GetUserProfile(user_index); if (!user) { return X_ERROR_NO_SUCH_USER; } + uint32_t proper_title_id = + title_id ? title_id.value() + : kernel_state()->xam_state()->spa_info()->title_id(); + const auto info = kernel_state()->xam_state()->user_tracker()->GetUserTitleInfo( - user->xuid(), kernel_state()->xam_state()->spa_info()->title_id()); + user->xuid(), proper_title_id); if (!info) { return X_ERROR_NO_SUCH_USER; diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index e7cbe1690..19d68ab05 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -638,7 +638,10 @@ dword_result_t XamReadTile_entry(dword_t tile_type, dword_t title_id, dword_t overlapped_ptr) { auto user = kernel_state()->xam_state()->GetUserProfile(user_index); if (!user) { - return X_ERROR_INVALID_PARAMETER; + user = kernel_state()->xam_state()->GetUserProfile(item_id); + if (!user) { + return X_ERROR_INVALID_PARAMETER; + } } if (!buffer_size_ptr) { @@ -802,7 +805,7 @@ dword_result_t XamReadTileToTexture_entry(dword_t tile_type, dword_t title_id, } DECLARE_XAM_EXPORT1(XamReadTileToTexture, kUserProfiles, kStub); -dword_result_t XamWriteGamerTile_entry(dword_t arg1, dword_t arg2, +dword_result_t XamWriteGamerTile_entry(dword_t user_index, dword_t title_id, dword_t small_tile_id, dword_t big_tile_id, dword_t arg5, dword_t overlapped_ptr) { diff --git a/src/xenia/vfs/devices/stfs_xbox.h b/src/xenia/vfs/devices/stfs_xbox.h index 8c133a601..702291047 100644 --- a/src/xenia/vfs/devices/stfs_xbox.h +++ b/src/xenia/vfs/devices/stfs_xbox.h @@ -89,7 +89,13 @@ enum XContentFlag : uint32_t { kForceUI = 0x200, // Enumeration - kExcludeCommon = 0x1000 + kExcludeCommon = 0x1000, + + // Other + kEnumerateAllProfiles = 0x10000000, + + // Device enumerator? + kExcludeReadOnlyDevices = 0x80000000, }; /* STFS structures */