misc: Move configuration management to the Ryujinx project (#2269)

* Decouple configuration from Ryujinx.HLE and Ryujinx.Input

* Move Configuration to the Ryujinx project
This commit is contained in:
Mary 2021-05-16 17:12:14 +02:00 committed by GitHub
parent f48828351c
commit bec67dbef7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 387 additions and 215 deletions

View File

@ -197,7 +197,7 @@ namespace Ryujinx.HLE.FileSystem.Content
} }
// fs must contain AOC nca files in its root // fs must contain AOC nca files in its root
public void AddAocData(IFileSystem fs, string containerPath, ulong aocBaseId) public void AddAocData(IFileSystem fs, string containerPath, ulong aocBaseId, IntegrityCheckLevel integrityCheckLevel)
{ {
_virtualFileSystem.ImportTickets(fs); _virtualFileSystem.ImportTickets(fs);
@ -214,7 +214,7 @@ namespace Ryujinx.HLE.FileSystem.Content
continue; continue;
} }
using var pfs0 = nca.OpenFileSystem(0, Switch.GetIntegrityCheckLevel()); using var pfs0 = nca.OpenFileSystem(0, integrityCheckLevel);
pfs0.OpenFile(out IFile cnmtFile, pfs0.EnumerateEntries().Single().FullPath.ToU8Span(), OpenMode.Read); pfs0.OpenFile(out IFile cnmtFile, pfs0.EnumerateEntries().Single().FullPath.ToU8Span(), OpenMode.Read);
@ -265,7 +265,7 @@ namespace Ryujinx.HLE.FileSystem.Content
public IList<ulong> GetAocTitleIds() => _aocData.Where(e => e.Value.Enabled).Select(e => e.Key).ToList(); public IList<ulong> GetAocTitleIds() => _aocData.Where(e => e.Value.Enabled).Select(e => e.Key).ToList();
public bool GetAocDataStorage(ulong aocTitleId, out IStorage aocStorage) public bool GetAocDataStorage(ulong aocTitleId, out IStorage aocStorage, IntegrityCheckLevel integrityCheckLevel)
{ {
aocStorage = null; aocStorage = null;
@ -289,7 +289,7 @@ namespace Ryujinx.HLE.FileSystem.Content
return false; // Print error? return false; // Print error?
} }
aocStorage = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage()).OpenStorage(NcaSectionType.Data, Switch.GetIntegrityCheckLevel()); aocStorage = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage()).OpenStorage(NcaSectionType.Data, integrityCheckLevel);
return true; return true;
} }
@ -710,8 +710,6 @@ namespace Ryujinx.HLE.FileSystem.Content
SystemVersion VerifyAndGetVersionZip(ZipArchive archive) SystemVersion VerifyAndGetVersionZip(ZipArchive archive)
{ {
IntegrityCheckLevel integrityCheckLevel = Switch.GetIntegrityCheckLevel();
SystemVersion systemVersion = null; SystemVersion systemVersion = null;
foreach (var entry in archive.Entries) foreach (var entry in archive.Entries)
@ -751,7 +749,7 @@ namespace Ryujinx.HLE.FileSystem.Content
{ {
Nca metaNca = new Nca(_virtualFileSystem.KeySet, ncaStream.AsStorage()); Nca metaNca = new Nca(_virtualFileSystem.KeySet, ncaStream.AsStorage());
IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel); IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath; string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
@ -781,7 +779,7 @@ namespace Ryujinx.HLE.FileSystem.Content
{ {
Nca nca = new Nca(_virtualFileSystem.KeySet, ncaStream.AsStorage()); Nca nca = new Nca(_virtualFileSystem.KeySet, ncaStream.AsStorage());
var romfs = nca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel); var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
if (romfs.OpenFile(out IFile systemVersionFile, "/file".ToU8Span(), OpenMode.Read).IsSuccess()) if (romfs.OpenFile(out IFile systemVersionFile, "/file".ToU8Span(), OpenMode.Read).IsSuccess())
{ {
@ -816,7 +814,7 @@ namespace Ryujinx.HLE.FileSystem.Content
{ {
Nca metaNca = new Nca(_virtualFileSystem.KeySet, metaNcaStream.AsStorage()); Nca metaNca = new Nca(_virtualFileSystem.KeySet, metaNcaStream.AsStorage());
IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel); IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath; string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
@ -873,8 +871,6 @@ namespace Ryujinx.HLE.FileSystem.Content
SystemVersion VerifyAndGetVersion(IFileSystem filesystem) SystemVersion VerifyAndGetVersion(IFileSystem filesystem)
{ {
IntegrityCheckLevel integrityCheckLevel = Switch.GetIntegrityCheckLevel();
SystemVersion systemVersion = null; SystemVersion systemVersion = null;
CnmtContentMetaEntry[] metaEntries = null; CnmtContentMetaEntry[] metaEntries = null;
@ -887,7 +883,7 @@ namespace Ryujinx.HLE.FileSystem.Content
if (nca.Header.TitleId == SystemUpdateTitleId && nca.Header.ContentType == NcaContentType.Meta) if (nca.Header.TitleId == SystemUpdateTitleId && nca.Header.ContentType == NcaContentType.Meta)
{ {
IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel); IFileSystem fs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath; string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
@ -905,7 +901,7 @@ namespace Ryujinx.HLE.FileSystem.Content
} }
else if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data) else if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data)
{ {
var romfs = nca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel); var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
if (romfs.OpenFile(out IFile systemVersionFile, "/file".ToU8Span(), OpenMode.Read).IsSuccess()) if (romfs.OpenFile(out IFile systemVersionFile, "/file".ToU8Span(), OpenMode.Read).IsSuccess())
{ {
@ -952,7 +948,7 @@ namespace Ryujinx.HLE.FileSystem.Content
Nca metaNca = new Nca(_virtualFileSystem.KeySet, metaStorage); Nca metaNca = new Nca(_virtualFileSystem.KeySet, metaStorage);
IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel); IFileSystem fs = metaNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath; string cnmtPath = fs.EnumerateEntries("/", "*.cnmt").Single().FullPath;
@ -1004,8 +1000,6 @@ namespace Ryujinx.HLE.FileSystem.Content
public SystemVersion GetCurrentFirmwareVersion() public SystemVersion GetCurrentFirmwareVersion()
{ {
IntegrityCheckLevel integrityCheckLevel = Switch.GetIntegrityCheckLevel();
LoadEntries(); LoadEntries();
lock (_lock) lock (_lock)
@ -1024,7 +1018,7 @@ namespace Ryujinx.HLE.FileSystem.Content
if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data) if (nca.Header.TitleId == SystemVersionTitleId && nca.Header.ContentType == NcaContentType.Data)
{ {
var romfs = nca.OpenFileSystem(NcaSectionType.Data, integrityCheckLevel); var romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid);
if (romfs.OpenFile(out IFile systemVersionFile, "/file".ToU8Span(), OpenMode.Read).IsSuccess()) if (romfs.OpenFile(out IFile systemVersionFile, "/file".ToU8Span(), OpenMode.Read).IsSuccess())
{ {

View File

@ -0,0 +1,179 @@
using LibHac.FsSystem;
using Ryujinx.Audio.Integration;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Graphics.GAL;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.SystemState;
using System;
using System.Collections.Generic;
namespace Ryujinx.HLE
{
/// <summary>
/// HLE configuration.
/// </summary>
public class HLEConfiguration
{
/// <summary>
/// The virtual file system used by the FS service.
/// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly VirtualFileSystem VirtualFileSystem;
/// <summary>
/// The account manager used by the account service.
/// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly AccountManager AccountManager;
/// <summary>
/// The content manager used by the NCM service.
/// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly ContentManager ContentManager;
/// <summary>
/// The persistant information between run for multi-application capabilities.
/// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
public readonly UserChannelPersistence UserChannelPersistence;
/// <summary>
/// The GPU renderer to use for all GPU operations.
/// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly IRenderer GpuRenderer;
/// <summary>
/// The audio device driver to use for all audio operations.
/// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly IHardwareDeviceDriver AudioDeviceDriver;
/// <summary>
/// The handler for various UI related operations needed outside of HLE.
/// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly IHostUiHandler HostUiHandler;
/// <summary>
/// Control the memory configuration used by the emulation context.
/// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly MemoryConfiguration MemoryConfiguration;
/// <summary>
/// The system language to use in the settings service.
/// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly SystemLanguage SystemLanguage;
/// <summary>
/// The system region to use in the settings service.
/// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly RegionCode Region;
/// <summary>
/// Control the initial state of the vertical sync in the SurfaceFlinger service.
/// </summary>
internal readonly bool EnableVsync;
/// <summary>
/// Control the initial state of the docked mode.
/// </summary>
internal readonly bool EnableDockedMode;
/// <summary>
/// Control if the Profiled Translation Cache (PTC) should be used.
/// </summary>
internal readonly bool EnablePtc;
/// <summary>
/// Control LibHac's integrity check level.
/// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly IntegrityCheckLevel FsIntegrityCheckLevel;
/// <summary>
/// Control LibHac's global access logging level. Value must be between 0 and 3.
/// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly int FsGlobalAccessLogMode;
/// <summary>
/// The system time offset to apply to the time service steady and local clocks.
/// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly long SystemTimeOffset;
/// <summary>
/// The system timezone used by the time service.
/// </summary>
/// <remarks>This cannot be changed after <see cref="Switch"/> instantiation.</remarks>
internal readonly string TimeZone;
/// <summary>
/// Control the inital state of the ignore missing services setting.
/// If this is set to true, when a missing service is encountered, it will try to automatically handle it instead of throwing an exception.
/// </summary>
/// TODO: Update this again.
public bool IgnoreMissingServices { internal get; set; }
/// <summary>
/// Aspect Ratio applied to the renderer window by the SurfaceFlinger service.
/// </summary>
public AspectRatio AspectRatio { internal get; set; }
/// <summary>
/// An action called when HLE force a refresh of output after docked mode changed.
/// </summary>
public Action RefreshInputConfig { internal get; set; }
public HLEConfiguration(VirtualFileSystem virtualFileSystem,
ContentManager contentManager,
AccountManager accountManager,
UserChannelPersistence userChannelPersistence,
IRenderer gpuRenderer,
IHardwareDeviceDriver audioDeviceDriver,
MemoryConfiguration memoryConfiguration,
IHostUiHandler hostUiHandler,
SystemLanguage systemLanguage,
RegionCode region,
bool enableVsync,
bool enableDockedMode,
bool enablePtc,
IntegrityCheckLevel fsIntegrityCheckLevel,
int fsGlobalAccessLogMode,
long systemTimeOffset,
string timeZone,
bool ignoreMissingServices,
AspectRatio aspectRatio)
{
VirtualFileSystem = virtualFileSystem;
AccountManager = accountManager;
ContentManager = contentManager;
UserChannelPersistence = userChannelPersistence;
GpuRenderer = gpuRenderer;
AudioDeviceDriver = audioDeviceDriver;
MemoryConfiguration = memoryConfiguration;
HostUiHandler = hostUiHandler;
SystemLanguage = systemLanguage;
Region = region;
EnableVsync = enableVsync;
EnableDockedMode = enableDockedMode;
EnablePtc = enablePtc;
FsIntegrityCheckLevel = fsIntegrityCheckLevel;
FsGlobalAccessLogMode = fsGlobalAccessLogMode;
SystemTimeOffset = systemTimeOffset;
TimeZone = timeZone;
IgnoreMissingServices = ignoreMissingServices;
AspectRatio = aspectRatio;
}
}
}

View File

@ -10,7 +10,6 @@ using LibHac.Ns;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Process;
using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.HLE.Loaders.Npdm; using Ryujinx.HLE.Loaders.Npdm;
@ -50,9 +49,6 @@ namespace Ryujinx.HLE.HOS
}; };
private readonly Switch _device; private readonly Switch _device;
private readonly ContentManager _contentManager;
private readonly VirtualFileSystem _fileSystem;
private string _titleName; private string _titleName;
private string _displayVersion; private string _displayVersion;
private BlitStruct<ApplicationControlProperty> _controlData; private BlitStruct<ApplicationControlProperty> _controlData;
@ -66,12 +62,9 @@ namespace Ryujinx.HLE.HOS
public string TitleIdText => TitleId.ToString("x16"); public string TitleIdText => TitleId.ToString("x16");
public ApplicationLoader(Switch device, VirtualFileSystem fileSystem, ContentManager contentManager) public ApplicationLoader(Switch device)
{ {
_device = device; _device = device;
_contentManager = contentManager;
_fileSystem = fileSystem;
_controlData = new BlitStruct<ApplicationControlProperty>(1); _controlData = new BlitStruct<ApplicationControlProperty>(1);
} }
@ -79,14 +72,14 @@ namespace Ryujinx.HLE.HOS
{ {
if (romFsFile != null) if (romFsFile != null)
{ {
_fileSystem.LoadRomFs(romFsFile); _device.Configuration.VirtualFileSystem.LoadRomFs(romFsFile);
} }
LocalFileSystem codeFs = new LocalFileSystem(exeFsDir); LocalFileSystem codeFs = new LocalFileSystem(exeFsDir);
Npdm metaData = ReadNpdm(codeFs); Npdm metaData = ReadNpdm(codeFs);
_fileSystem.ModLoader.CollectMods(new[] { TitleId }, _fileSystem.ModLoader.GetModsBasePath()); _device.Configuration.VirtualFileSystem.ModLoader.CollectMods(new[] { TitleId }, _device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath());
if (TitleId != 0) if (TitleId != 0)
{ {
@ -209,7 +202,7 @@ namespace Ryujinx.HLE.HOS
public void LoadXci(string xciFile) public void LoadXci(string xciFile)
{ {
FileStream file = new FileStream(xciFile, FileMode.Open, FileAccess.Read); FileStream file = new FileStream(xciFile, FileMode.Open, FileAccess.Read);
Xci xci = new Xci(_fileSystem.KeySet, file.AsStorage()); Xci xci = new Xci(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage());
if (!xci.HasPartition(XciPartitionType.Secure)) if (!xci.HasPartition(XciPartitionType.Secure))
{ {
@ -226,7 +219,7 @@ namespace Ryujinx.HLE.HOS
try try
{ {
(mainNca, patchNca, controlNca) = GetGameData(_fileSystem, securePartition, _device.UserChannelPersistence.Index); (mainNca, patchNca, controlNca) = GetGameData(_device.Configuration.VirtualFileSystem, securePartition, _device.Configuration.UserChannelPersistence.Index);
} }
catch (Exception e) catch (Exception e)
{ {
@ -242,9 +235,9 @@ namespace Ryujinx.HLE.HOS
return; return;
} }
_contentManager.LoadEntries(_device); _device.Configuration.ContentManager.LoadEntries(_device);
_contentManager.ClearAocData(); _device.Configuration.ContentManager.ClearAocData();
_contentManager.AddAocData(securePartition, xciFile, mainNca.Header.TitleId); _device.Configuration.ContentManager.AddAocData(securePartition, xciFile, mainNca.Header.TitleId, _device.Configuration.FsIntegrityCheckLevel);
LoadNca(mainNca, patchNca, controlNca); LoadNca(mainNca, patchNca, controlNca);
} }
@ -260,7 +253,7 @@ namespace Ryujinx.HLE.HOS
try try
{ {
(mainNca, patchNca, controlNca) = GetGameData(_fileSystem, nsp, _device.UserChannelPersistence.Index); (mainNca, patchNca, controlNca) = GetGameData(_device.Configuration.VirtualFileSystem, nsp, _device.Configuration.UserChannelPersistence.Index);
} }
catch (Exception e) catch (Exception e)
{ {
@ -278,8 +271,8 @@ namespace Ryujinx.HLE.HOS
if (mainNca != null) if (mainNca != null)
{ {
_contentManager.ClearAocData(); _device.Configuration.ContentManager.ClearAocData();
_contentManager.AddAocData(nsp, nspFile, mainNca.Header.TitleId); _device.Configuration.ContentManager.AddAocData(nsp, nspFile, mainNca.Header.TitleId, _device.Configuration.FsIntegrityCheckLevel);
LoadNca(mainNca, patchNca, controlNca); LoadNca(mainNca, patchNca, controlNca);
@ -293,7 +286,7 @@ namespace Ryujinx.HLE.HOS
public void LoadNca(string ncaFile) public void LoadNca(string ncaFile)
{ {
FileStream file = new FileStream(ncaFile, FileMode.Open, FileAccess.Read); FileStream file = new FileStream(ncaFile, FileMode.Open, FileAccess.Read);
Nca nca = new Nca(_fileSystem.KeySet, file.AsStorage(false)); Nca nca = new Nca(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false));
LoadNca(nca, null, null); LoadNca(nca, null, null);
} }
@ -310,7 +303,7 @@ namespace Ryujinx.HLE.HOS
IStorage dataStorage = null; IStorage dataStorage = null;
IFileSystem codeFs = null; IFileSystem codeFs = null;
(Nca updatePatchNca, Nca updateControlNca) = GetGameUpdateData(_fileSystem, mainNca.Header.TitleId.ToString("x16"), _device.UserChannelPersistence.Index, out _); (Nca updatePatchNca, Nca updateControlNca) = GetGameUpdateData(_device.Configuration.VirtualFileSystem, mainNca.Header.TitleId.ToString("x16"), _device.Configuration.UserChannelPersistence.Index, out _);
if (updatePatchNca != null) if (updatePatchNca != null)
{ {
@ -323,7 +316,7 @@ namespace Ryujinx.HLE.HOS
} }
// Load program 0 control NCA as we are going to need it for display version. // Load program 0 control NCA as we are going to need it for display version.
(_, Nca updateProgram0ControlNca) = GetGameUpdateData(_fileSystem, mainNca.Header.TitleId.ToString("x16"), 0, out _); (_, Nca updateProgram0ControlNca) = GetGameUpdateData(_device.Configuration.VirtualFileSystem, mainNca.Header.TitleId.ToString("x16"), 0, out _);
// Load Aoc // Load Aoc
string titleAocMetadataPath = Path.Combine(AppDataManager.GamesDirPath, mainNca.Header.TitleId.ToString("x16"), "dlc.json"); string titleAocMetadataPath = Path.Combine(AppDataManager.GamesDirPath, mainNca.Header.TitleId.ToString("x16"), "dlc.json");
@ -336,7 +329,7 @@ namespace Ryujinx.HLE.HOS
{ {
foreach (DlcNca dlcNca in dlcContainer.DlcNcaList) foreach (DlcNca dlcNca in dlcContainer.DlcNcaList)
{ {
_contentManager.AddAocItem(dlcNca.TitleId, dlcContainer.Path, dlcNca.Path, dlcNca.Enabled); _device.Configuration.ContentManager.AddAocItem(dlcNca.TitleId, dlcContainer.Path, dlcNca.Path, dlcNca.Enabled);
} }
} }
} }
@ -375,7 +368,7 @@ namespace Ryujinx.HLE.HOS
Npdm metaData = ReadNpdm(codeFs); Npdm metaData = ReadNpdm(codeFs);
_fileSystem.ModLoader.CollectMods(_contentManager.GetAocTitleIds().Prepend(TitleId), _fileSystem.ModLoader.GetModsBasePath()); _device.Configuration.VirtualFileSystem.ModLoader.CollectMods(_device.Configuration.ContentManager.GetAocTitleIds().Prepend(TitleId), _device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath());
if (controlNca != null) if (controlNca != null)
{ {
@ -388,7 +381,7 @@ namespace Ryujinx.HLE.HOS
// NOTE: Nintendo doesn't guarantee that the display version will be updated on sub programs when updating a multi program application. // NOTE: Nintendo doesn't guarantee that the display version will be updated on sub programs when updating a multi program application.
// BODY: As such, to avoid PTC cache confusion, we only trust the the program 0 display version when launching a sub program. // BODY: As such, to avoid PTC cache confusion, we only trust the the program 0 display version when launching a sub program.
if (updateProgram0ControlNca != null && _device.UserChannelPersistence.Index != 0) if (updateProgram0ControlNca != null && _device.Configuration.UserChannelPersistence.Index != 0)
{ {
string dummyTitleName = ""; string dummyTitleName = "";
BlitStruct<ApplicationControlProperty> dummyControl = new BlitStruct<ApplicationControlProperty>(1); BlitStruct<ApplicationControlProperty> dummyControl = new BlitStruct<ApplicationControlProperty>(1);
@ -402,9 +395,9 @@ namespace Ryujinx.HLE.HOS
} }
else else
{ {
IStorage newStorage = _fileSystem.ModLoader.ApplyRomFsMods(TitleId, dataStorage); IStorage newStorage = _device.Configuration.VirtualFileSystem.ModLoader.ApplyRomFsMods(TitleId, dataStorage);
_fileSystem.SetRomFs(newStorage.AsStream(FileAccess.Read)); _device.Configuration.VirtualFileSystem.SetRomFs(newStorage.AsStream(FileAccess.Read));
} }
if (TitleId != 0) if (TitleId != 0)
@ -470,7 +463,7 @@ namespace Ryujinx.HLE.HOS
private void LoadExeFs(IFileSystem codeFs, Npdm metaData = null) private void LoadExeFs(IFileSystem codeFs, Npdm metaData = null)
{ {
if (_fileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs)) if (_device.Configuration.VirtualFileSystem.ModLoader.ReplaceExefsPartition(TitleId, ref codeFs))
{ {
metaData = null; //TODO: Check if we should retain old npdm metaData = null; //TODO: Check if we should retain old npdm
} }
@ -496,7 +489,7 @@ namespace Ryujinx.HLE.HOS
} }
// ExeFs file replacements // ExeFs file replacements
ModLoadResult modLoadResult = _fileSystem.ModLoader.ApplyExefsMods(TitleId, nsos); ModLoadResult modLoadResult = _device.Configuration.VirtualFileSystem.ModLoader.ApplyExefsMods(TitleId, nsos);
// collect the nsos, ignoring ones that aren't used // collect the nsos, ignoring ones that aren't used
NsoExecutable[] programs = nsos.Where(x => x != null).ToArray(); NsoExecutable[] programs = nsos.Where(x => x != null).ToArray();
@ -507,9 +500,9 @@ namespace Ryujinx.HLE.HOS
metaData = modLoadResult.Npdm; metaData = modLoadResult.Npdm;
} }
_fileSystem.ModLoader.ApplyNsoPatches(TitleId, programs); _device.Configuration.VirtualFileSystem.ModLoader.ApplyNsoPatches(TitleId, programs);
_contentManager.LoadEntries(_device); _device.Configuration.ContentManager.LoadEntries(_device);
bool usePtc = _device.System.EnablePtc; bool usePtc = _device.System.EnablePtc;
@ -528,7 +521,7 @@ namespace Ryujinx.HLE.HOS
ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, executables: programs); ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, executables: programs);
_fileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine); _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine);
} }
public void LoadProgram(string filePath) public void LoadProgram(string filePath)
@ -569,7 +562,7 @@ namespace Ryujinx.HLE.HOS
if (romfsSize != 0) if (romfsSize != 0)
{ {
_fileSystem.SetRomFs(new HomebrewRomFsStream(input, obj.FileSize + (long)romfsOffset)); _device.Configuration.VirtualFileSystem.SetRomFs(new HomebrewRomFsStream(input, obj.FileSize + (long)romfsOffset));
} }
if (nacpSize != 0) if (nacpSize != 0)
@ -617,7 +610,7 @@ namespace Ryujinx.HLE.HOS
executable = new NsoExecutable(new LocalStorage(filePath, FileAccess.Read), Path.GetFileNameWithoutExtension(filePath)); executable = new NsoExecutable(new LocalStorage(filePath, FileAccess.Read), Path.GetFileNameWithoutExtension(filePath));
} }
_contentManager.LoadEntries(_device); _device.Configuration.ContentManager.LoadEntries(_device);
_titleName = metaData.TitleName; _titleName = metaData.TitleName;
TitleId = metaData.Aci0.TitleId; TitleId = metaData.Aci0.TitleId;
@ -629,7 +622,7 @@ namespace Ryujinx.HLE.HOS
ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, executables: executable); ProgramLoader.LoadNsos(_device.System.KernelContext, out ProcessTamperInfo tamperInfo, metaData, executables: executable);
_fileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine); _device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(TitleId, tamperInfo, _device.TamperMachine);
} }
private Npdm GetDefaultNpdm() private Npdm GetDefaultNpdm()
@ -664,7 +657,7 @@ namespace Ryujinx.HLE.HOS
"No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games."); "No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games.");
} }
FileSystemClient fileSystem = _fileSystem.FsClient; FileSystemClient fileSystem = _device.Configuration.VirtualFileSystem.FsClient;
Result resultCode = fileSystem.EnsureApplicationCacheStorage(out _, applicationId, ref control); Result resultCode = fileSystem.EnsureApplicationCacheStorage(out _, applicationId, ref control);
if (resultCode.IsFailure()) if (resultCode.IsFailure())

