Configuration.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. using ARMeilleure;
  2. using LibHac.Fs;
  3. using OpenTK.Input;
  4. using Ryujinx.Common;
  5. using Ryujinx.Common.Logging;
  6. using Ryujinx.HLE;
  7. using Ryujinx.HLE.HOS.SystemState;
  8. using Ryujinx.HLE.HOS.Services;
  9. using Ryujinx.HLE.Input;
  10. using Ryujinx.UI.Input;
  11. using System;
  12. using System.IO;
  13. using System.Threading.Tasks;
  14. using Utf8Json;
  15. using Utf8Json.Resolvers;
  16. namespace Ryujinx
  17. {
  18. public class Configuration
  19. {
  20. /// <summary>
  21. /// The default configuration instance
  22. /// </summary>
  23. public static Configuration Instance { get; private set; }
  24. /// <summary>
  25. /// Dumps shaders in this local directory
  26. /// </summary>
  27. public string GraphicsShadersDumpPath { get; private set; }
  28. /// <summary>
  29. /// Enables printing debug log messages
  30. /// </summary>
  31. public bool LoggingEnableDebug { get; private set; }
  32. /// <summary>
  33. /// Enables printing stub log messages
  34. /// </summary>
  35. public bool LoggingEnableStub { get; private set; }
  36. /// <summary>
  37. /// Enables printing info log messages
  38. /// </summary>
  39. public bool LoggingEnableInfo { get; private set; }
  40. /// <summary>
  41. /// Enables printing warning log messages
  42. /// </summary>
  43. public bool LoggingEnableWarn { get; private set; }
  44. /// <summary>
  45. /// Enables printing error log messages
  46. /// </summary>
  47. public bool LoggingEnableError { get; private set; }
  48. /// <summary>
  49. /// Enables printing guest log messages
  50. /// </summary>
  51. public bool LoggingEnableGuest { get; private set; }
  52. /// <summary>
  53. /// Enables printing FS access log messages
  54. /// </summary>
  55. public bool LoggingEnableFsAccessLog { get; private set; }
  56. /// <summary>
  57. /// Controls which log messages are written to the log targets
  58. /// </summary>
  59. public LogClass[] LoggingFilteredClasses { get; private set; }
  60. /// <summary>
  61. /// Enables or disables logging to a file on disk
  62. /// </summary>
  63. public bool EnableFileLog { get; private set; }
  64. /// <summary>
  65. /// Change System Language
  66. /// </summary>
  67. public SystemLanguage SystemLanguage { get; private set; }
  68. /// <summary>
  69. /// Enables or disables Docked Mode
  70. /// </summary>
  71. public bool DockedMode { get; private set; }
  72. /// <summary>
  73. /// Enables or disables Discord Rich Presence
  74. /// </summary>
  75. public bool EnableDiscordIntegration { get; private set; }
  76. /// <summary>
  77. /// Enables or disables Vertical Sync
  78. /// </summary>
  79. public bool EnableVsync { get; private set; }
  80. /// <summary>
  81. /// Enables or disables multi-core scheduling of threads
  82. /// </summary>
  83. public bool EnableMulticoreScheduling { get; private set; }
  84. /// <summary>
  85. /// Enables integrity checks on Game content files
  86. /// </summary>
  87. public bool EnableFsIntegrityChecks { get; private set; }
  88. /// <summary>
  89. /// Enables FS access log output to the console. Possible modes are 0-3
  90. /// </summary>
  91. public int FsGlobalAccessLogMode { get; private set; }
  92. /// <summary>
  93. /// Use old ChocolArm64 ARM emulator
  94. /// </summary>
  95. public bool EnableLegacyJit { get; private set; }
  96. /// <summary>
  97. /// Enable or disable ignoring missing services
  98. /// </summary>
  99. public bool IgnoreMissingServices { get; private set; }
  100. /// <summary>
  101. /// The primary controller's type
  102. /// </summary>
  103. public ControllerStatus ControllerType { get; private set; }
  104. /// <summary>
  105. /// Enable or disable keyboard support (Independent from controllers binding)
  106. /// </summary>
  107. public bool EnableKeyboard { get; private set; }
  108. /// <summary>
  109. /// Keyboard control bindings
  110. /// </summary>
  111. public NpadKeyboard KeyboardControls { get; private set; }
  112. /// <summary>
  113. /// Controller control bindings
  114. /// </summary>
  115. public UI.Input.NpadController JoystickControls { get; private set; }
  116. /// <summary>
  117. /// Loads a configuration file from disk
  118. /// </summary>
  119. /// <param name="path">The path to the JSON configuration file</param>
  120. public static void Load(string path)
  121. {
  122. var resolver = CompositeResolver.Create(
  123. new[] { new ConfigurationEnumFormatter<Key>() },
  124. new[] { StandardResolver.AllowPrivateSnakeCase }
  125. );
  126. using (Stream stream = File.OpenRead(path))
  127. {
  128. Instance = JsonSerializer.Deserialize<Configuration>(stream, resolver);
  129. }
  130. }
  131. /// <summary>
  132. /// Loads a configuration file asynchronously from disk
  133. /// </summary>
  134. /// <param name="path">The path to the JSON configuration file</param>
  135. public static async Task LoadAsync(string path)
  136. {
  137. var resolver = CompositeResolver.Create(
  138. new[] { new ConfigurationEnumFormatter<Key>() },
  139. new[] { StandardResolver.AllowPrivateSnakeCase }
  140. );
  141. using (Stream stream = File.OpenRead(path))
  142. {
  143. Instance = await JsonSerializer.DeserializeAsync<Configuration>(stream, resolver);
  144. }
  145. }
  146. /// <summary>
  147. /// Configures a <see cref="Switch"/> instance
  148. /// </summary>
  149. /// <param name="device">The instance to configure</param>
  150. public static void Configure(Switch device)
  151. {
  152. if (Instance == null)
  153. {
  154. throw new InvalidOperationException("Configuration has not been loaded yet.");
  155. }
  156. GraphicsConfig.ShadersDumpPath = Instance.GraphicsShadersDumpPath;
  157. Logger.AddTarget(new AsyncLogTargetWrapper(
  158. new ConsoleLogTarget(),
  159. 1000,
  160. AsyncLogTargetOverflowAction.Block
  161. ));
  162. if (Instance.EnableFileLog)
  163. {
  164. Logger.AddTarget(new AsyncLogTargetWrapper(
  165. new FileLogTarget(Path.Combine(Program.ApplicationDirectory, "Ryujinx.log")),
  166. 1000,
  167. AsyncLogTargetOverflowAction.Block
  168. ));
  169. }
  170. Logger.SetEnable(LogLevel.Debug, Instance.LoggingEnableDebug);
  171. Logger.SetEnable(LogLevel.Stub, Instance.LoggingEnableStub);
  172. Logger.SetEnable(LogLevel.Info, Instance.LoggingEnableInfo);
  173. Logger.SetEnable(LogLevel.Warning, Instance.LoggingEnableWarn);
  174. Logger.SetEnable(LogLevel.Error, Instance.LoggingEnableError);
  175. Logger.SetEnable(LogLevel.Guest, Instance.LoggingEnableGuest);
  176. Logger.SetEnable(LogLevel.AccessLog, Instance.LoggingEnableFsAccessLog);
  177. if (Instance.LoggingFilteredClasses.Length > 0)
  178. {
  179. foreach (var logClass in EnumExtensions.GetValues<LogClass>())
  180. {
  181. Logger.SetEnable(logClass, false);
  182. }
  183. foreach (var logClass in Instance.LoggingFilteredClasses)
  184. {
  185. Logger.SetEnable(logClass, true);
  186. }
  187. }
  188. device.System.State.DiscordIntegrationEnabled = Instance.EnableDiscordIntegration;
  189. device.EnableDeviceVsync = Instance.EnableVsync;
  190. device.System.State.DockedMode = Instance.DockedMode;
  191. device.System.State.SetLanguage(Instance.SystemLanguage);
  192. if (Instance.EnableMulticoreScheduling)
  193. {
  194. device.System.EnableMultiCoreScheduling();
  195. }
  196. device.System.FsIntegrityCheckLevel = Instance.EnableFsIntegrityChecks
  197. ? IntegrityCheckLevel.ErrorOnInvalid
  198. : IntegrityCheckLevel.None;
  199. device.System.GlobalAccessLogMode = Instance.FsGlobalAccessLogMode;
  200. device.System.UseLegacyJit = Instance.EnableLegacyJit;
  201. ServiceConfiguration.IgnoreMissingServices = Instance.IgnoreMissingServices;
  202. if (Instance.JoystickControls.Enabled)
  203. {
  204. if (!Joystick.GetState(Instance.JoystickControls.Index).IsConnected)
  205. {
  206. Instance.JoystickControls.SetEnabled(false);
  207. }
  208. }
  209. device.Hid.InitializePrimaryController(Instance.ControllerType);
  210. device.Hid.InitializeKeyboard();
  211. }
  212. private class ConfigurationEnumFormatter<T> : IJsonFormatter<T>
  213. where T : struct
  214. {
  215. public void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver)
  216. {
  217. formatterResolver.GetFormatterWithVerify<string>()
  218. .Serialize(ref writer, value.ToString(), formatterResolver);
  219. }
  220. public T Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
  221. {
  222. if (reader.ReadIsNull())
  223. {
  224. return default(T);
  225. }
  226. string enumName = formatterResolver.GetFormatterWithVerify<string>()
  227. .Deserialize(ref reader, formatterResolver);
  228. if (Enum.TryParse<T>(enumName, out T result))
  229. {
  230. return result;
  231. }
  232. return default(T);
  233. }
  234. }
  235. }
  236. }