diff options
| author | 2018-08-08 22:26:42 +1000 | |
|---|---|---|
| committer | 2018-08-08 22:26:42 +1000 | |
| commit | 6f691e71bfa30de8789327a969cb7c2fdd1669f2 (patch) | |
| tree | c48798f2d3fdde5b0ff5ab2dc6d2a4f6fdc9b5c8 /src/core | |
| parent | Switched uuids from u128 to new UUID struct (diff) | |
| download | yuzu-6f691e71bfa30de8789327a969cb7c2fdd1669f2.tar.gz yuzu-6f691e71bfa30de8789327a969cb7c2fdd1669f2.tar.xz yuzu-6f691e71bfa30de8789327a969cb7c2fdd1669f2.zip | |
began initial implementation of "ProfileManager"
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/service/acc/acc.cpp | 17 | ||||
| -rw-r--r-- | src/core/hle/service/acc/acc.h | 41 | ||||
| -rw-r--r-- | src/core/hle/service/acc/profile_manager.cpp | 89 | ||||
| -rw-r--r-- | src/core/hle/service/acc/profile_manager.h | 97 |
5 files changed, 202 insertions, 44 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index cceb1564b..4d39ba409 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -114,6 +114,8 @@ add_library(core STATIC | |||
| 114 | hle/service/acc/acc_u0.h | 114 | hle/service/acc/acc_u0.h |
| 115 | hle/service/acc/acc_u1.cpp | 115 | hle/service/acc/acc_u1.cpp |
| 116 | hle/service/acc/acc_u1.h | 116 | hle/service/acc/acc_u1.h |
| 117 | hle/service/acc/profile_manager.cpp | ||
| 118 | hle/service/acc/profile_manager.h | ||
| 117 | hle/service/am/am.cpp | 119 | hle/service/am/am.cpp |
| 118 | hle/service/am/am.h | 120 | hle/service/am/am.h |
| 119 | hle/service/am/applet_ae.cpp | 121 | hle/service/am/applet_ae.cpp |
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 1fb3d96f6..8efaf6171 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -28,7 +28,7 @@ struct UserData { | |||
| 28 | static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size"); | 28 | static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size"); |
| 29 | 29 | ||
| 30 | struct ProfileBase { | 30 | struct ProfileBase { |
| 31 | u128 user_id; | 31 | UUID user_id; |
| 32 | u64 timestamp; | 32 | u64 timestamp; |
| 33 | std::array<u8, 0x20> username; | 33 | std::array<u8, 0x20> username; |
| 34 | }; | 34 | }; |
| @@ -53,7 +53,7 @@ private: | |||
| 53 | void Get(Kernel::HLERequestContext& ctx) { | 53 | void Get(Kernel::HLERequestContext& ctx) { |
| 54 | LOG_WARNING(Service_ACC, "(STUBBED) called"); | 54 | LOG_WARNING(Service_ACC, "(STUBBED) called"); |
| 55 | ProfileBase profile_base{}; | 55 | ProfileBase profile_base{}; |
| 56 | profile_base.user_id = user_id.uuid; | 56 | profile_base.user_id = user_id; |
| 57 | if (Settings::values.username.size() > profile_base.username.size()) { | 57 | if (Settings::values.username.size() > profile_base.username.size()) { |
| 58 | std::copy_n(Settings::values.username.begin(), profile_base.username.size(), | 58 | std::copy_n(Settings::values.username.begin(), profile_base.username.size(), |
| 59 | profile_base.username.begin()); | 59 | profile_base.username.begin()); |
| @@ -72,7 +72,7 @@ private: | |||
| 72 | 72 | ||
| 73 | // TODO(Subv): Retrieve this information from somewhere. | 73 | // TODO(Subv): Retrieve this information from somewhere. |
| 74 | ProfileBase profile_base{}; | 74 | ProfileBase profile_base{}; |
| 75 | profile_base.user_id = user_id.uuid; | 75 | profile_base.user_id = user_id; |
| 76 | if (Settings::values.username.size() > profile_base.username.size()) { | 76 | if (Settings::values.username.size() > profile_base.username.size()) { |
| 77 | std::copy_n(Settings::values.username.begin(), profile_base.username.size(), | 77 | std::copy_n(Settings::values.username.begin(), profile_base.username.size(), |
| 78 | profile_base.username.begin()); | 78 | profile_base.username.begin()); |
| @@ -122,17 +122,20 @@ private: | |||
| 122 | }; | 122 | }; |
| 123 | 123 | ||
| 124 | void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { | 124 | void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { |
| 125 | LOG_WARNING(Service_ACC, "(STUBBED) called"); | 125 | LOG_INFO(Service_ACC, "called"); |
| 126 | IPC::ResponseBuilder rb{ctx, 3}; | 126 | IPC::ResponseBuilder rb{ctx, 3}; |
| 127 | rb.Push(RESULT_SUCCESS); | 127 | rb.Push(RESULT_SUCCESS); |
| 128 | rb.Push<u32>(1); | 128 | rb.Push<u32>(static_cast<u32>(profile_manager->GetUserCount())); |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { | 131 | void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { |
| 132 | LOG_WARNING(Service_ACC, "(STUBBED) called"); | 132 | IPC::RequestParser rp{ctx}; |
| 133 | UUID user_id = rp.PopRaw<UUID>(); | ||
| 134 | LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); | ||
| 135 | |||
| 133 | IPC::ResponseBuilder rb{ctx, 3}; | 136 | IPC::ResponseBuilder rb{ctx, 3}; |
| 134 | rb.Push(RESULT_SUCCESS); | 137 | rb.Push(RESULT_SUCCESS); |
| 135 | rb.Push(true); // TODO: Check when this is supposed to return true and when not | 138 | rb.Push(profile_manager->UserExists(user_id)); |
| 136 | } | 139 | } |
| 137 | 140 | ||
| 138 | void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) { | 141 | void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index e392b3557..a9bea77ce 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h | |||
| @@ -5,46 +5,10 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | #include "profile_manager.h" | ||
| 8 | 9 | ||
| 9 | namespace Service::Account { | 10 | namespace Service::Account { |
| 10 | 11 | ||
| 11 | struct UUID { | ||
| 12 | // UUIDs which are 0 are considered invalid! | ||
| 13 | u128 uuid{0, 0}; | ||
| 14 | UUID() = default; | ||
| 15 | explicit UUID(const u128& id) { | ||
| 16 | uuid[0] = id[0]; | ||
| 17 | uuid[1] = id[1]; | ||
| 18 | }; | ||
| 19 | explicit UUID(const u64& lo, const u64& hi) { | ||
| 20 | uuid[0] = lo; | ||
| 21 | uuid[1] = hi; | ||
| 22 | }; | ||
| 23 | operator bool() const { | ||
| 24 | return uuid[0] != 0x0 && uuid[1] != 0x0; | ||
| 25 | } | ||
| 26 | |||
| 27 | bool operator==(const UUID& rhs) { | ||
| 28 | return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1]; | ||
| 29 | } | ||
| 30 | |||
| 31 | bool operator!=(const UUID& rhs) { | ||
| 32 | return uuid[0] != rhs.uuid[0] || uuid[1] != rhs.uuid[1]; | ||
| 33 | } | ||
| 34 | |||
| 35 | // TODO(ogniK): Properly generate uuids based on RFC-4122 | ||
| 36 | const UUID& Generate() { | ||
| 37 | uuid[0] = (static_cast<u64>(std::rand()) << 32) | std::rand(); | ||
| 38 | uuid[1] = (static_cast<u64>(std::rand()) << 32) | std::rand(); | ||
| 39 | return *this; | ||
| 40 | } | ||
| 41 | |||
| 42 | std::string Format() { | ||
| 43 | return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]); | ||
| 44 | } | ||
| 45 | }; | ||
| 46 | static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); | ||
| 47 | |||
| 48 | class Module final { | 12 | class Module final { |
| 49 | public: | 13 | public: |
| 50 | class Interface : public ServiceFramework<Interface> { | 14 | class Interface : public ServiceFramework<Interface> { |
| @@ -60,6 +24,9 @@ public: | |||
| 60 | void InitializeApplicationInfo(Kernel::HLERequestContext& ctx); | 24 | void InitializeApplicationInfo(Kernel::HLERequestContext& ctx); |
| 61 | void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx); | 25 | void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx); |
| 62 | 26 | ||
| 27 | private: | ||
| 28 | std::unique_ptr<ProfileManager> profile_manager{}; | ||
| 29 | |||
| 63 | protected: | 30 | protected: |
| 64 | std::shared_ptr<Module> module; | 31 | std::shared_ptr<Module> module; |
| 65 | }; | 32 | }; |
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp new file mode 100644 index 000000000..8819c5703 --- /dev/null +++ b/src/core/hle/service/acc/profile_manager.cpp | |||
| @@ -0,0 +1,89 @@ | |||
| 1 | #include "profile_manager.h" | ||
| 2 | |||
| 3 | namespace Service::Account { | ||
| 4 | // TODO(ogniK): Get actual error codes | ||
| 5 | constexpr ResultCode ERROR_TOO_MANY_USERS(ErrorModule::Account, -1); | ||
| 6 | constexpr ResultCode ERROR_ARGUMENT_IS_NULL(ErrorModule::Account, 20); | ||
| 7 | |||
| 8 | size_t ProfileManager::AddToProfiles(const ProfileInfo& user) { | ||
| 9 | if (user_count >= MAX_USERS) { | ||
| 10 | return -1; | ||
| 11 | } | ||
| 12 | profiles[user_count] = std::move(user); | ||
| 13 | return user_count++; | ||
| 14 | } | ||
| 15 | |||
| 16 | bool ProfileManager::RemoveProfileAtIdx(size_t index) { | ||
| 17 | if (index >= MAX_USERS || index < 0 || index >= user_count) | ||
| 18 | return false; | ||
| 19 | profiles[index] = ProfileInfo{}; | ||
| 20 | if (index < user_count - 1) | ||
| 21 | for (size_t i = index; i < user_count - 1; i++) | ||
| 22 | profiles[i] = profiles[i + 1]; // Shift upper profiles down | ||
| 23 | user_count--; | ||
| 24 | return true; | ||
| 25 | } | ||
| 26 | |||
| 27 | ResultCode ProfileManager::AddUser(ProfileInfo user) { | ||
| 28 | if (AddToProfiles(user) == -1) { | ||
| 29 | return ERROR_TOO_MANY_USERS; | ||
| 30 | } | ||
| 31 | return RESULT_SUCCESS; | ||
| 32 | } | ||
| 33 | |||
| 34 | ResultCode ProfileManager::CreateNewUser(UUID uuid, std::array<u8, 0x20> username) { | ||
| 35 | if (user_count == MAX_USERS) | ||
| 36 | return ERROR_TOO_MANY_USERS; | ||
| 37 | if (!uuid) | ||
| 38 | return ERROR_ARGUMENT_IS_NULL; | ||
| 39 | if (username[0] == 0x0) | ||
| 40 | return ERROR_ARGUMENT_IS_NULL; | ||
| 41 | ProfileInfo prof_inf; | ||
| 42 | prof_inf.user_uuid = uuid; | ||
| 43 | prof_inf.username = username; | ||
| 44 | prof_inf.data = std::array<u8, MAX_DATA>(); | ||
| 45 | prof_inf.creation_time = 0x0; | ||
| 46 | return AddUser(prof_inf); | ||
| 47 | } | ||
| 48 | |||
| 49 | size_t ProfileManager::GetUserIndex(UUID uuid) { | ||
| 50 | for (unsigned i = 0; i < user_count; i++) | ||
| 51 | if (profiles[i].user_uuid == uuid) | ||
| 52 | return i; | ||
| 53 | return -1; | ||
| 54 | } | ||
| 55 | |||
| 56 | size_t ProfileManager::GetUserIndex(ProfileInfo user) { | ||
| 57 | return GetUserIndex(user.user_uuid); | ||
| 58 | } | ||
| 59 | |||
| 60 | bool ProfileManager::GetProfileBase(size_t index, ProfileBase& profile) { | ||
| 61 | if (index >= MAX_USERS) { | ||
| 62 | profile.Invalidate(); | ||
| 63 | return false; | ||
| 64 | } | ||
| 65 | auto prof_info = profiles[index]; | ||
| 66 | profile.user_uuid = prof_info.user_uuid; | ||
| 67 | profile.username = prof_info.username; | ||
| 68 | profile.timestamp = prof_info.creation_time; | ||
| 69 | return true; | ||
| 70 | } | ||
| 71 | |||
| 72 | bool ProfileManager::GetProfileBase(UUID uuid, ProfileBase& profile) { | ||
| 73 | auto idx = GetUserIndex(uuid); | ||
| 74 | return GetProfileBase(idx, profile); | ||
| 75 | } | ||
| 76 | |||
| 77 | bool ProfileManager::GetProfileBase(ProfileInfo user, ProfileBase& profile) { | ||
| 78 | return GetProfileBase(user.user_uuid, profile); | ||
| 79 | } | ||
| 80 | |||
| 81 | size_t ProfileManager::GetUserCount() { | ||
| 82 | return user_count; | ||
| 83 | } | ||
| 84 | |||
| 85 | bool ProfileManager::UserExists(UUID uuid) { | ||
| 86 | return (GetUserIndex(uuid) != -1); | ||
| 87 | } | ||
| 88 | |||
| 89 | }; // namespace Service::Account | ||
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h new file mode 100644 index 000000000..5aa73a030 --- /dev/null +++ b/src/core/hle/service/acc/profile_manager.h | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | #pragma once | ||
| 2 | #include <array> | ||
| 3 | #include "common/common_types.h" | ||
| 4 | #include "common/swap.h" | ||
| 5 | #include "core/hle/result.h" | ||
| 6 | |||
| 7 | namespace Service::Account { | ||
| 8 | constexpr size_t MAX_USERS = 8; | ||
| 9 | constexpr size_t MAX_DATA = 128; | ||
| 10 | |||
| 11 | struct UUID { | ||
| 12 | // UUIDs which are 0 are considered invalid! | ||
| 13 | u128 uuid{0, 0}; | ||
| 14 | UUID() = default; | ||
| 15 | explicit UUID(const u128& id) { | ||
| 16 | uuid[0] = id[0]; | ||
| 17 | uuid[1] = id[1]; | ||
| 18 | }; | ||
| 19 | explicit UUID(const u64& lo, const u64& hi) { | ||
| 20 | uuid[0] = lo; | ||
| 21 | uuid[1] = hi; | ||
| 22 | }; | ||
| 23 | operator bool() const { | ||
| 24 | return uuid[0] != 0x0 && uuid[1] != 0x0; | ||
| 25 | } | ||
| 26 | |||
| 27 | bool operator==(const UUID& rhs) { | ||
| 28 | return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1]; | ||
| 29 | } | ||
| 30 | |||
| 31 | bool operator!=(const UUID& rhs) { | ||
| 32 | return uuid[0] != rhs.uuid[0] || uuid[1] != rhs.uuid[1]; | ||
| 33 | } | ||
| 34 | |||
| 35 | // TODO(ogniK): Properly generate uuids based on RFC-4122 | ||
| 36 | const UUID& Generate() { | ||
| 37 | uuid[0] = (static_cast<u64>(std::rand()) << 32) | std::rand(); | ||
| 38 | uuid[1] = (static_cast<u64>(std::rand()) << 32) | std::rand(); | ||
| 39 | return *this; | ||
| 40 | } | ||
| 41 | void Invalidate() { | ||
| 42 | uuid[0] = 0; | ||
| 43 | uuid[1] = 0; | ||
| 44 | } | ||
| 45 | std::string Format() { | ||
| 46 | return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]); | ||
| 47 | } | ||
| 48 | }; | ||
| 49 | static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); | ||
| 50 | |||
| 51 | /// This holds general information about a users profile. This is where we store all the information | ||
| 52 | /// based on a specific user | ||
| 53 | struct ProfileInfo { | ||
| 54 | UUID user_uuid; | ||
| 55 | std::array<u8, 0x20> username; | ||
| 56 | u64 creation_time; | ||
| 57 | std::array<u8, MAX_DATA> data; | ||
| 58 | }; | ||
| 59 | |||
| 60 | struct ProfileBase { | ||
| 61 | UUID user_uuid; | ||
| 62 | u64_le timestamp; | ||
| 63 | std::array<u8, 0x20> username; | ||
| 64 | |||
| 65 | const void Invalidate() { | ||
| 66 | user_uuid.Invalidate(); | ||
| 67 | timestamp = 0; | ||
| 68 | username.fill(0); | ||
| 69 | } | ||
| 70 | }; | ||
| 71 | static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase is an invalid size"); | ||
| 72 | |||
| 73 | /// The profile manager is used for handling multiple user profiles at once. It keeps track of open | ||
| 74 | /// users, all the accounts registered on the "system" as well as fetching individual "ProfileInfo" | ||
| 75 | /// objects | ||
| 76 | class ProfileManager { | ||
| 77 | public: | ||
| 78 | ProfileManager() = default; // TODO(ogniK): Load from system save | ||
| 79 | ResultCode AddUser(ProfileInfo user); | ||
| 80 | ResultCode CreateNewUser(UUID uuid, std::array<u8, 0x20> username); | ||
| 81 | size_t GetUserIndex(UUID uuid); | ||
| 82 | size_t GetUserIndex(ProfileInfo user); | ||
| 83 | bool GetProfileBase(size_t index, ProfileBase& profile); | ||
| 84 | bool GetProfileBase(UUID uuid, ProfileBase& profile); | ||
| 85 | bool GetProfileBase(ProfileInfo user, ProfileBase& profile); | ||
| 86 | size_t GetUserCount(); | ||
| 87 | bool UserExists(UUID uuid); | ||
| 88 | |||
| 89 | private: | ||
| 90 | std::array<ProfileInfo, MAX_USERS> profiles{}; | ||
| 91 | size_t user_count = 0; | ||
| 92 | size_t AddToProfiles(const ProfileInfo& profile); | ||
| 93 | bool RemoveProfileAtIdx(size_t index); | ||
| 94 | }; | ||
| 95 | using ProfileManagerPtr = std::unique_ptr<ProfileManager>; | ||
| 96 | |||
| 97 | }; // namespace Service::Account | ||