diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2024-01-29 18:45:40 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-29 22:45:40 +0100 |
| commit | 4117c13377b51b83ff87b1d00393be1a5ab5bfff (patch) | |
| tree | c59181e229947070b76c20d88e7b9cbba314a4e9 /src/Ryujinx.HLE/HOS/Services | |
| parent | 20a392ad552ce5cdbff1cb74f1d26d2f797cca31 (diff) | |
Migrate friends service to new IPC (#6174)
* Migrate friends service to new IPC
* Add a note that the pointer buffer size and domain counts are wrong
* Wrong length
* Format whitespace
* PR feedback
* Fill in structs from PR feedback
* Missed that one
* Somehow forgot to save that one
* Fill in enums from PR review
* Language enum, NotificationTime
* Format whitespace
* Fix the warning
Diffstat (limited to 'src/Ryujinx.HLE/HOS/Services')
16 files changed, 12 insertions, 873 deletions
diff --git a/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs b/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs index 924ac3fb..c724660e 100644 --- a/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs +++ b/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs @@ -4,6 +4,7 @@ using LibHac.Fs; using LibHac.Fs.Shim; using Ryujinx.Common; using Ryujinx.Common.Logging; +using Ryujinx.Horizon.Sdk.Account; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -11,7 +12,7 @@ using System.Linq; namespace Ryujinx.HLE.HOS.Services.Account.Acc { - public class AccountManager + public class AccountManager : IEmulatorAccountManager { public static readonly UserId DefaultUserId = new("00000000000000010000000000000000"); @@ -106,6 +107,11 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc _accountSaveDataManager.Save(_profiles); } + public void OpenUserOnlinePlay(Uid userId) + { + OpenUserOnlinePlay(new UserId((long)userId.Low, (long)userId.High)); + } + public void OpenUserOnlinePlay(UserId userId) { if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile)) @@ -127,6 +133,11 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc _accountSaveDataManager.Save(_profiles); } + public void CloseUserOnlinePlay(Uid userId) + { + CloseUserOnlinePlay(new UserId((long)userId.Low, (long)userId.High)); + } + public void CloseUserOnlinePlay(UserId userId) { if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile)) diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs b/src/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs deleted file mode 100644 index 3f15f3fc..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator; - -namespace Ryujinx.HLE.HOS.Services.Friend -{ - [Service("friend:a", FriendServicePermissionLevel.Administrator)] - [Service("friend:m", FriendServicePermissionLevel.Manager)] - [Service("friend:s", FriendServicePermissionLevel.System)] - [Service("friend:u", FriendServicePermissionLevel.User)] - [Service("friend:v", FriendServicePermissionLevel.Viewer)] - class IServiceCreator : IpcService - { - private readonly FriendServicePermissionLevel _permissionLevel; - - public IServiceCreator(ServiceCtx context, FriendServicePermissionLevel permissionLevel) - { - _permissionLevel = permissionLevel; - } - - [CommandCmif(0)] - // CreateFriendService() -> object<nn::friends::detail::ipc::IFriendService> - public ResultCode CreateFriendService(ServiceCtx context) - { - MakeObject(context, new IFriendService(_permissionLevel)); - - return ResultCode.Success; - } - - [CommandCmif(1)] // 2.0.0+ - // CreateNotificationService(nn::account::Uid userId) -> object<nn::friends::detail::ipc::INotificationService> - public ResultCode CreateNotificationService(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct<UserId>(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - MakeObject(context, new INotificationService(context, userId, _permissionLevel)); - - return ResultCode.Success; - } - - [CommandCmif(2)] // 4.0.0+ - // CreateDaemonSuspendSessionService() -> object<nn::friends::detail::ipc::IDaemonSuspendSessionService> - public ResultCode CreateDaemonSuspendSessionService(ServiceCtx context) - { - MakeObject(context, new IDaemonSuspendSessionService(_permissionLevel)); - - return ResultCode.Success; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ResultCode.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ResultCode.cs deleted file mode 100644 index 9f612059..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ResultCode.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Friend -{ - enum ResultCode - { - ModuleId = 121, - ErrorCodeShift = 9, - - Success = 0, - - InvalidArgument = (2 << ErrorCodeShift) | ModuleId, - InternetRequestDenied = (6 << ErrorCodeShift) | ModuleId, - NotificationQueueEmpty = (15 << ErrorCodeShift) | ModuleId, - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/Friend.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/Friend.cs deleted file mode 100644 index 28745c3f..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/Friend.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Ryujinx.HLE.HOS.Services.Account.Acc; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService -{ - [StructLayout(LayoutKind.Sequential, Pack = 0x8, Size = 0x200, CharSet = CharSet.Ansi)] - struct Friend - { - public UserId UserId; - public long NetworkUserId; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x21)] - public string Nickname; - - public UserPresence presence; - - [MarshalAs(UnmanagedType.I1)] - public bool IsFavourite; - - [MarshalAs(UnmanagedType.I1)] - public bool IsNew; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x6)] - readonly char[] Unknown; - - [MarshalAs(UnmanagedType.I1)] - public bool IsValid; - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/FriendFilter.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/FriendFilter.cs deleted file mode 100644 index 5f13f313..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/FriendFilter.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService -{ - [StructLayout(LayoutKind.Sequential)] - struct FriendFilter - { - public PresenceStatusFilter PresenceStatus; - - [MarshalAs(UnmanagedType.I1)] - public bool IsFavoriteOnly; - - [MarshalAs(UnmanagedType.I1)] - public bool IsSameAppPresenceOnly; - - [MarshalAs(UnmanagedType.I1)] - public bool IsSameAppPlayedOnly; - - [MarshalAs(UnmanagedType.I1)] - public bool IsArbitraryAppPlayedOnly; - - public long PresenceGroupId; - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatus.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatus.cs deleted file mode 100644 index 7930aff0..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatus.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService -{ - enum PresenceStatus : uint - { - Offline, - Online, - OnlinePlay, - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatusFilter.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatusFilter.cs deleted file mode 100644 index c9a54250..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatusFilter.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService -{ - enum PresenceStatusFilter : uint - { - None, - Online, - OnlinePlay, - OnlineOrOnlinePlay, - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/UserPresence.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/UserPresence.cs deleted file mode 100644 index 80d14205..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/UserPresence.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Ryujinx.Common.Memory; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService -{ - [StructLayout(LayoutKind.Sequential, Pack = 0x8)] - struct UserPresence - { - public UserId UserId; - public long LastTimeOnlineTimestamp; - public PresenceStatus Status; - - [MarshalAs(UnmanagedType.I1)] - public bool SamePresenceGroupApplication; - - public Array3<byte> Unknown; - private AppKeyValueStorageHolder _appKeyValueStorage; - - public Span<byte> AppKeyValueStorage => MemoryMarshal.Cast<AppKeyValueStorageHolder, byte>(MemoryMarshal.CreateSpan(ref _appKeyValueStorage, AppKeyValueStorageHolder.Size)); - - [StructLayout(LayoutKind.Sequential, Pack = 0x1, Size = Size)] - private struct AppKeyValueStorageHolder - { - public const int Size = 0xC0; - } - - public readonly override string ToString() - { - return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status} }}"; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IDaemonSuspendSessionService.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IDaemonSuspendSessionService.cs deleted file mode 100644 index 3b1601ab..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IDaemonSuspendSessionService.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator -{ - class IDaemonSuspendSessionService : IpcService - { -#pragma warning disable IDE0052 // Remove unread private member - private readonly FriendServicePermissionLevel _permissionLevel; -#pragma warning restore IDE0052 - - public IDaemonSuspendSessionService(FriendServicePermissionLevel permissionLevel) - { - _permissionLevel = permissionLevel; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs deleted file mode 100644 index 54d23e88..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs +++ /dev/null @@ -1,374 +0,0 @@ -using LibHac.Ns; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.Common.Memory; -using Ryujinx.Common.Utilities; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService; -using Ryujinx.Horizon.Common; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator -{ - class IFriendService : IpcService - { -#pragma warning disable IDE0052 // Remove unread private member - private readonly FriendServicePermissionLevel _permissionLevel; -#pragma warning restore IDE0052 - private KEvent _completionEvent; - - public IFriendService(FriendServicePermissionLevel permissionLevel) - { - _permissionLevel = permissionLevel; - } - - [CommandCmif(0)] - // GetCompletionEvent() -> handle<copy> - public ResultCode GetCompletionEvent(ServiceCtx context) - { - _completionEvent ??= new KEvent(context.Device.System.KernelContext); - - if (context.Process.HandleTable.GenerateHandle(_completionEvent.ReadableEvent, out int completionEventHandle) != Result.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - _completionEvent.WritableEvent.Signal(); - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(completionEventHandle); - - return ResultCode.Success; - } - - [CommandCmif(1)] - // nn::friends::Cancel() - public ResultCode Cancel(ServiceCtx context) - { - // TODO: Original service sets an internal field to 1 here. Determine usage. - Logger.Stub?.PrintStub(LogClass.ServiceFriend); - - return ResultCode.Success; - } - - [CommandCmif(10100)] - // 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> - public ResultCode GetFriendListIds(ServiceCtx context) - { - int offset = context.RequestData.ReadInt32(); - - // Padding - context.RequestData.ReadInt32(); - - UserId userId = context.RequestData.ReadStruct<UserId>(); - FriendFilter filter = context.RequestData.ReadStruct<FriendFilter>(); - - // Pid placeholder - context.RequestData.ReadInt64(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // There are no friends online, so we return 0 because the nn::account::NetworkServiceAccountId array is empty. - context.ResponseData.Write(0); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new - { - UserId = userId.ToString(), - offset, - filter.PresenceStatus, - filter.IsFavoriteOnly, - filter.IsSameAppPresenceOnly, - filter.IsSameAppPlayedOnly, - filter.IsArbitraryAppPlayedOnly, - filter.PresenceGroupId, - }); - - return ResultCode.Success; - } - - [CommandCmif(10101)] - // 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> - public ResultCode GetFriendList(ServiceCtx context) - { - int offset = context.RequestData.ReadInt32(); - - // Padding - context.RequestData.ReadInt32(); - - UserId userId = context.RequestData.ReadStruct<UserId>(); - FriendFilter filter = context.RequestData.ReadStruct<FriendFilter>(); - - // Pid placeholder - context.RequestData.ReadInt64(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // There are no friends online, so we return 0 because the nn::account::NetworkServiceAccountId array is empty. - context.ResponseData.Write(0); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new - { - UserId = userId.ToString(), - offset, - filter.PresenceStatus, - filter.IsFavoriteOnly, - filter.IsSameAppPresenceOnly, - filter.IsSameAppPlayedOnly, - filter.IsArbitraryAppPlayedOnly, - filter.PresenceGroupId, - }); - - return ResultCode.Success; - } - - [CommandCmif(10120)] // 10.0.0+ - // nn::friends::IsFriendListCacheAvailable(nn::account::Uid userId) -> bool - public ResultCode IsFriendListCacheAvailable(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct<UserId>(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // TODO: Service mount the friends:/ system savedata and try to load friend.cache file, returns true if exists, false otherwise. - // NOTE: If no cache is available, guest then calls nn::friends::EnsureFriendListAvailable, we can avoid that by faking the cache check. - context.ResponseData.Write(true); - - // TODO: Since we don't support friend features, it's fine to stub it for now. - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10121)] // 10.0.0+ - // nn::friends::EnsureFriendListAvailable(nn::account::Uid userId) - public ResultCode EnsureFriendListAvailable(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct<UserId>(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // TODO: Service mount the friends:/ system savedata and create a friend.cache file for the given user id. - // Since we don't support friend features, it's fine to stub it for now. - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10400)] - // nn::friends::GetBlockedUserListIds(int offset, nn::account::Uid userId) -> (u32, buffer<nn::account::NetworkServiceAccountId, 0xa>) - public ResultCode GetBlockedUserListIds(ServiceCtx context) - { - int offset = context.RequestData.ReadInt32(); - - // Padding - context.RequestData.ReadInt32(); - - UserId userId = context.RequestData.ReadStruct<UserId>(); - - // There are no friends blocked, so we return 0 because the nn::account::NetworkServiceAccountId array is empty. - context.ResponseData.Write(0); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { offset, UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10420)] - // nn::friends::CheckBlockedUserListAvailability(nn::account::Uid userId) -> bool - public ResultCode CheckBlockedUserListAvailability(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct<UserId>(); - - // Yes, it is available. - context.ResponseData.Write(true); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10600)] - // nn::friends::DeclareOpenOnlinePlaySession(nn::account::Uid userId) - public ResultCode DeclareOpenOnlinePlaySession(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct<UserId>(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - context.Device.System.AccountManager.OpenUserOnlinePlay(userId); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10601)] - // nn::friends::DeclareCloseOnlinePlaySession(nn::account::Uid userId) - public ResultCode DeclareCloseOnlinePlaySession(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct<UserId>(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - context.Device.System.AccountManager.CloseUserOnlinePlay(userId); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10610)] - // nn::friends::UpdateUserPresence(nn::account::Uid, u64, pid, buffer<nn::friends::detail::UserPresenceImpl, 0x19>) - public ResultCode UpdateUserPresence(ServiceCtx context) - { - UserId uuid = context.RequestData.ReadStruct<UserId>(); - - // Pid placeholder - context.RequestData.ReadInt64(); - - ulong position = context.Request.PtrBuff[0].Position; - ulong size = context.Request.PtrBuff[0].Size; - - ReadOnlySpan<UserPresence> userPresenceInputArray = MemoryMarshal.Cast<byte, UserPresence>(context.Memory.GetSpan(position, (int)size)); - - if (uuid.IsNull) - { - return ResultCode.InvalidArgument; - } - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray = userPresenceInputArray.ToArray() }); - - return ResultCode.Success; - } - - [CommandCmif(10700)] - // nn::friends::GetPlayHistoryRegistrationKey(b8 unknown, nn::account::Uid) -> buffer<nn::friends::PlayHistoryRegistrationKey, 0x1a> - public ResultCode GetPlayHistoryRegistrationKey(ServiceCtx context) - { - bool unknownBool = context.RequestData.ReadBoolean(); - UserId userId = context.RequestData.ReadStruct<UserId>(); - - context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize(0x40UL); - - ulong bufferPosition = context.Request.RecvListBuff[0].Position; - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // NOTE: Calls nn::friends::detail::service::core::PlayHistoryManager::GetInstance and stores the instance. - - byte[] randomBytes = new byte[8]; - - Random.Shared.NextBytes(randomBytes); - - // NOTE: Calls nn::friends::detail::service::core::UuidManager::GetInstance and stores the instance. - // Then call nn::friends::detail::service::core::AccountStorageManager::GetInstance and store the instance. - // Then it checks if an Uuid is already stored for the UserId, if not it generates a random Uuid. - // And store it in the savedata 8000000000000080 in the friends:/uid.bin file. - - Array16<byte> randomGuid = new(); - - Guid.NewGuid().ToByteArray().AsSpan().CopyTo(randomGuid.AsSpan()); - - PlayHistoryRegistrationKey playHistoryRegistrationKey = new() - { - Type = 0x101, - KeyIndex = (byte)(randomBytes[0] & 7), - UserIdBool = 0, // TODO: Find it. - UnknownBool = (byte)(unknownBool ? 1 : 0), // TODO: Find it. - Reserved = new Array11<byte>(), - Uuid = randomGuid, - }; - - ReadOnlySpan<byte> playHistoryRegistrationKeyBuffer = SpanHelpers.AsByteSpan(ref playHistoryRegistrationKey); - - /* - - NOTE: The service uses the KeyIndex to get a random key from a keys buffer (since the key index is stored in the returned buffer). - We currently don't support play history and online services so we can use a blank key for now. - Code for reference: - - byte[] hmacKey = new byte[0x20]; - - HMACSHA256 hmacSha256 = new HMACSHA256(hmacKey); - byte[] hmacHash = hmacSha256.ComputeHash(playHistoryRegistrationKeyBuffer); - - */ - - context.Memory.Write(bufferPosition, playHistoryRegistrationKeyBuffer); - context.Memory.Write(bufferPosition + 0x20, new byte[0x20]); // HmacHash - - return ResultCode.Success; - } - - [CommandCmif(10702)] - // nn::friends::AddPlayHistory(nn::account::Uid, u64, pid, buffer<nn::friends::PlayHistoryRegistrationKey, 0x19>, buffer<nn::friends::InAppScreenName, 0x19>, buffer<nn::friends::InAppScreenName, 0x19>) - public ResultCode AddPlayHistory(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct<UserId>(); - - // Pid placeholder - context.RequestData.ReadInt64(); -#pragma warning disable IDE0059 // Remove unnecessary value assignment - ulong pid = context.Request.HandleDesc.PId; - - ulong playHistoryRegistrationKeyPosition = context.Request.PtrBuff[0].Position; - ulong playHistoryRegistrationKeySize = context.Request.PtrBuff[0].Size; - - ulong inAppScreenName1Position = context.Request.PtrBuff[1].Position; -#pragma warning restore IDE0059 - ulong inAppScreenName1Size = context.Request.PtrBuff[1].Size; - -#pragma warning disable IDE0059 // Remove unnecessary value assignment - ulong inAppScreenName2Position = context.Request.PtrBuff[2].Position; -#pragma warning restore IDE0059 - ulong inAppScreenName2Size = context.Request.PtrBuff[2].Size; - - if (userId.IsNull || inAppScreenName1Size > 0x48 || inAppScreenName2Size > 0x48) - { - return ResultCode.InvalidArgument; - } - - // TODO: Call nn::arp::GetApplicationControlProperty here when implemented. -#pragma warning disable IDE0059 // Remove unnecessary value assignment - ApplicationControlProperty controlProperty = context.Device.Processes.ActiveApplication.ApplicationControlProperties; -#pragma warning restore IDE0059 - - /* - - NOTE: The service calls nn::friends::detail::service::core::PlayHistoryManager to store informations using the registration key computed in GetPlayHistoryRegistrationKey. - Then calls nn::friends::detail::service::core::FriendListManager to update informations on the friend list. - We currently don't support play history and online services so it's fine to do nothing. - - */ - - Logger.Stub?.PrintStub(LogClass.ServiceFriend); - - return ResultCode.Success; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs deleted file mode 100644 index 8fc7a460..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs +++ /dev/null @@ -1,178 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService; -using Ryujinx.Horizon.Common; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator -{ - class INotificationService : DisposableIpcService - { - private readonly UserId _userId; - private readonly FriendServicePermissionLevel _permissionLevel; - - private readonly object _lock = new(); - - private readonly KEvent _notificationEvent; - private int _notificationEventHandle = 0; - - private readonly LinkedList<NotificationInfo> _notifications; - - private bool _hasNewFriendRequest; - private bool _hasFriendListUpdate; - - public INotificationService(ServiceCtx context, UserId userId, FriendServicePermissionLevel permissionLevel) - { - _userId = userId; - _permissionLevel = permissionLevel; - _notifications = new LinkedList<NotificationInfo>(); - _notificationEvent = new KEvent(context.Device.System.KernelContext); - - _hasNewFriendRequest = false; - _hasFriendListUpdate = false; - - NotificationEventHandler.Instance.RegisterNotificationService(this); - } - - [CommandCmif(0)] //2.0.0+ - // nn::friends::detail::ipc::INotificationService::GetEvent() -> handle<copy> - public ResultCode GetEvent(ServiceCtx context) - { - if (_notificationEventHandle == 0) - { - if (context.Process.HandleTable.GenerateHandle(_notificationEvent.ReadableEvent, out _notificationEventHandle) != Result.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_notificationEventHandle); - - return ResultCode.Success; - } - - [CommandCmif(1)] //2.0.0+ - // nn::friends::detail::ipc::INotificationService::Clear() - public ResultCode Clear(ServiceCtx context) - { - lock (_lock) - { - _hasNewFriendRequest = false; - _hasFriendListUpdate = false; - - _notifications.Clear(); - } - - return ResultCode.Success; - } - - [CommandCmif(2)] // 2.0.0+ - // nn::friends::detail::ipc::INotificationService::Pop() -> nn::friends::detail::ipc::SizedNotificationInfo - public ResultCode Pop(ServiceCtx context) - { - lock (_lock) - { - if (_notifications.Count >= 1) - { - NotificationInfo notificationInfo = _notifications.First.Value; - _notifications.RemoveFirst(); - - if (notificationInfo.Type == NotificationEventType.FriendListUpdate) - { - _hasFriendListUpdate = false; - } - else if (notificationInfo.Type == NotificationEventType.NewFriendRequest) - { - _hasNewFriendRequest = false; - } - - context.ResponseData.WriteStruct(notificationInfo); - - return ResultCode.Success; - } - } - - return ResultCode.NotificationQueueEmpty; - } - - public void SignalFriendListUpdate(UserId targetId) - { - lock (_lock) - { - if (_userId == targetId) - { - if (!_hasFriendListUpdate) - { - NotificationInfo friendListNotification = new(); - - if (_notifications.Count != 0) - { - friendListNotification = _notifications.First.Value; - _notifications.RemoveFirst(); - } - - friendListNotification.Type = NotificationEventType.FriendListUpdate; - _hasFriendListUpdate = true; - - if (_hasNewFriendRequest) - { - NotificationInfo newFriendRequestNotification = new(); - - if (_notifications.Count != 0) - { - newFriendRequestNotification = _notifications.First.Value; - _notifications.RemoveFirst(); - } - - newFriendRequestNotification.Type = NotificationEventType.NewFriendRequest; - _notifications.AddFirst(newFriendRequestNotification); - } - - // We defer this to make sure we are on top of the queue. - _notifications.AddFirst(friendListNotification); - } - - _notificationEvent.ReadableEvent.Signal(); - } - } - } - - public void SignalNewFriendRequest(UserId targetId) - { - lock (_lock) - { - if ((_permissionLevel & FriendServicePermissionLevel.ViewerMask) != 0 && _userId == targetId) - { - if (!_hasNewFriendRequest) - { - if (_notifications.Count == 100) - { - SignalFriendListUpdate(targetId); - } - - NotificationInfo newFriendRequestNotification = new() - { - Type = NotificationEventType.NewFriendRequest, - }; - - _notifications.AddLast(newFriendRequestNotification); - _hasNewFriendRequest = true; - } - - _notificationEvent.ReadableEvent.Signal(); - } - } - } - - protected override void Dispose(bool isDisposing) - { - if (isDisposing) - { - NotificationEventHandler.Instance.UnregisterNotificationService(this); - } - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/NotificationEventHandler.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/NotificationEventHandler.cs deleted file mode 100644 index 88627fd7..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/NotificationEventHandler.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Ryujinx.HLE.HOS.Services.Account.Acc; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService -{ - public sealed class NotificationEventHandler - { - private static NotificationEventHandler _instance; - private static readonly object _instanceLock = new(); - - private readonly INotificationService[] _registry; - - public static NotificationEventHandler Instance - { - get - { - lock (_instanceLock) - { - _instance ??= new NotificationEventHandler(); - - return _instance; - } - } - } - - NotificationEventHandler() - { - _registry = new INotificationService[0x20]; - } - - internal void RegisterNotificationService(INotificationService service) - { - // NOTE: in case there isn't space anymore in the registry array, Nintendo doesn't return any errors. - for (int i = 0; i < _registry.Length; i++) - { - if (_registry[i] == null) - { - _registry[i] = service; - break; - } - } - } - - internal void UnregisterNotificationService(INotificationService service) - { - // NOTE: in case there isn't the entry in the registry array, Nintendo doesn't return any errors. - for (int i = 0; i < _registry.Length; i++) - { - if (_registry[i] == service) - { - _registry[i] = null; - break; - } - } - } - - // TODO: Use this when we will have enough things to go online. - public void SignalFriendListUpdate(UserId targetId) - { - for (int i = 0; i < _registry.Length; i++) - { - _registry[i]?.SignalFriendListUpdate(targetId); - } - } - - // TODO: Use this when we will have enough things to go online. - public void SignalNewFriendRequest(UserId targetId) - { - for (int i = 0; i < _registry.Length; i++) - { - _registry[i]?.SignalNewFriendRequest(targetId); - } - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationEventType.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationEventType.cs deleted file mode 100644 index 363e03ea..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationEventType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService -{ - enum NotificationEventType : uint - { - Invalid = 0x0, - FriendListUpdate = 0x1, - NewFriendRequest = 0x65, - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationInfo.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationInfo.cs deleted file mode 100644 index aa58433d..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService -{ - [StructLayout(LayoutKind.Sequential, Size = 0x10)] - struct NotificationInfo - { - public NotificationEventType Type; - private Array4<byte> _padding; - public long NetworkUserIdPlaceholder; - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/FriendServicePermissionLevel.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/FriendServicePermissionLevel.cs deleted file mode 100644 index 7902d9c5..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/FriendServicePermissionLevel.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator -{ - [Flags] - enum FriendServicePermissionLevel - { - UserMask = 1, - ViewerMask = 2, - ManagerMask = 4, - SystemMask = 8, - - Administrator = -1, - User = UserMask, - Viewer = UserMask | ViewerMask, - Manager = UserMask | ViewerMask | ManagerMask, - System = UserMask | SystemMask, - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/PlayHistoryRegistrationKey.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/PlayHistoryRegistrationKey.cs deleted file mode 100644 index 9687c547..00000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/PlayHistoryRegistrationKey.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator -{ - [StructLayout(LayoutKind.Sequential, Size = 0x20)] - struct PlayHistoryRegistrationKey - { - public ushort Type; - public byte KeyIndex; - public byte UserIdBool; - public byte UnknownBool; - public Array11<byte> Reserved; - public Array16<byte> Uuid; - } -} |
