From b2e88b04a85b41cc60af3485d88c90429e84a218 Mon Sep 17 00:00:00 2001
From: BaronKiko <BaronKiko@users.noreply.github.com>
Date: Tue, 16 Apr 2019 00:22:55 +0100
Subject: Config option to ignore missing services (#658)

* Implemented config option to ignore missing services

* Removed unused using statement

* Resolved comments from review
---
 Ryujinx.HLE/HOS/Services/DummyService.cs   | 20 ++++++++++++++++++++
 Ryujinx.HLE/HOS/Services/IpcService.cs     | 22 +++++++++++++++++++---
 Ryujinx.HLE/HOS/Services/ServiceFactory.cs | 12 ++++++++++++
 Ryujinx/Config.jsonc                       |  3 +++
 Ryujinx/Configuration.cs                   |  8 ++++++++
 Ryujinx/_schema.json                       | 11 +++++++++++
 6 files changed, 73 insertions(+), 3 deletions(-)
 create mode 100644 Ryujinx.HLE/HOS/Services/DummyService.cs

diff --git a/Ryujinx.HLE/HOS/Services/DummyService.cs b/Ryujinx.HLE/HOS/Services/DummyService.cs
new file mode 100644
index 00000000..28087bdf
--- /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<int, ServiceProcessRequest> _commands;
+
+        public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
+
+        public string ServiceName { get; set; }
+
+        public DummyService(string serviceName)
+        {
+            _commands = new Dictionary<int, ServiceProcessRequest>();
+            ServiceName = serviceName;
+        }
+    }
+}
diff --git a/Ryujinx.HLE/HOS/Services/IpcService.cs b/Ryujinx.HLE/HOS/Services/IpcService.cs
index 71683ce3..2a4a9319 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 83a217a5..113bbe51 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 6e808b56..151756f4 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 c4a1b436..560a6dab 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
         /// </summary>
         public bool EnableAggressiveCpuOpts { get; private set; }
 
+        /// <summary>
+        /// Enable or disable ignoring missing services
+        /// </summary>
+        public bool IgnoreMissingServices { get; private set; }
+
         /// <summary>
         ///  The primary controller's type
         /// </summary>
@@ -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 7e7e4665..11eff12b 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",
-- 
cgit v1.2.3-70-g09d2