Ryujinx/Ryujinx.HLE/HOS/Services/Sdb/Pdm/QueryService/QueryPlayStatisticsManager.cs
Thog ea14a95524
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
2020-02-02 14:24:17 +11:00

84 lines
3.4 KiB
C#

using ARMeilleure.Memory;
using Ryujinx.Common;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
{
static class QueryPlayStatisticsManager
{
private static Dictionary<UserId, ApplicationPlayStatistics> applicationPlayStatistics = new Dictionary<UserId, ApplicationPlayStatistics>();
internal static ResultCode GetPlayStatistics(ServiceCtx context, bool byUserId = false)
{
long inputPosition = context.Request.SendBuff[0].Position;
long inputSize = context.Request.SendBuff[0].Size;
long outputPosition = context.Request.ReceiveBuff[0].Position;
long outputSize = context.Request.ReceiveBuff[0].Size;
UserId userId = byUserId ? context.RequestData.ReadStruct<UserId>() : new UserId();
if (byUserId)
{
if (!context.Device.System.State.Account.TryGetUser(userId, out _))
{
return ResultCode.UserNotFound;
}
}
PlayLogQueryCapability queryCapability = (PlayLogQueryCapability)context.Device.System.ControlData.Value.PlayLogQueryCapability;
List<ulong> titleIds = new List<ulong>();
for (int i = 0; i < inputSize / sizeof(ulong); i++)
{
titleIds.Add(BitConverter.ToUInt64(context.Memory.ReadBytes(inputPosition, inputSize), 0));
}
if (queryCapability == PlayLogQueryCapability.WhiteList)
{
// Check if input title ids are in the whitelist.
foreach (ulong titleId in titleIds)
{
if (!context.Device.System.ControlData.Value.PlayLogQueryableApplicationId.Contains(titleId))
{
return (ResultCode)Am.ResultCode.ObjectInvalid;
}
}
}
MemoryHelper.FillWithZeros(context.Memory, outputPosition, (int)outputSize);
// Return ResultCode.ServiceUnavailable if data is locked by another process.
var filteredApplicationPlayStatistics = applicationPlayStatistics.AsEnumerable();
if (queryCapability == PlayLogQueryCapability.None)
{
filteredApplicationPlayStatistics = filteredApplicationPlayStatistics.Where(kv => kv.Value.TitleId == context.Process.TitleId);
}
else // PlayLogQueryCapability.All
{
filteredApplicationPlayStatistics = filteredApplicationPlayStatistics.Where(kv => titleIds.Contains(kv.Value.TitleId));
}
if (byUserId)
{
filteredApplicationPlayStatistics = filteredApplicationPlayStatistics.Where(kv => kv.Key == userId);
}
for (int i = 0; i < filteredApplicationPlayStatistics.Count(); i++)
{
MemoryHelper.Write(context.Memory, outputPosition + (i * Marshal.SizeOf<ApplicationPlayStatistics>()), filteredApplicationPlayStatistics.ElementAt(i).Value);
}
context.ResponseData.Write(filteredApplicationPlayStatistics.Count());
return ResultCode.Success;
}
}
}