[XAM] Add XamShowCreateProfileUI & XamProfileCreate impl.
Seems to kinda work, xshell uses XamProfileCreate and says that it's successful at least. Dash uses the ShowUI function, but doesn't seem to login to the created profile correctly for some reason... restarting with the toml configured for the new profile does seem to work though.
This commit is contained in:
parent
a2037b15bc
commit
dcfc9321f8
|
@ -286,6 +286,53 @@ std::wstring UserProfile::ExtractProfile(const std::wstring& path) {
|
|||
return package + L"\\";
|
||||
}
|
||||
|
||||
bool UserProfile::Create(X_XAMACCOUNTINFO* account, bool generate_gamertag) {
|
||||
// TODO: check for any existing profile with the same account->gamertag!
|
||||
|
||||
static int num_xuids = 0; // TODO: we really should save this between runs
|
||||
// Create some unique IDs for the profile
|
||||
xuid_offline_ = 0xE0000000BEEFCAFE + num_xuids;
|
||||
account->xuid_online = 0x09000000BEEFCAFE + num_xuids;
|
||||
if (generate_gamertag) {
|
||||
swprintf_s(account->gamertag, L"XeniaUser%d", num_xuids);
|
||||
}
|
||||
num_xuids++;
|
||||
|
||||
profile_path_ = path(xuid_offline_);
|
||||
profile_path_ = ExtractProfile(profile_path_);
|
||||
|
||||
memcpy(&account_, account, sizeof(X_XAMACCOUNTINFO));
|
||||
|
||||
if (!filesystem::PathExists(profile_path_)) {
|
||||
// Profile path doesn't exist - create new profile!
|
||||
if (!filesystem::CreateFolder(profile_path_)) {
|
||||
XELOGE("UserProfile::Create: Failed to create profile for '%S' at %S!",
|
||||
account->gamertag, path().c_str());
|
||||
return false;
|
||||
} else {
|
||||
// Write out an account file
|
||||
filesystem::CreateFile(
|
||||
path() + L"Account"); // MappedMemory needs an existing file...
|
||||
auto mmap_ = MappedMemory::Open(path() + L"Account",
|
||||
MappedMemory::Mode::kReadWrite, 0,
|
||||
sizeof(X_XAMACCOUNTINFO) + 0x18);
|
||||
if (!mmap_) {
|
||||
XELOGE("UserProfile::Create: Failed to create new Account at %S!",
|
||||
path().c_str());
|
||||
return false;
|
||||
} else {
|
||||
XELOGI("Writing Account file for '%S' to path %SAccount",
|
||||
account->gamertag, path().c_str());
|
||||
EncryptAccountFile(account, mmap_->data(), false);
|
||||
mmap_->Close();
|
||||
}
|
||||
|
||||
// Dash GPD will be updated below, after default settings are added
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UserProfile::Login(uint64_t offline_xuid) {
|
||||
xuid_offline_ = offline_xuid;
|
||||
auto profile_path = path(xuid_offline_);
|
||||
|
@ -308,12 +355,9 @@ bool UserProfile::Login(uint64_t offline_xuid) {
|
|||
"using temp. profile");
|
||||
|
||||
memset(&account_, 0, sizeof(X_XAMACCOUNTINFO));
|
||||
// Create some unique IDs for the profile
|
||||
static int num_xuids = 0;
|
||||
xuid_offline_ = 0xE0000000BEEFCAFE + num_xuids;
|
||||
account_.xuid_online = 0x09000000BEEFCAFE + num_xuids;
|
||||
swprintf_s(account_.gamertag, L"XeniaUser%d", num_xuids);
|
||||
num_xuids++;
|
||||
if (!Create(&account_, true)) {
|
||||
return false;
|
||||
}
|
||||
profile_path = path(xuid_offline_);
|
||||
}
|
||||
|
||||
|
@ -325,31 +369,7 @@ bool UserProfile::Login(uint64_t offline_xuid) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!filesystem::PathExists(profile_path_)) {
|
||||
// Profile path doesn't exist - create new profile!
|
||||
if (!filesystem::CreateFolder(profile_path_)) {
|
||||
XELOGE("UserProfile::Login: Failed to create profile for '%S' at %S!",
|
||||
account_.gamertag, path().c_str());
|
||||
} else {
|
||||
// Write out an account file
|
||||
filesystem::CreateFile(
|
||||
path() + L"Account"); // MappedMemory needs an existing file...
|
||||
auto mmap_ = MappedMemory::Open(path() + L"Account",
|
||||
MappedMemory::Mode::kReadWrite, 0,
|
||||
sizeof(X_XAMACCOUNTINFO) + 0x18);
|
||||
if (!mmap_) {
|
||||
XELOGE("UserProfile::Login: Failed to create new Account at %S!",
|
||||
path().c_str());
|
||||
} else {
|
||||
XELOGI("Writing Account file for '%S' to path %SAccount",
|
||||
account_.gamertag, path().c_str());
|
||||
EncryptAccountFile(&account_, mmap_->data(), false);
|
||||
mmap_->Close();
|
||||
}
|
||||
|
||||
// Dash GPD will be updated below, after default settings are added
|
||||
}
|
||||
} else {
|
||||
if (filesystem::PathExists(profile_path_)) {
|
||||
// Profile exists, load Account and any GPDs
|
||||
auto mmap_ =
|
||||
MappedMemory::Open(path() + L"Account", MappedMemory::Mode::kRead);
|
||||
|
|
|
@ -216,6 +216,7 @@ class UserProfile {
|
|||
// If no profiles are available, will use a Xenia-generated one
|
||||
bool Login(uint64_t offline_xuid = 0);
|
||||
void Logout();
|
||||
bool Create(X_XAMACCOUNTINFO* account, bool generate_gamertag = false);
|
||||
|
||||
private:
|
||||
// Extracts profile package if needed - returns path to extracted folder
|
||||
|
|
|
@ -490,6 +490,54 @@ void XamShowDirtyDiscErrorUI(dword_t user_index) {
|
|||
}
|
||||
DECLARE_XAM_EXPORT1(XamShowDirtyDiscErrorUI, kUI, kImplemented);
|
||||
|
||||
dword_result_t XamShowCreateProfileUI(dword_t user_index) {
|
||||
auto user = kernel_state()->user_profile(user_index, true);
|
||||
if (!user) {
|
||||
return X_ERROR_ACCESS_DENIED; // xam returns this when errors?
|
||||
}
|
||||
|
||||
// Broadcast XN_SYS_UI = true
|
||||
kernel_state()->BroadcastNotification(0x9, true);
|
||||
|
||||
xe::threading::Fence fence;
|
||||
std::wstring out_text;
|
||||
|
||||
++xam_dialogs_shown_;
|
||||
|
||||
auto display_window = kernel_state()->emulator()->display_window();
|
||||
display_window->loop()->PostSynchronous([&]() {
|
||||
// Create the dialog
|
||||
(new KeyboardInputDialog(display_window, L"Profile Creation",
|
||||
L"Choose a gamertag", L"", &out_text, 15))
|
||||
->Then(&fence);
|
||||
});
|
||||
|
||||
fence.Wait();
|
||||
|
||||
--xam_dialogs_shown_;
|
||||
|
||||
// Broadcast XN_SYS_UI = true
|
||||
kernel_state()->BroadcastNotification(0x9, false);
|
||||
|
||||
X_XAMACCOUNTINFO account;
|
||||
memset(&account, 0, sizeof(X_XAMACCOUNTINFO));
|
||||
memcpy(account.gamertag, out_text.c_str(),
|
||||
std::min((uint32_t)out_text.size(), 15u) * sizeof(wchar_t));
|
||||
|
||||
user->Logout();
|
||||
user->Create(&account, false);
|
||||
|
||||
// TODO: the following does seem to trigger dash and make it try reloading the
|
||||
// profile, but some reason it won't load properly until restart (no
|
||||
// gamertag/gamerscore/games shown, etc)
|
||||
// maybe need to set some notification for it or something?
|
||||
user->Login(user->xuid_offline());
|
||||
user->signin_state(1);
|
||||
|
||||
return X_ERROR_SUCCESS;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamShowCreateProfileUI, kUI, kImplemented);
|
||||
|
||||
void RegisterUIExports(xe::cpu::ExportResolver* export_resolver,
|
||||
KernelState* kernel_state) {}
|
||||
|
||||
|
|
|
@ -881,6 +881,31 @@ dword_result_t XamUserGetIndexFromXUID(qword_t xuid, dword_t r4,
|
|||
}
|
||||
DECLARE_XAM_EXPORT1(XamUserGetIndexFromXUID, kUserProfiles, kStub);
|
||||
|
||||
dword_result_t XamProfileCreate(dword_t flags, lpdword_t device_id,
|
||||
qword_t xuid,
|
||||
pointer_t<X_XAMACCOUNTINFO> account, dword_t r7,
|
||||
dword_t r8, dword_t r9, dword_t r10) {
|
||||
*device_id = 0xF00D0000;
|
||||
|
||||
X_XAMACCOUNTINFO swapped;
|
||||
memcpy(&swapped, account, sizeof(X_XAMACCOUNTINFO));
|
||||
xe::copy_and_swap<wchar_t>(swapped.gamertag, swapped.gamertag, 16);
|
||||
|
||||
if (xuid != 0) {
|
||||
// Why is this param even included?
|
||||
return X_E_INVALIDARG;
|
||||
}
|
||||
|
||||
xam::UserProfile profile(kernel_state());
|
||||
profile.Create(&swapped, false);
|
||||
auto new_xuid = profile.xuid_offline();
|
||||
|
||||
// TODO: r10 seems to be some kind of output?
|
||||
|
||||
return X_ERROR_SUCCESS;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamProfileCreate, kUserProfiles, kStub);
|
||||
|
||||
} // namespace xdbf
|
||||
} // namespace xam
|
||||
} // namespace kernel
|
||||
|
|
Loading…
Reference in New Issue