/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2022 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 #include #include #include #include #include "xenia/base/byte_stream.h" #include "xenia/kernel/util/property.h" #include "xenia/kernel/util/xuserdata.h" #include "xenia/xbox.h" namespace xe { namespace kernel { namespace xam { constexpr uint32_t kMaxSettingSize = 0x03E8; enum class X_USER_PROFILE_SETTING_SOURCE : uint32_t { NOT_SET = 0, DEFAULT = 1, TITLE = 2, UNKNOWN = 3, }; // Each setting contains 0x18 bytes long header struct X_USER_PROFILE_SETTING_HEADER { xe::be setting_id; xe::be unknown_1; xe::be setting_type; char unknown_2[3]; xe::be unknown_3; union { // Size is used only for types: CONTENT, WSTRING, BINARY be size; // Raw values that can be written. They do not need to be serialized. be s32; be s64; be u32; be f64; be f32; }; }; static_assert_size(X_USER_PROFILE_SETTING_HEADER, 0x18); struct X_USER_PROFILE_SETTING { xe::be from; union { xe::be user_index; xe::be xuid; }; xe::be setting_id; union { uint8_t data_bytes[sizeof(X_USER_DATA)]; X_USER_DATA data; }; }; static_assert_size(X_USER_PROFILE_SETTING, 40); class UserSetting { public: template UserSetting(uint32_t setting_id, T data) { header_.setting_id = setting_id; setting_id_.value = setting_id; CreateUserData(setting_id, data); } static bool is_title_specific(uint32_t setting_id) { return (setting_id & 0x3F00) == 0x3F00; } bool is_title_specific() const { return is_title_specific(setting_id_.value); } const uint32_t GetSettingId() const { return setting_id_.value; } const X_USER_PROFILE_SETTING_SOURCE GetSettingSource() const { return created_by_; } const X_USER_PROFILE_SETTING_HEADER* GetSettingHeader() const { return &header_; } UserData* GetSettingData() { return user_data_.get(); } void SetNewSettingSource(X_USER_PROFILE_SETTING_SOURCE new_source) { created_by_ = new_source; } void SetNewSettingHeader(X_USER_PROFILE_SETTING_HEADER* header) { header_ = *header; } private: void CreateUserData(uint32_t setting_id, uint32_t data) { header_.setting_type = static_cast(X_USER_DATA_TYPE::INT32); header_.s64 = data; user_data_ = std::make_unique(data); } void CreateUserData(uint32_t setting_id, int32_t data) { header_.setting_type = static_cast(X_USER_DATA_TYPE::INT32); header_.s32 = data; user_data_ = std::make_unique(data); } void CreateUserData(uint32_t setting_id, float data) { header_.setting_type = static_cast(X_USER_DATA_TYPE::FLOAT); header_.f32 = data; user_data_ = std::make_unique(data); } void CreateUserData(uint32_t setting_id, double data) { header_.setting_type = static_cast(X_USER_DATA_TYPE::DOUBLE); header_.f64 = data; user_data_ = std::make_unique(data); } void CreateUserData(uint32_t setting_id, int64_t data) { header_.setting_type = static_cast(X_USER_DATA_TYPE::INT64); header_.s64 = data; user_data_ = std::make_unique(data); } void CreateUserData(uint32_t setting_id, const std::u16string& data) { header_.setting_type = static_cast(X_USER_DATA_TYPE::WSTRING); header_.size = std::min(kMaxSettingSize, static_cast((data.size() + 1) * 2)); user_data_ = std::make_unique(data); } void CreateUserData(uint32_t setting_id, const std::vector& data) { header_.setting_type = static_cast(X_USER_DATA_TYPE::BINARY); header_.size = std::min(kMaxSettingSize, static_cast(data.size())); user_data_ = std::make_unique(data); } X_USER_PROFILE_SETTING_SOURCE created_by_ = X_USER_PROFILE_SETTING_SOURCE::DEFAULT; X_USER_PROFILE_SETTING_HEADER header_ = {}; AttributeKey setting_id_ = {}; std::unique_ptr user_data_ = nullptr; }; class UserProfile { public: UserProfile(uint64_t xuid, X_XAMACCOUNTINFO* account_info); uint64_t xuid() const { return xuid_; } std::string name() const { return account_info_.GetGamertagString(); } uint32_t signin_state() const { return 1; } uint32_t type() const { return 1 | 2; /* local | online profile? */ } uint32_t GetCachedFlags() const { return account_info_.GetCachedFlags(); }; void AddSetting(std::unique_ptr setting); UserSetting* GetSetting(uint32_t setting_id); bool AddProperty(const Property* property); Property* GetProperty(const AttributeKey id); std::map contexts_; private: uint64_t xuid_; X_XAMACCOUNTINFO account_info_; std::vector> setting_list_; std::unordered_map settings_; std::vector properties_; void LoadSetting(UserSetting*); void SaveSetting(UserSetting*); }; } // namespace xam } // namespace kernel } // namespace xe #endif // XENIA_KERNEL_XAM_USER_PROFILE_H_