forked from eden-emu/eden
		
	profile_manager: Load user icons, names, and UUIDs from system save
This commit is contained in:
		
							parent
							
								
									fe98903bfe
								
							
						
					
					
						commit
						8bdf2fe7b7
					
				
					 11 changed files with 308 additions and 133 deletions
				
			
		|  | @ -2,6 +2,7 @@ | ||||||
| // Licensed under GPLv2 or any later version
 | // Licensed under GPLv2 or any later version
 | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
|  | #include <algorithm> | ||||||
| #include <array> | #include <array> | ||||||
| #include "common/common_paths.h" | #include "common/common_paths.h" | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  | @ -33,9 +34,9 @@ struct UserData { | ||||||
| }; | }; | ||||||
| static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size"); | static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size"); | ||||||
| 
 | 
 | ||||||
| static std::string GetImagePath(const std::string& username) { | static std::string GetImagePath(UUID uuid) { | ||||||
|     return FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "users" + DIR_SEP + username + |     return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + | ||||||
|            ".jpg"; |            "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class IProfile final : public ServiceFramework<IProfile> { | class IProfile final : public ServiceFramework<IProfile> { | ||||||
|  | @ -49,15 +50,6 @@ public: | ||||||
|             {11, &IProfile::LoadImage, "LoadImage"}, |             {11, &IProfile::LoadImage, "LoadImage"}, | ||||||
|         }; |         }; | ||||||
|         RegisterHandlers(functions); |         RegisterHandlers(functions); | ||||||
| 
 |  | ||||||
