diff --git a/Ryujinx.HLE/HOS/Services/DummyService.cs b/Ryujinx.HLE/HOS/Services/DummyService.cs new file mode 100644 index 0000000000..28087bdf8b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/DummyService.cs @@ -0,0 +1,20 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services +{ + class DummyService : IpcService + { + private Dictionary _commands; + + public override IReadOnlyDictionary Commands => _commands; + + public string ServiceName { get; set; } + + public DummyService(string serviceName) + { + _commands = new Dictionary(); + ServiceName = serviceName; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/IpcService.cs b/Ryujinx.HLE/HOS/Services/IpcService.cs index 71683ce3c5..2a4a93192b 100644 --- a/Ryujinx.HLE/HOS/Services/IpcService.cs +++ b/Ryujinx.HLE/HOS/Services/IpcService.cs @@ -89,13 +89,29 @@ namespace Ryujinx.HLE.HOS.Services long sfciMagic = context.RequestData.ReadInt64(); int commandId = (int)context.RequestData.ReadInt64(); - if (service.Commands.TryGetValue(commandId, out ServiceProcessRequest processRequest)) + bool serviceExists = service.Commands.TryGetValue(commandId, out ServiceProcessRequest processRequest); + + if (ServiceConfiguration.IgnoreMissingServices || serviceExists) { + long result = 0; + context.ResponseData.BaseStream.Seek(_isDomain ? 0x20 : 0x10, SeekOrigin.Begin); - Logger.PrintDebug(LogClass.KernelIpc, $"{service.GetType().Name}: {processRequest.Method.Name}"); + if (serviceExists) + { + Logger.PrintDebug(LogClass.KernelIpc, $"{service.GetType().Name}: {processRequest.Method.Name}"); - long result = processRequest(context); + result = processRequest(context); + } + else + { + string serviceName; + DummyService dummyService = service as DummyService; + + serviceName = (dummyService == null) ? service.GetType().FullName : dummyService.ServiceName; + + Logger.PrintWarning(LogClass.KernelIpc, $"Missing service {serviceName}: {commandId} ignored"); + } if (_isDomain) { diff --git a/Ryujinx.HLE/HOS/Services/ServiceFactory.cs b/Ryujinx.HLE/HOS/Services/ServiceFactory.cs index 83a217a5d3..113bbe51c8 100644 --- a/Ryujinx.HLE/HOS/Services/ServiceFactory.cs +++ b/Ryujinx.HLE/HOS/Services/ServiceFactory.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Services.Acc; using Ryujinx.HLE.HOS.Services.Am; using Ryujinx.HLE.HOS.Services.Apm; @@ -30,6 +31,11 @@ using System; namespace Ryujinx.HLE.HOS.Services { + public static class ServiceConfiguration + { + public static bool IgnoreMissingServices { get; set; } + } + static class ServiceFactory { public static IpcService MakeService(Horizon system, string name) @@ -209,6 +215,12 @@ namespace Ryujinx.HLE.HOS.Services return new IApplicationRootService(); } + if (ServiceConfiguration.IgnoreMissingServices) + { + Logger.PrintWarning(LogClass.Service, $"Missing service {name} ignored"); + return new DummyService(name); + } + throw new NotImplementedException(name); } } diff --git a/Ryujinx/Config.jsonc b/Ryujinx/Config.jsonc index 6e808b56fd..151756f43c 100644 --- a/Ryujinx/Config.jsonc +++ b/Ryujinx/Config.jsonc @@ -44,6 +44,9 @@ // Enable or disable aggressive CPU optimizations "enable_aggressive_cpu_opts": true, + // Enable or disable ignoring missing services, this may cause instability + "ignore_missing_services": false, + // The primary controller's type // Supported Values: Handheld, ProController, NpadPair, NpadLeft, NpadRight "controller_type": "Handheld", diff --git a/Ryujinx/Configuration.cs b/Ryujinx/Configuration.cs index c4a1b4369f..560a6dab59 100644 --- a/Ryujinx/Configuration.cs +++ b/Ryujinx/Configuration.cs @@ -4,6 +4,7 @@ using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.HLE; using Ryujinx.HLE.HOS.SystemState; +using Ryujinx.HLE.HOS.Services; using Ryujinx.HLE.Input; using Ryujinx.UI.Input; using System; @@ -91,6 +92,11 @@ namespace Ryujinx /// public bool EnableAggressiveCpuOpts { get; private set; } + /// + /// Enable or disable ignoring missing services + /// + public bool IgnoreMissingServices { get; private set; } + /// /// The primary controller's type /// @@ -207,6 +213,8 @@ namespace Ryujinx Optimizations.AssumeStrictAbiCompliance = true; } + ServiceConfiguration.IgnoreMissingServices = Instance.IgnoreMissingServices; + if(Instance.GamepadControls.Enabled) { if (GamePad.GetName(Instance.GamepadControls.Index) == "Unmapped Controller") diff --git a/Ryujinx/_schema.json b/Ryujinx/_schema.json index 7e7e466594..11eff12b08 100644 --- a/Ryujinx/_schema.json +++ b/Ryujinx/_schema.json @@ -411,6 +411,17 @@ false ] }, + "ignore_missing_services": { + "$id": "#/properties/ignore_missing_services", + "type": "boolean", + "title": "Ignore Missing Services", + "description": "Enable or disable ignoring missing services, this may cause instability", + "default": false, + "examples": [ + true, + false + ] + }, "controller_type": { "$id": "#/properties/controller_type", "type": "string",