Просмотр исходного кода

began initial implementation of "ProfileManager"

David Marcec 8 лет назад
Родитель
Сommit
6f691e71bf

+ 2 - 0
src/core/CMakeLists.txt

@@ -114,6 +114,8 @@ add_library(core STATIC
     hle/service/acc/acc_u0.h
     hle/service/acc/acc_u0.h
     hle/service/acc/acc_u1.cpp
     hle/service/acc/acc_u1.cpp
     hle/service/acc/acc_u1.h
     hle/service/acc/acc_u1.h
+    hle/service/acc/profile_manager.cpp
+    hle/service/acc/profile_manager.h
     hle/service/am/am.cpp
     hle/service/am/am.cpp
     hle/service/am/am.h
     hle/service/am/am.h
     hle/service/am/applet_ae.cpp
     hle/service/am/applet_ae.cpp

+ 10 - 7
src/core/hle/service/acc/acc.cpp

@@ -28,7 +28,7 @@ struct UserData {
 static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size");
 static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size");
 
 
 struct ProfileBase {
 struct ProfileBase {
-    u128 user_id;
+    UUID user_id;
     u64 timestamp;
     u64 timestamp;
     std::array<u8, 0x20> username;
     std::array<u8, 0x20> username;
 };
 };
@@ -53,7 +53,7 @@ private:
     void Get(Kernel::HLERequestContext& ctx) {
     void Get(Kernel::HLERequestContext& ctx) {
         LOG_WARNING(Service_ACC, "(STUBBED) called");
         LOG_WARNING(Service_ACC, "(STUBBED) called");
         ProfileBase profile_base{};
         ProfileBase profile_base{};
-        profile_base.user_id = user_id.uuid;
+        profile_base.user_id = user_id;
         if (Settings::values.username.size() > profile_base.username.size()) {
         if (Settings::values.username.size() > profile_base.username.size()) {
             std::copy_n(Settings::values.username.begin(), profile_base.username.size(),
             std::copy_n(Settings::values.username.begin(), profile_base.username.size(),
                         profile_base.username.begin());
                         profile_base.username.begin());
@@ -72,7 +72,7 @@ private:
 
 
         // TODO(Subv): Retrieve this information from somewhere.
         // TODO(Subv): Retrieve this information from somewhere.
         ProfileBase profile_base{};
         ProfileBase profile_base{};
-        profile_base.user_id = user_id.uuid;
+        profile_base.user_id = user_id;
         if (Settings::values.username.size() > profile_base.username.size()) {
         if (Settings::values.username.size() > profile_base.username.size()) {
             std::copy_n(Settings::values.username.begin(), profile_base.username.size(),
             std::copy_n(Settings::values.username.begin(), profile_base.username.size(),
                         profile_base.username.begin());
                         profile_base.username.begin());
@@ -122,17 +122,20 @@ private:
 };
 };
 
 
 void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
 void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
-    LOG_WARNING(Service_ACC, "(STUBBED) called");
+    LOG_INFO(Service_ACC, "called");
     IPC::ResponseBuilder rb{ctx, 3};
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(RESULT_SUCCESS);
     rb.Push(RESULT_SUCCESS);
-    rb.Push<u32>(1);
+    rb.Push<u32>(static_cast<u32>(profile_manager->GetUserCount()));
 }
 }
 
 
 void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
 void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
-    LOG_WARNING(Service_ACC, "(STUBBED) called");
+    IPC::RequestParser rp{ctx};
+    UUID user_id = rp.PopRaw<UUID>();
+    LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
+
     IPC::ResponseBuilder rb{ctx, 3};
     IPC::ResponseBuilder rb{ctx, 3};
     rb.Push(RESULT_SUCCESS);
     rb.Push(RESULT_SUCCESS);
-    rb.Push(true); // TODO: Check when this is supposed to return true and when not
+    rb.Push(profile_manager->UserExists(user_id));
 }
 }
 
 
 void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) {
 void Module::Interface::ListAllUsers(Kernel::HLERequestContext& ctx) {

+ 4 - 37
src/core/hle/service/acc/acc.h

@@ -5,46 +5,10 @@
 #pragma once
 #pragma once
 
 
 #include "core/hle/service/service.h"
 #include "core/hle/service/service.h"
+#include "profile_manager.h"
 
 
 namespace Service::Account {
 namespace Service::Account {
 
 
-struct UUID {
-    // UUIDs which are 0 are considered invalid!
-    u128 uuid{0, 0};
-    UUID() = default;
-    explicit UUID(const u128& id) {
-        uuid[0] = id[0];
-        uuid[1] = id[1];
-    };
-    explicit UUID(const u64& lo, const u64& hi) {
-        uuid[0] = lo;
-        uuid[1] = hi;
-    };
-    operator bool() const {
-        return uuid[0] != 0x0 && uuid[1] != 0x0;
-    }
-
-    bool operator==(const UUID& rhs) {
-        return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1];
-    }
-
-    bool operator!=(const UUID& rhs) {
-        return uuid[0] != rhs.uuid[0] || uuid[1] != rhs.uuid[1];
-    }
-
-    // TODO(ogniK): Properly generate uuids based on RFC-4122
-    const UUID& Generate() {
-        uuid[0] = (static_cast<u64>(std::rand()) << 32) | std::rand();
-        uuid[1] = (static_cast<u64>(std::rand()) << 32) | std::rand();
-        return *this;
-    }
-
-    std::string Format() {
-        return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
-    }
-};
-static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
-
 class Module final {
 class Module final {
 public:
 public:
     class Interface : public ServiceFramework<Interface> {
     class Interface : public ServiceFramework<Interface> {
@@ -60,6 +24,9 @@ public:
         void InitializeApplicationInfo(Kernel::HLERequestContext& ctx);
         void InitializeApplicationInfo(Kernel::HLERequestContext& ctx);
         void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx);
         void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx);
 
 
+    private:
+        std::unique_ptr<ProfileManager> profile_manager{};
+
     protected:
     protected:
         std::shared_ptr<Module> module;
         std::shared_ptr<Module> module;
     };
     };

+ 89 - 0
src/core/hle/service/acc/profile_manager.cpp

@@ -0,0 +1,89 @@
+#include "profile_manager.h"
+
+namespace Service::Account {
+// TODO(ogniK): Get actual error codes
+constexpr ResultCode ERROR_TOO_MANY_USERS(ErrorModule::Account, -1);
+constexpr ResultCode ERROR_ARGUMENT_IS_NULL(ErrorModule::Account, 20);
+
+size_t ProfileManager::AddToProfiles(const ProfileInfo& user) {
+    if (user_count >= MAX_USERS) {
+        return -1;
+    }
+    profiles[user_count] = std::move(user);
+    return user_count++;
+}
+
+bool ProfileManager::RemoveProfileAtIdx(size_t index) {
+    if (index >= MAX_USERS || index < 0 || index >= user_count)
+        return false;
+    profiles[index] = ProfileInfo{};
+    if (index < user_count - 1)
+        for (size_t i = index; i < user_count - 1; i++)
+            profiles[i] = profiles[i + 1]; // Shift upper profiles down
+    user_count--;
+    return true;
+}
+
+ResultCode ProfileManager::AddUser(ProfileInfo user) {
+    if (AddToProfiles(user) == -1) {
+        return ERROR_TOO_MANY_USERS;
+    }
+    return RESULT_SUCCESS;
+}
+
+ResultCode ProfileManager::CreateNewUser(UUID uuid, std::array<u8, 0x20> username) {
+    if (user_count == MAX_USERS)
+        return ERROR_TOO_MANY_USERS;
+    if (!uuid)
+        return ERROR_ARGUMENT_IS_NULL;
+    if (username[0] == 0x0)
+        return ERROR_ARGUMENT_IS_NULL;
+    ProfileInfo prof_inf;
+    prof_inf.user_uuid = uuid;
+    prof_inf.username = username;
+    prof_inf.data = std::array<u8, MAX_DATA>();
+    prof_inf.creation_time = 0x0;
+    return AddUser(prof_inf);
+}
+
+size_t ProfileManager::GetUserIndex(UUID uuid) {
+    for (unsigned i = 0; i < user_count; i++)
+        if (profiles[i].user_uuid == uuid)
+            return i;
+    return -1;
+}
+
+size_t ProfileManager::GetUserIndex(ProfileInfo user) {
+    return GetUserIndex(user.user_uuid);
+}
+
+bool ProfileManager::GetProfileBase(size_t index, ProfileBase& profile) {
+    if (index >= MAX_USERS) {
+        profile.Invalidate();
+        return false;
+    }
+    auto prof_info = profiles[index];
+    profile.user_uuid = prof_info.user_uuid;
+    profile.username = prof_info.username;
+    profile.timestamp = prof_info.creation_time;
+    return true;
+}
+
+bool ProfileManager::GetProfileBase(UUID uuid, ProfileBase& profile) {
+    auto idx = GetUserIndex(uuid);
+    return GetProfileBase(idx, profile);
+}
+
+bool ProfileManager::GetProfileBase(ProfileInfo user, ProfileBase& profile) {
+    return GetProfileBase(user.user_uuid, profile);
+}
+
+size_t ProfileManager::GetUserCount() {
+    return user_count;
+}
+
+bool ProfileManager::UserExists(UUID uuid) {
+    return (GetUserIndex(uuid) != -1);
+}
+
+}; // namespace Service::Account

+ 97 - 0
src/core/hle/service/acc/profile_manager.h

@@ -0,0 +1,97 @@
+#pragma once
+#include <array>
+#include "common/common_types.h"
+#include "common/swap.h"
+#include "core/hle/result.h"
+
+namespace Service::Account {
+constexpr size_t MAX_USERS = 8;
+constexpr size_t MAX_DATA = 128;
+
+struct UUID {
+    // UUIDs which are 0 are considered invalid!
+    u128 uuid{0, 0};
+    UUID() = default;
+    explicit UUID(const u128& id) {
+        uuid[0] = id[0];
+        uuid[1] = id[1];
+    };
+    explicit UUID(const u64& lo, const u64& hi) {
+        uuid[0] = lo;
+        uuid[1] = hi;
+    };
+    operator bool() const {
+        return uuid[0] != 0x0 && uuid[1] != 0x0;
+    }
+
+    bool operator==(const UUID& rhs) {
+        return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1];
+    }
+
+    bool operator!=(const UUID& rhs) {
+        return uuid[0] != rhs.uuid[0] || uuid[1] != rhs.uuid[1];
+    }
+
+    // TODO(ogniK): Properly generate uuids based on RFC-4122
+    const UUID& Generate() {
+        uuid[0] = (static_cast<u64>(std::rand()) << 32) | std::rand();
+        uuid[1] = (static_cast<u64>(std::rand()) << 32) | std::rand();
+        return *this;
+    }
+    void Invalidate() {
+        uuid[0] = 0;
+        uuid[1] = 0;
+    }
+    std::string Format() {
+        return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
+    }
+};
+static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
+
+/// This holds general information about a users profile. This is where we store all the information
+/// based on a specific user
+struct ProfileInfo {
+    UUID user_uuid;
+    std::array<u8, 0x20> username;
+    u64 creation_time;
+    std::array<u8, MAX_DATA> data;
+};
+
+struct ProfileBase {
+    UUID user_uuid;
+    u64_le timestamp;
+    std::array<u8, 0x20> username;
+
+    const void Invalidate() {
+        user_uuid.Invalidate();
+        timestamp = 0;
+        username.fill(0);
+    }
+};
+static_assert(sizeof(ProfileBase) == 0x38, "ProfileBase is an invalid size");
+
+/// The profile manager is used for handling multiple user profiles at once. It keeps track of open
+/// users, all the accounts registered on the "system" as well as fetching individual "ProfileInfo"
+/// objects
+class ProfileManager {
+public:
+    ProfileManager() = default; // TODO(ogniK): Load from system save
+    ResultCode AddUser(ProfileInfo user);
+    ResultCode CreateNewUser(UUID uuid, std::array<u8, 0x20> username);
+    size_t GetUserIndex(UUID uuid);
+    size_t GetUserIndex(ProfileInfo user);
+    bool GetProfileBase(size_t index, ProfileBase& profile);
+    bool GetProfileBase(UUID uuid, ProfileBase& profile);
+    bool GetProfileBase(ProfileInfo user, ProfileBase& profile);
+    size_t GetUserCount();
+    bool UserExists(UUID uuid);
+
+private:
+    std::array<ProfileInfo, MAX_USERS> profiles{};
+    size_t user_count = 0;
+    size_t AddToProfiles(const ProfileInfo& profile);
+    bool RemoveProfileAtIdx(size_t index);
+};
+using ProfileManagerPtr = std::unique_ptr<ProfileManager>;
+
+}; // namespace Service::Account