QueryPlayStatisticsManager.cs 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. using Ryujinx.Common;
  2. using Ryujinx.Cpu;
  3. using Ryujinx.HLE.HOS.Services.Account.Acc;
  4. using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService.Types;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Runtime.InteropServices;
  9. namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
  10. {
  11. static class QueryPlayStatisticsManager
  12. {
  13. private static Dictionary<UserId, ApplicationPlayStatistics> applicationPlayStatistics = new Dictionary<UserId, ApplicationPlayStatistics>();
  14. internal static ResultCode GetPlayStatistics(ServiceCtx context, bool byUserId = false)
  15. {
  16. ref readonly var controlProperty = ref context.Device.Application.ControlData.Value;
  17. ulong inputPosition = context.Request.SendBuff[0].Position;
  18. ulong inputSize = context.Request.SendBuff[0].Size;
  19. ulong outputPosition = context.Request.ReceiveBuff[0].Position;
  20. ulong outputSize = context.Request.ReceiveBuff[0].Size;
  21. UserId userId = byUserId ? context.RequestData.ReadStruct<UserId>() : new UserId();
  22. if (byUserId)
  23. {
  24. if (!context.Device.System.AccountManager.TryGetUser(userId, out _))
  25. {
  26. return ResultCode.UserNotFound;
  27. }
  28. }
  29. PlayLogQueryCapability queryCapability = (PlayLogQueryCapability)controlProperty.PlayLogQueryCapability;
  30. List<ulong> titleIds = new List<ulong>();
  31. for (ulong i = 0; i < inputSize / sizeof(ulong); i++)
  32. {
  33. titleIds.Add(context.Memory.Read<ulong>(inputPosition));
  34. }
  35. if (queryCapability == PlayLogQueryCapability.WhiteList)
  36. {
  37. // Check if input title ids are in the whitelist.
  38. foreach (ulong titleId in titleIds)
  39. {
  40. if (!controlProperty.PlayLogQueryableApplicationId.ItemsRo.Contains(titleId))
  41. {
  42. return (ResultCode)Am.ResultCode.ObjectInvalid;
  43. }
  44. }
  45. }
  46. MemoryHelper.FillWithZeros(context.Memory, outputPosition, (int)outputSize);
  47. // Return ResultCode.ServiceUnavailable if data is locked by another process.
  48. var filteredApplicationPlayStatistics = applicationPlayStatistics.AsEnumerable();
  49. if (queryCapability == PlayLogQueryCapability.None)
  50. {
  51. filteredApplicationPlayStatistics = filteredApplicationPlayStatistics.Where(kv => kv.Value.TitleId == context.Process.TitleId);
  52. }
  53. else // PlayLogQueryCapability.All
  54. {
  55. filteredApplicationPlayStatistics = filteredApplicationPlayStatistics.Where(kv => titleIds.Contains(kv.Value.TitleId));
  56. }
  57. if (byUserId)
  58. {
  59. filteredApplicationPlayStatistics = filteredApplicationPlayStatistics.Where(kv => kv.Key == userId);
  60. }
  61. for (int i = 0; i < filteredApplicationPlayStatistics.Count(); i++)
  62. {
  63. MemoryHelper.Write(context.Memory, outputPosition + (ulong)(i * Marshal.SizeOf<ApplicationPlayStatistics>()), filteredApplicationPlayStatistics.ElementAt(i).Value);
  64. }
  65. context.ResponseData.Write(filteredApplicationPlayStatistics.Count());
  66. return ResultCode.Success;
  67. }
  68. }
  69. }