diff --git a/Ryujinx.HLE/FileSystem/SaveHelper.cs b/Ryujinx.HLE/FileSystem/SaveHelper.cs index 67f010169..087156d2a 100644 --- a/Ryujinx.HLE/FileSystem/SaveHelper.cs +++ b/Ryujinx.HLE/FileSystem/SaveHelper.cs @@ -1,5 +1,6 @@ using Ryujinx.HLE.HOS; using System.IO; +using System.Linq; using static Ryujinx.HLE.FileSystem.VirtualFileSystem; @@ -35,9 +36,11 @@ namespace Ryujinx.HLE.FileSystem } } + string SaveAccount = SaveMetaData.UserId.IsZero() ? "savecommon" : SaveMetaData.UserId.ToString(); + string SavePath = Path.Combine(BaseSavePath, SaveMetaData.SaveId.ToString("x16"), - SaveMetaData.UserId.ToString(), + SaveAccount, SaveMetaData.SaveDataType == SaveDataType.SaveData ? CurrentTitleId.ToString("x16") : string.Empty); return SavePath; diff --git a/Ryujinx.HLE/FileSystem/SaveInfo.cs b/Ryujinx.HLE/FileSystem/SaveInfo.cs index f3790ec78..3acd33fda 100644 --- a/Ryujinx.HLE/FileSystem/SaveInfo.cs +++ b/Ryujinx.HLE/FileSystem/SaveInfo.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.HOS.SystemState; +using Ryujinx.HLE.Utilities; namespace Ryujinx.HLE.FileSystem { @@ -6,7 +6,7 @@ namespace Ryujinx.HLE.FileSystem { public long TitleId { get; private set; } public long SaveId { get; private set; } - public UserId UserId { get; private set; } + public UInt128 UserId { get; private set; } public SaveDataType SaveDataType { get; private set; } public SaveSpaceId SaveSpaceId { get; private set; } @@ -15,7 +15,7 @@ namespace Ryujinx.HLE.FileSystem long TitleId, long SaveId, SaveDataType SaveDataType, - UserId UserId, + UInt128 UserId, SaveSpaceId SaveSpaceId) { this.TitleId = TitleId; diff --git a/Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs b/Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs index 8fd7bfeaf..347f2e20c 100644 --- a/Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs +++ b/Ryujinx.HLE/HOS/Services/Acc/IAccountService.cs @@ -1,6 +1,7 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.Logging; +using Ryujinx.HLE.Utilities; using System.Collections.Generic; using static Ryujinx.HLE.HOS.ErrorCode; @@ -37,7 +38,7 @@ namespace Ryujinx.HLE.HOS.Services.Acc public long GetUserExistence(ServiceCtx Context) { - UserId Uuid = new UserId( + UInt128 Uuid = new UInt128( Context.RequestData.ReadInt64(), Context.RequestData.ReadInt64()); @@ -70,12 +71,8 @@ namespace Ryujinx.HLE.HOS.Services.Acc break; } - byte[] Uuid = Profile.Uuid.Bytes; - - for (int Index = Uuid.Length - 1; Index >= 0; Index--) - { - Context.Memory.WriteByte(OutputPosition + Offset++, Uuid[Index]); - } + Context.Memory.WriteInt64(OutputPosition, Profile.Uuid.High); + Context.Memory.WriteInt64(OutputPosition + 8, Profile.Uuid.Low); } return 0; @@ -92,7 +89,7 @@ namespace Ryujinx.HLE.HOS.Services.Acc public long GetProfile(ServiceCtx Context) { - UserId Uuid = new UserId( + UInt128 Uuid = new UInt128( Context.RequestData.ReadInt64(), Context.RequestData.ReadInt64()); diff --git a/Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs b/Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs index d476f5d02..ebbe5fca0 100644 --- a/Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs +++ b/Ryujinx.HLE/HOS/Services/Friend/IFriendService.cs @@ -1,6 +1,7 @@ using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.Logging; +using Ryujinx.HLE.Utilities; using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Services.Friend @@ -24,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend // nn::friends::GetFriendListGetFriendListIds(nn::account::Uid, int Unknown0, nn::friends::detail::ipc::SizedFriendFilter, ulong Unknown1) -> int CounterIds, array public long GetFriendList(ServiceCtx Context) { - UserId Uuid = new UserId( + UInt128 Uuid = new UInt128( Context.RequestData.ReadInt64(), Context.RequestData.ReadInt64()); @@ -45,7 +46,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend // There are no friends online, so we return 0 because the nn::account::NetworkServiceAccountId array is empty. Context.ResponseData.Write(0); - Context.Device.Log.PrintStub(LogClass.ServiceFriend, $"Stubbed. UserId: {Uuid.UserIdHex} - " + + Context.Device.Log.PrintStub(LogClass.ServiceFriend, $"Stubbed. UserId: {Uuid.ToString()} - " + $"Unknown0: {Unknown0} - " + $"PresenceStatus: {Filter.PresenceStatus} - " + $"IsFavoriteOnly: {Filter.IsFavoriteOnly} - " + @@ -61,7 +62,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend // DeclareCloseOnlinePlaySession(nn::account::Uid) public long DeclareCloseOnlinePlaySession(ServiceCtx Context) { - UserId Uuid = new UserId( + UInt128 Uuid = new UInt128( Context.RequestData.ReadInt64(), Context.RequestData.ReadInt64()); @@ -70,7 +71,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend Profile.OnlinePlayState = OpenCloseState.Closed; } - Context.Device.Log.PrintStub(LogClass.ServiceFriend, $"Stubbed. Uuid: {Uuid.UserIdHex} - " + + Context.Device.Log.PrintStub(LogClass.ServiceFriend, $"Stubbed. Uuid: {Uuid.ToString()} - " + $"OnlinePlayState: {Profile.OnlinePlayState}"); return 0; @@ -79,7 +80,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend // UpdateUserPresence(nn::account::Uid, ulong Unknown0) -> buffer public long UpdateUserPresence(ServiceCtx Context) { - UserId Uuid = new UserId( + UInt128 Uuid = new UInt128( Context.RequestData.ReadInt64(), Context.RequestData.ReadInt64()); @@ -90,7 +91,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend //Todo: Write the buffer content. - Context.Device.Log.PrintStub(LogClass.ServiceFriend, $"Stubbed. Uuid: {Uuid.UserIdHex} - " + + Context.Device.Log.PrintStub(LogClass.ServiceFriend, $"Stubbed. Uuid: {Uuid.ToString()} - " + $"Unknown0: {Unknown0}"); return 0; diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs index 937ea6d6b..daf5e0b26 100644 --- a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs +++ b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs @@ -1,6 +1,6 @@ using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.SystemState; +using Ryujinx.HLE.Utilities; using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Services.FspSrv @@ -78,7 +78,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv long TitleId = Context.RequestData.ReadInt64(); - UserId UserId = new UserId( + UInt128 UserId = new UInt128( Context.RequestData.ReadInt64(), Context.RequestData.ReadInt64()); diff --git a/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs b/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs index 2a3c8288b..3833ce9ec 100644 --- a/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs +++ b/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs @@ -1,3 +1,4 @@ +using Ryujinx.HLE.Utilities; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -57,9 +58,10 @@ namespace Ryujinx.HLE.HOS.SystemState Profiles = new ConcurrentDictionary(); - UserId DefaultUuid = new UserId("00000000000000000000000000000001"); + UInt128 DefaultUuid = new UInt128("00000000000000000000000000000001"); AddUser(DefaultUuid, "Player"); + OpenUser(DefaultUuid); } @@ -85,24 +87,24 @@ namespace Ryujinx.HLE.HOS.SystemState ActiveAudioOutput = AudioOutputs[2]; } - public void AddUser(UserId Uuid, string Name) + public void AddUser(UInt128 Uuid, string Name) { UserProfile Profile = new UserProfile(Uuid, Name); - Profiles.AddOrUpdate(Uuid.UserIdHex, Profile, (Key, Old) => Profile); + Profiles.AddOrUpdate(Uuid.ToString(), Profile, (Key, Old) => Profile); } - public void OpenUser(UserId Uuid) + public void OpenUser(UInt128 Uuid) { - if (Profiles.TryGetValue(Uuid.UserIdHex, out UserProfile Profile)) + if (Profiles.TryGetValue(Uuid.ToString(), out UserProfile Profile)) { (LastOpenUser = Profile).AccountState = OpenCloseState.Open; } } - public void CloseUser(UserId Uuid) + public void CloseUser(UInt128 Uuid) { - if (Profiles.TryGetValue(Uuid.UserIdHex, out UserProfile Profile)) + if (Profiles.TryGetValue(Uuid.ToString(), out UserProfile Profile)) { Profile.AccountState = OpenCloseState.Closed; } @@ -113,9 +115,9 @@ namespace Ryujinx.HLE.HOS.SystemState return Profiles.Count; } - internal bool TryGetUser(UserId Uuid, out UserProfile Profile) + internal bool TryGetUser(UInt128 Uuid, out UserProfile Profile) { - return Profiles.TryGetValue(Uuid.UserIdHex, out Profile); + return Profiles.TryGetValue(Uuid.ToString(), out Profile); } internal IEnumerable GetAllUsers() diff --git a/Ryujinx.HLE/HOS/SystemState/UserId.cs b/Ryujinx.HLE/HOS/SystemState/UserId.cs deleted file mode 100644 index 1e7c53dd0..000000000 --- a/Ryujinx.HLE/HOS/SystemState/UserId.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Ryujinx.HLE.Utilities; -using System; -using System.IO; -using System.Linq; - -namespace Ryujinx.HLE.HOS.SystemState -{ - public struct UserId - { - public string UserIdHex { get; private set; } - - public byte[] Bytes { get; private set; } - - public UserId(long Low, long High) - { - if ((Low | High) == 0) - { - throw new ArgumentException("Zero is not a valid user id!"); - } - - byte[] Bytes = new byte[16]; - - int Index = Bytes.Length; - - void WriteBytes(long Value) - { - for (int Byte = 0; Byte < 8; Byte++) - { - Bytes[--Index] = (byte)(Value >> Byte * 8); - } - } - - WriteBytes(Low); - WriteBytes(High); - - UserIdHex = string.Empty; - - foreach (byte Byte in Bytes) - { - UserIdHex += Byte.ToString("X2"); - } - - this.Bytes = Bytes; - } - - public UserId(string UserIdHex) - { - if (UserIdHex == null || UserIdHex.Length != 32 || !UserIdHex.All("0123456789abcdefABCDEF".Contains)) - { - throw new ArgumentException("Invalid user id!", nameof(UserIdHex)); - } - - if (UserIdHex == "00000000000000000000000000000000") - { - throw new ArgumentException("Zero is not a valid user id!", nameof(UserIdHex)); - } - - this.UserIdHex = UserIdHex.ToUpper(); - - Bytes = StringUtils.HexToBytes(UserIdHex); - } - - internal void Write(BinaryWriter Writer) - { - for (int Index = Bytes.Length - 1; Index >= 0; Index--) - { - Writer.Write(Bytes[Index]); - } - } - - public override string ToString() - { - return UserIdHex; - } - } -} \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/SystemState/UserProfile.cs b/Ryujinx.HLE/HOS/SystemState/UserProfile.cs index 63852cdf4..e08bc48aa 100644 --- a/Ryujinx.HLE/HOS/SystemState/UserProfile.cs +++ b/Ryujinx.HLE/HOS/SystemState/UserProfile.cs @@ -1,4 +1,5 @@ -using System; +using Ryujinx.HLE.Utilities; +using System; namespace Ryujinx.HLE.HOS.SystemState { @@ -6,7 +7,7 @@ namespace Ryujinx.HLE.HOS.SystemState { private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - public UserId Uuid { get; private set; } + public UInt128 Uuid { get; private set; } public string Name { get; private set; } @@ -15,7 +16,7 @@ namespace Ryujinx.HLE.HOS.SystemState public OpenCloseState AccountState { get; set; } public OpenCloseState OnlinePlayState { get; set; } - public UserProfile(UserId Uuid, string Name) + public UserProfile(UInt128 Uuid, string Name) { this.Uuid = Uuid; this.Name = Name; diff --git a/Ryujinx.HLE/Utilities/UInt128.cs b/Ryujinx.HLE/Utilities/UInt128.cs new file mode 100644 index 000000000..a2546dd3c --- /dev/null +++ b/Ryujinx.HLE/Utilities/UInt128.cs @@ -0,0 +1,61 @@ +using Ryujinx.HLE.Utilities; +using System; +using System.IO; +using System.Linq; + +namespace Ryujinx.HLE.Utilities +{ + public struct UInt128 + { + public long High { get; private set; } + public long Low { get; private set; } + + public UInt128(long Low, long High) + { + this.Low = Low; + this.High = High; + + byte[] Bytes = new byte[16]; + + int Index = Bytes.Length; + + void WriteBytes(long Value) + { + for (int Byte = 0; Byte < 8; Byte++) + { + Bytes[--Index] = (byte)(Value >> Byte * 8); + } + } + + WriteBytes(Low); + WriteBytes(High); + } + + public UInt128(string UInt128Hex) + { + if (UInt128Hex == null || UInt128Hex.Length != 32 || !UInt128Hex.All("0123456789abcdefABCDEF".Contains)) + { + throw new ArgumentException("Invalid Hex value!", nameof(UInt128Hex)); + } + + Low = Convert.ToInt64(UInt128Hex.Substring(16),16); + High = Convert.ToInt64(UInt128Hex.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 bool IsZero() + { + return (Low | High) == 0; + } + } +} \ No newline at end of file