241 lines
6.8 KiB
C++
241 lines
6.8 KiB
C++
/**
|
|
******************************************************************************
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
******************************************************************************
|
|
* Copyright 2014 Ben Vanik. All rights reserved. *
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
******************************************************************************
|
|
*/
|
|
|
|
#ifndef XENIA_KERNEL_XAM_USER_PROFILE_H_
|
|
#define XENIA_KERNEL_XAM_USER_PROFILE_H_
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include "xenia/kernel/xam/xdbf/xdbf.h"
|
|
#include "xenia/xbox.h"
|
|
|
|
namespace xe {
|
|
namespace kernel {
|
|
class KernelState;
|
|
} // namespace kernel
|
|
} // namespace xe
|
|
|
|
namespace xe {
|
|
namespace kernel {
|
|
namespace xam {
|
|
|
|
constexpr uint32_t kMaxNumUsers = 4;
|
|
constexpr uint32_t kDashboardID = 0xFFFE07D1;
|
|
|
|
// https://github.com/jogolden/testdev/blob/master/xkelib/xam/_xamext.h#L68
|
|
enum class XTileType {
|
|
kAchievement,
|
|
kGameIcon,
|
|
kGamerTile,
|
|
kGamerTileSmall,
|
|
kLocalGamerTile,
|
|
kLocalGamerTileSmall,
|
|
kBkgnd,
|
|
kAwardedGamerTile,
|
|
kAwardedGamerTileSmall,
|
|
kGamerTileByImageId,
|
|
kPersonalGamerTile,
|
|
kPersonalGamerTileSmall,
|
|
kGamerTileByKey,
|
|
kAvatarGamerTile,
|
|
kAvatarGamerTileSmall,
|
|
kAvatarFullBody
|
|
};
|
|
|
|
// TODO: find filenames of other tile types that are stored in profile
|
|
static const std::map<XTileType, wchar_t*> kTileFileNames = {
|
|
{XTileType::kPersonalGamerTile, L"tile_64.png"},
|
|
{XTileType::kPersonalGamerTileSmall, L"tile_32.png"},
|
|
{XTileType::kAvatarGamerTile, L"avtr_64.png"},
|
|
{XTileType::kAvatarGamerTileSmall, L"avtr_32.png"},
|
|
};
|
|
|
|
// from https://github.com/xemio/testdev/blob/master/xkelib/xam/_xamext.h
|
|
#pragma pack(push, 4)
|
|
struct X_XAMACCOUNTINFO {
|
|
enum AccountReservedFlags {
|
|
kPasswordProtected = 0x10000000,
|
|
kLiveEnabled = 0x20000000,
|
|
kRecovering = 0x40000000,
|
|
kVersionMask = 0x000000FF
|
|
};
|
|
|
|
enum AccountUserFlags {
|
|
kPaymentInstrumentCreditCard = 1,
|
|
|
|
kCountryMask = 0xFF00,
|
|
kSubscriptionTierMask = 0xF00000,
|
|
kLanguageMask = 0x3E000000,
|
|
|
|
kParentalControlEnabled = 0x1000000,
|
|
};
|
|
|
|
enum AccountSubscriptionTier {
|
|
kSubscriptionTierSilver = 3,
|
|
kSubscriptionTierGold = 6,
|
|
kSubscriptionTierFamilyGold = 9
|
|
};
|
|
|
|
// already exists inside xdbf.h??
|
|
enum AccountLanguage {
|
|
kNoLanguage,
|
|
kEnglish,
|
|
kJapanese,
|
|
kGerman,
|
|
kFrench,
|
|
kSpanish,
|
|
kItalian,
|
|
kKorean,
|
|
kTChinese,
|
|
kPortuguese,
|
|
kSChinese,
|
|
kPolish,
|
|
kRussian,
|
|
kNorwegian = 15
|
|
};
|
|
|
|
enum AccountLiveFlags { kAcctRequiresManagement = 1 };
|
|
|
|
xe::be<uint32_t> reserved_flags;
|
|
xe::be<uint32_t> live_flags;
|
|
wchar_t gamertag[0x10];
|
|
xe::be<uint64_t> xuid_online; // 09....
|
|
xe::be<uint32_t> cached_user_flags;
|
|
xe::be<uint32_t> network_id;
|
|
char passcode[4];
|
|
char online_domain[0x14];
|
|
char online_kerberos_realm[0x18];
|
|
char online_key[0x10];
|
|
char passport_membername[0x72];
|
|
char passport_password[0x20];
|
|
char owner_passport_membername[0x72];
|
|
|
|
bool IsPasscodeEnabled() {
|
|
return (bool)(reserved_flags & AccountReservedFlags::kPasswordProtected);
|
|
}
|
|
|
|
bool IsLiveEnabled() {
|
|
return (bool)(reserved_flags & AccountReservedFlags::kLiveEnabled);
|
|
}
|
|
|
|
bool IsRecovering() {
|
|
return (bool)(reserved_flags & AccountReservedFlags::kRecovering);
|
|
}
|
|
|
|
bool IsPaymentInstrumentCreditCard() {
|
|
return (bool)(cached_user_flags &
|
|
AccountUserFlags::kPaymentInstrumentCreditCard);
|
|
}
|
|
|
|
bool IsParentalControlled() {
|
|
return (bool)(cached_user_flags &
|
|
AccountUserFlags::kParentalControlEnabled);
|
|
}
|
|
|
|
bool IsXUIDOffline() { return ((xuid_online >> 60) & 0xF) == 0xE; }
|
|
bool IsXUIDOnline() { return ((xuid_online >> 48) & 0xFFFF) == 0x9; }
|
|
bool IsXUIDValid() { return IsXUIDOffline() != IsXUIDOnline(); }
|
|
bool IsTeamXUID() {
|
|
return (xuid_online & 0xFF00000000000140) == 0xFE00000000000100;
|
|
}
|
|
|
|
uint32_t GetCountry() { return (cached_user_flags & kCountryMask) >> 8; }
|
|
|
|
AccountSubscriptionTier GetSubscriptionTier() {
|
|
return (AccountSubscriptionTier)(
|
|
(cached_user_flags & kSubscriptionTierMask) >> 20);
|
|
}
|
|
|
|
AccountLanguage GetLanguage() {
|
|
return (AccountLanguage)((cached_user_flags & kLanguageMask) >> 25);
|
|
}
|
|
|
|
std::string GetGamertagString() const;
|
|
};
|
|
// static_assert_size(X_XAMACCOUNTINFO, 0x17C);
|
|
#pragma pack(pop)
|
|
|
|
class UserProfile {
|
|
public:
|
|
static void CreateUsers(KernelState* kernel_state,
|
|
std::unique_ptr<UserProfile>* profiles);
|
|
|
|
// Returns map of OfflineXuid -> Path & AccountInfo pairs
|
|
static std::map<uint64_t, std::tuple<std::wstring, X_XAMACCOUNTINFO>>
|
|
Enumerate(KernelState* state, bool exclude_signed_in = false);
|
|
|
|
static uint64_t XuidFromPath(const std::wstring& path);
|
|
|
|
static bool DecryptAccountFile(const uint8_t* data, X_XAMACCOUNTINFO* output,
|
|
bool devkit = false);
|
|
|
|
static void EncryptAccountFile(const X_XAMACCOUNTINFO* input, uint8_t* output,
|
|
bool devkit = false);
|
|
|
|
static std::wstring base_path(KernelState* state);
|
|
|
|
UserProfile(KernelState* kernel_state);
|
|
|
|
uint64_t xuid() const { return account_.xuid_online; }
|
|
uint64_t xuid_offline() const { return xuid_offline_; }
|
|
std::string name() const { return account_.GetGamertagString(); }
|
|
std::wstring path() const;
|
|
std::wstring path(uint64_t xuid) const;
|
|
uint32_t signin_state() const { return signin_state_; }
|
|
void signin_state(uint32_t state) { signin_state_ = state; }
|
|
bool signed_in() { return signin_state_ != 0 && xuid_offline_ != 0; }
|
|
|
|
xdbf::GpdFile* SetTitleSpaData(const xdbf::SpaFile& spa_data);
|
|
xdbf::GpdFile* GetTitleGpd(uint32_t title_id = -1);
|
|
xdbf::GpdFile* GetDashboardGpd();
|
|
|
|
void GetTitles(std::vector<xdbf::GpdFile*>& titles);
|
|
|
|
bool UpdateTitleGpd(uint32_t title_id = -1);
|
|
bool UpdateAllGpds();
|
|
|
|
// Tries logging this user into a profile
|
|
// If XUID == 0, will use Xenia generated profile
|
|
// If XUID == 1, will try loading from any available profile
|
|
// If XUID is any other ID, will try loading from the profile it belongs to
|
|
bool Login(uint64_t offline_xuid = 0);
|
|
void Logout();
|
|
|
|
private:
|
|
// Extracts profile package if needed - returns path to extracted folder
|
|
std::wstring ExtractProfile(const std::wstring& path);
|
|
|
|
bool UpdateGpd(uint32_t title_id, xdbf::GpdFile& gpd_data);
|
|
|
|
bool AddSettingIfNotExist(xdbf::Setting& setting);
|
|
|
|
KernelState* kernel_state_;
|
|
|
|
std::wstring profile_path_;
|
|
std::wstring base_path_;
|
|
|
|
uint64_t xuid_offline_ = 0;
|
|
uint32_t signin_state_ = 0;
|
|
X_XAMACCOUNTINFO account_ = {0};
|
|
|
|
std::unordered_map<uint32_t, xdbf::GpdFile> title_gpds_;
|
|
xdbf::GpdFile dash_gpd_;
|
|
xdbf::GpdFile* curr_gpd_ = nullptr;
|
|
uint32_t curr_title_id_ = -1;
|
|
};
|
|
|
|
} // namespace xam
|
|
} // namespace kernel
|
|
} // namespace xe
|
|
|
|
#endif // XENIA_KERNEL_XAM_USER_PROFILE_H_
|