|         ProfileBase profile_base{}; |  | ||||||
|         if (profile_manager.GetProfileBase(user_id, profile_base)) { |  | ||||||
|             image = std::make_unique<FileUtil::IOFile>( |  | ||||||
|                 GetImagePath(Common::StringFromFixedZeroTerminatedBuffer( |  | ||||||
|                     reinterpret_cast<const char*>(profile_base.username.data()), |  | ||||||
|                     profile_base.username.size())), |  | ||||||
|                 "rb"); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  | @ -111,13 +103,15 @@ private: | ||||||
|         IPC::ResponseBuilder rb{ctx, 3}; |         IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|         rb.Push(RESULT_SUCCESS); |         rb.Push(RESULT_SUCCESS); | ||||||
| 
 | 
 | ||||||
|         if (image == nullptr) { |         const FileUtil::IOFile image(GetImagePath(user_id), "rb"); | ||||||
|  | 
 | ||||||
|  |         if (!image.IsOpen()) { | ||||||
|             ctx.WriteBuffer(backup_jpeg); |             ctx.WriteBuffer(backup_jpeg); | ||||||
|             rb.Push<u32>(backup_jpeg_size); |             rb.Push<u32>(backup_jpeg_size); | ||||||
|         } else { |         } else { | ||||||
|             const auto size = std::min<u32>(image->GetSize(), MAX_JPEG_IMAGE_SIZE); |             const auto size = std::min<u32>(image.GetSize(), MAX_JPEG_IMAGE_SIZE); | ||||||
|             std::vector<u8> buffer(size); |             std::vector<u8> buffer(size); | ||||||
|             image->ReadBytes(buffer.data(), buffer.size()); |             image.ReadBytes(buffer.data(), buffer.size()); | ||||||
| 
 | 
 | ||||||
|             ctx.WriteBuffer(buffer.data(), buffer.size()); |             ctx.WriteBuffer(buffer.data(), buffer.size()); | ||||||
|             rb.Push<u32>(buffer.size()); |             rb.Push<u32>(buffer.size()); | ||||||
|  | @ -130,15 +124,16 @@ private: | ||||||
|         IPC::ResponseBuilder rb{ctx, 3}; |         IPC::ResponseBuilder rb{ctx, 3}; | ||||||
|         rb.Push(RESULT_SUCCESS); |         rb.Push(RESULT_SUCCESS); | ||||||
| 
 | 
 | ||||||
|         if (image == nullptr) |         const FileUtil::IOFile image(GetImagePath(user_id), "rb"); | ||||||
|  | 
 | ||||||
|  |         if (!image.IsOpen()) | ||||||
|             rb.Push<u32>(backup_jpeg_size); |             rb.Push<u32>(backup_jpeg_size); | ||||||
|         else |         else | ||||||
|             rb.Push<u32>(std::min<u32>(image->GetSize(), MAX_JPEG_IMAGE_SIZE)); |             rb.Push<u32>(std::min<u32>(image.GetSize(), MAX_JPEG_IMAGE_SIZE)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const ProfileManager& profile_manager; |     const ProfileManager& profile_manager; | ||||||
|     UUID user_id; ///< The user id this profile refers to.
 |     UUID user_id; ///< The user id this profile refers to.
 | ||||||
|     std::unique_ptr<FileUtil::IOFile> image = nullptr; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { | class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { | ||||||
|  |  | ||||||
|  | @ -4,10 +4,27 @@ | ||||||
| 
 | 
 | ||||||
| #include <random> | #include <random> | ||||||
| #include <boost/optional.hpp> | #include <boost/optional.hpp> | ||||||
|  | #include "common/file_util.h" | ||||||
| #include "core/hle/service/acc/profile_manager.h" | #include "core/hle/service/acc/profile_manager.h" | ||||||
| #include "core/settings.h" | #include "core/settings.h" | ||||||
| 
 | 
 | ||||||
| namespace Service::Account { | namespace Service::Account { | ||||||
|  | 
 | ||||||
|  | struct UserRaw { | ||||||
|  |     UUID uuid; | ||||||
|  |     UUID uuid2; | ||||||
|  |     u64 timestamp; | ||||||
|  |     ProfileUsername username; | ||||||
|  |     INSERT_PADDING_BYTES(0x80); | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size."); | ||||||
|  | 
 | ||||||
|  | struct ProfileDataRaw { | ||||||
|  |     INSERT_PADDING_BYTES(0x10); | ||||||
|  |     std::array<UserRaw, MAX_USERS> users; | ||||||
|  | }; | ||||||
|  | static_assert(sizeof(ProfileDataRaw) == 0x650, "ProfileDataRaw has incorrect size."); | ||||||
|  | 
 | ||||||
| // TODO(ogniK): Get actual error codes
 | // TODO(ogniK): Get actual error codes
 | ||||||
| constexpr ResultCode ERROR_TOO_MANY_USERS(ErrorModule::Account, -1); | constexpr ResultCode ERROR_TOO_MANY_USERS(ErrorModule::Account, -1); | ||||||
| constexpr ResultCode ERROR_USER_ALREADY_EXISTS(ErrorModule::Account, -2); | constexpr ResultCode ERROR_USER_ALREADY_EXISTS(ErrorModule::Account, -2); | ||||||
|  | @ -23,15 +40,21 @@ const UUID& UUID::Generate() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ProfileManager::ProfileManager() { | ProfileManager::ProfileManager() { | ||||||
|     for (std::size_t i = 0; i < Settings::values.users.size(); ++i) { |     ParseUserSaveFile(); | ||||||
|         const auto& val = Settings::values.users[i]; |  | ||||||
|         ASSERT(CreateNewUser(val.second, val.first).IsSuccess()); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     OpenUser(Settings::values.users[Settings::values.current_user].second); |     if (user_count == 0) | ||||||
|  |         CreateNewUser(UUID{}.Generate(), "yuzu"); | ||||||
|  | 
 | ||||||
|  |     auto current = Settings::values.current_user; | ||||||
|  |     if (!GetAllUsers()[current]) | ||||||
|  |         current = 0; | ||||||
|  | 
 | ||||||
|  |     OpenUser(GetAllUsers()[current]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ProfileManager::~ProfileManager() = default; | ProfileManager::~ProfileManager() { | ||||||
|  |     WriteUserSaveFile(); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| /// After a users creation it needs to be "registered" to the system. AddToProfiles handles the
 | /// After a users creation it needs to be "registered" to the system. AddToProfiles handles the
 | ||||||
| /// internal management of the users profiles
 | /// internal management of the users profiles
 | ||||||
|  | @ -241,4 +264,70 @@ bool ProfileManager::CanSystemRegisterUser() const { | ||||||
|     // emulate qlaunch. Update this to dynamically change.
 |     // emulate qlaunch. Update this to dynamically change.
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool ProfileManager::RemoveUser(UUID uuid) { | ||||||
|  |     auto index = GetUserIndex(uuid); | ||||||
|  |     if (index == boost::none) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     profiles[*index] = ProfileInfo{}; | ||||||
|  |     std::stable_partition(profiles.begin(), profiles.end(), | ||||||
|  |                           [](const ProfileInfo& profile) { return profile.user_uuid; }); | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) { | ||||||
|  |     auto index = GetUserIndex(uuid); | ||||||
|  |     if (profile_new.user_uuid == UUID(INVALID_UUID) || index == boost::none) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     auto& profile = profiles[*index]; | ||||||
|  |     profile.user_uuid = profile_new.user_uuid; | ||||||
|  |     profile.username = profile_new.username; | ||||||
|  |     profile.creation_time = profile_new.timestamp; | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ProfileManager::ParseUserSaveFile() { | ||||||
|  |     FileUtil::IOFile save(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + | ||||||
|  |                               "/system/save/8000000000000010/su/avators/profiles.dat", | ||||||
|  |                           "rb"); | ||||||
|  | 
 | ||||||
|  |     ProfileDataRaw data; | ||||||
|  |     save.Seek(0, SEEK_SET); | ||||||
|  |     if (save.ReadBytes(&data, sizeof(ProfileDataRaw)) != sizeof(ProfileDataRaw)) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     for (std::size_t i = 0; i < MAX_USERS; ++i) { | ||||||
|  |         const auto& user = data.users[i]; | ||||||
|  | 
 | ||||||
|  |         if (user.uuid != UUID(INVALID_UUID)) | ||||||
|  |             AddUser({user.uuid, user.username, user.timestamp, {}, false}); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::stable_partition(profiles.begin(), profiles.end(), | ||||||
|  |                           [](const ProfileInfo& profile) { return profile.user_uuid; }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ProfileManager::WriteUserSaveFile() { | ||||||
|  |     ProfileDataRaw raw{}; | ||||||
|  | 
 | ||||||
|  |     for (std::size_t i = 0; i < MAX_USERS; ++i) { | ||||||
|  |         raw.users[i].username = profiles[i].username; | ||||||
|  |         raw.users[i].uuid2 = profiles[i].user_uuid; | ||||||
|  |         raw.users[i].uuid = profiles[i].user_uuid; | ||||||
|  |         raw.users[i].timestamp = profiles[i].creation_time; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     FileUtil::IOFile save(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + | ||||||
|  |                               "/system/save/8000000000000010/su/avators/profiles.dat", | ||||||
|  |                           "rb"); | ||||||
|  | 
 | ||||||
|  |     save.Resize(sizeof(ProfileDataRaw)); | ||||||
|  |     save.Seek(0, SEEK_SET); | ||||||
|  |     save.WriteBytes(&raw, sizeof(ProfileDataRaw)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| }; // namespace Service::Account
 | }; // namespace Service::Account
 | ||||||
|  |  | ||||||
|  | @ -45,6 +45,15 @@ struct UUID { | ||||||
|     std::string Format() const { |     std::string Format() const { | ||||||
|         return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]); |         return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     std::string FormatSwitch() const { | ||||||
|  |         std::array<u8, 16> s{}; | ||||||
|  |         std::memcpy(s.data(), uuid.data(), sizeof(u128)); | ||||||
|  |         return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{" | ||||||
|  |                            ":02x}{:02x}{:02x}{:02x}{:02x}", | ||||||
|  |                            s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11], | ||||||
|  |                            s[12], s[13], s[14], s[15]); | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); | static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); | ||||||
| 
 | 
 | ||||||
|  | @ -108,7 +117,13 @@ public: | ||||||
| 
 | 
 | ||||||
|     bool CanSystemRegisterUser() const; |     bool CanSystemRegisterUser() const; | ||||||
| 
 | 
 | ||||||
|  |     bool RemoveUser(UUID uuid); | ||||||
|  |     bool SetProfileBase(UUID uuid, const ProfileBase& profile); | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|  |     void ParseUserSaveFile(); | ||||||
|  |     void WriteUserSaveFile(); | ||||||
|  | 
 | ||||||
|     std::array<ProfileInfo, MAX_USERS> profiles{}; |     std::array<ProfileInfo, MAX_USERS> profiles{}; | ||||||
|     std::size_t user_count = 0; |     std::size_t user_count = 0; | ||||||
|     boost::optional<std::size_t> AddToProfiles(const ProfileInfo& profile); |     boost::optional<std::size_t> AddToProfiles(const ProfileInfo& profile); | ||||||
|  |  | ||||||
|  | @ -4,11 +4,13 @@ | ||||||
| 
 | 
 | ||||||
| #include <array> | #include <array> | ||||||
| #include <cinttypes> | #include <cinttypes> | ||||||
|  | #include <cstring> | ||||||
| #include <stack> | #include <stack> | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/hle/ipc_helpers.h" | #include "core/hle/ipc_helpers.h" | ||||||
| #include "core/hle/kernel/event.h" | #include "core/hle/kernel/event.h" | ||||||
| #include "core/hle/kernel/process.h" | #include "core/hle/kernel/process.h" | ||||||
|  | #include "core/hle/service/acc/profile_manager.h" | ||||||
| #include "core/hle/service/am/am.h" | #include "core/hle/service/am/am.h" | ||||||
| #include "core/hle/service/am/applet_ae.h" | #include "core/hle/service/am/applet_ae.h" | ||||||
| #include "core/hle/service/am/applet_oe.h" | #include "core/hle/service/am/applet_oe.h" | ||||||
|  | @ -734,8 +736,10 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | ||||||
|     std::vector<u8> buffer(POP_LAUNCH_PARAMETER_BUFFER_SIZE); |     std::vector<u8> buffer(POP_LAUNCH_PARAMETER_BUFFER_SIZE); | ||||||
| 
 | 
 | ||||||
|     std::memcpy(buffer.data(), header_data.data(), header_data.size()); |     std::memcpy(buffer.data(), header_data.data(), header_data.size()); | ||||||
|     const auto current_uuid = Settings::values.users[Settings::values.current_user].second.uuid; | 
 | ||||||
|     std::memcpy(buffer.data() + header_data.size(), current_uuid.data(), sizeof(u128)); |     Account::ProfileManager profile_manager{}; | ||||||
|  |     const auto uuid = profile_manager.GetAllUsers()[Settings::values.current_user].uuid; | ||||||
|  |     std::memcpy(buffer.data() + header_data.size(), uuid.data(), sizeof(u128)); | ||||||
| 
 | 
 | ||||||
|     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |     IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,7 +8,6 @@ | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <string> | #include <string> | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "core/hle/service/acc/profile_manager.h" |  | ||||||
| 
 | 
 | ||||||
| namespace Settings { | namespace Settings { | ||||||
| 
 | 
 | ||||||
|  | @ -116,7 +115,6 @@ struct Values { | ||||||
|     bool use_docked_mode; |     bool use_docked_mode; | ||||||
|     bool enable_nfc; |     bool enable_nfc; | ||||||
|     int current_user; |     int current_user; | ||||||
|     std::vector<std::pair<std::string, Service::Account::UUID>> users; |  | ||||||
|     int language_index; |     int language_index; | ||||||
| 
 | 
 | ||||||
|     // Controls
 |     // Controls
 | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <QSettings> | #include <QSettings> | ||||||
| #include "common/file_util.h" | #include "common/file_util.h" | ||||||
|  | #include "core/hle/service/acc/profile_manager.h" | ||||||
| #include "input_common/main.h" | #include "input_common/main.h" | ||||||
| #include "yuzu/configuration/config.h" | #include "yuzu/configuration/config.h" | ||||||
| #include "yuzu/ui_settings.h" | #include "yuzu/ui_settings.h" | ||||||
|  | @ -124,23 +125,7 @@ void Config::ReadValues() { | ||||||
|     Settings::values.use_docked_mode = qt_config->value("use_docked_mode", false).toBool(); |     Settings::values.use_docked_mode = qt_config->value("use_docked_mode", false).toBool(); | ||||||
|     Settings::values.enable_nfc = qt_config->value("enable_nfc", true).toBool(); |     Settings::values.enable_nfc = qt_config->value("enable_nfc", true).toBool(); | ||||||
| 
 | 
 | ||||||
|     Settings::values.users.clear(); |     Settings::values.current_user = std::clamp(qt_config->value("current_user", 0).toInt(), 0, 7); | ||||||
|     const auto size = qt_config->beginReadArray("users"); |  | ||||||
|     for (int i = 0; i < size; ++i) { |  | ||||||
|         qt_config->setArrayIndex(i); |  | ||||||
|         const Service::Account::UUID uuid(qt_config->value("uuid_low").toULongLong(), |  | ||||||
|                                           qt_config->value("uuid_high").toULongLong()); |  | ||||||
|         Settings::values.users.emplace_back(qt_config->value("username").toString().toStdString(), |  | ||||||
|                                             uuid); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     qt_config->endArray(); |  | ||||||
| 
 |  | ||||||
|     if (Settings::values.users.empty()) |  | ||||||
|         Settings::values.users.emplace_back("yuzu", Service::Account::UUID{}.Generate()); |  | ||||||
| 
 |  | ||||||
|     Settings::values.current_user = |  | ||||||
|         std::clamp(qt_config->value("current_user", 0).toInt(), 0, size); |  | ||||||
| 
 | 
 | ||||||
|     Settings::values.language_index = qt_config->value("language_index", 1).toInt(); |     Settings::values.language_index = qt_config->value("language_index", 1).toInt(); | ||||||
|     qt_config->endGroup(); |     qt_config->endGroup(); | ||||||
|  | @ -280,17 +265,6 @@ void Config::SaveValues() { | ||||||
|     qt_config->setValue("enable_nfc", Settings::values.enable_nfc); |     qt_config->setValue("enable_nfc", Settings::values.enable_nfc); | ||||||
|     qt_config->setValue("current_user", Settings::values.current_user); |     qt_config->setValue("current_user", Settings::values.current_user); | ||||||
| 
 | 
 | ||||||
|     qt_config->beginWriteArray("users", Settings::values.users.size()); |  | ||||||
|     for (std::size_t i = 0; i < Settings::values.users.size(); ++i) { |  | ||||||
|         qt_config->setArrayIndex(i); |  | ||||||
|         const auto& user = Settings::values.users[i]; |  | ||||||
|         qt_config->setValue("uuid_low", user.second.uuid[0]); |  | ||||||
|         qt_config->setValue("uuid_high", user.second.uuid[1]); |  | ||||||
|         qt_config->setValue("username", QString::fromStdString(user.first)); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     qt_config->endArray(); |  | ||||||
| 
 |  | ||||||
|     qt_config->setValue("language_index", Settings::values.language_index); |     qt_config->setValue("language_index", Settings::values.language_index); | ||||||
|     qt_config->endGroup(); |     qt_config->endGroup(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,10 +2,15 @@ | ||||||
| // Licensed under GPLv2 or any later version
 | // Licensed under GPLv2 or any later version
 | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include <QFileDialog> | ||||||
| #include <QGraphicsItem> | #include <QGraphicsItem> | ||||||
| #include <QList> | #include <QGraphicsScene> | ||||||
|  | #include <QInputDialog> | ||||||
| #include <QMessageBox> | #include <QMessageBox> | ||||||
| #include <qinputdialog.h> | #include <QStandardItemModel> | ||||||
|  | #include <QTreeView> | ||||||
|  | #include <QVBoxLayout> | ||||||
| #include "common/common_paths.h" | #include "common/common_paths.h" | ||||||
| #include "common/logging/backend.h" | #include "common/logging/backend.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
|  | @ -14,6 +19,11 @@ | ||||||
| #include "yuzu/configuration/configure_system.h" | #include "yuzu/configuration/configure_system.h" | ||||||
| #include "yuzu/main.h" | #include "yuzu/main.h" | ||||||
| 
 | 
 | ||||||
|  | static std::string GetImagePath(Service::Account::UUID uuid) { | ||||||
|  |     return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + | ||||||
|  |            "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static const std::array<int, 12> days_in_month = {{ | static const std::array<int, 12> days_in_month = {{ | ||||||
|     31, |     31, | ||||||
|     29, |     29, | ||||||
|  | @ -40,7 +50,9 @@ static constexpr std::array<u8, 107> backup_jpeg{ | ||||||
|     0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, |     0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureSystem) { | ConfigureSystem::ConfigureSystem(QWidget* parent) | ||||||
|  |     : QWidget(parent), ui(new Ui::ConfigureSystem), | ||||||
|  |       profile_manager(std::make_unique<Service::Account::ProfileManager>()) { | ||||||
|     ui->setupUi(this); |     ui->setupUi(this); | ||||||
|     connect(ui->combo_birthmonth, |     connect(ui->combo_birthmonth, | ||||||
|             static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, |             static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, | ||||||
|  | @ -82,6 +94,7 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui:: | ||||||
|     connect(ui->pm_add, &QPushButton::pressed, this, &ConfigureSystem::AddUser); |     connect(ui->pm_add, &QPushButton::pressed, this, &ConfigureSystem::AddUser); | ||||||
|     connect(ui->pm_rename, &QPushButton::pressed, this, &ConfigureSystem::RenameUser); |     connect(ui->pm_rename, &QPushButton::pressed, this, &ConfigureSystem::RenameUser); | ||||||
|     connect(ui->pm_remove, &QPushButton::pressed, this, &ConfigureSystem::DeleteUser); |     connect(ui->pm_remove, &QPushButton::pressed, this, &ConfigureSystem::DeleteUser); | ||||||
|  |     connect(ui->pm_set_image, &QPushButton::pressed, this, &ConfigureSystem::SetUserImage); | ||||||
| 
 | 
 | ||||||
|     scene = new QGraphicsScene; |     scene = new QGraphicsScene; | ||||||
|     ui->current_user_icon->setScene(scene); |     ui->current_user_icon->setScene(scene); | ||||||
|  | @ -99,49 +112,69 @@ void ConfigureSystem::setConfiguration() { | ||||||
|     item_model->removeRows(0, item_model->rowCount()); |     item_model->removeRows(0, item_model->rowCount()); | ||||||
|     list_items.clear(); |     list_items.clear(); | ||||||
| 
 | 
 | ||||||
|     std::transform(Settings::values.users.begin(), Settings::values.users.end(), |     ui->pm_add->setEnabled(profile_manager->GetUserCount() < 8); | ||||||
|                    std::back_inserter(list_items), |  | ||||||
|                    [](const std::pair<std::string, Service::Account::UUID>& user) { |  | ||||||
|                        const auto icon_url = QString::fromStdString( |  | ||||||
|                            FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "users" + |  | ||||||
|                            DIR_SEP + user.first + ".jpg"); |  | ||||||
|                        QPixmap icon{icon_url}; |  | ||||||
| 
 |  | ||||||
|                        if (!icon) { |  | ||||||
|                            icon.fill(QColor::fromRgb(0, 0, 0)); |  | ||||||
|                            icon.loadFromData(backup_jpeg.data(), backup_jpeg.size()); |  | ||||||
|                        } |  | ||||||
| 
 |  | ||||||
|                        return QList{new QStandardItem{ |  | ||||||
|                            icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), |  | ||||||
|                            QString::fromStdString(user.first + "\n" + user.second.Format())}}; |  | ||||||
|                    }); |  | ||||||
| 
 |  | ||||||
|     for (const auto& item : list_items) |  | ||||||
|         item_model->appendRow(item); |  | ||||||
| 
 | 
 | ||||||
|  |     PopulateUserList(); | ||||||
|     UpdateCurrentUser(); |     UpdateCurrentUser(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ConfigureSystem::UpdateCurrentUser() { | static QPixmap GetIcon(Service::Account::UUID uuid) { | ||||||
|     const auto& current_user = Settings::values.users[Settings::values.current_user]; |     const auto icon_url = QString::fromStdString(GetImagePath(uuid)); | ||||||
|     const auto icon_url = |  | ||||||
|         QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "users" + |  | ||||||
|                                DIR_SEP + current_user.first + ".jpg"); |  | ||||||
|     QPixmap icon{icon_url}; |     QPixmap icon{icon_url}; | ||||||
| 
 | 
 | ||||||
|     if (!icon) { |     if (!icon) { | ||||||
|         icon.fill(QColor::fromRgb(0, 0, 0)); |         icon.fill(Qt::black); | ||||||
|         icon.loadFromData(backup_jpeg.data(), backup_jpeg.size()); |         icon.loadFromData(backup_jpeg.data(), backup_jpeg.size()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     return icon; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureSystem::PopulateUserList() { | ||||||
|  |     const auto& profiles = profile_manager->GetAllUsers(); | ||||||
|  |     std::transform( | ||||||
|  |         profiles.begin(), profiles.end(), std::back_inserter(list_items), | ||||||
|  |         [this](const Service::Account::UUID& user) { | ||||||
|  |             Service::Account::ProfileBase profile; | ||||||
|  |             if (!profile_manager->GetProfileBase(user, profile)) | ||||||
|  |                 return QList<QStandardItem*>{}; | ||||||
|  |             const auto username = Common::StringFromFixedZeroTerminatedBuffer( | ||||||
|  |                 reinterpret_cast<const char*>(profile.username.data()), profile.username.size()); | ||||||
|  | 
 | ||||||
|  |             return QList<QStandardItem*>{new QStandardItem{ | ||||||
|  |                 GetIcon(user).scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), | ||||||
|  |                 QString::fromStdString(username + '\n' + user.FormatSwitch())}}; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     list_items.erase( | ||||||
|  |         std::remove_if(list_items.begin(), list_items.end(), | ||||||
|  |                        [](const auto& list) { return list == QList<QStandardItem*>{}; }), | ||||||
|  |         list_items.end()); | ||||||
|  | 
 | ||||||
|  |     for (const auto& item : list_items) | ||||||
|  |         item_model->appendRow(item); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ConfigureSystem::UpdateCurrentUser() { | ||||||
|  |     const auto& current_user = profile_manager->GetAllUsers()[Settings::values.current_user]; | ||||||
|  |     const auto username = GetAccountUsername(current_user); | ||||||
|  | 
 | ||||||
|     scene->clear(); |     scene->clear(); | ||||||
|     scene->addPixmap(icon.scaled(48, 48, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); |     scene->addPixmap( | ||||||
|     ui->current_user_username->setText(QString::fromStdString(current_user.first)); |         GetIcon(current_user).scaled(48, 48, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); | ||||||
|  |     ui->current_user_username->setText(QString::fromStdString(username)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ConfigureSystem::ReadSystemSettings() {} | void ConfigureSystem::ReadSystemSettings() {} | ||||||
| 
 | 
 | ||||||
|  | std::string ConfigureSystem::GetAccountUsername(Service::Account::UUID uuid) { | ||||||
|  |     Service::Account::ProfileBase profile; | ||||||
|  |     if (!profile_manager->GetProfileBase(uuid, profile)) | ||||||
|  |         return ""; | ||||||
|  |     return Common::StringFromFixedZeroTerminatedBuffer( | ||||||
|  |         reinterpret_cast<const char*>(profile.username.data()), profile.username.size()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void ConfigureSystem::applyConfiguration() { | void ConfigureSystem::applyConfiguration() { | ||||||
|     if (!enabled) |     if (!enabled) | ||||||
|         return; |         return; | ||||||
|  | @ -192,16 +225,16 @@ void ConfigureSystem::refreshConsoleID() { | ||||||
| 
 | 
 | ||||||
| void ConfigureSystem::SelectUser(const QModelIndex& index) { | void ConfigureSystem::SelectUser(const QModelIndex& index) { | ||||||
|     Settings::values.current_user = |     Settings::values.current_user = | ||||||
|         std::clamp<std::size_t>(index.row(), 0, Settings::values.users.size() - 1); |         std::clamp<std::size_t>(index.row(), 0, profile_manager->GetUserCount() - 1); | ||||||
| 
 | 
 | ||||||
|     UpdateCurrentUser(); |     UpdateCurrentUser(); | ||||||
| 
 | 
 | ||||||
|     if (Settings::values.users.size() >= 2) |     ui->pm_remove->setEnabled(profile_manager->GetUserCount() >= 2); | ||||||
|         ui->pm_remove->setEnabled(true); |  | ||||||
|     else |  | ||||||
|     ui->pm_remove->setEnabled(false); |     ui->pm_remove->setEnabled(false); | ||||||
| 
 | 
 | ||||||
|     ui->pm_rename->setEnabled(true); |     ui->pm_rename->setEnabled(true); | ||||||
|  | 
 | ||||||
|  |     ui->pm_set_image->setEnabled(true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ConfigureSystem::AddUser() { | void ConfigureSystem::AddUser() { | ||||||
|  | @ -212,33 +245,57 @@ void ConfigureSystem::AddUser() { | ||||||
|     const auto username = |     const auto username = | ||||||
|         QInputDialog::getText(this, tr("Enter Username"), tr("Enter a username for the new user:"), |         QInputDialog::getText(this, tr("Enter Username"), tr("Enter a username for the new user:"), | ||||||
|                               QLineEdit::Normal, QString(), &ok); |                               QLineEdit::Normal, QString(), &ok); | ||||||
|  |     if (!ok) | ||||||
|  |         return; | ||||||
| 
 | 
 | ||||||
|     Settings::values.users.emplace_back(username.toStdString(), uuid); |     profile_manager->CreateNewUser(uuid, username.toStdString()); | ||||||
| 
 | 
 | ||||||
|     setConfiguration(); |     item_model->appendRow(new QStandardItem{ | ||||||
|  |         GetIcon(uuid).scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), | ||||||
|  |         QString::fromStdString(username.toStdString() + '\n' + uuid.FormatSwitch())}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ConfigureSystem::RenameUser() { | void ConfigureSystem::RenameUser() { | ||||||
|     const auto user = tree_view->currentIndex().row(); |     const auto user = tree_view->currentIndex().row(); | ||||||
|  |     ASSERT(user < 8); | ||||||
|  | 
 | ||||||
|  |     const auto uuid = profile_manager->GetAllUsers()[user]; | ||||||
|  |     const auto username = GetAccountUsername(uuid); | ||||||
|  | 
 | ||||||
|  |     Service::Account::ProfileBase profile; | ||||||
|  |     if (!profile_manager->GetProfileBase(uuid, profile)) | ||||||
|  |         return; | ||||||
| 
 | 
 | ||||||
|     bool ok = false; |     bool ok = false; | ||||||
|     const auto new_username = QInputDialog::getText( |     const auto new_username = | ||||||
|         this, tr("Enter Username"), tr("Enter a new username:"), QLineEdit::Normal, |         QInputDialog::getText(this, tr("Enter Username"), tr("Enter a new username:"), | ||||||
|         QString::fromStdString(Settings::values.users[user].first), &ok); |                               QLineEdit::Normal, QString::fromStdString(username), &ok); | ||||||
| 
 | 
 | ||||||
|     if (!ok) |     if (!ok) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     Settings::values.users[user].first = new_username.toStdString(); |     const auto username_std = new_username.toStdString(); | ||||||
|  |     if (username_std.size() > profile.username.size()) | ||||||
|  |         std::copy_n(username_std.begin(), profile.username.size(), profile.username.begin()); | ||||||
|  |     else | ||||||
|  |         std::copy(username_std.begin(), username_std.end(), profile.username.begin()); | ||||||
| 
 | 
 | ||||||
|     setConfiguration(); |     profile_manager->SetProfileBase(uuid, profile); | ||||||
|  | 
 | ||||||
|  |     list_items[user][0] = new QStandardItem{ | ||||||
|  |         GetIcon(uuid).scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), | ||||||
|  |         QString::fromStdString(username_std + '\n' + uuid.FormatSwitch())}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ConfigureSystem::DeleteUser() { | void ConfigureSystem::DeleteUser() { | ||||||
|     const auto user = Settings::values.users.begin() + tree_view->currentIndex().row(); |     const auto index = tree_view->currentIndex().row(); | ||||||
|  |     ASSERT(index < 8); | ||||||
|  |     const auto uuid = profile_manager->GetAllUsers()[index]; | ||||||
|  |     const auto username = GetAccountUsername(uuid); | ||||||
|  | 
 | ||||||
|     const auto confirm = QMessageBox::question( |     const auto confirm = QMessageBox::question( | ||||||
|         this, tr("Confirm Delete"), |         this, tr("Confirm Delete"), | ||||||
|         tr("You are about to delete user with name %1. Are you sure?").arg(user->first.c_str())); |         tr("You are about to delete user with name %1. Are you sure?").arg(username.c_str())); | ||||||
| 
 | 
 | ||||||
|     if (confirm == QMessageBox::No) |     if (confirm == QMessageBox::No) | ||||||
|         return; |         return; | ||||||
|  | @ -246,10 +303,38 @@ void ConfigureSystem::DeleteUser() { | ||||||
|     if (Settings::values.current_user == tree_view->currentIndex().row()) |     if (Settings::values.current_user == tree_view->currentIndex().row()) | ||||||
|         Settings::values.current_user = 0; |         Settings::values.current_user = 0; | ||||||
| 
 | 
 | ||||||
|     Settings::values.users.erase(user); |     if (!profile_manager->RemoveUser(uuid)) | ||||||
|  |         return; | ||||||
| 
 | 
 | ||||||
|     setConfiguration(); |     item_model->removeRows(tree_view->currentIndex().row(), 1); | ||||||
| 
 | 
 | ||||||
|     ui->pm_remove->setEnabled(false); |     ui->pm_remove->setEnabled(false); | ||||||
|     ui->pm_rename->setEnabled(false); |     ui->pm_rename->setEnabled(false); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void ConfigureSystem::SetUserImage() { | ||||||
|  |     const auto index = tree_view->currentIndex().row(); | ||||||
|  |     ASSERT(index < 8); | ||||||
|  |     const auto uuid = profile_manager->GetAllUsers()[index]; | ||||||
|  |     const auto username = GetAccountUsername(uuid); | ||||||
|  | 
 | ||||||
|  |     const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(), | ||||||
|  |                                                    "JPEG Images (*.jpg *.jpeg)"); | ||||||
|  | 
 | ||||||
|  |     if (file.isEmpty()) | ||||||
|  |         return; | ||||||
|  | 
 | ||||||
|  |     FileUtil::Delete(GetImagePath(uuid)); | ||||||
|  | 
 | ||||||
|  |     const auto raw_path = | ||||||
|  |         FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000010"; | ||||||
|  |     if (FileUtil::Exists(raw_path) && !FileUtil::IsDirectory(raw_path)) | ||||||
|  |         FileUtil::Delete(raw_path); | ||||||
|  | 
 | ||||||
|  |     FileUtil::CreateFullPath(GetImagePath(uuid)); | ||||||
|  |     FileUtil::Copy(file.toStdString(), GetImagePath(uuid)); | ||||||
|  | 
 | ||||||
|  |     list_items[index][0] = new QStandardItem{ | ||||||
|  |         GetIcon(uuid).scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), | ||||||
|  |         QString::fromStdString(username + '\n' + uuid.FormatSwitch())}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -5,12 +5,16 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <QGraphicsScene> | 
 | ||||||
| #include <QList> | #include <QList> | ||||||
| #include <QStandardItemModel> |  | ||||||
| #include <QTreeView> |  | ||||||
| #include <QVBoxLayout> |  | ||||||
| #include <QWidget> | #include <QWidget> | ||||||
|  | #include "core/hle/service/acc/profile_manager.h" | ||||||
|  | 
 | ||||||
|  | class QVBoxLayout; | ||||||
|  | class QTreeView; | ||||||
|  | class QStandardItemModel; | ||||||
|  | class QGraphicsScene; | ||||||
|  | class QStandardItem; | ||||||
| 
 | 
 | ||||||
| namespace Ui { | namespace Ui { | ||||||
| class ConfigureSystem; | class ConfigureSystem; | ||||||
|  | @ -26,6 +30,7 @@ public: | ||||||
|     void applyConfiguration(); |     void applyConfiguration(); | ||||||
|     void setConfiguration(); |     void setConfiguration(); | ||||||
| 
 | 
 | ||||||
|  |     void PopulateUserList(); | ||||||
|     void UpdateCurrentUser(); |     void UpdateCurrentUser(); | ||||||
| 
 | 
 | ||||||
| public slots: | public slots: | ||||||
|  | @ -36,9 +41,11 @@ public slots: | ||||||
|     void AddUser(); |     void AddUser(); | ||||||
|     void RenameUser(); |     void RenameUser(); | ||||||
|     void DeleteUser(); |     void DeleteUser(); | ||||||
|  |     void SetUserImage(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void ReadSystemSettings(); |     void ReadSystemSettings(); | ||||||
|  |     std::string GetAccountUsername(Service::Account::UUID uuid); | ||||||
| 
 | 
 | ||||||
|     QVBoxLayout* layout; |     QVBoxLayout* layout; | ||||||
|     QTreeView* tree_view; |     QTreeView* tree_view; | ||||||
|  | @ -50,8 +57,9 @@ private: | ||||||
|     std::unique_ptr<Ui::ConfigureSystem> ui; |     std::unique_ptr<Ui::ConfigureSystem> ui; | ||||||
|     bool enabled; |     bool enabled; | ||||||
| 
 | 
 | ||||||
|     std::u16string username; |  | ||||||
|     int birthmonth, birthday; |     int birthmonth, birthday; | ||||||
|     int language_index; |     int language_index; | ||||||
|     int sound_index; |     int sound_index; | ||||||
|  | 
 | ||||||
|  |     std::unique_ptr<Service::Account::ProfileManager> profile_manager; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -333,6 +333,16 @@ | ||||||
|         </item> |         </item> | ||||||
|         <item row="2" column="0"> |         <item row="2" column="0"> | ||||||
|          <layout class="QHBoxLayout" name="horizontalLayout_3"> |          <layout class="QHBoxLayout" name="horizontalLayout_3"> | ||||||
|  |           <item> | ||||||
|  |            <widget class="QPushButton" name="pm_set_image"> | ||||||
|  |             <property name="enabled"> | ||||||
|  |              <bool>false</bool> | ||||||
|  |             </property> | ||||||
|  |             <property name="text"> | ||||||
|  |              <string>Set Image</string> | ||||||
|  |             </property> | ||||||
|  |            </widget> | ||||||
|  |           </item> | ||||||
|           <item> |           <item> | ||||||
|            <spacer name="horizontalSpacer"> |            <spacer name="horizontalSpacer"> | ||||||
|             <property name="orientation"> |             <property name="orientation"> | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ | ||||||
| // VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
 | // VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
 | ||||||
| #include "core/file_sys/vfs.h" | #include "core/file_sys/vfs.h" | ||||||
| #include "core/file_sys/vfs_real.h" | #include "core/file_sys/vfs_real.h" | ||||||
|  | #include "core/hle/service/acc/profile_manager.h" | ||||||
| 
 | 
 | ||||||
| // These are wrappers to avoid the calls to CreateDirectory and CreateFile becuase of the Windows
 | // These are wrappers to avoid the calls to CreateDirectory and CreateFile becuase of the Windows
 | ||||||
| // defines.
 | // defines.
 | ||||||
|  | @ -758,10 +759,22 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target | ||||||
|         const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); |         const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); | ||||||
|         ASSERT(program_id != 0); |         ASSERT(program_id != 0); | ||||||
| 
 | 
 | ||||||
|         QStringList list{}; |         Service::Account::ProfileManager manager{}; | ||||||
|         std::transform(Settings::values.users.begin(), Settings::values.users.end(), |         const auto user_ids = manager.GetAllUsers(); | ||||||
|                        std::back_inserter(list), |         QStringList list; | ||||||
|                        [](const auto& user) { return QString::fromStdString(user.first); }); |         std::transform( | ||||||
|  |             user_ids.begin(), user_ids.end(), std::back_inserter(list), | ||||||
|  |             [&manager](const auto& user_id) -> QString { | ||||||
|  |                 if (user_id == Service::Account::UUID{}) | ||||||
|  |                     return ""; | ||||||
|  |                 Service::Account::ProfileBase base; | ||||||
|  |                 if (!manager.GetProfileBase(user_id, base)) | ||||||
|  |                     return ""; | ||||||
|  | 
 | ||||||
|  |                 return QString::fromStdString(Common::StringFromFixedZeroTerminatedBuffer( | ||||||
|  |                     reinterpret_cast<const char*>(base.username.data()), base.username.size())); | ||||||
|  |             }); | ||||||
|  |         list.removeAll(""); | ||||||
| 
 | 
 | ||||||
|         bool ok = false; |         bool ok = false; | ||||||
|         const auto index_string = |         const auto index_string = | ||||||
|  | @ -772,12 +785,12 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target | ||||||
|             return; |             return; | ||||||
| 
 | 
 | ||||||
|         const auto index = list.indexOf(index_string); |         const auto index = list.indexOf(index_string); | ||||||
|         ASSERT(index != -1); |         ASSERT(index != -1 && index < 8); | ||||||
| 
 | 
 | ||||||
|         const auto user_id = Settings::values.users[index].second.uuid; |         const auto user_id = manager.GetAllUsers()[index]; | ||||||
|         path = nand_dir + FileSys::SaveDataFactory::GetFullPath(FileSys::SaveDataSpaceId::NandUser, |         path = nand_dir + FileSys::SaveDataFactory::GetFullPath(FileSys::SaveDataSpaceId::NandUser, | ||||||
|                                                                 FileSys::SaveDataType::SaveData, |                                                                 FileSys::SaveDataType::SaveData, | ||||||
|                                                                 program_id, user_id, 0); |                                                                 program_id, user_id.uuid, 0); | ||||||
| 
 | 
 | ||||||
|         if (!FileUtil::Exists(path)) { |         if (!FileUtil::Exists(path)) { | ||||||
|             FileUtil::CreateFullPath(path); |             FileUtil::CreateFullPath(path); | ||||||
|  |  | ||||||
|  | @ -128,24 +128,8 @@ void Config::ReadValues() { | ||||||
|     Settings::values.enable_nfc = sdl2_config->GetBoolean("System", "enable_nfc", true); |     Settings::values.enable_nfc = sdl2_config->GetBoolean("System", "enable_nfc", true); | ||||||
|     const auto size = sdl2_config->GetInteger("System", "users_size", 0); |     const auto size = sdl2_config->GetInteger("System", "users_size", 0); | ||||||
| 
 | 
 | ||||||
|     Settings::values.users.clear(); |     Settings::values.current_user = | ||||||
|     for (std::size_t i = 0; i < size; ++i) { |         std::clamp<int>(sdl2_config->GetInteger("System", "current_user", 0), 0, 7); | ||||||
|         const auto uuid_low = std::stoull( |  | ||||||
|             sdl2_config->Get("System", fmt::format("users_{}_uuid_low", i), "0"), nullptr, 0); |  | ||||||
|         const auto uuid_high = std::stoull( |  | ||||||
|             sdl2_config->Get("System", fmt::format("users_{}_uuid_high", i), "0"), nullptr, 0); |  | ||||||
|         Settings::values.users.emplace_back( |  | ||||||
|             sdl2_config->Get("System", fmt::format("users_{}_username", i), ""), |  | ||||||
|             Service::Account::UUID{uuid_low, uuid_high}); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (Settings::values.users.empty()) { |  | ||||||
|         Settings::values.users.emplace_back("yuzu", Service::Account::UUID{1, 0}); |  | ||||||
|         LOG_WARNING( |  | ||||||
|             Config, |  | ||||||
|             "You are using the default UUID of {1, 0}! This might cause issues down the road! " |  | ||||||
|             "Please consider randomizing a UUID and adding it to the sdl2_config.ini file."); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     // Miscellaneous
 |     // Miscellaneous
 | ||||||
|     Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace"); |     Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace"); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Zach Hilman
						Zach Hilman