no name: Mii Editor applet support (#2419)
* no name: Mii Editor applet support * addresses gdkchan feedback * Fix comment * Bypass MountCounter of MiiDatabaseManager * Fix GetSettingsPlatformRegion * Disable Applet Menu for unsupported firmwares
This commit is contained in:
parent
fefd4619a5
commit
a79b39b913
27 changed files with 591 additions and 33 deletions
|
@ -37,6 +37,7 @@ namespace Ryujinx.Common.Logging
|
|||
ServiceLdn,
|
||||
ServiceLdr,
|
||||
ServiceLm,
|
||||
ServiceMii,
|
||||
ServiceMm,
|
||||
ServiceNfc,
|
||||
ServiceNfp,
|
||||
|
|
|
@ -49,6 +49,7 @@ namespace Ryujinx.HLE.HOS
|
|||
internal const int FontSize = 0x1100000;
|
||||
internal const int IirsSize = 0x8000;
|
||||
internal const int TimeSize = 0x1000;
|
||||
internal const int AppletCaptureBufferSize = 0x384000;
|
||||
|
||||
internal KernelContext KernelContext { get; }
|
||||
|
||||
|
@ -82,6 +83,9 @@ namespace Ryujinx.HLE.HOS
|
|||
internal KSharedMemory HidSharedMem { get; private set; }
|
||||
internal KSharedMemory FontSharedMem { get; private set; }
|
||||
internal KSharedMemory IirsSharedMem { get; private set; }
|
||||
|
||||
internal KTransferMemory AppletCaptureBufferTransfer { get; private set; }
|
||||
|
||||
internal SharedFontManager Font { get; private set; }
|
||||
|
||||
internal AccountManager AccountManager { get; private set; }
|
||||
|
@ -133,21 +137,25 @@ namespace Ryujinx.HLE.HOS
|
|||
ulong fontPa = region.Address + HidSize;
|
||||
ulong iirsPa = region.Address + HidSize + FontSize;
|
||||
ulong timePa = region.Address + HidSize + FontSize + IirsSize;
|
||||
ulong appletCaptureBufferPa = region.Address + HidSize + FontSize + IirsSize + TimeSize;
|
||||
|
||||
KPageList hidPageList = new KPageList();
|
||||
KPageList fontPageList = new KPageList();
|
||||
KPageList iirsPageList = new KPageList();
|
||||
KPageList timePageList = new KPageList();
|
||||
KPageList appletCaptureBufferPageList = new KPageList();
|
||||
|
||||
hidPageList.AddRange(hidPa, HidSize / KPageTableBase.PageSize);
|
||||
fontPageList.AddRange(fontPa, FontSize / KPageTableBase.PageSize);
|
||||
iirsPageList.AddRange(iirsPa, IirsSize / KPageTableBase.PageSize);
|
||||
timePageList.AddRange(timePa, TimeSize / KPageTableBase.PageSize);
|
||||
appletCaptureBufferPageList.AddRange(appletCaptureBufferPa, AppletCaptureBufferSize / KPageTableBase.PageSize);
|
||||
|
||||
var hidStorage = new SharedMemoryStorage(KernelContext, hidPageList);
|
||||
var fontStorage = new SharedMemoryStorage(KernelContext, fontPageList);
|
||||
var iirsStorage = new SharedMemoryStorage(KernelContext, iirsPageList);
|
||||
var timeStorage = new SharedMemoryStorage(KernelContext, timePageList);
|
||||
var appletCaptureBufferStorage = new SharedMemoryStorage(KernelContext, appletCaptureBufferPageList);
|
||||
|
||||
HidStorage = hidStorage;
|
||||
|
||||
|
@ -159,6 +167,8 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
TimeServiceManager.Instance.Initialize(device, this, timeSharedMemory, timeStorage, TimeSize);
|
||||
|
||||
AppletCaptureBufferTransfer = new KTransferMemory(KernelContext, appletCaptureBufferStorage);
|
||||
|
||||
AppletState = new AppletStateMgr(this);
|
||||
|
||||
AppletState.SetFocus(true);
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
|
||||
{
|
||||
class ILibraryAppletProxy : IpcService
|
||||
{
|
||||
private readonly long _pid;
|
||||
|
||||
public ILibraryAppletProxy(long pid)
|
||||
{
|
||||
_pid = pid;
|
||||
}
|
||||
|
||||
[CommandHipc(0)]
|
||||
// GetCommonStateGetter() -> object<nn::am::service::ICommonStateGetter>
|
||||
public ResultCode GetCommonStateGetter(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new ICommonStateGetter(context));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(1)]
|
||||
// GetSelfController() -> object<nn::am::service::ISelfController>
|
||||
public ResultCode GetSelfController(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new ISelfController(context, _pid));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(2)]
|
||||
// GetWindowController() -> object<nn::am::service::IWindowController>
|
||||
public ResultCode GetWindowController(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IWindowController(_pid));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(3)]
|
||||
// GetAudioController() -> object<nn::am::service::IAudioController>
|
||||
public ResultCode GetAudioController(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IAudioController());
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(4)]
|
||||
// GetDisplayController() -> object<nn::am::service::IDisplayController>
|
||||
public ResultCode GetDisplayController(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IDisplayController(context));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(10)]
|
||||
// GetProcessWindingController() -> object<nn::am::service::IProcessWindingController>
|
||||
public ResultCode GetProcessWindingController(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IProcessWindingController());
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(11)]
|
||||
// GetLibraryAppletCreator() -> object<nn::am::service::ILibraryAppletCreator>
|
||||
public ResultCode GetLibraryAppletCreator(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new ILibraryAppletCreator());
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(20)]
|
||||
// OpenLibraryAppletSelfAccessor() -> object<nn::am::service::ILibraryAppletSelfAccessor>
|
||||
public ResultCode OpenLibraryAppletSelfAccessor(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new ILibraryAppletSelfAccessor(context));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(21)]
|
||||
// GetAppletCommonFunctions() -> object<nn::am::service::IAppletCommonFunctions>
|
||||
public ResultCode GetAppletCommonFunctions(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IAppletCommonFunctions());
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(1000)]
|
||||
// GetDebugFunctions() -> object<nn::am::service::IDebugFunctions>
|
||||
public ResultCode GetDebugFunctions(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IDebugFunctions());
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
|
|||
// GetSelfController() -> object<nn::am::service::ISelfController>
|
||||
public ResultCode GetSelfController(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new ISelfController(context.Device.System, _pid));
|
||||
MakeObject(context, new ISelfController(context, _pid));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService
|
|||
// GetDisplayController() -> object<nn::am::service::IDisplayController>
|
||||
public ResultCode GetDisplayController(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IDisplayController());
|
||||
MakeObject(context, new IDisplayController(context));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy
|
||||
{
|
||||
class AppletStandalone
|
||||
{
|
||||
public AppletId AppletId;
|
||||
public LibraryAppletMode LibraryAppletMode;
|
||||
public Queue<byte[]> InputData;
|
||||
|
||||
public AppletStandalone()
|
||||
{
|
||||
InputData = new Queue<byte[]>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
using Ryujinx.Common;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy
|
||||
{
|
||||
class ILibraryAppletSelfAccessor : IpcService
|
||||
{
|
||||
private AppletStandalone _appletStandalone = new AppletStandalone();
|
||||
|
||||
public ILibraryAppletSelfAccessor(ServiceCtx context)
|
||||
{
|
||||
if (context.Device.Application.TitleId == 0x0100000000001009)
|
||||
{
|
||||
// Create MiiEdit data.
|
||||
_appletStandalone = new AppletStandalone()
|
||||
{
|
||||
AppletId = AppletId.MiiEdit,
|
||||
LibraryAppletMode = LibraryAppletMode.AllForeground
|
||||
};
|
||||
|
||||
byte[] miiEditInputData = new byte[0x100];
|
||||
miiEditInputData[0] = 0x03; // Hardcoded unknown value.
|
||||
|
||||
_appletStandalone.InputData.Enqueue(miiEditInputData);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException($"{context.Device.Application.TitleId} applet is not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
[CommandHipc(0)]
|
||||
// PopInData() -> object<nn::am::service::IStorage>
|
||||
public ResultCode PopInData(ServiceCtx context)
|
||||
{
|
||||
byte[] appletData = _appletStandalone.InputData.Dequeue();
|
||||
|
||||
if (appletData.Length == 0)
|
||||
{
|
||||
return ResultCode.NotAvailable;
|
||||
}
|
||||
|
||||
MakeObject(context, new IStorage(appletData));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(11)]
|
||||
// GetLibraryAppletInfo() -> nn::am::service::LibraryAppletInfo
|
||||
public ResultCode GetLibraryAppletInfo(ServiceCtx context)
|
||||
{
|
||||
LibraryAppletInfo libraryAppletInfo = new LibraryAppletInfo()
|
||||
{
|
||||
AppletId = _appletStandalone.AppletId,
|
||||
LibraryAppletMode = _appletStandalone.LibraryAppletMode
|
||||
};
|
||||
|
||||
context.ResponseData.WriteStruct(libraryAppletInfo);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(14)]
|
||||
// GetCallerAppletIdentityInfo() -> nn::am::service::AppletIdentityInfo
|
||||
public ResultCode GetCallerAppletIdentityInfo(ServiceCtx context)
|
||||
{
|
||||
AppletIdentifyInfo appletIdentifyInfo = new AppletIdentifyInfo()
|
||||
{
|
||||
AppletId = AppletId.QLaunch,
|
||||
TitleId = 0x0100000000001000
|
||||
};
|
||||
|
||||
context.ResponseData.WriteStruct(appletIdentifyInfo);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using Ryujinx.Common;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.LibraryAppletProxy
|
||||
{
|
||||
class IProcessWindingController : IpcService
|
||||
{
|
||||
public IProcessWindingController() { }
|
||||
|
||||
[CommandHipc(0)]
|
||||
// GetLaunchReason() -> nn::am::service::AppletProcessLaunchReason
|
||||
public ResultCode GetLaunchReason(ServiceCtx context)
|
||||
{
|
||||
// NOTE: Flag is set by using an internal field.
|
||||
AppletProcessLaunchReason appletProcessLaunchReason = new AppletProcessLaunchReason()
|
||||
{
|
||||
Flag = 0
|
||||
};
|
||||
|
||||
context.ResponseData.WriteStruct(appletProcessLaunchReason);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
|
||||
{
|
||||
class IAppletCommonFunctions : IpcService
|
||||
{
|
||||
public IAppletCommonFunctions() { }
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@ using Ryujinx.Common.Logging;
|
|||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Settings.Types;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
|
||||
|
@ -241,6 +243,18 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
return (ResultCode)_apmSystemManagerServer.GetCurrentPerformanceConfiguration(context);
|
||||
}
|
||||
|
||||
[CommandHipc(300)] // 9.0.0+
|
||||
// GetSettingsPlatformRegion() -> u8
|
||||
public ResultCode GetSettingsPlatformRegion(ServiceCtx context)
|
||||
{
|
||||
PlatformRegion platformRegion = context.Device.System.State.DesiredRegionCode == (uint)RegionCode.China ? PlatformRegion.China : PlatformRegion.Global;
|
||||
|
||||
// FIXME: Call set:sys GetPlatformRegion
|
||||
context.ResponseData.Write((byte)platformRegion);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(900)] // 11.0.0+
|
||||
// SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled()
|
||||
public ResultCode SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(ServiceCtx context)
|
||||
|
|
|
@ -1,7 +1,106 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.SystemAppletProxy
|
||||
{
|
||||
class IDisplayController : IpcService
|
||||
{
|
||||
public IDisplayController() { }
|
||||
private KTransferMemory _transferMem;
|
||||
private bool _lastApplicationCaptureBufferAcquired;
|
||||
private bool _callerAppletCaptureBufferAcquired;
|
||||
|
||||
public IDisplayController(ServiceCtx context)
|
||||
{
|
||||
_transferMem = context.Device.System.AppletCaptureBufferTransfer;
|
||||
}
|
||||
|
||||
[CommandHipc(8)] // 2.0.0+
|
||||
// TakeScreenShotOfOwnLayer(b8, s32)
|
||||
public ResultCode TakeScreenShotOfOwnLayer(ServiceCtx context)
|
||||
{
|
||||
bool unknown1 = context.RequestData.ReadBoolean();
|
||||
int unknown2 = context.RequestData.ReadInt32();
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { unknown1, unknown2 });
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(11)]
|
||||
// ReleaseLastApplicationCaptureBuffer()
|
||||
public ResultCode ReleaseLastApplicationCaptureBuffer(ServiceCtx context)
|
||||
{
|
||||
if (!_lastApplicationCaptureBufferAcquired)
|
||||
{
|
||||
return ResultCode.BufferNotAcquired;
|
||||
}
|
||||
|
||||
_lastApplicationCaptureBufferAcquired = false;
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(15)]
|
||||
// ReleaseCallerAppletCaptureBuffer()
|
||||
public ResultCode ReleaseCallerAppletCaptureBuffer(ServiceCtx context)
|
||||
{
|
||||
if (!_callerAppletCaptureBufferAcquired)
|
||||
{
|
||||
return ResultCode.BufferNotAcquired;
|
||||
}
|
||||
|
||||
_callerAppletCaptureBufferAcquired = false;
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(16)]
|
||||
// AcquireLastApplicationCaptureBufferEx() -> (b8, handle<copy>)
|
||||
public ResultCode AcquireLastApplicationCaptureBufferEx(ServiceCtx context)
|
||||
{
|
||||
if (_lastApplicationCaptureBufferAcquired)
|
||||
{
|
||||
return ResultCode.BufferAlreadyAcquired;
|
||||
}
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(_transferMem, out int handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
|
||||
_lastApplicationCaptureBufferAcquired = true;
|
||||
|
||||
context.ResponseData.Write(_lastApplicationCaptureBufferAcquired);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(18)]
|
||||
// AcquireCallerAppletCaptureBufferEx() -> (b8, handle<copy>)
|
||||
public ResultCode AcquireCallerAppletCaptureBufferEx(ServiceCtx context)
|
||||
{
|
||||
if (_callerAppletCaptureBufferAcquired)
|
||||
{
|
||||
return ResultCode.BufferAlreadyAcquired;
|
||||
}
|
||||
|
||||
if (context.Process.HandleTable.GenerateHandle(_transferMem, out int handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle);
|
||||
|
||||
_callerAppletCaptureBufferAcquired = true;
|
||||
|
||||
context.ResponseData.Write(_callerAppletCaptureBufferAcquired);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,9 +35,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
private uint _screenShotImageOrientation = 0;
|
||||
private uint _idleTimeDetectionExtension = 0;
|
||||
|
||||
public ISelfController(Horizon system, long pid)
|
||||
public ISelfController(ServiceCtx context, long pid)
|
||||
{
|
||||
_libraryAppletLaunchableEvent = new KEvent(system.KernelContext);
|
||||
_libraryAppletLaunchableEvent = new KEvent(context.Device.System.KernelContext);
|
||||
_pid = pid;
|
||||
}
|
||||
|
||||
|
@ -225,6 +225,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE.AllSystemAppletProxiesService.Sys
|
|||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(41)] // 4.0.0+
|
||||
// IsSystemBufferSharingEnabled()
|
||||
public ResultCode IsSystemBufferSharingEnabled(ServiceCtx context)
|
||||
{
|
||||
// NOTE: Service checks a private field and return an error if the SystemBufferSharing is disabled.
|
||||
|
||||
return ResultCode.NotImplemented;
|
||||
}
|
||||
|
||||
[CommandHipc(44)] // 10.0.0+
|
||||
// CreateManagedDisplaySeparableLayer() -> (u64, u64)
|
||||
public ResultCode CreateManagedDisplaySeparableLayer(ServiceCtx context)
|
||||
|
|
|
@ -15,5 +15,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
|
|||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(200)]
|
||||
[CommandHipc(201)] // 3.0.0+
|
||||
// OpenLibraryAppletProxy(u64, pid, handle<copy>) -> object<nn::am::service::ILibraryAppletProxy>
|
||||
public ResultCode OpenLibraryAppletProxy(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new ILibraryAppletProxy(context.Request.HandleDesc.PId));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
struct AppletIdentifyInfo
|
||||
{
|
||||
public AppletId AppletId;
|
||||
public uint Padding;
|
||||
public ulong TitleId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x4)]
|
||||
struct AppletProcessLaunchReason
|
||||
{
|
||||
public byte Flag;
|
||||
public ushort Unknown1;
|
||||
public byte Unknown2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x8)]
|
||||
struct LibraryAppletInfo
|
||||
{
|
||||
public AppletId AppletId;
|
||||
public LibraryAppletMode LibraryAppletMode;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am.AppletAE
|
||||
{
|
||||
[Flags]
|
||||
enum LibraryAppletMode : uint
|
||||
{
|
||||
AllForeground,
|
||||
PartialForeground,
|
||||
NoUi,
|
||||
PartialForegroundWithIndirectDisplay,
|
||||
AllForegroundInitiallyHidden
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
|
|||
// GetSelfController() -> object<nn::am::service::ISelfController>
|
||||
public ResultCode GetSelfController(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new ISelfController(context.Device.System, _pid));
|
||||
MakeObject(context, new ISelfController(context, _pid));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService
|
|||
// GetDisplayController() -> object<nn::am::service::IDisplayController>
|
||||
public ResultCode GetDisplayController(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IDisplayController());
|
||||
MakeObject(context, new IDisplayController(context));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
ObjectInvalid = (500 << ErrorCodeShift) | ModuleId,
|
||||
IStorageInUse = (502 << ErrorCodeShift) | ModuleId,
|
||||
OutOfBounds = (503 << ErrorCodeShift) | ModuleId,
|
||||
BufferNotAcquired = (504 << ErrorCodeShift) | ModuleId,
|
||||
BufferAlreadyAcquired = (505 << ErrorCodeShift) | ModuleId,
|
||||
InvalidParameters = (506 << ErrorCodeShift) | ModuleId,
|
||||
OpenedAsWrongType = (511 << ErrorCodeShift) | ModuleId,
|
||||
UnbalancedFatalSection = (512 << ErrorCodeShift) | ModuleId,
|
||||
|
|
|
@ -499,6 +499,15 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
|||
return (ResultCode)result.Value;
|
||||
}
|
||||
|
||||
[CommandHipc(1003)]
|
||||
// DisableAutoSaveDataCreation()
|
||||
public ResultCode DisableAutoSaveDataCreation(ServiceCtx context)
|
||||
{
|
||||
// NOTE: This call does nothing in original service.
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(1004)]
|
||||
// SetGlobalAccessLogMode(u32 mode)
|
||||
public ResultCode SetGlobalAccessLogMode(ServiceCtx context)
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii
|
|||
public static UInt128 GetDeviceId()
|
||||
{
|
||||
// FIXME: call set:sys GetMiiAuthorId
|
||||
return new UInt128(0, 1);
|
||||
return new UInt128("5279754d69694e780000000000000000"); // RyuMiiNx
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<byte> Ver3FacelineColorTable => new byte[] { 0, 1, 2, 3, 4, 5 };
|
||||
|
|
|
@ -1,8 +1,41 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Mii
|
||||
using Ryujinx.Common.Logging;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Mii
|
||||
{
|
||||
[Service("miiimg")] // 5.0.0+
|
||||
class IImageDatabaseService : IpcService
|
||||
{
|
||||
private uint _imageCount;
|
||||
private bool _isDirty;
|
||||
|
||||
public IImageDatabaseService(ServiceCtx context) { }
|
||||
|
||||
[CommandHipc(0)]
|
||||
// Initialize(b8) -> b8
|
||||
public ResultCode Initialize(ServiceCtx context)
|
||||
{
|
||||
// TODO: Service uses MiiImage:/database.dat if true, seems to use hardcoded data if false.
|
||||
bool useHardcodedData = context.RequestData.ReadBoolean();
|
||||
|
||||
_imageCount = 0;
|
||||
_isDirty = false;
|
||||
|
||||
context.ResponseData.Write(_isDirty);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceMii, new { useHardcodedData });
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(11)]
|
||||
// GetCount() -> u32
|
||||
public ResultCode GetCount(ServiceCtx context)
|
||||
{
|
||||
context.ResponseData.Write(_imageCount);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceMii);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -101,6 +101,9 @@ namespace Ryujinx.HLE.HOS.Services.Mii
|
|||
// Ensure we have valid data in the database
|
||||
_database.Format();
|
||||
|
||||
// TODO: Unmount is currently not implemented properly at dispose, implement that and decrement MountCounter.
|
||||
MountCounter = 0;
|
||||
|
||||
MountSave();
|
||||
}
|
||||
|
||||
|
@ -151,8 +154,6 @@ namespace Ryujinx.HLE.HOS.Services.Mii
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -183,6 +184,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii
|
|||
if (result.IsSuccess())
|
||||
{
|
||||
result = _filesystemClient.GetFileSize(out long fileSize, handle);
|
||||
|
||||
if (result.IsSuccess())
|
||||
{
|
||||
if (fileSize == Unsafe.SizeOf<NintendoFigurineDatabase>())
|
||||
|
|
|
@ -7,6 +7,7 @@ using LibHac.FsSystem.NcaUtils;
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
@ -271,6 +272,20 @@ namespace Ryujinx.HLE.HOS.Services.Settings
|
|||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(90)]
|
||||
// GetMiiAuthorId() -> nn::util::Uuid
|
||||
public ResultCode GetMiiAuthorId(ServiceCtx context)
|
||||
{
|
||||
// NOTE: If miiAuthorId is null ResultCode.NullMiiAuthorIdBuffer is returned.
|
||||
// Doesn't occur in our case.
|
||||
|
||||
UInt128 miiAuthorId = Mii.Helper.GetDeviceId();
|
||||
|
||||
miiAuthorId.Write(context.ResponseData);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
public byte[] GetFirmwareData(Switch device)
|
||||
{
|
||||
const ulong SystemVersionTitleId = 0x0100000000000809;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Settings.Types
|
||||
{
|
||||
enum PlatformRegion
|
||||
{
|
||||
Global = 1,
|
||||
China = 2
|
||||
}
|
||||
}
|
|
@ -55,8 +55,8 @@ namespace Ryujinx.HLE.HOS.SystemState
|
|||
|
||||
DesiredTitleLanguage = language switch
|
||||
{
|
||||
SystemLanguage.Taiwanese or
|
||||
SystemLanguage.TraditionalChinese => TitleLanguage.Taiwanese,
|
||||
SystemLanguage.Taiwanese => TitleLanguage.Taiwanese,
|
||||
SystemLanguage.TraditionalChinese or
|
||||
SystemLanguage.Chinese or
|
||||
SystemLanguage.SimplifiedChinese => TitleLanguage.Chinese,
|
||||
_ => Enum.Parse<TitleLanguage>(Enum.GetName(typeof(SystemLanguage), language)),
|
||||
|
|
|
@ -3,6 +3,7 @@ using ARMeilleure.Translation.PTC;
|
|||
using Gtk;
|
||||
using LibHac.Common;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.FsSystem.NcaUtils;
|
||||
using LibHac.Ns;
|
||||
using Ryujinx.Audio.Backends.Dummy;
|
||||
using Ryujinx.Audio.Backends.OpenAL;
|
||||
|
@ -87,6 +88,10 @@ namespace Ryujinx.Ui
|
|||
[GUI] Box _statusBar;
|
||||
[GUI] MenuItem _optionMenu;
|
||||
[GUI] MenuItem _manageUserProfiles;
|
||||
[GUI] MenuItem _fileMenu;
|
||||
[GUI] MenuItem _loadApplicationFile;
|
||||
[GUI] MenuItem _loadApplicationFolder;
|
||||
[GUI] MenuItem _appletMenu;
|
||||
[GUI] MenuItem _actionMenu;
|
||||
[GUI] MenuItem _stopEmulation;
|
||||
[GUI] MenuItem _simulateWakeUpMessage;
|
||||
|
@ -165,6 +170,7 @@ namespace Ryujinx.Ui
|
|||
_applicationLibrary.ApplicationAdded += Application_Added;
|
||||
_applicationLibrary.ApplicationCountUpdated += ApplicationCount_Updated;
|
||||
|
||||
_fileMenu.StateChanged += FileMenu_StateChanged;
|
||||
_actionMenu.StateChanged += ActionMenu_StateChanged;
|
||||
_optionMenu.StateChanged += OptionMenu_StateChanged;
|
||||
|
||||
|
@ -576,6 +582,14 @@ namespace Ryujinx.Ui
|
|||
SystemVersion firmwareVersion = _contentManager.GetCurrentFirmwareVersion();
|
||||
|
||||
bool isDirectory = Directory.Exists(path);
|
||||
bool isFirmwareTitle = false;
|
||||
|
||||
if (path.StartsWith("@SystemContent"))
|
||||
{
|
||||
path = _virtualFileSystem.SwitchPathToSystemPath(path);
|
||||
|
||||
isFirmwareTitle = true;
|
||||
}
|
||||
|
||||
if (!SetupValidator.CanStartApplication(_contentManager, path, out UserError userError))
|
||||
{
|
||||
|
@ -636,7 +650,13 @@ namespace Ryujinx.Ui
|
|||
|
||||
Logger.Notice.Print(LogClass.Application, $"Using Firmware Version: {firmwareVersion?.VersionString}");
|
||||
|
||||
if (Directory.Exists(path))
|
||||
if (isFirmwareTitle)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Application, "Loading as Firmware Title (NCA).");
|
||||
|
||||
_emulationContext.LoadNca(path);
|
||||
}
|
||||
else if (Directory.Exists(path))
|
||||
{
|
||||
string[] romFsFiles = Directory.GetFiles(path, "*.istorage");
|
||||
|
||||
|
@ -1100,6 +1120,20 @@ namespace Ryujinx.Ui
|
|||
}
|
||||
}
|
||||
|
||||
private void FileMenu_StateChanged(object o, StateChangedArgs args)
|
||||
{
|
||||
_appletMenu.Sensitive = _emulationContext == null && _contentManager.GetCurrentFirmwareVersion() != null && _contentManager.GetCurrentFirmwareVersion().Major > 3;
|
||||
_loadApplicationFile.Sensitive = _emulationContext == null;
|
||||
_loadApplicationFolder.Sensitive = _emulationContext == null;
|
||||
}
|
||||
|
||||
private void Load_Mii_Edit_Applet(object sender, EventArgs args)
|
||||
{
|
||||
string contentPath = _contentManager.GetInstalledContentPath(0x0100000000001009, StorageId.NandSystem, NcaContentType.Program);
|
||||
|
||||
LoadApplication(contentPath);
|
||||
}
|
||||
|
||||
private void Open_Ryu_Folder(object sender, EventArgs args)
|
||||
{
|
||||
OpenHelper.OpenFolder(AppDataManager.BaseDirPath);
|
||||
|
@ -1217,6 +1251,15 @@ namespace Ryujinx.Ui
|
|||
|
||||
GtkDialog.CreateInfoDialog(dialogTitle, message);
|
||||
Logger.Info?.Print(LogClass.Application, message);
|
||||
|
||||
// Purge Applet Cache.
|
||||
|
||||
DirectoryInfo miiEditorCacheFolder = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
|
||||
|
||||
if (miiEditorCacheFolder.Exists)
|
||||
{
|
||||
miiEditorCacheFolder.Delete(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="FileMenu">
|
||||
<object class="GtkMenuItem" id="_fileMenu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">File</property>
|
||||
|
@ -29,7 +29,7 @@
|
|||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="LoadApplicationFile">
|
||||
<object class="GtkMenuItem" id="_loadApplicationFile">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Open a file chooser to chose a switch compatible file to load</property>
|
||||
|
@ -39,7 +39,7 @@
|
|||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="LoadApplicationFolder">
|
||||
<object class="GtkMenuItem" id="_loadApplicationFolder">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Open a file chooser to chose a switch compatible, unpacked application to load</property>
|
||||
|
@ -48,6 +48,30 @@
|
|||
<signal name="activate" handler="Load_Application_Folder" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="_appletMenu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Load Applet</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child type="submenu">
|
||||
<object class="GtkMenu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkMenuItem" id="LoadMiiEditApplet">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Open Mii Editor Applet in Standalone mode</property>
|
||||
<property name="label" translatable="yes">Mii Editor</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="activate" handler="Load_Mii_Edit_Applet" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem">
|
||||
<property name="visible">True</property>
|
||||
|
|
Loading…
Reference in a new issue