AccountManager.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. using LibHac;
  2. using LibHac.Common;
  3. using LibHac.Fs;
  4. using LibHac.Fs.Shim;
  5. using Ryujinx.Common;
  6. using System;
  7. using System.Collections.Concurrent;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. namespace Ryujinx.HLE.HOS.Services.Account.Acc
  11. {
  12. public class AccountManager
  13. {
  14. public static readonly UserId DefaultUserId = new UserId("00000000000000010000000000000000");
  15. private readonly AccountSaveDataManager _accountSaveDataManager;
  16. // Todo: The account service doesn't have the permissions to delete save data. Qlaunch takes care of deleting
  17. // save data, so we're currently passing a client with full permissions. Consider moving save data deletion
  18. // outside of the AccountManager.
  19. private readonly HorizonClient _horizonClient;
  20. private ConcurrentDictionary<string, UserProfile> _profiles;
  21. public UserProfile LastOpenedUser { get; private set; }
  22. public AccountManager(HorizonClient horizonClient)
  23. {
  24. _horizonClient = horizonClient;
  25. _profiles = new ConcurrentDictionary<string, UserProfile>();
  26. _accountSaveDataManager = new AccountSaveDataManager(_profiles);
  27. if (!_profiles.TryGetValue(DefaultUserId.ToString(), out _))
  28. {
  29. byte[] defaultUserImage = EmbeddedResources.Read("Ryujinx.HLE/HOS/Services/Account/Acc/DefaultUserImage.jpg");
  30. AddUser("RyuPlayer", defaultUserImage, DefaultUserId);
  31. OpenUser(DefaultUserId);
  32. }
  33. else
  34. {
  35. OpenUser(_accountSaveDataManager.LastOpened);
  36. }
  37. }
  38. public void AddUser(string name, byte[] image, UserId userId = new UserId())
  39. {
  40. if (userId.IsNull)
  41. {
  42. userId = new UserId(Guid.NewGuid().ToString().Replace("-", ""));
  43. }
  44. UserProfile profile = new UserProfile(userId, name, image);
  45. _profiles.AddOrUpdate(userId.ToString(), profile, (key, old) => profile);
  46. _accountSaveDataManager.Save(_profiles);
  47. }
  48. public void OpenUser(UserId userId)
  49. {
  50. if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile))
  51. {
  52. // TODO: Support multiple open users ?
  53. foreach (UserProfile userProfile in GetAllUsers())
  54. {
  55. if (userProfile == LastOpenedUser)
  56. {
  57. userProfile.AccountState = AccountState.Closed;
  58. break;
  59. }
  60. }
  61. (LastOpenedUser = profile).AccountState = AccountState.Open;
  62. _accountSaveDataManager.LastOpened = userId;
  63. }
  64. _accountSaveDataManager.Save(_profiles);
  65. }
  66. public void CloseUser(UserId userId)
  67. {
  68. if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile))
  69. {
  70. profile.AccountState = AccountState.Closed;
  71. }
  72. _accountSaveDataManager.Save(_profiles);
  73. }
  74. public void OpenUserOnlinePlay(UserId userId)
  75. {
  76. if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile))
  77. {
  78. // TODO: Support multiple open online users ?
  79. foreach (UserProfile userProfile in GetAllUsers())
  80. {
  81. if (userProfile == LastOpenedUser)
  82. {
  83. userProfile.OnlinePlayState = AccountState.Closed;
  84. break;
  85. }
  86. }
  87. profile.OnlinePlayState = AccountState.Open;
  88. }
  89. _accountSaveDataManager.Save(_profiles);
  90. }
  91. public void CloseUserOnlinePlay(UserId userId)
  92. {
  93. if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile))
  94. {
  95. profile.OnlinePlayState = AccountState.Closed;
  96. }
  97. _accountSaveDataManager.Save(_profiles);
  98. }
  99. public void SetUserImage(UserId userId, byte[] image)
  100. {
  101. foreach (UserProfile userProfile in GetAllUsers())
  102. {
  103. if (userProfile.UserId == userId)
  104. {
  105. userProfile.Image = image;
  106. break;
  107. }
  108. }
  109. _accountSaveDataManager.Save(_profiles);
  110. }
  111. public void SetUserName(UserId userId, string name)
  112. {
  113. foreach (UserProfile userProfile in GetAllUsers())
  114. {
  115. if (userProfile.UserId == userId)
  116. {
  117. userProfile.Name = name;
  118. break;
  119. }
  120. }
  121. _accountSaveDataManager.Save(_profiles);
  122. }
  123. public void DeleteUser(UserId userId)
  124. {
  125. DeleteSaveData(userId);
  126. _profiles.Remove(userId.ToString(), out _);
  127. OpenUser(DefaultUserId);
  128. _accountSaveDataManager.Save(_profiles);
  129. }
  130. private void DeleteSaveData(UserId userId)
  131. {
  132. SaveDataFilter saveDataFilter = new SaveDataFilter();
  133. saveDataFilter.SetUserId(new LibHac.Fs.UserId((ulong)userId.High, (ulong)userId.Low));
  134. using var saveDataIterator = new UniqueRef<SaveDataIterator>();
  135. _horizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref(), SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
  136. Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
  137. while (true)
  138. {
  139. saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure();
  140. if (readCount == 0)
  141. {
  142. break;
  143. }
  144. for (int i = 0; i < readCount; i++)
  145. {
  146. _horizonClient.Fs.DeleteSaveData(SaveDataSpaceId.User, saveDataInfo[i].SaveDataId).ThrowIfFailure();
  147. }
  148. }
  149. }
  150. internal int GetUserCount()
  151. {
  152. return _profiles.Count;
  153. }
  154. internal bool TryGetUser(UserId userId, out UserProfile profile)
  155. {
  156. return _profiles.TryGetValue(userId.ToString(), out profile);
  157. }
  158. public IEnumerable<UserProfile> GetAllUsers()
  159. {
  160. return _profiles.Values;
  161. }
  162. internal IEnumerable<UserProfile> GetOpenedUsers()
  163. {
  164. return _profiles.Values.Where(x => x.AccountState == AccountState.Open);
  165. }
  166. internal UserProfile GetFirst()
  167. {
  168. return _profiles.First().Value;
  169. }
  170. }
  171. }