ryujinx/Ryujinx.HLE/HOS/Services/Ns/Aoc/IAddOnContentManager.cs
Ac_K b72f7de405
aoc: Fixes some inconsistencies (#2434)
* aoc: Fixes some inconsistencies

This PR fixes an wrong returned value (introduced in #2414) which cause some DLC not recognized in some games like Super Robot War T.
Additionnally to that, I've removed the EventHandle check too, because it could cause some issues, but sadly it doesn't do the job so I reverted the changes. It should fix Diablo III: Eternal Collection.

* Fix loop

* Revert TitleLanguage change

* write only available ids
2021-07-06 20:17:06 +02:00

297 lines
11 KiB
C#

using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading;
using System;
using System.Collections.Generic;
namespace Ryujinx.HLE.HOS.Services.Ns.Aoc
{
[Service("aoc:u")]
class IAddOnContentManager : IpcService
{
private readonly KEvent _addOnContentListChangedEvent;
private int _addOnContentListChangedEventHandle;
private ulong _addOnContentBaseId;
public IAddOnContentManager(ServiceCtx context)
{
_addOnContentListChangedEvent = new KEvent(context.Device.System.KernelContext);
}
[CommandHipc(0)] // 1.0.0-6.2.0
// CountAddOnContentByApplicationId(u64 title_id) -> u32
public ResultCode CountAddOnContentByApplicationId(ServiceCtx context)
{
ulong titleId = context.RequestData.ReadUInt64();
return CountAddOnContentImpl(context, titleId);
}
[CommandHipc(1)] // 1.0.0-6.2.0
// ListAddOnContentByApplicationId(u64 title_id, u32 start_index, u32 buffer_size) -> (u32 count, buffer<u32>)
public ResultCode ListAddOnContentByApplicationId(ServiceCtx context)
{
ulong titleId = context.RequestData.ReadUInt64();
return ListAddContentImpl(context, titleId);
}
[CommandHipc(2)]
// CountAddOnContent(pid) -> u32
public ResultCode CountAddOnContent(ServiceCtx context)
{
long pid = context.Request.HandleDesc.PId;
// NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId.
return CountAddOnContentImpl(context, context.Device.Application.TitleId);
}
[CommandHipc(3)]
// ListAddOnContent(u32 start_index, u32 buffer_size, pid) -> (u32 count, buffer<u32>)
public ResultCode ListAddOnContent(ServiceCtx context)
{
long pid = context.Request.HandleDesc.PId;
// NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId.
return ListAddContentImpl(context, context.Device.Application.TitleId);
}
[CommandHipc(4)] // 1.0.0-6.2.0
// GetAddOnContentBaseIdByApplicationId(u64 title_id) -> u64
public ResultCode GetAddOnContentBaseIdByApplicationId(ServiceCtx context)
{
ulong titleId = context.RequestData.ReadUInt64();
return GetAddOnContentBaseIdImpl(context, titleId);
}
[CommandHipc(5)]
// GetAddOnContentBaseId(pid) -> u64
public ResultCode GetAddOnContentBaseId(ServiceCtx context)
{
long pid = context.Request.HandleDesc.PId;
// NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId.
return GetAddOnContentBaseIdImpl(context, context.Device.Application.TitleId);
}
[CommandHipc(6)] // 1.0.0-6.2.0
// PrepareAddOnContentByApplicationId(u64 title_id, u32 index)
public ResultCode PrepareAddOnContentByApplicationId(ServiceCtx context)
{
ulong titleId = context.RequestData.ReadUInt64();
return PrepareAddOnContentImpl(context, titleId);
}
[CommandHipc(7)]
// PrepareAddOnContent(u32 index, pid)
public ResultCode PrepareAddOnContent(ServiceCtx context)
{
long pid = context.Request.HandleDesc.PId;
// NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId.
return PrepareAddOnContentImpl(context, context.Device.Application.TitleId);
}
[CommandHipc(8)] // 4.0.0+
// GetAddOnContentListChangedEvent() -> handle<copy>
public ResultCode GetAddOnContentListChangedEvent(ServiceCtx context)
{
return GetAddOnContentListChangedEventImpl(context);
}
[CommandHipc(9)] // 10.0.0+
// GetAddOnContentLostErrorCode() -> u64
public ResultCode GetAddOnContentLostErrorCode(ServiceCtx context)
{
// NOTE: 0x7D0A4 -> 2164-1000
context.ResponseData.Write(GetAddOnContentLostErrorCodeImpl(0x7D0A4));
return ResultCode.Success;
}
[CommandHipc(10)] // 11.0.0+
// GetAddOnContentListChangedEventWithProcessId(pid) -> handle<copy>
public ResultCode GetAddOnContentListChangedEventWithProcessId(ServiceCtx context)
{
long pid = context.Request.HandleDesc.PId;
// NOTE: Service call arp:r GetApplicationLaunchProperty to get TitleId using the PId.
// TODO: Found where stored value is used.
ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, context.Device.Application.TitleId);
if (resultCode != ResultCode.Success)
{
return resultCode;
}
return GetAddOnContentListChangedEventImpl(context);
}
[CommandHipc(100)] // 7.0.0+
// CreateEcPurchasedEventManager() -> object<nn::ec::IPurchaseEventManager>
public ResultCode CreateEcPurchasedEventManager(ServiceCtx context)
{
MakeObject(context, new IPurchaseEventManager(context.Device.System));
return ResultCode.Success;
}
[CommandHipc(101)] // 9.0.0+
// CreatePermanentEcPurchasedEventManager() -> object<nn::ec::IPurchaseEventManager>
public ResultCode CreatePermanentEcPurchasedEventManager(ServiceCtx context)
{
// NOTE: Service call arp:r to get the TitleId, do some extra checks and pass it to returned interface.
MakeObject(context, new IPurchaseEventManager(context.Device.System));
return ResultCode.Success;
}
[CommandHipc(110)] // 12.0.0+
// CreateContentsServiceManager() -> object<nn::ec::IContentsServiceManager>
public ResultCode CreateContentsServiceManager(ServiceCtx context)
{
MakeObject(context, new IContentsServiceManager());
return ResultCode.Success;
}
private ResultCode CountAddOnContentImpl(ServiceCtx context, ulong titleId)
{
// NOTE: Service call sys:set GetQuestFlag and store it internally.
// If QuestFlag is true, counts some extra titles.
ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, titleId);
if (resultCode != ResultCode.Success)
{
return resultCode;
}
// TODO: This should use _addOnContentBaseId;
uint aocCount = (uint)context.Device.System.ContentManager.GetAocCount();
context.ResponseData.Write(aocCount);
return ResultCode.Success;
}
private ResultCode ListAddContentImpl(ServiceCtx context, ulong titleId)
{
// NOTE: Service call sys:set GetQuestFlag and store it internally.
// If QuestFlag is true, counts some extra titles.
uint startIndex = context.RequestData.ReadUInt32();
uint indexNumber = context.RequestData.ReadUInt32();
ulong bufferPosition = context.Request.ReceiveBuff[0].Position;
ulong bufferSize = context.Request.ReceiveBuff[0].Size;
// TODO: This should use _addOnContentBaseId;
uint aocTotalCount = (uint)context.Device.System.ContentManager.GetAocCount();
if (indexNumber > bufferSize / sizeof(uint))
{
return ResultCode.InvalidBufferSize;
}
if (aocTotalCount <= startIndex)
{
context.ResponseData.Write(0);
return ResultCode.Success;
}
IList<ulong> aocTitleIds = context.Device.System.ContentManager.GetAocTitleIds();
GetAddOnContentBaseIdFromTitleId(context, titleId);
uint indexCounter = 0;
for (int i = 0; i < indexNumber; i++)
{
if (i + (int)startIndex < aocTitleIds.Count)
{
context.Memory.Write(bufferPosition + (ulong)i * sizeof(uint), (uint)(aocTitleIds[i + (int)startIndex] - _addOnContentBaseId));
indexCounter++;
}
}
context.ResponseData.Write(indexCounter);
return ResultCode.Success;
}
private ResultCode GetAddOnContentBaseIdImpl(ServiceCtx context, ulong titleId)
{
ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, titleId);
context.ResponseData.Write(_addOnContentBaseId);
return resultCode;
}
private ResultCode GetAddOnContentBaseIdFromTitleId(ServiceCtx context, ulong titleId)
{
// NOTE: Service calls arp:r GetApplicationControlProperty to get AddOnContentBaseId using TitleId,
// If the call fails, it returns ResultCode.InvalidPid.
_addOnContentBaseId = context.Device.Application.ControlData.Value.AddOnContentBaseId;
if (_addOnContentBaseId == 0)
{
_addOnContentBaseId = titleId + 0x1000;
}
return ResultCode.Success;
}
private ResultCode PrepareAddOnContentImpl(ServiceCtx context, ulong titleId)
{
uint index = context.RequestData.ReadUInt32();
ResultCode resultCode = GetAddOnContentBaseIdFromTitleId(context, context.Device.Application.TitleId);
if (resultCode != ResultCode.Success)
{
return resultCode;
}
// TODO: Service calls ns:am RegisterContentsExternalKey?, GetOwnedApplicationContentMetaStatus? etc...
// Ideally, this should probably initialize the AocData values for the specified index
Logger.Stub?.PrintStub(LogClass.ServiceNs, new { index });
return ResultCode.Success;
}
private ResultCode GetAddOnContentListChangedEventImpl(ServiceCtx context)
{
if (_addOnContentListChangedEventHandle == 0)
{
if (context.Process.HandleTable.GenerateHandle(_addOnContentListChangedEvent.ReadableEvent, out _addOnContentListChangedEventHandle) != KernelResult.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_addOnContentListChangedEventHandle);
return ResultCode.Success;
}
private static ulong GetAddOnContentLostErrorCodeImpl(int errorCode)
{
return ((ulong)errorCode & 0x1FF | ((((ulong)errorCode >> 9) & 0x1FFF) << 32)) + 2000;
}
}
}