account: Adds AccountManager (#2184)

* account: Adds Account Manager

In a way to have Custom User Profiles merged in master faster, this PR adds a `AccountManager` class (based on `AccountUtils` class) and the following changes have been made:
- Adds a "default profile values" which were the old hardcoded ones.
- The image profile is moved to the Account service folder.
- The hardcoded UserId for the savedata is now using the `AccountManager` last opened one.
- The DeviceId in Mii service is changed to the right value (checked by REd sys:set call).

* Fix csproj

* Addresses gdkchan's comments

* Fix UserProfile fields

* Fix mii GetDeviceId()

* Update Ryujinx.HLE.csproj
This commit is contained in:
Ac_K 2021-04-13 03:16:43 +02:00 committed by GitHub
parent 001005b3d5
commit 7344dee475
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 89 additions and 81 deletions

View file

@ -1,23 +1,31 @@
using System.Collections.Concurrent;
using Ryujinx.Common;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace Ryujinx.HLE.HOS.Services.Account.Acc
{
public class AccountUtils
public class AccountManager
{
private ConcurrentDictionary<string, UserProfile> _profiles;
internal UserProfile LastOpenedUser { get; private set; }
public UserProfile LastOpenedUser { get; private set; }
public AccountUtils()
public AccountManager()
{
_profiles = new ConcurrentDictionary<string, UserProfile>();
UserId defaultUserId = new UserId("00000000000000010000000000000000");
byte[] defaultUserImage = EmbeddedResources.Read("Ryujinx.HLE/HOS/Services/Account/Acc/DefaultUserImage.jpg");
AddUser(defaultUserId, "Player", defaultUserImage);
OpenUser(defaultUserId);
}
public void AddUser(UserId userId, string name)
public void AddUser(UserId userId, string name, byte[] image)
{
UserProfile profile = new UserProfile(userId, name);
UserProfile profile = new UserProfile(userId, name, image);
_profiles.AddOrUpdate(userId.ToString(), profile, (key, old) => profile);
}

View file

@ -1,8 +1,6 @@
using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.HLE.Utilities;
using System.IO;
using System.Reflection;
using System.Text;
namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
@ -10,12 +8,10 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
class ProfileServer
{
private UserProfile _profile;
private Stream _profilePictureStream;
public ProfileServer(UserProfile profile)
{
_profile = profile;
_profilePictureStream = Assembly.GetCallingAssembly().GetManifestResourceStream("Ryujinx.HLE.RyujinxProfileImage.jpg");
_profile = profile;
}
public ResultCode Get(ServiceCtx context)
@ -54,7 +50,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
public ResultCode GetImageSize(ServiceCtx context)
{
context.ResponseData.Write(_profilePictureStream.Length);
context.ResponseData.Write(_profile.Image.Length);
return ResultCode.Success;
}
@ -64,13 +60,14 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
long bufferPosition = context.Request.ReceiveBuff[0].Position;
long bufferLen = context.Request.ReceiveBuff[0].Size;
byte[] profilePictureData = new byte[bufferLen];
if (_profile.Image.Length > bufferLen)
{
return ResultCode.InvalidBufferSize;
}
_profilePictureStream.Read(profilePictureData, 0, profilePictureData.Length);
context.Memory.Write((ulong)bufferPosition, _profile.Image);
context.Memory.Write((ulong)bufferPosition, profilePictureData);
context.ResponseData.Write(_profilePictureStream.Length);
context.ResponseData.Write(_profile.Image.Length);
return ResultCode.Success;
}
@ -100,16 +97,16 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
context.Memory.Read((ulong)userDataPosition, userData);
long profilePicturePosition = context.Request.SendBuff[0].Position;
long profilePictureSize = context.Request.SendBuff[0].Size;
long profileImagePosition = context.Request.SendBuff[0].Position;
long profileImageSize = context.Request.SendBuff[0].Size;
byte[] profilePictureData = new byte[profilePictureSize];
byte[] profileImageData = new byte[profileImageSize];
context.Memory.Read((ulong)profilePicturePosition, profilePictureData);
context.Memory.Read((ulong)profileImagePosition, profileImageData);
// TODO: Read the nn::account::profile::ProfileBase and store everything in the savedata.
Logger.Stub?.PrintStub(LogClass.ServiceAcc, new { userDataSize, profilePictureSize });
Logger.Stub?.PrintStub(LogClass.ServiceAcc, new { userDataSize, profileImageSize });
return ResultCode.Success;
}

View file

@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
public ResultCode GetUserCountImpl(ServiceCtx context)
{
context.ResponseData.Write(context.Device.System.State.Account.GetUserCount());
context.ResponseData.Write(context.Device.System.AccountManager.GetUserCount());
return ResultCode.Success;
}
@ -31,26 +31,26 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
return resultCode;
}
context.ResponseData.Write(context.Device.System.State.Account.TryGetUser(userId, out _));
context.ResponseData.Write(context.Device.System.AccountManager.TryGetUser(userId, out _));
return ResultCode.Success;
}
public ResultCode ListAllUsers(ServiceCtx context)
{
return WriteUserList(context, context.Device.System.State.Account.GetAllUsers());
return WriteUserList(context, context.Device.System.AccountManager.GetAllUsers());
}
public ResultCode ListOpenUsers(ServiceCtx context)
{
return WriteUserList(context, context.Device.System.State.Account.GetOpenedUsers());
return WriteUserList(context, context.Device.System.AccountManager.GetOpenedUsers());
}
private ResultCode WriteUserList(ServiceCtx context, IEnumerable<UserProfile> profiles)
{
if (context.Request.RecvListBuff.Count == 0)
{
return ResultCode.InvalidInputBuffer;
return ResultCode.InvalidBuffer;
}
long outputPosition = context.Request.RecvListBuff[0].Position;
@ -78,7 +78,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
public ResultCode GetLastOpenedUser(ServiceCtx context)
{
context.Device.System.State.Account.LastOpenedUser.UserId.Write(context.ResponseData);
context.Device.System.AccountManager.LastOpenedUser.UserId.Write(context.ResponseData);
return ResultCode.Success;
}
@ -94,7 +94,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
return resultCode;
}
if (!context.Device.System.State.Account.TryGetUser(userId, out UserProfile userProfile))
if (!context.Device.System.AccountManager.TryGetUser(userId, out UserProfile userProfile))
{
Logger.Warning?.Print(LogClass.ServiceAcc, $"User 0x{userId} not found!");
@ -118,7 +118,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
public ResultCode TrySelectUserWithoutInteraction(ServiceCtx context)
{
if (context.Device.System.State.Account.GetUserCount() != 1)
if (context.Device.System.AccountManager.GetUserCount() != 1)
{
// Invalid UserId.
UserId.Null.Write(context.ResponseData);
@ -137,7 +137,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
}
// NOTE: As we returned an invalid UserId if there is more than one user earlier, now we can return only the first one.
context.Device.System.State.Account.GetFirst().UserId.Write(context.ResponseData);
context.Device.System.AccountManager.GetFirst().UserId.Write(context.ResponseData);
return ResultCode.Success;
}
@ -153,7 +153,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
if (context.Request.SendBuff.Count == 0)
{
return ResultCode.InvalidInputBuffer;
return ResultCode.InvalidBuffer;
}
long inputPosition = context.Request.SendBuff[0].Position;
@ -161,7 +161,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
if (inputSize != 0x24000)
{
return ResultCode.InvalidInputBufferSize;
return ResultCode.InvalidBufferSize;
}
byte[] thumbnailBuffer = new byte[inputSize];
@ -205,7 +205,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
{
// TODO: Determine how users are "qualified". We assume all users are "qualified" for now.
return WriteUserList(context, context.Device.System.State.Account.GetAllUsers());
return WriteUserList(context, context.Device.System.AccountManager.GetAllUsers());
}
public ResultCode CheckUserId(ServiceCtx context, out UserId userId)

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View file

@ -111,7 +111,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
{
UserId userId = context.RequestData.ReadStruct<UserId>();
if (!context.Device.System.State.Account.TryGetUser(userId, out UserProfile userProfile))
if (!context.Device.System.AccountManager.TryGetUser(userId, out UserProfile userProfile))
{
Logger.Warning?.Print(LogClass.ServiceAcc, $"User 0x{userId} not found!");

View file

@ -1,26 +1,29 @@
using Ryujinx.HLE.Utilities;
using System;
using System;
namespace Ryujinx.HLE.HOS.Services.Account.Acc
{
class UserProfile
public class UserProfile
{
private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public UserId UserId { get; private set; }
public UserId UserId { get; }
public string Name { get; private set; }
public string Name { get; }
public byte[] Image { get; }
public long LastModifiedTimestamp { get; private set; }
public AccountState AccountState { get; set; }
public AccountState AccountState { get; set; }
public AccountState OnlinePlayState { get; set; }
public UserProfile(UserId userId, string name)
public UserProfile(UserId userId, string name, byte[] image)
{
UserId = userId;
Name = name;
Image = image;
LastModifiedTimestamp = 0;
AccountState = AccountState.Closed;