Fix inconsistencies with UserId (#906)
* Fix inconsistencies with UserId The account user id isn't an UUID. This PR adds a new UserId type with the correct value ordering to avoid mismatch with LibHac's Uid. This also fix an hardcoded value of the UserId. As the userid has been invalid for quite some time (and to avoid forcing users to their recreate saves), the userid has been changed to "00000000000000010000000000000000". Also implement a stub for IApplicationFunctions::GetSaveDataSize. (see the sources for the reason) Fix #626 * Address jd's & Ac_k's comments
This commit is contained in:
parent
f373f870f7
commit
ea14a95524
18 changed files with 172 additions and 72 deletions
|
@ -1,4 +1,4 @@
|
||||||
using Ryujinx.HLE.Utilities;
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.FileSystem
|
namespace Ryujinx.HLE.FileSystem
|
||||||
{
|
{
|
||||||
|
@ -8,14 +8,14 @@ namespace Ryujinx.HLE.FileSystem
|
||||||
public long SaveId { get; private set; }
|
public long SaveId { get; private set; }
|
||||||
public SaveDataType SaveDataType { get; private set; }
|
public SaveDataType SaveDataType { get; private set; }
|
||||||
public SaveSpaceId SaveSpaceId { get; private set; }
|
public SaveSpaceId SaveSpaceId { get; private set; }
|
||||||
public UInt128 UserId { get; private set; }
|
public UserId UserId { get; private set; }
|
||||||
|
|
||||||
public SaveInfo(
|
public SaveInfo(
|
||||||
ulong titleId,
|
ulong titleId,
|
||||||
long saveId,
|
long saveId,
|
||||||
SaveDataType saveDataType,
|
SaveDataType saveDataType,
|
||||||
SaveSpaceId saveSpaceId,
|
SaveSpaceId saveSpaceId,
|
||||||
UInt128 userId = new UInt128())
|
UserId userId = new UserId())
|
||||||
{
|
{
|
||||||
TitleId = titleId;
|
TitleId = titleId;
|
||||||
SaveId = saveId;
|
SaveId = saveId;
|
||||||
|
|
|
@ -669,8 +669,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
{
|
{
|
||||||
Logger.PrintInfo(LogClass.Application, "Ensuring required savedata exists.");
|
Logger.PrintInfo(LogClass.Application, "Ensuring required savedata exists.");
|
||||||
|
|
||||||
UInt128 lastOpenedUser = State.Account.LastOpenedUser.UserId;
|
Uid user = State.Account.LastOpenedUser.UserId.ToLibHacUid();
|
||||||
Uid user = new Uid((ulong)lastOpenedUser.Low, (ulong)lastOpenedUser.High);
|
|
||||||
|
|
||||||
ref ApplicationControlProperty control = ref ControlData.Value;
|
ref ApplicationControlProperty control = ref ControlData.Value;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using Ryujinx.HLE.Utilities;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
@ -16,14 +15,14 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
_profiles = new ConcurrentDictionary<string, UserProfile>();
|
_profiles = new ConcurrentDictionary<string, UserProfile>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddUser(UInt128 userId, string name)
|
public void AddUser(UserId userId, string name)
|
||||||
{
|
{
|
||||||
UserProfile profile = new UserProfile(userId, name);
|
UserProfile profile = new UserProfile(userId, name);
|
||||||
|
|
||||||
_profiles.AddOrUpdate(userId.ToString(), profile, (key, old) => profile);
|
_profiles.AddOrUpdate(userId.ToString(), profile, (key, old) => profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OpenUser(UInt128 userId)
|
public void OpenUser(UserId userId)
|
||||||
{
|
{
|
||||||
if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile))
|
if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile))
|
||||||
{
|
{
|
||||||
|
@ -31,7 +30,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CloseUser(UInt128 userId)
|
public void CloseUser(UserId userId)
|
||||||
{
|
{
|
||||||
if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile))
|
if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile))
|
||||||
{
|
{
|
||||||
|
@ -44,7 +43,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
return _profiles.Count;
|
return _profiles.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool TryGetUser(UInt128 userId, out UserProfile profile)
|
internal bool TryGetUser(UserId userId, out UserProfile profile)
|
||||||
{
|
{
|
||||||
return _profiles.TryGetValue(userId.ToString(), out profile);
|
return _profiles.TryGetValue(userId.ToString(), out profile);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.HOS.Services.Arp;
|
using Ryujinx.HLE.HOS.Services.Arp;
|
||||||
using Ryujinx.HLE.Utilities;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
|
@ -28,7 +28,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
// GetUserExistence(nn::account::Uid) -> bool
|
// GetUserExistence(nn::account::Uid) -> bool
|
||||||
public ResultCode GetUserExistence(ServiceCtx context)
|
public ResultCode GetUserExistence(ServiceCtx context)
|
||||||
{
|
{
|
||||||
UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10));
|
UserId userId = context.RequestData.ReadStruct<UserId>();
|
||||||
|
|
||||||
if (userId.IsNull)
|
if (userId.IsNull)
|
||||||
{
|
{
|
||||||
|
@ -75,8 +75,8 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Memory.WriteInt64(outputPosition + (long)offset, userProfile.UserId.Low);
|
context.Memory.WriteInt64(outputPosition + (long)offset, userProfile.UserId.High);
|
||||||
context.Memory.WriteInt64(outputPosition + (long)offset + 8, userProfile.UserId.High);
|
context.Memory.WriteInt64(outputPosition + (long)offset + 8, userProfile.UserId.Low);
|
||||||
|
|
||||||
offset += 0x10;
|
offset += 0x10;
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
// GetProfile(nn::account::Uid) -> object<nn::account::profile::IProfile>
|
// GetProfile(nn::account::Uid) -> object<nn::account::profile::IProfile>
|
||||||
public ResultCode GetProfile(ServiceCtx context)
|
public ResultCode GetProfile(ServiceCtx context)
|
||||||
{
|
{
|
||||||
UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10));
|
UserId userId = context.RequestData.ReadStruct<UserId>();
|
||||||
|
|
||||||
if (!context.Device.System.State.Account.TryGetUser(userId, out UserProfile userProfile))
|
if (!context.Device.System.State.Account.TryGetUser(userId, out UserProfile userProfile))
|
||||||
{
|
{
|
||||||
|
@ -131,7 +131,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
if (context.Device.System.State.Account.GetUserCount() != 1)
|
if (context.Device.System.State.Account.GetUserCount() != 1)
|
||||||
{
|
{
|
||||||
// Invalid UserId.
|
// Invalid UserId.
|
||||||
new UInt128(0, 0).Write(context.ResponseData);
|
new UserId(0, 0).Write(context.ResponseData);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
// GetBaasAccountManagerForApplication(nn::account::Uid) -> object<nn::account::baas::IManagerForApplication>
|
// GetBaasAccountManagerForApplication(nn::account::Uid) -> object<nn::account::baas::IManagerForApplication>
|
||||||
public ResultCode GetBaasAccountManagerForApplication(ServiceCtx context)
|
public ResultCode GetBaasAccountManagerForApplication(ServiceCtx context)
|
||||||
{
|
{
|
||||||
UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10));
|
UserId userId = context.RequestData.ReadStruct<UserId>();
|
||||||
|
|
||||||
if (userId.IsNull)
|
if (userId.IsNull)
|
||||||
{
|
{
|
||||||
|
@ -220,7 +220,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
return ResultCode.InvalidArgument;
|
return ResultCode.InvalidArgument;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10));
|
UserId userId = context.RequestData.ReadStruct<UserId>();
|
||||||
|
|
||||||
if (userId.IsNull)
|
if (userId.IsNull)
|
||||||
{
|
{
|
||||||
|
@ -258,7 +258,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
return ResultCode.InvalidArgument;
|
return ResultCode.InvalidArgument;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10));
|
UserId userId = context.RequestData.ReadStruct<UserId>();
|
||||||
|
|
||||||
if (userId.IsNull)
|
if (userId.IsNull)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.HOS.Services.Arp;
|
using Ryujinx.HLE.HOS.Services.Arp;
|
||||||
using Ryujinx.HLE.Utilities;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
{
|
{
|
||||||
class IManagerForApplication : IpcService
|
class IManagerForApplication : IpcService
|
||||||
{
|
{
|
||||||
private UInt128 _userId;
|
private UserId _userId;
|
||||||
private ApplicationLaunchProperty _applicationLaunchProperty;
|
private ApplicationLaunchProperty _applicationLaunchProperty;
|
||||||
|
|
||||||
public IManagerForApplication(UInt128 userId, ApplicationLaunchProperty applicationLaunchProperty)
|
public IManagerForApplication(UserId userId, ApplicationLaunchProperty applicationLaunchProperty)
|
||||||
{
|
{
|
||||||
_userId = userId;
|
_userId = userId;
|
||||||
_applicationLaunchProperty = applicationLaunchProperty;
|
_applicationLaunchProperty = applicationLaunchProperty;
|
||||||
|
|
81
Ryujinx.HLE/HOS/Services/Account/Acc/Types/UserId.cs
Normal file
81
Ryujinx.HLE/HOS/Services/Account/Acc/Types/UserId.cs
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
using LibHac.Account;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct UserId : IEquatable<UserId>
|
||||||
|
{
|
||||||
|
public readonly long High;
|
||||||
|
public readonly long Low;
|
||||||
|
|
||||||
|
public bool IsNull => (Low | High) == 0;
|
||||||
|
|
||||||
|
public UserId(long low, long high)
|
||||||
|
{
|
||||||
|
Low = low;
|
||||||
|
High = high;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserId(byte[] bytes)
|
||||||
|
{
|
||||||
|
High = BitConverter.ToInt64(bytes, 0);
|
||||||
|
Low = BitConverter.ToInt64(bytes, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserId(string hex)
|
||||||
|
{
|
||||||
|
if (hex == null || hex.Length != 32 || !hex.All("0123456789abcdefABCDEF".Contains))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Invalid Hex value!", nameof(hex));
|
||||||
|
}
|
||||||
|
|
||||||
|
Low = Convert.ToInt64(hex.Substring(16), 16);
|
||||||
|
High = Convert.ToInt64(hex.Substring(0, 16), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(BinaryWriter binaryWriter)
|
||||||
|
{
|
||||||
|
binaryWriter.Write(High);
|
||||||
|
binaryWriter.Write(Low);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return High.ToString("x16") + Low.ToString("x16");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(UserId x, UserId y)
|
||||||
|
{
|
||||||
|
return x.Equals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(UserId x, UserId y)
|
||||||
|
{
|
||||||
|
return !x.Equals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is UserId userId && Equals(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(UserId cmpObj)
|
||||||
|
{
|
||||||
|
return Low == cmpObj.Low && High == cmpObj.High;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(Low, High);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Uid ToLibHacUid()
|
||||||
|
{
|
||||||
|
return new Uid((ulong)High, (ulong)Low);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
{
|
{
|
||||||
private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
|
||||||
public UInt128 UserId { get; private set; }
|
public UserId UserId { get; private set; }
|
||||||
|
|
||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
public AccountState AccountState { get; set; }
|
public AccountState AccountState { get; set; }
|
||||||
public AccountState OnlinePlayState { get; set; }
|
public AccountState OnlinePlayState { get; set; }
|
||||||
|
|
||||||
public UserProfile(UInt128 userId, string name)
|
public UserProfile(UserId userId, string name)
|
||||||
{
|
{
|
||||||
UserId = userId;
|
UserId = userId;
|
||||||
Name = name;
|
Name = name;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.IO;
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.Storage
|
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.Storage
|
||||||
{
|
{
|
||||||
|
@ -6,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.Storage
|
||||||
{
|
{
|
||||||
private const uint LaunchParamsMagic = 0xc79497ca;
|
private const uint LaunchParamsMagic = 0xc79497ca;
|
||||||
|
|
||||||
public static byte[] MakeLaunchParams()
|
public static byte[] MakeLaunchParams(UserProfile userProfile)
|
||||||
{
|
{
|
||||||
// Size needs to be at least 0x88 bytes otherwise application errors.
|
// Size needs to be at least 0x88 bytes otherwise application errors.
|
||||||
using (MemoryStream ms = new MemoryStream())
|
using (MemoryStream ms = new MemoryStream())
|
||||||
|
@ -17,8 +18,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.Storage
|
||||||
|
|
||||||
writer.Write(LaunchParamsMagic);
|
writer.Write(LaunchParamsMagic);
|
||||||
writer.Write(1); // IsAccountSelected? Only lower 8 bits actually used.
|
writer.Write(1); // IsAccountSelected? Only lower 8 bits actually used.
|
||||||
writer.Write(1L); // User Id Low (note: User Id needs to be != 0)
|
userProfile.UserId.Write(writer);
|
||||||
writer.Write(0L); // User Id High
|
|
||||||
|
|
||||||
return ms.ToArray();
|
return ms.ToArray();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using LibHac;
|
using LibHac;
|
||||||
using LibHac.Account;
|
using LibHac.Account;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
|
using LibHac.Fs;
|
||||||
using LibHac.Ncm;
|
using LibHac.Ncm;
|
||||||
using LibHac.Ns;
|
using LibHac.Ns;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
|
@ -13,6 +14,7 @@ using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
using static LibHac.Fs.ApplicationSaveDataManagement;
|
using static LibHac.Fs.ApplicationSaveDataManagement;
|
||||||
|
using AccountUid = Ryujinx.HLE.HOS.Services.Account.Acc.UserId;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy
|
namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy
|
||||||
{
|
{
|
||||||
|
@ -30,7 +32,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||||
public ResultCode PopLaunchParameter(ServiceCtx context)
|
public ResultCode PopLaunchParameter(ServiceCtx context)
|
||||||
{
|
{
|
||||||
// Only the first 0x18 bytes of the Data seems to be actually used.
|
// Only the first 0x18 bytes of the Data seems to be actually used.
|
||||||
MakeObject(context, new AppletAE.IStorage(StorageHelper.MakeLaunchParams()));
|
MakeObject(context, new AppletAE.IStorage(StorageHelper.MakeLaunchParams(context.Device.System.State.Account.LastOpenedUser)));
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||||
// EnsureSaveData(nn::account::Uid) -> u64
|
// EnsureSaveData(nn::account::Uid) -> u64
|
||||||
public ResultCode EnsureSaveData(ServiceCtx context)
|
public ResultCode EnsureSaveData(ServiceCtx context)
|
||||||
{
|
{
|
||||||
Uid userId = context.RequestData.ReadStruct<Uid>();
|
Uid userId = context.RequestData.ReadStruct<AccountUid>().ToLibHacUid();
|
||||||
TitleId titleId = new TitleId(context.Process.TitleId);
|
TitleId titleId = new TitleId(context.Process.TitleId);
|
||||||
|
|
||||||
BlitStruct<ApplicationControlProperty> controlHolder = context.Device.System.ControlData;
|
BlitStruct<ApplicationControlProperty> controlHolder = context.Device.System.ControlData;
|
||||||
|
@ -108,6 +110,23 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSaveDataSize(u8, nn::account::Uid) -> (u64, u64)
|
||||||
|
[Command(26)] // 3.0.0+
|
||||||
|
public ResultCode GetSaveDataSize(ServiceCtx context)
|
||||||
|
{
|
||||||
|
SaveDataType saveDataType = (SaveDataType)context.RequestData.ReadByte();
|
||||||
|
context.RequestData.BaseStream.Seek(7, System.IO.SeekOrigin.Current);
|
||||||
|
|
||||||
|
Uid userId = context.RequestData.ReadStruct<AccountUid>().ToLibHacUid();
|
||||||
|
|
||||||
|
// TODO: We return a size of 2GB as we use a directory based save system. This should be enough for most of the games.
|
||||||
|
context.ResponseData.Write(2000000000u);
|
||||||
|
|
||||||
|
Logger.PrintStub(LogClass.ServiceAm, new { saveDataType, userId });
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
[Command(40)]
|
[Command(40)]
|
||||||
// NotifyRunning() -> b8
|
// NotifyRunning() -> b8
|
||||||
public ResultCode NotifyRunning(ServiceCtx context)
|
public ResultCode NotifyRunning(ServiceCtx context)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator;
|
using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator;
|
||||||
using Ryujinx.HLE.Utilities;
|
using Ryujinx.HLE.Utilities;
|
||||||
|
|
||||||
|
@ -28,10 +29,10 @@ namespace Ryujinx.HLE.HOS.Services.Friend
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(1)] // 2.0.0+
|
[Command(1)] // 2.0.0+
|
||||||
// CreateNotificationService(nn::account::Uid) -> object<nn::friends::detail::ipc::INotificationService>
|
// CreateNotificationService(nn::account::Uid userId) -> object<nn::friends::detail::ipc::INotificationService>
|
||||||
public ResultCode CreateNotificationService(ServiceCtx context)
|
public ResultCode CreateNotificationService(ServiceCtx context)
|
||||||
{
|
{
|
||||||
UInt128 userId = context.RequestData.ReadStruct<UInt128>();
|
UserId userId = context.RequestData.ReadStruct<UserId>();
|
||||||
|
|
||||||
if (userId.IsNull)
|
if (userId.IsNull)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using Ryujinx.HLE.Utilities;
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||||
|
@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8, Size = 0x200, CharSet = CharSet.Ansi)]
|
[StructLayout(LayoutKind.Sequential, Pack = 0x8, Size = 0x200, CharSet = CharSet.Ansi)]
|
||||||
struct Friend
|
struct Friend
|
||||||
{
|
{
|
||||||
public UInt128 UserId;
|
public UserId UserId;
|
||||||
public long NetworkUserId;
|
public long NetworkUserId;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x21)]
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x21)]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using Ryujinx.HLE.Utilities;
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||||
|
@ -6,7 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8, CharSet = CharSet.Ansi)]
|
[StructLayout(LayoutKind.Sequential, Pack = 0x8, CharSet = CharSet.Ansi)]
|
||||||
struct UserPresence
|
struct UserPresence
|
||||||
{
|
{
|
||||||
public UInt128 UserId;
|
public UserId UserId;
|
||||||
public long LastTimeOnlineTimestamp;
|
public long LastTimeOnlineTimestamp;
|
||||||
public PresenceStatus Status;
|
public PresenceStatus Status;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService;
|
using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService;
|
||||||
using Ryujinx.HLE.Utilities;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
@ -18,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(10100)]
|
[Command(10100)]
|
||||||
// nn::friends::GetFriendListIds(int offset, nn::account::Uid userUUID, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid)
|
// nn::friends::GetFriendListIds(int offset, nn::account::Uid userId, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid)
|
||||||
// -> int outCount, array<nn::account::NetworkServiceAccountId, 0xa>
|
// -> int outCount, array<nn::account::NetworkServiceAccountId, 0xa>
|
||||||
public ResultCode GetFriendListIds(ServiceCtx context)
|
public ResultCode GetFriendListIds(ServiceCtx context)
|
||||||
{
|
{
|
||||||
|
@ -27,13 +26,13 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||||
// Padding
|
// Padding
|
||||||
context.RequestData.ReadInt32();
|
context.RequestData.ReadInt32();
|
||||||
|
|
||||||
UInt128 uuid = context.RequestData.ReadStruct<UInt128>();
|
UserId userId = context.RequestData.ReadStruct<UserId>();
|
||||||
FriendFilter filter = context.RequestData.ReadStruct<FriendFilter>();
|
FriendFilter filter = context.RequestData.ReadStruct<FriendFilter>();
|
||||||
|
|
||||||
// Pid placeholder
|
// Pid placeholder
|
||||||
context.RequestData.ReadInt64();
|
context.RequestData.ReadInt64();
|
||||||
|
|
||||||
if (uuid.IsNull)
|
if (userId.IsNull)
|
||||||
{
|
{
|
||||||
return ResultCode.InvalidArgument;
|
return ResultCode.InvalidArgument;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +42,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||||
|
|
||||||
Logger.PrintStub(LogClass.ServiceFriend, new
|
Logger.PrintStub(LogClass.ServiceFriend, new
|
||||||
{
|
{
|
||||||
UserId = uuid.ToString(),
|
UserId = userId.ToString(),
|
||||||
offset,
|
offset,
|
||||||
filter.PresenceStatus,
|
filter.PresenceStatus,
|
||||||
filter.IsFavoriteOnly,
|
filter.IsFavoriteOnly,
|
||||||
|
@ -57,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(10101)]
|
[Command(10101)]
|
||||||
// nn::friends::GetFriendList(int offset, nn::account::Uid userUUID, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid)
|
// nn::friends::GetFriendList(int offset, nn::account::Uid userId, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid)
|
||||||
// -> int outCount, array<nn::friends::detail::FriendImpl, 0x6>
|
// -> int outCount, array<nn::friends::detail::FriendImpl, 0x6>
|
||||||
public ResultCode GetFriendList(ServiceCtx context)
|
public ResultCode GetFriendList(ServiceCtx context)
|
||||||
{
|
{
|
||||||
|
@ -66,13 +65,13 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||||
// Padding
|
// Padding
|
||||||
context.RequestData.ReadInt32();
|
context.RequestData.ReadInt32();
|
||||||
|
|
||||||
UInt128 uuid = context.RequestData.ReadStruct<UInt128>();
|
UserId userId = context.RequestData.ReadStruct<UserId>();
|
||||||
FriendFilter filter = context.RequestData.ReadStruct<FriendFilter>();
|
FriendFilter filter = context.RequestData.ReadStruct<FriendFilter>();
|
||||||
|
|
||||||
// Pid placeholder
|
// Pid placeholder
|
||||||
context.RequestData.ReadInt64();
|
context.RequestData.ReadInt64();
|
||||||
|
|
||||||
if (uuid.IsNull)
|
if (userId.IsNull)
|
||||||
{
|
{
|
||||||
return ResultCode.InvalidArgument;
|
return ResultCode.InvalidArgument;
|
||||||
}
|
}
|
||||||
|
@ -81,7 +80,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||||
context.ResponseData.Write(0);
|
context.ResponseData.Write(0);
|
||||||
|
|
||||||
Logger.PrintStub(LogClass.ServiceFriend, new {
|
Logger.PrintStub(LogClass.ServiceFriend, new {
|
||||||
UserId = uuid.ToString(),
|
UserId = userId.ToString(),
|
||||||
offset,
|
offset,
|
||||||
filter.PresenceStatus,
|
filter.PresenceStatus,
|
||||||
filter.IsFavoriteOnly,
|
filter.IsFavoriteOnly,
|
||||||
|
@ -95,43 +94,43 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(10600)]
|
[Command(10600)]
|
||||||
// nn::friends::DeclareOpenOnlinePlaySession(nn::account::Uid)
|
// nn::friends::DeclareOpenOnlinePlaySession(nn::account::Uid userId)
|
||||||
public ResultCode DeclareOpenOnlinePlaySession(ServiceCtx context)
|
public ResultCode DeclareOpenOnlinePlaySession(ServiceCtx context)
|
||||||
{
|
{
|
||||||
UInt128 uuid = context.RequestData.ReadStruct<UInt128>();
|
UserId userId = context.RequestData.ReadStruct<UserId>();
|
||||||
|
|
||||||
if (uuid.IsNull)
|
if (userId.IsNull)
|
||||||
{
|
{
|
||||||
return ResultCode.InvalidArgument;
|
return ResultCode.InvalidArgument;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.Device.System.State.Account.TryGetUser(uuid, out UserProfile profile))
|
if (context.Device.System.State.Account.TryGetUser(userId, out UserProfile profile))
|
||||||
{
|
{
|
||||||
profile.OnlinePlayState = AccountState.Open;
|
profile.OnlinePlayState = AccountState.Open;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), profile.OnlinePlayState });
|
Logger.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString(), profile.OnlinePlayState });
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command(10601)]
|
[Command(10601)]
|
||||||
// nn::friends::DeclareCloseOnlinePlaySession(nn::account::Uid)
|
// nn::friends::DeclareCloseOnlinePlaySession(nn::account::Uid userId)
|
||||||
public ResultCode DeclareCloseOnlinePlaySession(ServiceCtx context)
|
public ResultCode DeclareCloseOnlinePlaySession(ServiceCtx context)
|
||||||
{
|
{
|
||||||
UInt128 uuid = context.RequestData.ReadStruct<UInt128>();
|
UserId userId = context.RequestData.ReadStruct<UserId>();
|
||||||
|
|
||||||
if (uuid.IsNull)
|
if (userId.IsNull)
|
||||||
{
|
{
|
||||||
return ResultCode.InvalidArgument;
|
return ResultCode.InvalidArgument;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.Device.System.State.Account.TryGetUser(uuid, out UserProfile profile))
|
if (context.Device.System.State.Account.TryGetUser(userId, out UserProfile profile))
|
||||||
{
|
{
|
||||||
profile.OnlinePlayState = AccountState.Closed;
|
profile.OnlinePlayState = AccountState.Closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), profile.OnlinePlayState });
|
Logger.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString(), profile.OnlinePlayState });
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
@ -140,7 +139,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||||
// nn::friends::UpdateUserPresence(nn::account::Uid, u64, pid, buffer<nn::friends::detail::UserPresenceImpl, 0x19>)
|
// nn::friends::UpdateUserPresence(nn::account::Uid, u64, pid, buffer<nn::friends::detail::UserPresenceImpl, 0x19>)
|
||||||
public ResultCode UpdateUserPresence(ServiceCtx context)
|
public ResultCode UpdateUserPresence(ServiceCtx context)
|
||||||
{
|
{
|
||||||
UInt128 uuid = context.RequestData.ReadStruct<UInt128>();
|
UserId uuid = context.RequestData.ReadStruct<UserId>();
|
||||||
|
|
||||||
// Pid placeholder
|
// Pid placeholder
|
||||||
context.RequestData.ReadInt64();
|
context.RequestData.ReadInt64();
|
||||||
|
|
|
@ -2,8 +2,8 @@ using Ryujinx.Common;
|
||||||
using Ryujinx.HLE.HOS.Ipc;
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService;
|
using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService;
|
||||||
using Ryujinx.HLE.Utilities;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||||
{
|
{
|
||||||
class INotificationService : IpcService, IDisposable
|
class INotificationService : IpcService, IDisposable
|
||||||
{
|
{
|
||||||
private readonly UInt128 _userId;
|
private readonly UserId _userId;
|
||||||
private readonly FriendServicePermissionLevel _permissionLevel;
|
private readonly FriendServicePermissionLevel _permissionLevel;
|
||||||
|
|
||||||
private readonly object _lock = new object();
|
private readonly object _lock = new object();
|
||||||
|
@ -24,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||||
private bool _hasNewFriendRequest;
|
private bool _hasNewFriendRequest;
|
||||||
private bool _hasFriendListUpdate;
|
private bool _hasFriendListUpdate;
|
||||||
|
|
||||||
public INotificationService(ServiceCtx context, UInt128 userId, FriendServicePermissionLevel permissionLevel)
|
public INotificationService(ServiceCtx context, UserId userId, FriendServicePermissionLevel permissionLevel)
|
||||||
{
|
{
|
||||||
_userId = userId;
|
_userId = userId;
|
||||||
_permissionLevel = permissionLevel;
|
_permissionLevel = permissionLevel;
|
||||||
|
@ -98,7 +98,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||||
return ResultCode.NotificationQueueEmpty;
|
return ResultCode.NotificationQueueEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SignalFriendListUpdate(UInt128 targetId)
|
public void SignalFriendListUpdate(UserId targetId)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
|
@ -140,7 +140,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SignalNewFriendRequest(UInt128 targetId)
|
public void SignalNewFriendRequest(UserId targetId)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.HLE.Utilities;
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
|
using Ryujinx.HLE.Utilities;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService
|
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService
|
||||||
{
|
{
|
||||||
|
@ -57,7 +58,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Use this when we will have enough things to go online.
|
// TODO: Use this when we will have enough things to go online.
|
||||||
public void SignalFriendListUpdate(UInt128 targetId)
|
public void SignalFriendListUpdate(UserId targetId)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _registry.Length; i++)
|
for (int i = 0; i < _registry.Length; i++)
|
||||||
{
|
{
|
||||||
|
@ -69,7 +70,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Use this when we will have enough things to go online.
|
// TODO: Use this when we will have enough things to go online.
|
||||||
public void SignalNewFriendRequest(UInt128 targetId)
|
public void SignalNewFriendRequest(UserId targetId)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _registry.Length; i++)
|
for (int i = 0; i < _registry.Length; i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using MsgPack.Serialization;
|
using MsgPack.Serialization;
|
||||||
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
using Ryujinx.HLE.Utilities;
|
using Ryujinx.HLE.Utilities;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
@ -48,7 +50,7 @@ namespace Ryujinx.HLE.HOS.Services.Prepo
|
||||||
|
|
||||||
private ResultCode ProcessReport(ServiceCtx context, bool withUserID)
|
private ResultCode ProcessReport(ServiceCtx context, bool withUserID)
|
||||||
{
|
{
|
||||||
UInt128 userId = withUserID ? new UInt128(context.RequestData.ReadBytes(0x10)) : new UInt128();
|
UserId userId = withUserID ? context.RequestData.ReadStruct<UserId>() : new UserId();
|
||||||
string gameRoom = StringUtils.ReadUtf8String(context);
|
string gameRoom = StringUtils.ReadUtf8String(context);
|
||||||
|
|
||||||
if (withUserID)
|
if (withUserID)
|
||||||
|
@ -79,7 +81,7 @@ namespace Ryujinx.HLE.HOS.Services.Prepo
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ReadReportBuffer(byte[] buffer, string room, UInt128 userId)
|
private string ReadReportBuffer(byte[] buffer, string room, UserId userId)
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService.Types;
|
using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService.Types;
|
||||||
using Ryujinx.HLE.Utilities;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -10,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
||||||
{
|
{
|
||||||
static class QueryPlayStatisticsManager
|
static class QueryPlayStatisticsManager
|
||||||
{
|
{
|
||||||
private static Dictionary<UInt128, ApplicationPlayStatistics> applicationPlayStatistics = new Dictionary<UInt128, ApplicationPlayStatistics>();
|
private static Dictionary<UserId, ApplicationPlayStatistics> applicationPlayStatistics = new Dictionary<UserId, ApplicationPlayStatistics>();
|
||||||
|
|
||||||
internal static ResultCode GetPlayStatistics(ServiceCtx context, bool byUserId = false)
|
internal static ResultCode GetPlayStatistics(ServiceCtx context, bool byUserId = false)
|
||||||
{
|
{
|
||||||
|
@ -20,7 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
||||||
long outputPosition = context.Request.ReceiveBuff[0].Position;
|
long outputPosition = context.Request.ReceiveBuff[0].Position;
|
||||||
long outputSize = context.Request.ReceiveBuff[0].Size;
|
long outputSize = context.Request.ReceiveBuff[0].Size;
|
||||||
|
|
||||||
UInt128 userId = byUserId ? new UInt128(context.RequestData.ReadBytes(0x10)) : new UInt128();
|
UserId userId = byUserId ? context.RequestData.ReadStruct<UserId>() : new UserId();
|
||||||
|
|
||||||
if (byUserId)
|
if (byUserId)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
using Ryujinx.HLE.Utilities;
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.SystemState
|
namespace Ryujinx.HLE.HOS.SystemState
|
||||||
|
@ -54,7 +53,7 @@ namespace Ryujinx.HLE.HOS.SystemState
|
||||||
|
|
||||||
Account = new AccountUtils();
|
Account = new AccountUtils();
|
||||||
|
|
||||||
UInt128 defaultUid = new UInt128("00000000000000000000000000000001");
|
UserId defaultUid = new UserId("00000000000000010000000000000000");
|
||||||
|
|
||||||
Account.AddUser(defaultUid, "Player");
|
Account.AddUser(defaultUid, "Player");
|
||||||
Account.OpenUser(defaultUid);
|
Account.OpenUser(defaultUid);
|
||||||
|
|
Reference in a new issue