using ARMeilleure;
using Gommon;
using LibHac.Tools.FsSystem;
using Ryujinx.Ava.Systems.Configuration.System;
using Ryujinx.Ava.Systems.Configuration.UI;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.Helper;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE;
using System.Collections.Generic;
using System.Linq;
using RyuLogger = Ryujinx.Common.Logging.Logger;
namespace Ryujinx.Ava.Systems.Configuration
{
public partial class ConfigurationState
{
///
/// UI configuration section
///
public class UISection
{
public class Columns
{
public ReactiveObject FavColumn { get; private set; }
public ReactiveObject IconColumn { get; private set; }
public ReactiveObject AppColumn { get; private set; }
public ReactiveObject DevColumn { get; private set; }
public ReactiveObject VersionColumn { get; private set; }
public ReactiveObject LdnInfoColumn { get; private set; }
public ReactiveObject TimePlayedColumn { get; private set; }
public ReactiveObject LastPlayedColumn { get; private set; }
public ReactiveObject FileExtColumn { get; private set; }
public ReactiveObject FileSizeColumn { get; private set; }
public ReactiveObject PathColumn { get; private set; }
public Columns()
{
FavColumn = new ReactiveObject();
IconColumn = new ReactiveObject();
AppColumn = new ReactiveObject();
DevColumn = new ReactiveObject();
VersionColumn = new ReactiveObject();
LdnInfoColumn = new ReactiveObject();
TimePlayedColumn = new ReactiveObject();
LastPlayedColumn = new ReactiveObject();
FileExtColumn = new ReactiveObject();
FileSizeColumn = new ReactiveObject();
PathColumn = new ReactiveObject();
}
}
public class ColumnSortSettings
{
public ReactiveObject SortColumnId { get; private set; }
public ReactiveObject SortAscending { get; private set; }
public ColumnSortSettings()
{
SortColumnId = new ReactiveObject();
SortAscending = new ReactiveObject();
}
}
///
/// Used to toggle which file types are shown in the UI
///
public class ShownFileTypeSettings
{
public ReactiveObject NSP { get; private set; }
public ReactiveObject PFS0 { get; private set; }
public ReactiveObject XCI { get; private set; }
public ReactiveObject NCA { get; private set; }
public ReactiveObject NRO { get; private set; }
public ReactiveObject NSO { get; private set; }
public ShownFileTypeSettings()
{
NSP = new ReactiveObject();
PFS0 = new ReactiveObject();
XCI = new ReactiveObject();
NCA = new ReactiveObject();
NRO = new ReactiveObject();
NSO = new ReactiveObject();
}
}
//
/// Determines main window start-up position, size and state
///
public class WindowStartupSettings
{
public ReactiveObject WindowSizeWidth { get; private set; }
public ReactiveObject WindowSizeHeight { get; private set; }
public ReactiveObject WindowPositionX { get; private set; }
public ReactiveObject WindowPositionY { get; private set; }
public ReactiveObject WindowMaximized { get; private set; }
public WindowStartupSettings()
{
WindowSizeWidth = new ReactiveObject();
WindowSizeHeight = new ReactiveObject();
WindowPositionX = new ReactiveObject();
WindowPositionY = new ReactiveObject();
WindowMaximized = new ReactiveObject();
}
}
///
/// Used to toggle columns in the GUI
///
public Columns GuiColumns { get; private set; }
///
/// Used to configure column sort settings in the GUI
///
public ColumnSortSettings ColumnSort { get; private set; }
///
/// A list of directories containing games to be used to load games into the games list
///
public ReactiveObject> GameDirs { get; private set; }
///
/// A list of directories containing DLC/updates the user wants to autoload during library refreshes
///
public ReactiveObject> AutoloadDirs { get; private set; }
///
/// A list of file types to be hidden in the games List
///
public ShownFileTypeSettings ShownFileTypes { get; private set; }
///
/// Determines main window start-up position, size and state
///
public WindowStartupSettings WindowStartup { get; private set; }
///
/// Language Code for the UI
///
public ReactiveObject LanguageCode { get; private set; }
///
/// Selects the base style
///
public ReactiveObject BaseStyle { get; private set; }
///
/// Start games in fullscreen mode
///
public ReactiveObject StartFullscreen { get; private set; }
///
/// Start games with UI hidden
///
public ReactiveObject StartNoUI { get; private set; }
///
/// Hide / Show Console Window
///
public ReactiveObject ShowConsole { get; private set; }
///
/// View Mode of the Game list
///
public ReactiveObject GameListViewMode { get; private set; }
///
/// Show application name in Grid Mode
///
public ReactiveObject ShowNames { get; private set; }
///
/// Sets App Icon Size in Grid Mode
///
public ReactiveObject GridSize { get; private set; }
///
/// Sorts Apps in Grid Mode
///
public ReactiveObject ApplicationSort { get; private set; }
///
/// Sets if Grid is ordered in Ascending Order
///
public ReactiveObject IsAscendingOrder { get; private set; }
public UISection()
{
GuiColumns = new Columns();
ColumnSort = new ColumnSortSettings();
GameDirs = new ReactiveObject>();
AutoloadDirs = new ReactiveObject>();
ShownFileTypes = new ShownFileTypeSettings();
WindowStartup = new WindowStartupSettings();
BaseStyle = new ReactiveObject();
StartFullscreen = new ReactiveObject();
StartNoUI = new ReactiveObject();
GameListViewMode = new ReactiveObject();
ShowNames = new ReactiveObject();
GridSize = new ReactiveObject();
ApplicationSort = new ReactiveObject();
IsAscendingOrder = new ReactiveObject();
LanguageCode = new ReactiveObject();
ShowConsole = new ReactiveObject();
ShowConsole.Event += static (_, e) => ConsoleHelper.SetConsoleWindowState(e.NewValue);
}
}
///
/// Logger configuration section
///
public class LoggerSection
{
///
/// Enables printing debug log messages
///
public ReactiveObject EnableDebug { get; private set; }
///
/// Enables printing stub log messages
///
public ReactiveObject EnableStub { get; private set; }
///
/// Enables printing info log messages
///
public ReactiveObject EnableInfo { get; private set; }
///
/// Enables printing warning log messages
///
public ReactiveObject EnableWarn { get; private set; }
///
/// Enables printing error log messages
///
public ReactiveObject EnableError { get; private set; }
///
/// Enables printing trace log messages
///
public ReactiveObject EnableTrace { get; private set; }
///
/// Enables printing guest log messages
///
public ReactiveObject EnableGuest { get; private set; }
///
/// Enables printing FS access log messages
///
public ReactiveObject EnableFsAccessLog { get; private set; }
///
/// Enables log messages from Avalonia
///
public ReactiveObject EnableAvaloniaLog { get; private set; }
///
/// Controls which log messages are written to the log targets
///
public ReactiveObject FilteredClasses { get; private set; }
///
/// Enables or disables logging to a file on disk
///
public ReactiveObject EnableFileLog { get; private set; }
///
/// Controls which OpenGL log messages are recorded in the log
///
public ReactiveObject GraphicsDebugLevel { get; private set; }
public LoggerSection()
{
EnableDebug = new ReactiveObject();
EnableDebug.LogChangesToValue(nameof(EnableDebug));
EnableStub = new ReactiveObject();
EnableInfo = new ReactiveObject();
EnableWarn = new ReactiveObject();
EnableError = new ReactiveObject();
EnableTrace = new ReactiveObject();
EnableGuest = new ReactiveObject();
EnableFsAccessLog = new ReactiveObject();
EnableAvaloniaLog = new ReactiveObject();
FilteredClasses = new ReactiveObject();
EnableFileLog = new ReactiveObject();
EnableFileLog.LogChangesToValue(nameof(EnableFileLog));
GraphicsDebugLevel = new ReactiveObject();
}
}
///
/// System configuration section
///
public class SystemSection
{
///
/// Change System Language
///
public ReactiveObject Language { get; private set; }
///
/// Change System Region
///
public ReactiveObject Region { get; private set; }
///
/// Change System TimeZone
///
public ReactiveObject TimeZone { get; private set; }
///
/// System Time Offset in Seconds
///
public ReactiveObject SystemTimeOffset { get; private set; }
///
/// Instead of setting the time via configuration, use the values provided by the system.
///
public ReactiveObject MatchSystemTime { get; private set; }
///
/// Enable or disable use global input config (Independent from controllers binding)
///
public ReactiveObject UseInputGlobalConfig { get; private set; }
///
/// Enables or disables Docked Mode
///
public ReactiveObject EnableDockedMode { get; private set; }
///
/// Enables or disables persistent profiled translation cache
///
public ReactiveObject EnablePtc { get; private set; }
///
/// Clock tick scalar, in percent points (100 = 1.0).
///
public ReactiveObject TickScalar { get; set; }
///
/// Enables or disables low-power persistent profiled translation cache loading
///
public ReactiveObject EnableLowPowerPtc { get; private set; }
///
/// Enables or disables guest Internet access
///
public ReactiveObject EnableInternetAccess { get; private set; }
///
/// Enables integrity checks on Game content files
///
public ReactiveObject EnableFsIntegrityChecks { get; private set; }
public IntegrityCheckLevel IntegrityCheckLevel => EnableFsIntegrityChecks
? IntegrityCheckLevel.ErrorOnInvalid
: IntegrityCheckLevel.None;
///
/// Enables FS access log output to the console. Possible modes are 0-3
///
public ReactiveObject FsGlobalAccessLogMode { get; private set; }
///
/// The selected audio backend
///
public ReactiveObject AudioBackend { get; private set; }
///
/// The audio backend volume
///
public ReactiveObject AudioVolume { get; private set; }
///
/// The selected memory manager mode
///
public ReactiveObject MemoryManagerMode { get; private set; }
///
/// Defines the amount of RAM available on the emulated system, and how it is distributed
///
public ReactiveObject DramSize { get; private set; }
///
/// Enable or disable ignoring missing services
///
public ReactiveObject IgnoreMissingServices { get; private set; }
///
/// Ignore Controller Applet
///
public ReactiveObject IgnoreControllerApplet { get; private set; }
///
/// Skip User Profiles Manager
///
public ReactiveObject SkipUserProfilesManager { get; private set; }
///
/// Uses Hypervisor over JIT if available
///
public ReactiveObject UseHypervisor { get; private set; }
public SystemSection()
{
Language = new ReactiveObject();
Language.LogChangesToValue(nameof(Language));
Region = new ReactiveObject();
Region.LogChangesToValue(nameof(Region));
TimeZone = new ReactiveObject();
TimeZone.LogChangesToValue(nameof(TimeZone));
SystemTimeOffset = new ReactiveObject();
SystemTimeOffset.LogChangesToValue(nameof(SystemTimeOffset));
MatchSystemTime = new ReactiveObject();
MatchSystemTime.LogChangesToValue(nameof(MatchSystemTime));
UseInputGlobalConfig = new ReactiveObject();
UseInputGlobalConfig.LogChangesToValue(nameof(UseInputGlobalConfig));
EnableDockedMode = new ReactiveObject();
EnableDockedMode.LogChangesToValue(nameof(EnableDockedMode));
EnablePtc = new ReactiveObject();
EnablePtc.LogChangesToValue(nameof(EnablePtc));
EnableLowPowerPtc = new ReactiveObject();
EnableLowPowerPtc.LogChangesToValue(nameof(EnableLowPowerPtc));
EnableLowPowerPtc.Event += (_, evnt)
=> Optimizations.LowPower = evnt.NewValue;
TickScalar = new ReactiveObject();
TickScalar.LogChangesToValue(nameof(TickScalar));
TickScalar.Event += (_, evnt) =>
{
if (Switch.Shared is null)
return;
Switch.Shared.Configuration.TickScalar = evnt.NewValue;
};
EnableInternetAccess = new ReactiveObject();
EnableInternetAccess.LogChangesToValue(nameof(EnableInternetAccess));
EnableFsIntegrityChecks = new ReactiveObject();
EnableFsIntegrityChecks.LogChangesToValue(nameof(EnableFsIntegrityChecks));
FsGlobalAccessLogMode = new ReactiveObject();
FsGlobalAccessLogMode.LogChangesToValue(nameof(FsGlobalAccessLogMode));
AudioBackend = new ReactiveObject();
AudioBackend.LogChangesToValue(nameof(AudioBackend));
MemoryManagerMode = new ReactiveObject();
MemoryManagerMode.LogChangesToValue(nameof(MemoryManagerMode));
DramSize = new ReactiveObject();
DramSize.LogChangesToValue(nameof(DramSize));
IgnoreMissingServices = new ReactiveObject();
IgnoreMissingServices.LogChangesToValue(nameof(IgnoreMissingServices));
IgnoreControllerApplet = new ReactiveObject();
IgnoreControllerApplet.LogChangesToValue(nameof(IgnoreControllerApplet));
SkipUserProfilesManager = new ReactiveObject();
SkipUserProfilesManager.LogChangesToValue(nameof(SkipUserProfilesManager));
AudioVolume = new ReactiveObject();
AudioVolume.LogChangesToValue(nameof(AudioVolume));
UseHypervisor = new ReactiveObject();
UseHypervisor.LogChangesToValue(nameof(UseHypervisor));
}
}
///
/// Hid configuration section
///
public class HidSection
{
///
/// Enable or disable keyboard support (Independent from controllers binding)
///
public ReactiveObject EnableKeyboard { get; private set; }
///
/// Enable or disable mouse support (Independent from controllers binding)
///
public ReactiveObject EnableMouse { get; private set; }
///
/// Enable/disable the ability to control Ryujinx when it's not the currently focused window.
///
public ReactiveObject DisableInputWhenOutOfFocus { get; private set; }
///
/// Hotkey Keyboard Bindings
///
public ReactiveObject Hotkeys { get; private set; }
///
/// Input device configuration.
/// NOTE: This ReactiveObject won't issue an event when the List has elements added or removed.
/// TODO: Implement a ReactiveList class.
///
public ReactiveObject> InputConfig { get; private set; }
public ReactiveObject> UseInputGlobalConfig { get; private set; }
///
/// The speed of spectrum cycling for the Rainbow LED feature.
///
public ReactiveObject RainbowSpeed { get; }
public HidSection()
{
EnableKeyboard = new ReactiveObject();
EnableMouse = new ReactiveObject();
DisableInputWhenOutOfFocus = new ReactiveObject();
Hotkeys = new ReactiveObject();
InputConfig = new ReactiveObject>();
UseInputGlobalConfig = new ReactiveObject>();
RainbowSpeed = new ReactiveObject();
RainbowSpeed.Event += (_, args) => Rainbow.Speed = args.NewValue;
}
}
///
/// Graphics configuration section
///
public class GraphicsSection
{
///
/// Whether or not backend threading is enabled. The "Auto" setting will determine whether threading should be enabled at runtime.
///
public ReactiveObject BackendThreading { get; private set; }
///
/// Max Anisotropy. Values range from 0 - 16. Set to -1 to let the game decide.
///
public ReactiveObject MaxAnisotropy { get; private set; }
///
/// Aspect Ratio applied to the renderer window.
///
public ReactiveObject AspectRatio { get; private set; }
///
/// Resolution Scale. An integer scale applied to applicable render targets. Values 1-4, or -1 to use a custom floating point scale instead.
///
public ReactiveObject ResScale { get; private set; }
///
/// Custom Resolution Scale. A custom floating point scale applied to applicable render targets. Only active when Resolution Scale is -1.
///
public ReactiveObject ResScaleCustom { get; private set; }
///
/// Dumps shaders in this local directory
///
public ReactiveObject ShadersDumpPath { get; private set; }
///
/// Toggles the present interval mode. Options are Switch (60Hz), Unbounded (previously Vsync off), and Custom, if enabled.
///
public ReactiveObject VSyncMode { get; private set; }
///
/// Enables or disables the custom present interval mode.
///
public ReactiveObject EnableCustomVSyncInterval { get; private set; }
///
/// Changes the custom present interval.
///
public ReactiveObject CustomVSyncInterval { get; private set; }
///
/// Enables or disables Shader cache
///
public ReactiveObject EnableShaderCache { get; private set; }
///
/// Enables or disables texture recompression
///
public ReactiveObject EnableTextureRecompression { get; private set; }
///
/// Enables or disables Macro high-level emulation
///
public ReactiveObject EnableMacroHLE { get; private set; }
///
/// Enables or disables color space passthrough, if available.
///
public ReactiveObject EnableColorSpacePassthrough { get; private set; }
///
/// Graphics backend
///
public ReactiveObject GraphicsBackend { get; private set; }
///
/// Applies anti-aliasing to the renderer.
///
public ReactiveObject AntiAliasing { get; private set; }
///
/// Sets the framebuffer upscaling type.
///
public ReactiveObject ScalingFilter { get; private set; }
///
/// Sets the framebuffer upscaling level.
///
public ReactiveObject ScalingFilterLevel { get; private set; }
///
/// Preferred GPU
///
public ReactiveObject PreferredGpu { get; private set; }
public GraphicsSection()
{
BackendThreading = new ReactiveObject();
BackendThreading.LogChangesToValue(nameof(BackendThreading));
ResScale = new ReactiveObject();
ResScale.LogChangesToValue(nameof(ResScale));
ResScaleCustom = new ReactiveObject();
ResScaleCustom.LogChangesToValue(nameof(ResScaleCustom));
MaxAnisotropy = new ReactiveObject();
MaxAnisotropy.LogChangesToValue(nameof(MaxAnisotropy));
AspectRatio = new ReactiveObject();
AspectRatio.LogChangesToValue(nameof(AspectRatio));
ShadersDumpPath = new ReactiveObject();
VSyncMode = new ReactiveObject();
VSyncMode.LogChangesToValue(nameof(VSyncMode));
EnableCustomVSyncInterval = new ReactiveObject();
EnableCustomVSyncInterval.LogChangesToValue(nameof(EnableCustomVSyncInterval));
CustomVSyncInterval = new ReactiveObject();
CustomVSyncInterval.LogChangesToValue(nameof(CustomVSyncInterval));
EnableShaderCache = new ReactiveObject();
EnableShaderCache.LogChangesToValue(nameof(EnableShaderCache));
EnableTextureRecompression = new ReactiveObject();
EnableTextureRecompression.LogChangesToValue(nameof(EnableTextureRecompression));
GraphicsBackend = new ReactiveObject();
GraphicsBackend.LogChangesToValue(nameof(GraphicsBackend));
PreferredGpu = new ReactiveObject();
PreferredGpu.LogChangesToValue(nameof(PreferredGpu));
EnableMacroHLE = new ReactiveObject();
EnableMacroHLE.LogChangesToValue(nameof(EnableMacroHLE));
EnableColorSpacePassthrough = new ReactiveObject();
EnableColorSpacePassthrough.LogChangesToValue(nameof(EnableColorSpacePassthrough));
AntiAliasing = new ReactiveObject();
AntiAliasing.LogChangesToValue(nameof(AntiAliasing));
ScalingFilter = new ReactiveObject();
ScalingFilter.LogChangesToValue(nameof(ScalingFilter));
ScalingFilterLevel = new ReactiveObject();
ScalingFilterLevel.LogChangesToValue(nameof(ScalingFilterLevel));
}
}
///
/// Multiplayer configuration section
///
public class MultiplayerSection
{
///
/// GUID for the network interface used by LAN (or 0 for default)
///
public ReactiveObject LanInterfaceId { get; private set; }
///
/// Multiplayer Mode
///
public ReactiveObject Mode { get; private set; }
///
/// Disable P2P
///
public ReactiveObject DisableP2p { get; private set; }
///
/// LDN PassPhrase
///
public ReactiveObject LdnPassphrase { get; private set; }
///
/// LDN Server
///
public ReactiveObject LdnServer { get; private set; }
public string GetLdnServer()
{
string ldnServer = LdnServer;
return string.IsNullOrEmpty(ldnServer)
? SharedConstants.DefaultLanPlayHost
: ldnServer;
}
public MultiplayerSection()
{
LanInterfaceId = new ReactiveObject();
Mode = new ReactiveObject();
Mode.LogChangesToValue(nameof(MultiplayerMode));
DisableP2p = new ReactiveObject();
DisableP2p.LogChangesToValue(nameof(DisableP2p));
LdnPassphrase = new ReactiveObject();
LdnPassphrase.LogChangesToValue(nameof(LdnPassphrase));
LdnServer = new ReactiveObject();
LdnServer.LogChangesToValue(nameof(LdnServer));
}
}
public class HacksSection
{
///
/// Show toggles for dirty hacks in the UI.
///
public ReactiveObject ShowDirtyHacks { get; private set; }
public ReactiveObject Xc2MenuSoftlockFix { get; private set; }
public ReactiveObject DisableNifmIsAnyInternetRequestAccepted { get; private set; }
public HacksSection()
{
ShowDirtyHacks = new ReactiveObject();
Xc2MenuSoftlockFix = new ReactiveObject();
Xc2MenuSoftlockFix.Event += HackChanged;
DisableNifmIsAnyInternetRequestAccepted = new ReactiveObject();
DisableNifmIsAnyInternetRequestAccepted.Event += HackChanged;
}
private void HackChanged(object sender, ReactiveEventArgs rxe)
{
if (!ShowDirtyHacks)
return;
string newHacks = EnabledHacks.Select(x => x.Hack)
.JoinToString(", ");
if (newHacks != _lastHackCollection)
{
RyuLogger.Info?.Print(LogClass.Configuration,
$"EnabledDirtyHacks set to: [{newHacks}]", "LogValueChange");
_lastHackCollection = newHacks;
}
}
private static string _lastHackCollection;
public EnabledDirtyHack[] EnabledHacks
{
get
{
List enabledHacks = [];
if (Xc2MenuSoftlockFix)
Apply(DirtyHack.Xc2MenuSoftlockFix);
if (DisableNifmIsAnyInternetRequestAccepted)
Apply(DirtyHack.NifmServiceDisableIsAnyInternetRequestAccepted);
return enabledHacks.ToArray();
void Apply(DirtyHack hack, int value = 0)
{
enabledHacks.Add(new EnabledDirtyHack(hack, value));
}
}
}
}
///
/// The default configuration instance
///
public static ConfigurationState Instance { get; private set; }
public static ConfigurationState InstanceExtra{ get; private set; }
///
/// The UI section
///
public UISection UI { get; private set; }
///
/// The Logger section
///
public LoggerSection Logger { get; private set; }
///
/// The System section
///
public SystemSection System { get; private set; }
///
/// The Graphics section
///
public GraphicsSection Graphics { get; private set; }
///
/// The Hid section
///
public HidSection Hid { get; private set; }
///
/// The Multiplayer section
///
public MultiplayerSection Multiplayer { get; private set; }
///
/// The Dirty Hacks section
///
public HacksSection Hacks { get; private set; }
///
/// Enables or disables Discord Rich Presence
///
public ReactiveObject EnableDiscordIntegration { get; private set; }
///
/// Checks for updates when Ryujinx starts when enabled, either prompting when an update is found or just showing a notification.
///
public ReactiveObject UpdateCheckerType { get; private set; }
///
/// How the emulator should behave when you click off/on the window.
///
public ReactiveObject FocusLostActionType { get; private set; }
///
/// Show "Confirm Exit" Dialog
///
public ReactiveObject ShowConfirmExit { get; private set; }
///
/// Enables or disables save window size, position and state on close.
///
public ReactiveObject RememberWindowState { get; private set; }
///
/// Disable the new title bar layout & window layout changes.
///
public ReactiveObject ShowOldUI { get; private set; }
///
/// Enables hardware-accelerated rendering for Avalonia
///
public ReactiveObject EnableHardwareAcceleration { get; private set; }
///
/// Hide Cursor on Idle
///
public ReactiveObject HideCursor { get; private set; }
private ConfigurationState()
{
UI = new UISection();
Logger = new LoggerSection();
System = new SystemSection();
Graphics = new GraphicsSection();
Hid = new HidSection();
Multiplayer = new MultiplayerSection();
Hacks = new HacksSection();
UpdateCheckerType = new ReactiveObject();
FocusLostActionType = new ReactiveObject();
HideCursor = new ReactiveObject();
EnableDiscordIntegration = new ReactiveObject();
ShowConfirmExit = new ReactiveObject();
RememberWindowState = new ReactiveObject();
ShowOldUI = new ReactiveObject();
EnableHardwareAcceleration = new ReactiveObject();
}
public HleConfiguration CreateHleConfiguration() =>
new(
System.DramSize,
System.Language.Value.ToHLE(),
System.Region.Value.ToHLE(),
Graphics.VSyncMode,
System.EnableDockedMode,
System.EnablePtc,
System.TickScalar,
System.EnableInternetAccess,
System.EnableFsIntegrityChecks
? IntegrityCheckLevel.ErrorOnInvalid
: IntegrityCheckLevel.None,
System.FsGlobalAccessLogMode,
System.MatchSystemTime
? 0
: System.SystemTimeOffset,
System.TimeZone,
System.MemoryManagerMode,
System.IgnoreMissingServices,
Graphics.AspectRatio,
System.AudioVolume,
System.UseHypervisor,
Multiplayer.LanInterfaceId,
Multiplayer.Mode,
Multiplayer.DisableP2p,
Multiplayer.LdnPassphrase,
Multiplayer.GetLdnServer(),
Graphics.CustomVSyncInterval,
Hacks.ShowDirtyHacks ? Hacks.EnabledHacks : null);
}
}