View File

@ -8,8 +8,6 @@ using Ryujinx.Audio.Integration;
using Ryujinx.Audio.Output; using Ryujinx.Audio.Output;
using Ryujinx.Audio.Renderer.Device; using Ryujinx.Audio.Renderer.Device;
using Ryujinx.Audio.Renderer.Server; using Ryujinx.Audio.Renderer.Server;
using Ryujinx.Common;
using Ryujinx.Configuration;
using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Font; using Ryujinx.HLE.HOS.Font;
using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel;
@ -111,13 +109,13 @@ namespace Ryujinx.HLE.HOS
internal LibHac.Horizon LibHacHorizonServer { get; private set; } internal LibHac.Horizon LibHacHorizonServer { get; private set; }
internal HorizonClient LibHacHorizonClient { get; private set; } internal HorizonClient LibHacHorizonClient { get; private set; }
public Horizon(Switch device, ContentManager contentManager, AccountManager accountManager, MemoryConfiguration memoryConfiguration) public Horizon(Switch device)
{ {
KernelContext = new KernelContext( KernelContext = new KernelContext(
device, device,
device.Memory, device.Memory,
memoryConfiguration.ToKernelMemorySize(), device.Configuration.MemoryConfiguration.ToKernelMemorySize(),
memoryConfiguration.ToKernelMemoryArrange()); device.Configuration.MemoryConfiguration.ToKernelMemoryArrange());
Device = device; Device = device;
@ -166,8 +164,8 @@ namespace Ryujinx.HLE.HOS
DisplayResolutionChangeEvent = new KEvent(KernelContext); DisplayResolutionChangeEvent = new KEvent(KernelContext);
AccountManager = accountManager; AccountManager = device.Configuration.AccountManager;
ContentManager = contentManager; ContentManager = device.Configuration.ContentManager;
CaptureManager = new CaptureManager(device); CaptureManager = new CaptureManager(device);
// TODO: use set:sys (and get external clock source id from settings) // TODO: use set:sys (and get external clock source id from settings)
@ -179,7 +177,7 @@ namespace Ryujinx.HLE.HOS
TimeSpanType systemTime = TimeSpanType.FromSeconds((long)rtcValue); TimeSpanType systemTime = TimeSpanType.FromSeconds((long)rtcValue);
// Configure and setup internal offset // Configure and setup internal offset
TimeSpanType internalOffset = TimeSpanType.FromSeconds(ConfigurationState.Instance.System.SystemTimeOffset); TimeSpanType internalOffset = TimeSpanType.FromSeconds(device.Configuration.SystemTimeOffset);
TimeSpanType systemTimeOffset = new TimeSpanType(systemTime.NanoSeconds + internalOffset.NanoSeconds); TimeSpanType systemTimeOffset = new TimeSpanType(systemTime.NanoSeconds + internalOffset.NanoSeconds);
@ -219,8 +217,6 @@ namespace Ryujinx.HLE.HOS
SurfaceFlinger = new SurfaceFlinger(device); SurfaceFlinger = new SurfaceFlinger(device);
ConfigurationState.Instance.System.EnableDockedMode.Event += OnDockedModeChange;
InitLibHacHorizon(); InitLibHacHorizon();
InitializeAudioRenderer(); InitializeAudioRenderer();
} }
@ -313,11 +309,11 @@ namespace Ryujinx.HLE.HOS
LibHacHorizonClient = ryujinxClient; LibHacHorizonClient = ryujinxClient;
} }
private void OnDockedModeChange(object sender, ReactiveEventArgs<bool> e) public void ChangeDockedModeState(bool newState)
{ {
if (e.NewValue != State.DockedMode) if (newState != State.DockedMode)
{ {
State.DockedMode = e.NewValue; State.DockedMode = newState;
PerformanceState.PerformanceMode = State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default; PerformanceState.PerformanceMode = State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default;
AppletState.Messages.Enqueue(MessageInfo.OperationModeChanged); AppletState.Messages.Enqueue(MessageInfo.OperationModeChanged);
@ -326,8 +322,7 @@ namespace Ryujinx.HLE.HOS
SignalDisplayResolutionChange(); SignalDisplayResolutionChange();
// Reconfigure controllers Device.Configuration.RefreshInputConfig?.Invoke();
Device.Hid.RefreshInputConfig(ConfigurationState.Instance.Hid.InputConfig.Value);
} }
} }
@ -388,8 +383,6 @@ namespace Ryujinx.HLE.HOS
{ {
if (!_isDisposed && disposing) if (!_isDisposed && disposing)
{ {
ConfigurationState.Instance.System.EnableDockedMode.Event -= OnDockedModeChange;
_isDisposed = true; _isDisposed = true;
KProcess terminationProcess = new KProcess(KernelContext); KProcess terminationProcess = new KProcess(KernelContext);

View File

@ -57,7 +57,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
switch (kind) switch (kind)
{ {
case LaunchParameterKind.UserChannel: case LaunchParameterKind.UserChannel:
storageData = context.Device.UserChannelPersistence.Pop(); storageData = context.Device.Configuration.UserChannelPersistence.Pop();
break; break;
case LaunchParameterKind.PreselectedUser: case LaunchParameterKind.PreselectedUser:
// Only the first 0x18 bytes of the Data seems to be actually used. // Only the first 0x18 bytes of the Data seems to be actually used.
@ -453,7 +453,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
// ClearUserChannel() // ClearUserChannel()
public ResultCode ClearUserChannel(ServiceCtx context) public ResultCode ClearUserChannel(ServiceCtx context)
{ {
context.Device.UserChannelPersistence.Clear(); context.Device.Configuration.UserChannelPersistence.Clear();
return ResultCode.Success; return ResultCode.Success;
} }
@ -464,7 +464,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
{ {
AppletAE.IStorage data = GetObject<AppletAE.IStorage>(context, 0); AppletAE.IStorage data = GetObject<AppletAE.IStorage>(context, 0);
context.Device.UserChannelPersistence.Push(data.Data); context.Device.Configuration.UserChannelPersistence.Push(data.Data);
return ResultCode.Success; return ResultCode.Success;
} }
@ -473,7 +473,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
// GetPreviousProgramIndex() -> s32 program_index // GetPreviousProgramIndex() -> s32 program_index
public ResultCode GetPreviousProgramIndex(ServiceCtx context) public ResultCode GetPreviousProgramIndex(ServiceCtx context)
{ {
int previousProgramIndex = context.Device.UserChannelPersistence.PreviousIndex; int previousProgramIndex = context.Device.Configuration.UserChannelPersistence.PreviousIndex;
context.ResponseData.Write(previousProgramIndex); context.ResponseData.Write(previousProgramIndex);

View File

@ -396,7 +396,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
// We do a mitm here to find if the request is for an AOC. // We do a mitm here to find if the request is for an AOC.
// This is because AOC can be distributed over multiple containers in the emulator. // This is because AOC can be distributed over multiple containers in the emulator.
if (context.Device.System.ContentManager.GetAocDataStorage((ulong)titleId, out LibHac.Fs.IStorage aocStorage)) if (context.Device.System.ContentManager.GetAocDataStorage((ulong)titleId, out LibHac.Fs.IStorage aocStorage, context.Device.Configuration.FsIntegrityCheckLevel))
{ {
Logger.Info?.Print(LogClass.Loader, $"Opened AddOnContent Data TitleID={titleId:X16}"); Logger.Info?.Print(LogClass.Loader, $"Opened AddOnContent Data TitleID={titleId:X16}");

View File

@ -65,7 +65,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
Npads = new NpadDevices(_device, true); Npads = new NpadDevices(_device, true);
} }
internal void RefreshInputConfig(List<InputConfig> inputConfig) public void RefreshInputConfig(List<InputConfig> inputConfig)
{ {
ControllerConfig[] npadConfig = new ControllerConfig[inputConfig.Count]; ControllerConfig[] npadConfig = new ControllerConfig[inputConfig.Count];
@ -78,11 +78,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid
_device.Hid.Npads.Configure(npadConfig); _device.Hid.Npads.Configure(npadConfig);
} }
internal void RefreshInputConfigEvent(object _, ReactiveEventArgs<List<InputConfig>> args)
{
RefreshInputConfig(args.NewValue);
}
public ControllerKeys UpdateStickButtons(JoystickPosition leftStick, JoystickPosition rightStick) public ControllerKeys UpdateStickButtons(JoystickPosition leftStick, JoystickPosition rightStick)
{ {
const int stickButtonThreshold = short.MaxValue / 2; const int stickButtonThreshold = short.MaxValue / 2;

View File

@ -109,7 +109,7 @@ namespace Ryujinx.HLE.HOS.Services
bool serviceExists = service.HipcCommands.TryGetValue(commandId, out MethodInfo processRequest); bool serviceExists = service.HipcCommands.TryGetValue(commandId, out MethodInfo processRequest);
if (ServiceConfiguration.IgnoreMissingServices || serviceExists) if (context.Device.Configuration.IgnoreMissingServices || serviceExists)
{ {
ResultCode result = ResultCode.Success; ResultCode result = ResultCode.Success;
@ -163,7 +163,7 @@ namespace Ryujinx.HLE.HOS.Services
bool serviceExists = TipcCommands.TryGetValue(commandId, out MethodInfo processRequest); bool serviceExists = TipcCommands.TryGetValue(commandId, out MethodInfo processRequest);
if (ServiceConfiguration.IgnoreMissingServices || serviceExists) if (context.Device.Configuration.IgnoreMissingServices || serviceExists)
{ {
ResultCode result = ResultCode.Success; ResultCode result = ResultCode.Success;

View File

@ -1,7 +0,0 @@
namespace Ryujinx.HLE.HOS.Services
{
public static class ServiceConfiguration
{
public static bool IgnoreMissingServices { get; set; }
}
}

View File

@ -98,7 +98,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
} }
else else
{ {
if (ServiceConfiguration.IgnoreMissingServices) if (context.Device.Configuration.IgnoreMissingServices)
{ {
Logger.Warning?.Print(LogClass.Service, $"Missing service {name} ignored"); Logger.Warning?.Print(LogClass.Service, $"Missing service {name} ignored");
} }

View File

@ -1,6 +1,5 @@
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Configuration;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap; using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap;
@ -351,7 +350,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
bool flipX = item.Transform.HasFlag(NativeWindowTransform.FlipX); bool flipX = item.Transform.HasFlag(NativeWindowTransform.FlipX);
bool flipY = item.Transform.HasFlag(NativeWindowTransform.FlipY); bool flipY = item.Transform.HasFlag(NativeWindowTransform.FlipY);
AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value; AspectRatio aspectRatio = _device.Configuration.AspectRatio;
bool isStretched = aspectRatio == AspectRatio.Stretched; bool isStretched = aspectRatio == AspectRatio.Stretched;
ImageCrop crop = new ImageCrop( ImageCrop crop = new ImageCrop(

View File

@ -5,7 +5,6 @@ using LibHac.Fs.Fsa;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.FsSystem.NcaUtils; using LibHac.FsSystem.NcaUtils;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Configuration;
using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.FileSystem.Content;
@ -47,10 +46,8 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
InitializeLocationNameCache(); InitializeLocationNameCache();
} }
public string SanityCheckDeviceLocationName() public string SanityCheckDeviceLocationName(string locationName)
{ {
string locationName = ConfigurationState.Instance.System.TimeZone;
if (IsLocationNameValid(locationName)) if (IsLocationNameValid(locationName))
{ {
return locationName; return locationName;
@ -58,8 +55,6 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
Logger.Warning?.Print(LogClass.ServiceTime, $"Invalid device TimeZone {locationName}, switching back to UTC"); Logger.Warning?.Print(LogClass.ServiceTime, $"Invalid device TimeZone {locationName}, switching back to UTC");
ConfigurationState.Instance.System.TimeZone.Value = "UTC";
return "UTC"; return "UTC";
} }
@ -69,7 +64,7 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
SteadyClockTimePoint timeZoneUpdatedTimePoint = timeManager.StandardSteadyClock.GetCurrentTimePoint(null); SteadyClockTimePoint timeZoneUpdatedTimePoint = timeManager.StandardSteadyClock.GetCurrentTimePoint(null);
string deviceLocationName = SanityCheckDeviceLocationName(); string deviceLocationName = SanityCheckDeviceLocationName(device.Configuration.TimeZone);
ResultCode result = GetTimeZoneBinary(deviceLocationName, out Stream timeZoneBinaryStream, out LocalStorage ncaFile); ResultCode result = GetTimeZoneBinary(deviceLocationName, out Stream timeZoneBinaryStream, out LocalStorage ncaFile);

View File

@ -1,22 +1,14 @@
using LibHac.FsSystem;
using Ryujinx.Audio.Backends.CompatLayer; using Ryujinx.Audio.Backends.CompatLayer;
using Ryujinx.Audio.Integration; using Ryujinx.Audio.Integration;
using Ryujinx.Common;
using Ryujinx.Configuration;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.Host1x; using Ryujinx.Graphics.Host1x;
using Ryujinx.Graphics.Nvdec; using Ryujinx.Graphics.Nvdec;
using Ryujinx.Graphics.Vic; using Ryujinx.Graphics.Vic;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.Services.Apm; using Ryujinx.HLE.HOS.Services.Apm;
using Ryujinx.HLE.HOS.Services.Hid; using Ryujinx.HLE.HOS.Services.Hid;
using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices; using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices;
using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.Memory; using Ryujinx.Memory;
using System; using System;
@ -24,69 +16,60 @@ namespace Ryujinx.HLE
{ {
public class Switch : IDisposable public class Switch : IDisposable
{ {
private MemoryConfiguration _memoryConfiguration; public HLEConfiguration Configuration { get; }
public IHardwareDeviceDriver AudioDeviceDriver { get; private set; } public IHardwareDeviceDriver AudioDeviceDriver { get; }
internal MemoryBlock Memory { get; private set; } internal MemoryBlock Memory { get; }
public GpuContext Gpu { get; private set; } public GpuContext Gpu { get; }
internal NvMemoryAllocator MemoryAllocator { get; private set; } internal NvMemoryAllocator MemoryAllocator { get; }
internal Host1xDevice Host1x { get; } internal Host1xDevice Host1x { get; }
public VirtualFileSystem FileSystem { get; private set; } public VirtualFileSystem FileSystem => Configuration.VirtualFileSystem;
public Horizon System { get; private set; } public Horizon System { get; }
public ApplicationLoader Application { get; } public ApplicationLoader Application { get; }
public PerformanceStatistics Statistics { get; private set; } public PerformanceStatistics Statistics { get; }
public UserChannelPersistence UserChannelPersistence { get; } public Hid Hid { get; }
public Hid Hid { get; private set; } public TamperMachine TamperMachine { get; }
public TamperMachine TamperMachine { get; private set; } public IHostUiHandler UiHandler { get; }
public IHostUiHandler UiHandler { get; set; }
public bool EnableDeviceVsync { get; set; } = true; public bool EnableDeviceVsync { get; set; } = true;
public Switch( public Switch(HLEConfiguration configuration)
VirtualFileSystem fileSystem,
ContentManager contentManager,
AccountManager accountManager,
UserChannelPersistence userChannelPersistence,
IRenderer renderer,
IHardwareDeviceDriver audioDeviceDriver,
MemoryConfiguration memoryConfiguration)
{ {
if (renderer == null) if (configuration.GpuRenderer == null)
{ {
throw new ArgumentNullException(nameof(renderer)); throw new ArgumentNullException(nameof(configuration.GpuRenderer));
} }
if (audioDeviceDriver == null) if (configuration.AudioDeviceDriver == null)
{ {
throw new ArgumentNullException(nameof(audioDeviceDriver)); throw new ArgumentNullException(nameof(configuration.AudioDeviceDriver));
} }
if (userChannelPersistence == null) if (configuration.UserChannelPersistence== null)
{ {
throw new ArgumentNullException(nameof(userChannelPersistence)); throw new ArgumentNullException(nameof(configuration.UserChannelPersistence));
} }
UserChannelPersistence = userChannelPersistence; Configuration = configuration;
_memoryConfiguration = memoryConfiguration; UiHandler = configuration.HostUiHandler;
AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(audioDeviceDriver); AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(configuration.AudioDeviceDriver);
Memory = new MemoryBlock(memoryConfiguration.ToDramSize()); Memory = new MemoryBlock(configuration.MemoryConfiguration.ToDramSize());
Gpu = new GpuContext(renderer); Gpu = new GpuContext(configuration.GpuRenderer);
MemoryAllocator = new NvMemoryAllocator(); MemoryAllocator = new NvMemoryAllocator();
@ -111,9 +94,7 @@ namespace Ryujinx.HLE
} }
}; };
FileSystem = fileSystem; System = new Horizon(this);
System = new Horizon(this, contentManager, accountManager, memoryConfiguration);
System.InitializeServices(); System.InitializeServices();
Statistics = new PerformanceStatistics(); Statistics = new PerformanceStatistics();
@ -121,45 +102,30 @@ namespace Ryujinx.HLE
Hid = new Hid(this, System.HidBaseAddress); Hid = new Hid(this, System.HidBaseAddress);
Hid.InitDevices(); Hid.InitDevices();
Application = new ApplicationLoader(this, fileSystem, contentManager); Application = new ApplicationLoader(this);
TamperMachine = new TamperMachine(); TamperMachine = new TamperMachine();
Initialize();
} }
public void Initialize() private void Initialize()
{ {
System.State.SetLanguage((SystemLanguage)ConfigurationState.Instance.System.Language.Value); System.State.SetLanguage(Configuration.SystemLanguage);
System.State.SetRegion((RegionCode)ConfigurationState.Instance.System.Region.Value); System.State.SetRegion(Configuration.Region);
EnableDeviceVsync = ConfigurationState.Instance.Graphics.EnableVsync; EnableDeviceVsync = Configuration.EnableVsync;
System.State.DockedMode = ConfigurationState.Instance.System.EnableDockedMode; System.State.DockedMode = Configuration.EnableDockedMode;
System.PerformanceState.PerformanceMode = System.State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default; System.PerformanceState.PerformanceMode = System.State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default;
System.EnablePtc = ConfigurationState.Instance.System.EnablePtc; System.EnablePtc = Configuration.EnablePtc;
System.FsIntegrityCheckLevel = GetIntegrityCheckLevel(); System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel;
System.GlobalAccessLogMode = ConfigurationState.Instance.System.FsGlobalAccessLogMode; System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode;
ServiceConfiguration.IgnoreMissingServices = ConfigurationState.Instance.System.IgnoreMissingServices;
ConfigurationState.Instance.System.IgnoreMissingServices.Event += (object _, ReactiveEventArgs<bool> args) =>
{
ServiceConfiguration.IgnoreMissingServices = args.NewValue;
};
// Configure controllers
Hid.RefreshInputConfig(ConfigurationState.Instance.Hid.InputConfig.Value);
ConfigurationState.Instance.Hid.InputConfig.Event += Hid.RefreshInputConfigEvent;
}
public static IntegrityCheckLevel GetIntegrityCheckLevel()
{
return ConfigurationState.Instance.System.EnableFsIntegrityChecks
? IntegrityCheckLevel.ErrorOnInvalid
: IntegrityCheckLevel.None;
} }
public void LoadCart(string exeFsDir, string romFsFile = null) public void LoadCart(string exeFsDir, string romFsFile = null)
@ -223,8 +189,6 @@ namespace Ryujinx.HLE
{ {
if (disposing) if (disposing)
{ {
ConfigurationState.Instance.Hid.InputConfig.Event -= Hid.RefreshInputConfigEvent;
System.Dispose(); System.Dispose();
Host1x.Dispose(); Host1x.Dispose();
AudioDeviceDriver.Dispose(); AudioDeviceDriver.Dispose();

View File

@ -1,8 +1,6 @@
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Configuration.Hid.Keyboard; using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Configuration;
using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Hid; using Ryujinx.HLE.HOS.Services.Hid;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -10,6 +8,7 @@ using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using CemuHookClient = Ryujinx.Input.Motion.CemuHook.Client; using CemuHookClient = Ryujinx.Input.Motion.CemuHook.Client;
using Switch = Ryujinx.HLE.Switch;
namespace Ryujinx.Input.HLE namespace Ryujinx.Input.HLE
{ {
@ -31,30 +30,41 @@ namespace Ryujinx.Input.HLE
private bool _isDisposed; private bool _isDisposed;
private List<InputConfig> _inputConfig; private List<InputConfig> _inputConfig;
private bool _enableKeyboard;
private Switch _device;
public NpadManager(IGamepadDriver keyboardDriver, IGamepadDriver gamepadDriver) public NpadManager(IGamepadDriver keyboardDriver, IGamepadDriver gamepadDriver)
{ {
_controllers = new NpadController[MaxControllers]; _controllers = new NpadController[MaxControllers];
_cemuHookClient = new CemuHookClient(); _cemuHookClient = new CemuHookClient(this);
_keyboardDriver = keyboardDriver; _keyboardDriver = keyboardDriver;
_gamepadDriver = gamepadDriver; _gamepadDriver = gamepadDriver;
_inputConfig = ConfigurationState.Instance.Hid.InputConfig.Value; _inputConfig = new List<InputConfig>();
_enableKeyboard = false;
_gamepadDriver.OnGamepadConnected += HandleOnGamepadConnected; _gamepadDriver.OnGamepadConnected += HandleOnGamepadConnected;
_gamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected; _gamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected;
} }
private void RefreshInputConfigForHLE()
{
lock (_lock)
{
_device.Hid.RefreshInputConfig(_inputConfig);
}
}
private void HandleOnGamepadDisconnected(string obj) private void HandleOnGamepadDisconnected(string obj)
{ {
// Force input reload // Force input reload
ReloadConfiguration(ConfigurationState.Instance.Hid.InputConfig.Value); ReloadConfiguration(_inputConfig, _enableKeyboard);
} }
private void HandleOnGamepadConnected(string id) private void HandleOnGamepadConnected(string id)
{ {
// Force input reload // Force input reload
ReloadConfiguration(ConfigurationState.Instance.Hid.InputConfig.Value); ReloadConfiguration(_inputConfig, _enableKeyboard);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -83,7 +93,7 @@ namespace Ryujinx.Input.HLE
} }
} }
public void ReloadConfiguration(List<InputConfig> inputConfig) public void ReloadConfiguration(List<InputConfig> inputConfig, bool enableKeyboard)
{ {
lock (_lock) lock (_lock)
{ {
@ -110,10 +120,9 @@ namespace Ryujinx.Input.HLE
} }
_inputConfig = inputConfig; _inputConfig = inputConfig;
_enableKeyboard = enableKeyboard;
// Enforce an update of the property that will be updated by HLE. _device.Hid.RefreshInputConfig(inputConfig);
// TODO: Move that in the input manager maybe?
ConfigurationState.Instance.Hid.InputConfig.Value = inputConfig;
} }
} }
@ -133,7 +142,15 @@ namespace Ryujinx.Input.HLE
} }
} }
public void Update(Hid hleHid, TamperMachine tamperMachine) public void Initialize(Switch device, List<InputConfig> inputConfig, bool enableKeyboard)
{
_device = device;
_device.Configuration.RefreshInputConfig = RefreshInputConfigForHLE;
ReloadConfiguration(inputConfig, enableKeyboard);
}
public void Update()
{ {
lock (_lock) lock (_lock)
{ {
@ -159,11 +176,11 @@ namespace Ryujinx.Input.HLE
inputState = controller.GetHLEInputState(); inputState = controller.GetHLEInputState();
inputState.Buttons |= hleHid.UpdateStickButtons(inputState.LStick, inputState.RStick); inputState.Buttons |= _device.Hid.UpdateStickButtons(inputState.LStick, inputState.RStick);
motionState = controller.GetHLEMotionState(); motionState = controller.GetHLEMotionState();
if (ConfigurationState.Instance.Hid.EnableKeyboard) if (_enableKeyboard)
{ {
hleKeyboardInput = controller.GetHLEKeyboardInput(); hleKeyboardInput = controller.GetHLEKeyboardInput();
} }
@ -181,15 +198,23 @@ namespace Ryujinx.Input.HLE
hleMotionStates.Add(motionState); hleMotionStates.Add(motionState);
} }
hleHid.Npads.Update(hleInputStates); _device.Hid.Npads.Update(hleInputStates);
hleHid.Npads.UpdateSixAxis(hleMotionStates); _device.Hid.Npads.UpdateSixAxis(hleMotionStates);
if (hleKeyboardInput.HasValue) if (hleKeyboardInput.HasValue)
{ {
hleHid.Keyboard.Update(hleKeyboardInput.Value); _device.Hid.Keyboard.Update(hleKeyboardInput.Value);
} }
tamperMachine.UpdateInput(hleInputStates); _device.TamperMachine.UpdateInput(hleInputStates);
}
}
internal InputConfig GetPlayerInputConfigByIndex(int index)
{
lock (_lock)
{
return _inputConfig.Find(x => x.PlayerIndex == (Ryujinx.Common.Configuration.Hid.PlayerIndex)index);
} }
} }

View File

@ -4,7 +4,7 @@ using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Configuration.Hid.Controller.Motion; using Ryujinx.Common.Configuration.Hid.Controller.Motion;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Configuration; using Ryujinx.Input.HLE;
using Ryujinx.Input.Motion.CemuHook.Protocol; using Ryujinx.Input.Motion.CemuHook.Protocol;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -29,9 +29,11 @@ namespace Ryujinx.Input.Motion.CemuHook
private readonly bool[] _clientErrorStatus = new bool[Enum.GetValues(typeof(PlayerIndex)).Length]; private readonly bool[] _clientErrorStatus = new bool[Enum.GetValues(typeof(PlayerIndex)).Length];
private readonly long[] _clientRetryTimer = new long[Enum.GetValues(typeof(PlayerIndex)).Length]; private readonly long[] _clientRetryTimer = new long[Enum.GetValues(typeof(PlayerIndex)).Length];
private NpadManager _npadManager;
public Client() public Client(NpadManager npadManager)
{ {
_npadManager = npadManager;
_hosts = new Dictionary<int, IPEndPoint>(); _hosts = new Dictionary<int, IPEndPoint>();
_motionData = new Dictionary<int, Dictionary<int, MotionInput>>(); _motionData = new Dictionary<int, Dictionary<int, MotionInput>>();
_clients = new Dictionary<int, UdpClient>(); _clients = new Dictionary<int, UdpClient>();
@ -323,7 +325,7 @@ namespace Ryujinx.Input.Motion.CemuHook
ulong timestamp = inputData.MotionTimestamp; ulong timestamp = inputData.MotionTimestamp;
InputConfig config = ConfigurationState.Instance.Hid.InputConfig.Value.Find(x => x.PlayerIndex == (PlayerIndex)clientId); InputConfig config = _npadManager.GetPlayerInputConfigByIndex(clientId);
lock (_motionData) lock (_motionData)
{ {

View File

@ -1,7 +1,6 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using System; using System;
using System.IO;
namespace Ryujinx.Configuration namespace Ryujinx.Configuration
{ {

View File

@ -131,7 +131,7 @@ namespace Ryujinx.Ui.Applet
public void ExecuteProgram(HLE.Switch device, ProgramSpecifyKind kind, ulong value) public void ExecuteProgram(HLE.Switch device, ProgramSpecifyKind kind, ulong value)
{ {
device.UserChannelPersistence.ExecuteProgram(kind, value); device.Configuration.UserChannelPersistence.ExecuteProgram(kind, value);
((MainWindow)_parent).RendererWidget?.Exit(); ((MainWindow)_parent).RendererWidget?.Exit();
} }

View File

@ -2,12 +2,14 @@ using ARMeilleure.Translation;
using ARMeilleure.Translation.PTC; using ARMeilleure.Translation.PTC;
using Gtk; using Gtk;
using LibHac.Common; using LibHac.Common;
using LibHac.FsSystem;
using LibHac.Ns; using LibHac.Ns;
using Ryujinx.Audio.Backends.Dummy; using Ryujinx.Audio.Backends.Dummy;
using Ryujinx.Audio.Backends.OpenAL; using Ryujinx.Audio.Backends.OpenAL;
using Ryujinx.Audio.Backends.SDL2; using Ryujinx.Audio.Backends.SDL2;
using Ryujinx.Audio.Backends.SoundIo; using Ryujinx.Audio.Backends.SoundIo;
using Ryujinx.Audio.Integration; using Ryujinx.Audio.Integration;
using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.System; using Ryujinx.Common.System;
@ -18,6 +20,7 @@ using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.Input.GTK3; using Ryujinx.Input.GTK3;
using Ryujinx.Input.HLE; using Ryujinx.Input.HLE;
using Ryujinx.Input.SDL2; using Ryujinx.Input.SDL2;
@ -166,6 +169,10 @@ namespace Ryujinx.Ui
RendererWidgetBase.StatusUpdatedEvent += Update_StatusBar; RendererWidgetBase.StatusUpdatedEvent += Update_StatusBar;
ConfigurationState.Instance.System.IgnoreMissingServices.Event += UpdateIgnoreMissingServicesState;
ConfigurationState.Instance.Graphics.AspectRatio.Event += UpdateAspectRatioState;
ConfigurationState.Instance.System.EnableDockedMode.Event += UpdateDockedModeState;
if (ConfigurationState.Instance.Ui.StartFullscreen) if (ConfigurationState.Instance.Ui.StartFullscreen)
{ {
_startFullScreen.Active = true; _startFullScreen.Active = true;
@ -236,6 +243,30 @@ namespace Ryujinx.Ui
InputManager = new InputManager(new GTK3KeyboardDriver(this), new SDL2GamepadDriver()); InputManager = new InputManager(new GTK3KeyboardDriver(this), new SDL2GamepadDriver());
} }
private void UpdateIgnoreMissingServicesState(object sender, ReactiveEventArgs<bool> args)
{
if (_emulationContext != null)
{
_emulationContext.Configuration.IgnoreMissingServices = args.NewValue;
}
}
private void UpdateAspectRatioState(object sender, ReactiveEventArgs<AspectRatio> args)
{
if (_emulationContext != null)
{
_emulationContext.Configuration.AspectRatio = args.NewValue;
}
}
private void UpdateDockedModeState(object sender, ReactiveEventArgs<bool> e)
{
if (_emulationContext != null)
{
_emulationContext.System.ChangeDockedModeState(e.NewValue);
}
}
private void WindowStateEvent_Changed(object o, WindowStateEventArgs args) private void WindowStateEvent_Changed(object o, WindowStateEventArgs args)
{ {
_fullScreen.Label = args.Event.NewWindowState.HasFlag(Gdk.WindowState.Fullscreen) ? "Exit Fullscreen" : "Enter Fullscreen"; _fullScreen.Label = args.Event.NewWindowState.HasFlag(Gdk.WindowState.Fullscreen) ? "Exit Fullscreen" : "Enter Fullscreen";
@ -380,19 +411,29 @@ namespace Ryujinx.Ui
? HLE.MemoryConfiguration.MemoryConfiguration6GB ? HLE.MemoryConfiguration.MemoryConfiguration6GB
: HLE.MemoryConfiguration.MemoryConfiguration4GB; : HLE.MemoryConfiguration.MemoryConfiguration4GB;
_emulationContext = new HLE.Switch( IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None;
_virtualFileSystem,
HLE.HLEConfiguration configuration = new HLE.HLEConfiguration(_virtualFileSystem,
_contentManager, _contentManager,
_accountManager, _accountManager,
_userChannelPersistence, _userChannelPersistence,
renderer, renderer,
deviceDriver, deviceDriver,
memoryConfiguration) memoryConfiguration,
{ _uiHandler,
UiHandler = _uiHandler (SystemLanguage)ConfigurationState.Instance.System.Language.Value,
}; (RegionCode)ConfigurationState.Instance.System.Region.Value,
ConfigurationState.Instance.Graphics.EnableVsync,
ConfigurationState.Instance.System.EnableDockedMode,
ConfigurationState.Instance.System.EnablePtc,
fsIntegrityCheckLevel,
ConfigurationState.Instance.System.FsGlobalAccessLogMode,
ConfigurationState.Instance.System.SystemTimeOffset,
ConfigurationState.Instance.System.TimeZone,
ConfigurationState.Instance.System.IgnoreMissingServices,
ConfigurationState.Instance.Graphics.AspectRatio);
_emulationContext.Initialize(); _emulationContext = new HLE.Switch(configuration);
} }
private void SetupProgressUiHandlers() private void SetupProgressUiHandlers()

View File

@ -73,8 +73,6 @@ namespace Ryujinx.Ui
NpadManager = _inputManager.CreateNpadManager(); NpadManager = _inputManager.CreateNpadManager();
_keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0"); _keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0");
NpadManager.ReloadConfiguration(ConfigurationState.Instance.Hid.InputConfig.Value.ToList());
WaitEvent = new ManualResetEvent(false); WaitEvent = new ManualResetEvent(false);
_glLogLevel = glLogLevel; _glLogLevel = glLogLevel;
@ -300,6 +298,8 @@ namespace Ryujinx.Ui
Device = device; Device = device;
Renderer = Device.Gpu.Renderer; Renderer = Device.Gpu.Renderer;
Renderer?.Window.SetSize(_windowWidth, _windowHeight); Renderer?.Window.SetSize(_windowWidth, _windowHeight);
NpadManager.Initialize(device, ConfigurationState.Instance.Hid.InputConfig, ConfigurationState.Instance.Hid.EnableKeyboard);
} }
public void Render() public void Render()
@ -488,7 +488,7 @@ namespace Ryujinx.Ui
}); });
} }
NpadManager.Update(Device.Hid, Device.TamperMachine); NpadManager.Update();
if (_isFocused) if (_isFocused)
{ {

View File

@ -1143,7 +1143,7 @@ namespace Ryujinx.Ui.Windows
if (_mainWindow.RendererWidget != null) if (_mainWindow.RendererWidget != null)
{ {
_mainWindow.RendererWidget.NpadManager.ReloadConfiguration(newConfig); _mainWindow.RendererWidget.NpadManager.ReloadConfiguration(newConfig, ConfigurationState.Instance.Hid.EnableKeyboard);
} }
// Atomically replace and signal input change. // Atomically replace and signal input change.

View File

@ -263,7 +263,7 @@ namespace Ryujinx.Ui.Windows
} }
_systemTimeZoneEntry.WidthChars = Math.Max(20, maxLocationLength + 1); // Ensure minimum Entry width _systemTimeZoneEntry.WidthChars = Math.Max(20, maxLocationLength + 1); // Ensure minimum Entry width
_systemTimeZoneEntry.Text = _timeZoneContentManager.SanityCheckDeviceLocationName(); _systemTimeZoneEntry.Text = _timeZoneContentManager.SanityCheckDeviceLocationName(ConfigurationState.Instance.System.TimeZone);
_systemTimeZoneCompletion.MatchFunc = TimeZoneMatchFunc; _systemTimeZoneCompletion.MatchFunc = TimeZoneMatchFunc;
@ -462,7 +462,7 @@ namespace Ryujinx.Ui.Windows
{ {
if (!_validTzRegions.Contains(_systemTimeZoneEntry.Text)) if (!_validTzRegions.Contains(_systemTimeZoneEntry.Text))
{ {
_systemTimeZoneEntry.Text = _timeZoneContentManager.SanityCheckDeviceLocationName(); _systemTimeZoneEntry.Text = _timeZoneContentManager.SanityCheckDeviceLocationName(ConfigurationState.Instance.System.TimeZone);
} }
} }