diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 21dc3eb0b..aeb12a575 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -64,14 +64,9 @@ jobs:
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
- - name: Publish Ryujinx.Headless.SDL2
- run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained
- if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
-
- name: Set executable bit
run: |
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
- chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh
if: github.event_name == 'pull_request' && matrix.platform.os == 'ubuntu-latest'
- name: Build AppImage
@@ -119,13 +114,6 @@ jobs:
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}-AppImage
path: publish_appimage
- - name: Upload Ryujinx.Headless.SDL2 artifact
- uses: actions/upload-artifact@v4
- with:
- name: nogui-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}
- path: publish_sdl2_headless
- if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
-
build_macos:
name: macOS Universal (${{ matrix.configuration }})
runs-on: ubuntu-latest
@@ -171,20 +159,9 @@ jobs:
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp publish ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
- - name: Publish macOS Ryujinx.Headless.SDL2
- run: |
- ./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
-
- name: Upload Ryujinx artifact
uses: actions/upload-artifact@v4
with:
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
path: "publish/*.tar.gz"
if: github.event_name == 'pull_request'
-
- - name: Upload Ryujinx.Headless.SDL2 artifact
- uses: actions/upload-artifact@v4
- with:
- name: nogui-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
- path: "publish_headless/*.tar.gz"
- if: github.event_name == 'pull_request'
diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml
index c17b06046..a0653f540 100644
--- a/.github/workflows/canary.yml
+++ b/.github/workflows/canary.yml
@@ -116,7 +116,6 @@ jobs:
- name: Publish
run: |
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained
- dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained
- name: Packing Windows builds
if: matrix.platform.os == 'windows-latest'
@@ -125,11 +124,6 @@ jobs:
rm publish/libarmeilleure-jitsupport.dylib
7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
popd
-
- pushd publish_sdl2_headless
- rm publish/libarmeilleure-jitsupport.dylib
- 7z a ../release_output/nogui-ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
- popd
shell: bash
- name: Packing Linux builds
@@ -140,12 +134,6 @@ jobs:
chmod +x publish/Ryujinx.sh publish/Ryujinx
tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
popd
-
- pushd publish_sdl2_headless
- rm publish/libarmeilleure-jitsupport.dylib
- chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
- tar -czvf ../release_output/nogui-ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
- popd
shell: bash
#- name: Build AppImage (Linux)
@@ -191,7 +179,7 @@ jobs:
with:
name: ${{ steps.version_info.outputs.build_version }}
artifacts: "release_output/*.tar.gz,release_output/*.zip"
- #artifacts: "release_output/*.tar.gz,release_output/*.zip/*AppImage*"
+ #artifacts: "release_output/*.tar.gz,release_output/*.zip,release_output/*AppImage*"
tag: ${{ steps.version_info.outputs.build_version }}
body: |
# Canary builds:
@@ -262,15 +250,11 @@ jobs:
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1
- - name: Publish macOS Ryujinx.Headless.SDL2
- run: |
- ./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1
-
- name: Pushing new release
uses: ncipollo/release-action@v1
with:
name: "Canary ${{ steps.version_info.outputs.build_version }}"
- artifacts: "publish_ava/*.tar.gz, publish_headless/*.tar.gz"
+ artifacts: "publish_ava/*.tar.gz"
tag: ${{ steps.version_info.outputs.build_version }}
body: ""
omitBodyDuringUpdate: true
diff --git a/.github/workflows/nightly_pr_comment.yml b/.github/workflows/nightly_pr_comment.yml
index b9128f13d..6ca4710dc 100644
--- a/.github/workflows/nightly_pr_comment.yml
+++ b/.github/workflows/nightly_pr_comment.yml
@@ -38,21 +38,16 @@ jobs:
return core.error(`No artifacts found`);
}
let body = `Download the artifacts for this pull request:\n`;
- let hidden_headless_artifacts = `\n\n GUI-less
\n`;
let hidden_debug_artifacts = `\n\n Only for Developers
\n`;
for (const art of artifacts) {
const url = `https://github.com/Ryubing/Ryujinx/actions/runs/${run_id}/artifacts/${art.id}`;
if(art.name.includes('Debug')) {
hidden_debug_artifacts += `\n* [${art.name}](${url})`;
- } else if(art.name.includes('nogui-ryujinx')) {
- hidden_headless_artifacts += `\n* [${art.name}](${url})`;
} else {
body += `\n* [${art.name}](${url})`;
}
}
- hidden_headless_artifacts += `\n `;
hidden_debug_artifacts += `\n `;
- body += hidden_headless_artifacts;
body += hidden_debug_artifacts;
const {data: comments} = await github.rest.issues.listComments({repo, owner, issue_number});
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index a24b58a5d..584507d75 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -112,7 +112,6 @@ jobs:
- name: Publish
run: |
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained
- dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained
- name: Packing Windows builds
if: matrix.platform.os == 'windows-latest'
@@ -121,11 +120,6 @@ jobs:
rm libarmeilleure-jitsupport.dylib
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
popd
-
- pushd publish_sdl2_headless
- rm libarmeilleure-jitsupport.dylib
- 7z a ../release_output/nogui-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
- popd
shell: bash
- name: Build AppImage (Linux)
@@ -172,11 +166,6 @@ jobs:
chmod +x Ryujinx.sh Ryujinx
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
popd
-
- pushd publish_sdl2_headless
- chmod +x Ryujinx.sh Ryujinx.Headless.SDL2
- tar -czvf ../release_output/nogui-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
- popd
shell: bash
- name: Pushing new release
@@ -251,15 +240,11 @@ jobs:
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
- - name: Publish macOS Ryujinx.Headless.SDL2
- run: |
- ./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
-
- name: Pushing new release
uses: ncipollo/release-action@v1
with:
name: ${{ steps.version_info.outputs.build_version }}
- artifacts: "publish/*.tar.gz, publish_headless/*.tar.gz"
+ artifacts: "publish/*.tar.gz"
tag: ${{ steps.version_info.outputs.build_version }}
body: ""
omitBodyDuringUpdate: true
diff --git a/Ryujinx.sln b/Ryujinx.sln
index e9f57df39..87c1021c1 100644
--- a/Ryujinx.sln
+++ b/Ryujinx.sln
@@ -57,8 +57,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Headless.SDL2", "src\Ryujinx.Headless.SDL2\Ryujinx.Headless.SDL2.csproj", "{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
@@ -213,10 +211,6 @@ Global
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
- {390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.Build.0 = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/src/Ryujinx.Common/Logging/Logger.cs b/src/Ryujinx.Common/Logging/Logger.cs
index 26d343969..6ea6b7ac3 100644
--- a/src/Ryujinx.Common/Logging/Logger.cs
+++ b/src/Ryujinx.Common/Logging/Logger.cs
@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
@@ -157,21 +158,16 @@ namespace Ryujinx.Common.Logging
_time.Restart();
}
- private static ILogTarget GetTarget(string targetName)
- {
- foreach (var target in _logTargets)
- {
- if (target.Name.Equals(targetName))
- {
- return target;
- }
- }
-
- return null;
- }
+ private static ILogTarget GetTarget(string targetName)
+ => _logTargets.FirstOrDefault(target => target.Name.Equals(targetName));
public static void AddTarget(ILogTarget target)
{
+ if (_logTargets.Any(t => t.Name == target.Name))
+ {
+ return;
+ }
+
_logTargets.Add(target);
Updated += target.Log;
diff --git a/src/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs b/src/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs
index a9dbe646a..1fcfea4da 100644
--- a/src/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs
+++ b/src/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs
@@ -27,11 +27,7 @@ namespace Ryujinx.Common.Logging.Targets
private readonly int _overflowTimeout;
- string ILogTarget.Name { get => _target.Name; }
-
- public AsyncLogTargetWrapper(ILogTarget target)
- : this(target, -1)
- { }
+ string ILogTarget.Name => _target.Name;
public AsyncLogTargetWrapper(ILogTarget target, int queueLimit = -1, AsyncLogTargetOverflowAction overflowAction = AsyncLogTargetOverflowAction.Block)
{
diff --git a/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountSaveDataManager.cs b/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountSaveDataManager.cs
index b1ef0761c..aa57a0310 100644
--- a/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountSaveDataManager.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountSaveDataManager.cs
@@ -1,3 +1,4 @@
+using Gommon;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
@@ -6,12 +7,13 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
namespace Ryujinx.HLE.HOS.Services.Account.Acc
{
- class AccountSaveDataManager
+ public class AccountSaveDataManager
{
- private readonly string _profilesJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "Profiles.json");
+ private static readonly string _profilesJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "Profiles.json");
private static readonly ProfilesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
@@ -49,6 +51,16 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
}
}
+ public static Optional GetLastUsedUser()
+ {
+ ProfilesJson profilesJson = JsonHelper.DeserializeFromFile(_profilesJsonPath, _serializerContext.ProfilesJson);
+
+ return profilesJson.Profiles
+ .FindFirst(profile => profile.AccountState == AccountState.Open)
+ .Convert(profileJson => new UserProfile(new UserId(profileJson.UserId), profileJson.Name,
+ profileJson.Image, profileJson.LastModifiedTimestamp));
+ }
+
public void Save(ConcurrentDictionary profiles)
{
ProfilesJson profilesJson = new()
diff --git a/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj b/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj
deleted file mode 100644
index d39f2b481..000000000
--- a/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
-
- win-x64;osx-x64;linux-x64
- Exe
- true
- 1.0.0-dirty
- $(DefineConstants);$(ExtraDefineConstants)
- -
- true
- $(DefaultItemExcludes);._*
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Always
- THIRDPARTY.md
-
-
- Always
- LICENSE.txt
-
-
-
-
-
- Always
-
-
-
-
-
-
-
-
-
- false
- ..\Ryujinx\Ryujinx.ico
-
-
-
- true
- true
- partial
-
-
diff --git a/src/Ryujinx.Headless.SDL2/Ryujinx.bmp b/src/Ryujinx.Headless.SDL2/Ryujinx.bmp
deleted file mode 100644
index 1daa7ce94..000000000
Binary files a/src/Ryujinx.Headless.SDL2/Ryujinx.bmp and /dev/null differ
diff --git a/src/Ryujinx.UI.Common/Configuration/System/Language.cs b/src/Ryujinx.UI.Common/Configuration/System/Language.cs
index d1d395b00..8ca4e542b 100644
--- a/src/Ryujinx.UI.Common/Configuration/System/Language.cs
+++ b/src/Ryujinx.UI.Common/Configuration/System/Language.cs
@@ -1,4 +1,5 @@
using Ryujinx.Common.Utilities;
+using Ryujinx.HLE.HOS.SystemState;
using System.Text.Json.Serialization;
namespace Ryujinx.UI.Common.Configuration.System
diff --git a/src/Ryujinx.UI.Common/Helper/FileAssociationHelper.cs b/src/Ryujinx.UI.Common/Helper/FileAssociationHelper.cs
index 44860d080..b1463989d 100644
--- a/src/Ryujinx.UI.Common/Helper/FileAssociationHelper.cs
+++ b/src/Ryujinx.UI.Common/Helper/FileAssociationHelper.cs
@@ -132,7 +132,7 @@ namespace Ryujinx.UI.Common.Helper
if (uninstall)
{
- // If the types don't already exist, there's nothing to do and we can call this operation successful.
+ // If the types don't already exist, there's nothing to do, and we can call this operation successful.
if (!AreMimeTypesRegisteredWindows())
{
return true;
diff --git a/src/Ryujinx.Headless.SDL2/HeadlessDynamicTextInputHandler.cs b/src/Ryujinx/Headless/HeadlessDynamicTextInputHandler.cs
similarity index 97%
rename from src/Ryujinx.Headless.SDL2/HeadlessDynamicTextInputHandler.cs
rename to src/Ryujinx/Headless/HeadlessDynamicTextInputHandler.cs
index 40eb5ba98..2a507d2b7 100644
--- a/src/Ryujinx.Headless.SDL2/HeadlessDynamicTextInputHandler.cs
+++ b/src/Ryujinx/Headless/HeadlessDynamicTextInputHandler.cs
@@ -2,7 +2,7 @@ using Ryujinx.HLE.UI;
using System.Threading;
using System.Threading.Tasks;
-namespace Ryujinx.Headless.SDL2
+namespace Ryujinx.Headless
{
///
/// Headless text processing class, right now there is no way to forward the input to it.
diff --git a/src/Ryujinx.Headless.SDL2/HeadlessHostUiTheme.cs b/src/Ryujinx/Headless/HeadlessHostUiTheme.cs
similarity index 93%
rename from src/Ryujinx.Headless.SDL2/HeadlessHostUiTheme.cs
rename to src/Ryujinx/Headless/HeadlessHostUiTheme.cs
index 78cd43ae5..b5e1ce526 100644
--- a/src/Ryujinx.Headless.SDL2/HeadlessHostUiTheme.cs
+++ b/src/Ryujinx/Headless/HeadlessHostUiTheme.cs
@@ -1,6 +1,6 @@
using Ryujinx.HLE.UI;
-namespace Ryujinx.Headless.SDL2
+namespace Ryujinx.Headless
{
internal class HeadlessHostUiTheme : IHostUITheme
{
diff --git a/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs
new file mode 100644
index 000000000..ba84e53a5
--- /dev/null
+++ b/src/Ryujinx/Headless/HeadlessRyujinx.Init.cs
@@ -0,0 +1,367 @@
+using DiscordRPC;
+using LibHac.Tools.FsSystem;
+using Ryujinx.Audio.Backends.SDL2;
+using Ryujinx.Ava;
+using Ryujinx.Common.Configuration;
+using Ryujinx.Common.Configuration.Hid;
+using Ryujinx.Common.Configuration.Hid.Controller;
+using Ryujinx.Common.Configuration.Hid.Controller.Motion;
+using Ryujinx.Common.Configuration.Hid.Keyboard;
+using Ryujinx.Common.Logging;
+using Ryujinx.Common.Utilities;
+using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.GAL.Multithreading;
+using Ryujinx.Graphics.Metal;
+using Ryujinx.Graphics.OpenGL;
+using Ryujinx.Graphics.Vulkan;
+using Ryujinx.HLE;
+using Ryujinx.Input;
+using Ryujinx.UI.Common;
+using Ryujinx.UI.Common.Configuration;
+using Silk.NET.Vulkan;
+using System;
+using System.IO;
+using System.Text.Json;
+using System.Threading.Tasks;
+using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
+using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
+using Key = Ryujinx.Common.Configuration.Hid.Key;
+
+namespace Ryujinx.Headless
+{
+ public partial class HeadlessRyujinx
+ {
+ public static void Initialize()
+ {
+ // Ensure Discord presence timestamp begins at the absolute start of when Ryujinx is launched
+ DiscordIntegrationModule.StartedAt = Timestamps.Now;
+
+ // Delete backup files after updating.
+ Task.Run(Updater.CleanupUpdate);
+
+ // Hook unhandled exception and process exit events.
+ AppDomain.CurrentDomain.UnhandledException += (sender, e)
+ => Program.ProcessUnhandledException(sender, e.ExceptionObject as Exception, e.IsTerminating);
+ AppDomain.CurrentDomain.ProcessExit += (_, _) => Program.Exit();
+
+ // Initialize the configuration.
+ ConfigurationState.Initialize();
+
+ // Initialize Discord integration.
+ DiscordIntegrationModule.Initialize();
+
+ // Logging system information.
+ Program.PrintSystemInfo();
+ }
+
+ private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
+ {
+ if (inputId == null)
+ {
+ if (index == PlayerIndex.Player1)
+ {
+ Logger.Info?.Print(LogClass.Application, $"{index} not configured, defaulting to default keyboard.");
+
+ // Default to keyboard
+ inputId = "0";
+ }
+ else
+ {
+ Logger.Info?.Print(LogClass.Application, $"{index} not configured");
+
+ return null;
+ }
+ }
+
+ IGamepad gamepad = _inputManager.KeyboardDriver.GetGamepad(inputId);
+
+ bool isKeyboard = true;
+
+ if (gamepad == null)
+ {
+ gamepad = _inputManager.GamepadDriver.GetGamepad(inputId);
+ isKeyboard = false;
+
+ if (gamepad == null)
+ {
+ Logger.Error?.Print(LogClass.Application, $"{index} gamepad not found (\"{inputId}\")");
+
+ return null;
+ }
+ }
+
+ string gamepadName = gamepad.Name;
+
+ gamepad.Dispose();
+
+ InputConfig config;
+
+ if (inputProfileName == null || inputProfileName.Equals("default"))
+ {
+ if (isKeyboard)
+ {
+ config = new StandardKeyboardInputConfig
+ {
+ Version = InputConfig.CurrentVersion,
+ Backend = InputBackendType.WindowKeyboard,
+ Id = null,
+ ControllerType = ControllerType.JoyconPair,
+ LeftJoycon = new LeftJoyconCommonConfig
+ {
+ DpadUp = Key.Up,
+ DpadDown = Key.Down,
+ DpadLeft = Key.Left,
+ DpadRight = Key.Right,
+ ButtonMinus = Key.Minus,
+ ButtonL = Key.E,
+ ButtonZl = Key.Q,
+ ButtonSl = Key.Unbound,
+ ButtonSr = Key.Unbound,
+ },
+
+ LeftJoyconStick = new JoyconConfigKeyboardStick
+ {
+ StickUp = Key.W,
+ StickDown = Key.S,
+ StickLeft = Key.A,
+ StickRight = Key.D,
+ StickButton = Key.F,
+ },
+
+ RightJoycon = new RightJoyconCommonConfig
+ {
+ ButtonA = Key.Z,
+ ButtonB = Key.X,
+ ButtonX = Key.C,
+ ButtonY = Key.V,
+ ButtonPlus = Key.Plus,
+ ButtonR = Key.U,
+ ButtonZr = Key.O,
+ ButtonSl = Key.Unbound,
+ ButtonSr = Key.Unbound,
+ },
+
+ RightJoyconStick = new JoyconConfigKeyboardStick
+ {
+ StickUp = Key.I,
+ StickDown = Key.K,
+ StickLeft = Key.J,
+ StickRight = Key.L,
+ StickButton = Key.H,
+ },
+ };
+ }
+ else
+ {
+ bool isNintendoStyle = gamepadName.Contains("Nintendo");
+
+ config = new StandardControllerInputConfig
+ {
+ Version = InputConfig.CurrentVersion,
+ Backend = InputBackendType.GamepadSDL2,
+ Id = null,
+ ControllerType = ControllerType.JoyconPair,
+ DeadzoneLeft = 0.1f,
+ DeadzoneRight = 0.1f,
+ RangeLeft = 1.0f,
+ RangeRight = 1.0f,
+ TriggerThreshold = 0.5f,
+ LeftJoycon = new LeftJoyconCommonConfig
+ {
+ DpadUp = ConfigGamepadInputId.DpadUp,
+ DpadDown = ConfigGamepadInputId.DpadDown,
+ DpadLeft = ConfigGamepadInputId.DpadLeft,
+ DpadRight = ConfigGamepadInputId.DpadRight,
+ ButtonMinus = ConfigGamepadInputId.Minus,
+ ButtonL = ConfigGamepadInputId.LeftShoulder,
+ ButtonZl = ConfigGamepadInputId.LeftTrigger,
+ ButtonSl = ConfigGamepadInputId.Unbound,
+ ButtonSr = ConfigGamepadInputId.Unbound,
+ },
+
+ LeftJoyconStick = new JoyconConfigControllerStick
+ {
+ Joystick = ConfigStickInputId.Left,
+ StickButton = ConfigGamepadInputId.LeftStick,
+ InvertStickX = false,
+ InvertStickY = false,
+ Rotate90CW = false,
+ },
+
+ RightJoycon = new RightJoyconCommonConfig
+ {
+ ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B,
+ ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A,
+ ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y,
+ ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X,
+ ButtonPlus = ConfigGamepadInputId.Plus,
+ ButtonR = ConfigGamepadInputId.RightShoulder,
+ ButtonZr = ConfigGamepadInputId.RightTrigger,
+ ButtonSl = ConfigGamepadInputId.Unbound,
+ ButtonSr = ConfigGamepadInputId.Unbound,
+ },
+
+ RightJoyconStick = new JoyconConfigControllerStick
+ {
+ Joystick = ConfigStickInputId.Right,
+ StickButton = ConfigGamepadInputId.RightStick,
+ InvertStickX = false,
+ InvertStickY = false,
+ Rotate90CW = false,
+ },
+
+ Motion = new StandardMotionConfigController
+ {
+ MotionBackend = MotionInputBackendType.GamepadDriver,
+ EnableMotion = true,
+ Sensitivity = 100,
+ GyroDeadzone = 1,
+ },
+ Rumble = new RumbleConfigController
+ {
+ StrongRumble = 1f,
+ WeakRumble = 1f,
+ EnableRumble = false,
+ },
+ };
+ }
+ }
+ else
+ {
+ string profileBasePath;
+
+ if (isKeyboard)
+ {
+ profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "keyboard");
+ }
+ else
+ {
+ profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "controller");
+ }
+
+ string path = Path.Combine(profileBasePath, inputProfileName + ".json");
+
+ if (!File.Exists(path))
+ {
+ Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" not found for \"{inputId}\"");
+
+ return null;
+ }
+
+ try
+ {
+ config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig);
+ }
+ catch (JsonException)
+ {
+ Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" parsing failed for \"{inputId}\"");
+
+ return null;
+ }
+ }
+
+ config.Id = inputId;
+ config.PlayerIndex = index;
+
+ string inputTypeName = isKeyboard ? "Keyboard" : "Gamepad";
+
+ Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} configured with {inputTypeName} \"{config.Id}\"");
+
+ // If both stick ranges are 0 (usually indicative of an outdated profile load) then both sticks will be set to 1.0.
+ if (config is StandardControllerInputConfig controllerConfig)
+ {
+ if (controllerConfig.RangeLeft <= 0.0f && controllerConfig.RangeRight <= 0.0f)
+ {
+ controllerConfig.RangeLeft = 1.0f;
+ controllerConfig.RangeRight = 1.0f;
+
+ Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} stick range reset. Save the profile now to update your configuration");
+ }
+ }
+
+ return config;
+ }
+
+ private static IRenderer CreateRenderer(Options options, WindowBase window)
+ {
+ if (options.GraphicsBackend == GraphicsBackend.Vulkan && window is VulkanWindow vulkanWindow)
+ {
+ string preferredGpuId = string.Empty;
+ Vk api = Vk.GetApi();
+
+ if (!string.IsNullOrEmpty(options.PreferredGPUVendor))
+ {
+ string preferredGpuVendor = options.PreferredGPUVendor.ToLowerInvariant();
+ var devices = VulkanRenderer.GetPhysicalDevices(api);
+
+ foreach (var device in devices)
+ {
+ if (device.Vendor.ToLowerInvariant() == preferredGpuVendor)
+ {
+ preferredGpuId = device.Id;
+ break;
+ }
+ }
+ }
+
+ return new VulkanRenderer(
+ api,
+ (instance, vk) => new SurfaceKHR((ulong)(vulkanWindow.CreateWindowSurface(instance.Handle))),
+ vulkanWindow.GetRequiredInstanceExtensions,
+ preferredGpuId);
+ }
+
+ if (options.GraphicsBackend == GraphicsBackend.Metal && window is MetalWindow metalWindow && OperatingSystem.IsMacOS())
+ {
+ return new MetalRenderer(metalWindow.GetLayer);
+ }
+
+ return new OpenGLRenderer();
+ }
+
+ private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options)
+ {
+ BackendThreading threadingMode = options.BackendThreading;
+
+ bool threadedGAL = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
+
+ if (threadedGAL)
+ {
+ renderer = new ThreadedRenderer(renderer);
+ }
+
+ HLEConfiguration configuration = new(_virtualFileSystem,
+ _libHacHorizonManager,
+ _contentManager,
+ _accountManager,
+ _userChannelPersistence,
+ renderer,
+ new SDL2HardwareDeviceDriver(),
+ options.DramSize,
+ window,
+ options.SystemLanguage,
+ options.SystemRegion,
+ options.VSyncMode,
+ !options.DisableDockedMode,
+ !options.DisablePTC,
+ options.EnableInternetAccess,
+ !options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
+ options.FsGlobalAccessLogMode,
+ options.SystemTimeOffset,
+ options.SystemTimeZone,
+ options.MemoryManagerMode,
+ options.IgnoreMissingServices,
+ options.AspectRatio,
+ options.AudioVolume,
+ options.UseHypervisor ?? true,
+ options.MultiplayerLanInterfaceId,
+ Common.Configuration.Multiplayer.MultiplayerMode.Disabled,
+ false,
+ string.Empty,
+ string.Empty,
+ options.CustomVSyncInterval);
+
+ return new Switch(configuration);
+ }
+ }
+}
diff --git a/src/Ryujinx.Headless.SDL2/Program.cs b/src/Ryujinx/Headless/HeadlessRyujinx.cs
similarity index 53%
rename from src/Ryujinx.Headless.SDL2/Program.cs
rename to src/Ryujinx/Headless/HeadlessRyujinx.cs
index ea789095e..eabe72cbe 100644
--- a/src/Ryujinx.Headless.SDL2/Program.cs
+++ b/src/Ryujinx/Headless/HeadlessRyujinx.cs
@@ -1,13 +1,9 @@
using CommandLine;
using Gommon;
-using LibHac.Tools.FsSystem;
-using Ryujinx.Audio.Backends.SDL2;
+using Ryujinx.Ava;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
-using Ryujinx.Common.Configuration.Hid.Controller;
-using Ryujinx.Common.Configuration.Hid.Controller.Motion;
-using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Logging.Targets;
@@ -15,16 +11,12 @@ using Ryujinx.Common.SystemInterop;
using Ryujinx.Common.Utilities;
using Ryujinx.Cpu;
using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.Gpu.Shader;
using Ryujinx.Graphics.Metal;
using Ryujinx.Graphics.OpenGL;
using Ryujinx.Graphics.Vulkan;
using Ryujinx.Graphics.Vulkan.MoltenVK;
-using Ryujinx.Headless.SDL2.Metal;
-using Ryujinx.Headless.SDL2.OpenGL;
-using Ryujinx.Headless.SDL2.Vulkan;
using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
@@ -33,22 +25,16 @@ using Ryujinx.Input;
using Ryujinx.Input.HLE;
using Ryujinx.Input.SDL2;
using Ryujinx.SDL2.Common;
-using Silk.NET.Vulkan;
+using Ryujinx.UI.Common.Configuration;
using System;
using System.Collections.Generic;
using System.IO;
-using System.Text.Json;
using System.Threading;
-using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
-using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
-using Key = Ryujinx.Common.Configuration.Hid.Key;
-namespace Ryujinx.Headless.SDL2
+namespace Ryujinx.Headless
{
- class Program
+ public partial class HeadlessRyujinx
{
- public static string Version { get; private set; }
-
private static VirtualFileSystem _virtualFileSystem;
private static ContentManager _contentManager;
private static AccountManager _accountManager;
@@ -58,20 +44,18 @@ namespace Ryujinx.Headless.SDL2
private static Switch _emulationContext;
private static WindowBase _window;
private static WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution;
- private static List _inputConfiguration;
+ private static List _inputConfiguration = [];
private static bool _enableKeyboard;
private static bool _enableMouse;
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
- static void Main(string[] args)
+ public static void Entrypoint(string[] args)
{
- Version = ReleaseInformation.Version;
-
// Make process DPI aware for proper window sizing on high-res screens.
ForceDpiAware.Windows();
- Console.Title = $"Ryujinx Console {Version} (Headless SDL2)";
+ Console.Title = $"Ryujinx Console {Program.Version} (Headless)";
if (OperatingSystem.IsMacOS() || OperatingSystem.IsLinux())
{
@@ -99,7 +83,7 @@ namespace Ryujinx.Headless.SDL2
}
Parser.Default.ParseArguments(args)
- .WithParsed(Load)
+ .WithParsed(options => Load(args, options))
.WithNotParsed(errors =>
{
Logger.Error?.PrintMsg(LogClass.Application, "Error parsing command-line arguments:");
@@ -107,239 +91,81 @@ namespace Ryujinx.Headless.SDL2
errors.ForEach(err => Logger.Error?.PrintMsg(LogClass.Application, $" - {err.Tag}"));
});
}
-
- private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
+
+ public static void ReloadConfig(string customConfigPath = null)
{
- if (inputId == null)
+ string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName);
+ string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName);
+
+ string configurationPath = null;
+
+ // Now load the configuration as the other subsystems are now registered
+ if (customConfigPath != null && File.Exists(customConfigPath))
{
- if (index == PlayerIndex.Player1)
- {
- Logger.Info?.Print(LogClass.Application, $"{index} not configured, defaulting to default keyboard.");
-
- // Default to keyboard
- inputId = "0";
- }
- else
- {
- Logger.Info?.Print(LogClass.Application, $"{index} not configured");
-
- return null;
- }
+ configurationPath = customConfigPath;
+ }
+ else if (File.Exists(localConfigurationPath))
+ {
+ configurationPath = localConfigurationPath;
+ }
+ else if (File.Exists(appDataConfigurationPath))
+ {
+ configurationPath = appDataConfigurationPath;
}
- IGamepad gamepad = _inputManager.KeyboardDriver.GetGamepad(inputId);
-
- bool isKeyboard = true;
-
- if (gamepad == null)
+ if (configurationPath == null)
{
- gamepad = _inputManager.GamepadDriver.GetGamepad(inputId);
- isKeyboard = false;
+ // No configuration, we load the default values and save it to disk
+ configurationPath = appDataConfigurationPath;
+ Logger.Notice.Print(LogClass.Application, $"No configuration file found. Saving default configuration to: {configurationPath}");
- if (gamepad == null)
- {
- Logger.Error?.Print(LogClass.Application, $"{index} gamepad not found (\"{inputId}\")");
-
- return null;
- }
- }
-
- string gamepadName = gamepad.Name;
-
- gamepad.Dispose();
-
- InputConfig config;
-
- if (inputProfileName == null || inputProfileName.Equals("default"))
- {
- if (isKeyboard)
- {
- config = new StandardKeyboardInputConfig
- {
- Version = InputConfig.CurrentVersion,
- Backend = InputBackendType.WindowKeyboard,
- Id = null,
- ControllerType = ControllerType.JoyconPair,
- LeftJoycon = new LeftJoyconCommonConfig
- {
- DpadUp = Key.Up,
- DpadDown = Key.Down,
- DpadLeft = Key.Left,
- DpadRight = Key.Right,
- ButtonMinus = Key.Minus,
- ButtonL = Key.E,
- ButtonZl = Key.Q,
- ButtonSl = Key.Unbound,
- ButtonSr = Key.Unbound,
- },
-
- LeftJoyconStick = new JoyconConfigKeyboardStick
- {
- StickUp = Key.W,
- StickDown = Key.S,
- StickLeft = Key.A,
- StickRight = Key.D,
- StickButton = Key.F,
- },
-
- RightJoycon = new RightJoyconCommonConfig
- {
- ButtonA = Key.Z,
- ButtonB = Key.X,
- ButtonX = Key.C,
- ButtonY = Key.V,
- ButtonPlus = Key.Plus,
- ButtonR = Key.U,
- ButtonZr = Key.O,
- ButtonSl = Key.Unbound,
- ButtonSr = Key.Unbound,
- },
-
- RightJoyconStick = new JoyconConfigKeyboardStick
- {
- StickUp = Key.I,
- StickDown = Key.K,
- StickLeft = Key.J,
- StickRight = Key.L,
- StickButton = Key.H,
- },
- };
- }
- else
- {
- bool isNintendoStyle = gamepadName.Contains("Nintendo");
-
- config = new StandardControllerInputConfig
- {
- Version = InputConfig.CurrentVersion,
- Backend = InputBackendType.GamepadSDL2,
- Id = null,
- ControllerType = ControllerType.JoyconPair,
- DeadzoneLeft = 0.1f,
- DeadzoneRight = 0.1f,
- RangeLeft = 1.0f,
- RangeRight = 1.0f,
- TriggerThreshold = 0.5f,
- LeftJoycon = new LeftJoyconCommonConfig
- {
- DpadUp = ConfigGamepadInputId.DpadUp,
- DpadDown = ConfigGamepadInputId.DpadDown,
- DpadLeft = ConfigGamepadInputId.DpadLeft,
- DpadRight = ConfigGamepadInputId.DpadRight,
- ButtonMinus = ConfigGamepadInputId.Minus,
- ButtonL = ConfigGamepadInputId.LeftShoulder,
- ButtonZl = ConfigGamepadInputId.LeftTrigger,
- ButtonSl = ConfigGamepadInputId.Unbound,
- ButtonSr = ConfigGamepadInputId.Unbound,
- },
-
- LeftJoyconStick = new JoyconConfigControllerStick
- {
- Joystick = ConfigStickInputId.Left,
- StickButton = ConfigGamepadInputId.LeftStick,
- InvertStickX = false,
- InvertStickY = false,
- Rotate90CW = false,
- },
-
- RightJoycon = new RightJoyconCommonConfig
- {
- ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B,
- ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A,
- ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y,
- ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X,
- ButtonPlus = ConfigGamepadInputId.Plus,
- ButtonR = ConfigGamepadInputId.RightShoulder,
- ButtonZr = ConfigGamepadInputId.RightTrigger,
- ButtonSl = ConfigGamepadInputId.Unbound,
- ButtonSr = ConfigGamepadInputId.Unbound,
- },
-
- RightJoyconStick = new JoyconConfigControllerStick
- {
- Joystick = ConfigStickInputId.Right,
- StickButton = ConfigGamepadInputId.RightStick,
- InvertStickX = false,
- InvertStickY = false,
- Rotate90CW = false,
- },
-
- Motion = new StandardMotionConfigController
- {
- MotionBackend = MotionInputBackendType.GamepadDriver,
- EnableMotion = true,
- Sensitivity = 100,
- GyroDeadzone = 1,
- },
- Rumble = new RumbleConfigController
- {
- StrongRumble = 1f,
- WeakRumble = 1f,
- EnableRumble = false,
- },
- };
- }
+ ConfigurationState.Instance.LoadDefault();
+ ConfigurationState.Instance.ToFileFormat().SaveConfig(configurationPath);
}
else
{
- string profileBasePath;
+ Logger.Notice.Print(LogClass.Application, $"Loading configuration from: {configurationPath}");
- if (isKeyboard)
+ if (ConfigurationFileFormat.TryLoad(configurationPath, out ConfigurationFileFormat configurationFileFormat))
{
- profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "keyboard");
+ ConfigurationState.Instance.Load(configurationFileFormat, configurationPath);
}
else
{
- profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "controller");
- }
+ Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location: {configurationPath}");
- string path = Path.Combine(profileBasePath, inputProfileName + ".json");
-
- if (!File.Exists(path))
- {
- Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" not found for \"{inputId}\"");
-
- return null;
- }
-
- try
- {
- config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig);
- }
- catch (JsonException)
- {
- Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" parsing failed for \"{inputId}\"");
-
- return null;
+ ConfigurationState.Instance.LoadDefault();
}
}
-
- config.Id = inputId;
- config.PlayerIndex = index;
-
- string inputTypeName = isKeyboard ? "Keyboard" : "Gamepad";
-
- Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} configured with {inputTypeName} \"{config.Id}\"");
-
- // If both stick ranges are 0 (usually indicative of an outdated profile load) then both sticks will be set to 1.0.
- if (config is StandardControllerInputConfig controllerConfig)
- {
- if (controllerConfig.RangeLeft <= 0.0f && controllerConfig.RangeRight <= 0.0f)
- {
- controllerConfig.RangeLeft = 1.0f;
- controllerConfig.RangeRight = 1.0f;
-
- Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} stick range reset. Save the profile now to update your configuration");
- }
- }
-
- return config;
}
- static void Load(Options option)
+ static void Load(string[] originalArgs, Options option)
{
- AppDataManager.Initialize(option.BaseDataDir);
+ Initialize();
+ bool useLastUsedProfile = false;
+
+ if (option.InheritConfig)
+ {
+ option.InheritMainConfig(originalArgs, ConfigurationState.Instance, out useLastUsedProfile);
+ }
+
+ AppDataManager.Initialize(option.BaseDataDir);
+
+ if (useLastUsedProfile && AccountSaveDataManager.GetLastUsedUser().TryGet(out var profile))
+ option.UserProfile = profile.Name;
+
+ // Check if keys exists.
+ if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")))
+ {
+ if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys"))))
+ {
+ Logger.Error?.Print(LogClass.Application, "Keys not found");
+ }
+ }
+
+ ReloadConfig();
+
_virtualFileSystem = VirtualFileSystem.CreateInstance();
_libHacHorizonManager = new LibHacHorizonManager();
@@ -354,7 +180,7 @@ namespace Ryujinx.Headless.SDL2
_inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver());
- GraphicsConfig.EnableShaderCache = true;
+ GraphicsConfig.EnableShaderCache = !option.DisableShaderCache;
if (OperatingSystem.IsMacOS())
{
@@ -365,15 +191,13 @@ namespace Ryujinx.Headless.SDL2
}
}
- IGamepad gamepad;
-
if (option.ListInputIds)
{
Logger.Info?.Print(LogClass.Application, "Input Ids:");
foreach (string id in _inputManager.KeyboardDriver.GamepadsIds)
{
- gamepad = _inputManager.KeyboardDriver.GetGamepad(id);
+ IGamepad gamepad = _inputManager.KeyboardDriver.GetGamepad(id);
Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")");
@@ -382,7 +206,7 @@ namespace Ryujinx.Headless.SDL2
foreach (string id in _inputManager.GamepadDriver.GamepadsIds)
{
- gamepad = _inputManager.GamepadDriver.GetGamepad(id);
+ IGamepad gamepad = _inputManager.GamepadDriver.GetGamepad(id);
Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")");
@@ -399,7 +223,7 @@ namespace Ryujinx.Headless.SDL2
return;
}
- _inputConfiguration = new List();
+ _inputConfiguration ??= [];
_enableKeyboard = option.EnableKeyboard;
_enableMouse = option.EnableMouse;
@@ -412,9 +236,9 @@ namespace Ryujinx.Headless.SDL2
_inputConfiguration.Add(inputConfig);
}
}
-
+
LoadPlayerConfiguration(option.InputProfile1Name, option.InputId1, PlayerIndex.Player1);
- LoadPlayerConfiguration(option.InputProfile2Name, option.InputId2, PlayerIndex.Player2);
+ LoadPlayerConfiguration(option.InputProfile2Name, option.InputId2, PlayerIndex.Player2);
LoadPlayerConfiguration(option.InputProfile3Name, option.InputId3, PlayerIndex.Player3);
LoadPlayerConfiguration(option.InputProfile4Name, option.InputId4, PlayerIndex.Player4);
LoadPlayerConfiguration(option.InputProfile5Name, option.InputId5, PlayerIndex.Player5);
@@ -422,6 +246,7 @@ namespace Ryujinx.Headless.SDL2
LoadPlayerConfiguration(option.InputProfile7Name, option.InputId7, PlayerIndex.Player7);
LoadPlayerConfiguration(option.InputProfile8Name, option.InputId8, PlayerIndex.Player8);
LoadPlayerConfiguration(option.InputProfileHandheldName, option.InputIdHandheld, PlayerIndex.Handheld);
+
if (_inputConfiguration.Count == 0)
{
@@ -433,7 +258,7 @@ namespace Ryujinx.Headless.SDL2
Logger.SetEnable(LogLevel.Stub, !option.LoggingDisableStub);
Logger.SetEnable(LogLevel.Info, !option.LoggingDisableInfo);
Logger.SetEnable(LogLevel.Warning, !option.LoggingDisableWarning);
- Logger.SetEnable(LogLevel.Error, option.LoggingEnableError);
+ Logger.SetEnable(LogLevel.Error, !option.LoggingDisableError);
Logger.SetEnable(LogLevel.Trace, option.LoggingEnableTrace);
Logger.SetEnable(LogLevel.Guest, !option.LoggingDisableGuest);
Logger.SetEnable(LogLevel.AccessLog, option.LoggingEnableFsAccessLog);
@@ -522,88 +347,6 @@ namespace Ryujinx.Headless.SDL2
};
}
- private static IRenderer CreateRenderer(Options options, WindowBase window)
- {
- if (options.GraphicsBackend == GraphicsBackend.Vulkan && window is VulkanWindow vulkanWindow)
- {
- string preferredGpuId = string.Empty;
- Vk api = Vk.GetApi();
-
- if (!string.IsNullOrEmpty(options.PreferredGPUVendor))
- {
- string preferredGpuVendor = options.PreferredGPUVendor.ToLowerInvariant();
- var devices = VulkanRenderer.GetPhysicalDevices(api);
-
- foreach (var device in devices)
- {
- if (device.Vendor.ToLowerInvariant() == preferredGpuVendor)
- {
- preferredGpuId = device.Id;
- break;
- }
- }
- }
-
- return new VulkanRenderer(
- api,
- (instance, vk) => new SurfaceKHR((ulong)(vulkanWindow.CreateWindowSurface(instance.Handle))),
- vulkanWindow.GetRequiredInstanceExtensions,
- preferredGpuId);
- }
-
- if (options.GraphicsBackend == GraphicsBackend.Metal && window is MetalWindow metalWindow && OperatingSystem.IsMacOS())
- {
- return new MetalRenderer(metalWindow.GetLayer);
- }
-
- return new OpenGLRenderer();
- }
-
- private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options)
- {
- BackendThreading threadingMode = options.BackendThreading;
-
- bool threadedGAL = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
-
- if (threadedGAL)
- {
- renderer = new ThreadedRenderer(renderer);
- }
-
- HLEConfiguration configuration = new(_virtualFileSystem,
- _libHacHorizonManager,
- _contentManager,
- _accountManager,
- _userChannelPersistence,
- renderer,
- new SDL2HardwareDeviceDriver(),
- options.DramSize,
- window,
- options.SystemLanguage,
- options.SystemRegion,
- options.VSyncMode,
- !options.DisableDockedMode,
- !options.DisablePTC,
- options.EnableInternetAccess,
- !options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
- options.FsGlobalAccessLogMode,
- options.SystemTimeOffset,
- options.SystemTimeZone,
- options.MemoryManagerMode,
- options.IgnoreMissingServices,
- options.AspectRatio,
- options.AudioVolume,
- options.UseHypervisor ?? true,
- options.MultiplayerLanInterfaceId,
- Common.Configuration.Multiplayer.MultiplayerMode.Disabled,
- false,
- string.Empty,
- string.Empty,
- options.CustomVSyncInterval);
-
- return new Switch(configuration);
- }
-
private static void ExecutionEntrypoint()
{
if (OperatingSystem.IsWindows())
diff --git a/src/Ryujinx.Headless.SDL2/Metal/MetalWindow.cs b/src/Ryujinx/Headless/Metal/MetalWindow.cs
similarity index 97%
rename from src/Ryujinx.Headless.SDL2/Metal/MetalWindow.cs
rename to src/Ryujinx/Headless/Metal/MetalWindow.cs
index 5140d639b..a2693c69d 100644
--- a/src/Ryujinx.Headless.SDL2/Metal/MetalWindow.cs
+++ b/src/Ryujinx/Headless/Metal/MetalWindow.cs
@@ -5,7 +5,7 @@ using SharpMetal.QuartzCore;
using System.Runtime.Versioning;
using static SDL2.SDL;
-namespace Ryujinx.Headless.SDL2.Metal
+namespace Ryujinx.Headless
{
[SupportedOSPlatform("macos")]
class MetalWindow : WindowBase
diff --git a/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs b/src/Ryujinx/Headless/OpenGL/OpenGLWindow.cs
similarity index 99%
rename from src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs
rename to src/Ryujinx/Headless/OpenGL/OpenGLWindow.cs
index 8c4854a11..c00a0648f 100644
--- a/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs
+++ b/src/Ryujinx/Headless/OpenGL/OpenGLWindow.cs
@@ -7,7 +7,7 @@ using Ryujinx.Input.HLE;
using System;
using static SDL2.SDL;
-namespace Ryujinx.Headless.SDL2.OpenGL
+namespace Ryujinx.Headless
{
class OpenGLWindow : WindowBase
{
diff --git a/src/Ryujinx.Headless.SDL2/Options.cs b/src/Ryujinx/Headless/Options.cs
similarity index 63%
rename from src/Ryujinx.Headless.SDL2/Options.cs
rename to src/Ryujinx/Headless/Options.cs
index 4e2ad5b58..0dd4216f0 100644
--- a/src/Ryujinx.Headless.SDL2/Options.cs
+++ b/src/Ryujinx/Headless/Options.cs
@@ -1,13 +1,168 @@
using CommandLine;
+using Gommon;
using Ryujinx.Common.Configuration;
+using Ryujinx.Common.Configuration.Hid;
using Ryujinx.HLE;
+using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.SystemState;
+using Ryujinx.UI.Common.Configuration;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
-namespace Ryujinx.Headless.SDL2
+namespace Ryujinx.Headless
{
public class Options
{
+ public void InheritMainConfig(string[] originalArgs, ConfigurationState configurationState, out bool needsProfileSet)
+ {
+ needsProfileSet = NeedsOverride(nameof(UserProfile));
+
+ if (NeedsOverride(nameof(IsFullscreen)))
+ IsFullscreen = configurationState.UI.StartFullscreen;
+
+ if (NeedsOverride(nameof(EnableKeyboard)))
+ EnableKeyboard = configurationState.Hid.EnableKeyboard;
+
+ if (NeedsOverride(nameof(EnableMouse)))
+ EnableMouse = configurationState.Hid.EnableMouse;
+
+ if (NeedsOverride(nameof(HideCursorMode)))
+ HideCursorMode = configurationState.HideCursor;
+
+ if (NeedsOverride(nameof(DisablePTC)))
+ DisablePTC = !configurationState.System.EnablePtc;
+
+ if (NeedsOverride(nameof(EnableInternetAccess)))
+ EnableInternetAccess = configurationState.System.EnableInternetAccess;
+
+ if (NeedsOverride(nameof(DisableFsIntegrityChecks)))
+ DisableFsIntegrityChecks = configurationState.System.EnableFsIntegrityChecks;
+
+ if (NeedsOverride(nameof(FsGlobalAccessLogMode)))
+ FsGlobalAccessLogMode = configurationState.System.FsGlobalAccessLogMode;
+
+ if (NeedsOverride(nameof(VSyncMode)))
+ VSyncMode = configurationState.Graphics.VSyncMode;
+
+ if (NeedsOverride(nameof(CustomVSyncInterval)))
+ CustomVSyncInterval = configurationState.Graphics.CustomVSyncInterval;
+
+ if (NeedsOverride(nameof(DisableShaderCache)))
+ DisableShaderCache = !configurationState.Graphics.EnableShaderCache;
+
+ if (NeedsOverride(nameof(EnableTextureRecompression)))
+ EnableTextureRecompression = configurationState.Graphics.EnableTextureRecompression;
+
+ if (NeedsOverride(nameof(DisableDockedMode)))
+ DisableDockedMode = !configurationState.System.EnableDockedMode;
+
+ if (NeedsOverride(nameof(SystemLanguage)))
+ SystemLanguage = (SystemLanguage)(int)configurationState.System.Language.Value;
+
+ if (NeedsOverride(nameof(SystemRegion)))
+ SystemRegion = (RegionCode)(int)configurationState.System.Region.Value;
+
+ if (NeedsOverride(nameof(SystemTimeZone)))
+ SystemTimeZone = configurationState.System.TimeZone;
+
+ if (NeedsOverride(nameof(SystemTimeOffset)))
+ SystemTimeOffset = configurationState.System.SystemTimeOffset;
+
+ if (NeedsOverride(nameof(MemoryManagerMode)))
+ MemoryManagerMode = configurationState.System.MemoryManagerMode;
+
+ if (NeedsOverride(nameof(AudioVolume)))
+ AudioVolume = configurationState.System.AudioVolume;
+
+ if (NeedsOverride(nameof(UseHypervisor)) && OperatingSystem.IsMacOS())
+ UseHypervisor = configurationState.System.UseHypervisor;
+
+ if (NeedsOverride(nameof(MultiplayerLanInterfaceId)))
+ MultiplayerLanInterfaceId = configurationState.Multiplayer.LanInterfaceId;
+
+ if (NeedsOverride(nameof(DisableFileLog)))
+ DisableFileLog = !configurationState.Logger.EnableFileLog;
+
+ if (NeedsOverride(nameof(LoggingEnableDebug)))
+ LoggingEnableDebug = configurationState.Logger.EnableDebug;
+
+ if (NeedsOverride(nameof(LoggingDisableStub)))
+ LoggingDisableStub = !configurationState.Logger.EnableStub;
+
+ if (NeedsOverride(nameof(LoggingDisableInfo)))
+ LoggingDisableInfo = !configurationState.Logger.EnableInfo;
+
+ if (NeedsOverride(nameof(LoggingDisableWarning)))
+ LoggingDisableWarning = !configurationState.Logger.EnableWarn;
+
+ if (NeedsOverride(nameof(LoggingDisableError)))
+ LoggingDisableError = !configurationState.Logger.EnableError;
+
+ if (NeedsOverride(nameof(LoggingEnableTrace)))
+ LoggingEnableTrace = configurationState.Logger.EnableTrace;
+
+ if (NeedsOverride(nameof(LoggingDisableGuest)))
+ LoggingDisableGuest = !configurationState.Logger.EnableGuest;
+
+ if (NeedsOverride(nameof(LoggingEnableFsAccessLog)))
+ LoggingEnableFsAccessLog = configurationState.Logger.EnableFsAccessLog;
+
+ if (NeedsOverride(nameof(LoggingGraphicsDebugLevel)))
+ LoggingGraphicsDebugLevel = configurationState.Logger.GraphicsDebugLevel;
+
+ if (NeedsOverride(nameof(ResScale)))
+ ResScale = configurationState.Graphics.ResScale;
+
+ if (NeedsOverride(nameof(MaxAnisotropy)))
+ MaxAnisotropy = configurationState.Graphics.MaxAnisotropy;
+
+ if (NeedsOverride(nameof(AspectRatio)))
+ AspectRatio = configurationState.Graphics.AspectRatio;
+
+ if (NeedsOverride(nameof(BackendThreading)))
+ BackendThreading = configurationState.Graphics.BackendThreading;
+
+ if (NeedsOverride(nameof(DisableMacroHLE)))
+ DisableMacroHLE = !configurationState.Graphics.EnableMacroHLE;
+
+ if (NeedsOverride(nameof(GraphicsShadersDumpPath)))
+ GraphicsShadersDumpPath = configurationState.Graphics.ShadersDumpPath;
+
+ if (NeedsOverride(nameof(GraphicsBackend)))
+ GraphicsBackend = configurationState.Graphics.GraphicsBackend;
+
+ if (NeedsOverride(nameof(AntiAliasing)))
+ AntiAliasing = configurationState.Graphics.AntiAliasing;
+
+ if (NeedsOverride(nameof(ScalingFilter)))
+ ScalingFilter = configurationState.Graphics.ScalingFilter;
+
+ if (NeedsOverride(nameof(ScalingFilterLevel)))
+ ScalingFilterLevel = configurationState.Graphics.ScalingFilterLevel;
+
+ if (NeedsOverride(nameof(DramSize)))
+ DramSize = configurationState.System.DramSize;
+
+ if (NeedsOverride(nameof(IgnoreMissingServices)))
+ IgnoreMissingServices = configurationState.System.IgnoreMissingServices;
+
+ if (NeedsOverride(nameof(IgnoreControllerApplet)))
+ IgnoreControllerApplet = configurationState.IgnoreApplet;
+
+ return;
+
+ bool NeedsOverride(string argKey) => originalArgs.None(arg => arg.TrimStart('-').EqualsIgnoreCase(OptionName(argKey)));
+
+ string OptionName(string propertyName) =>
+ typeof(Options)!.GetProperty(propertyName)!.GetCustomAttribute()!.LongName;
+ }
+
// General
+
+ [Option("use-main-config", Required = false, Default = false, HelpText = "Use the settings from what was configured via the UI.")]
+ public bool InheritConfig { get; set; }
[Option("root-data-dir", Required = false, HelpText = "Set the custom folder path for Ryujinx data.")]
public string BaseDataDir { get; set; }
@@ -172,7 +327,7 @@ namespace Ryujinx.Headless.SDL2
public bool LoggingDisableWarning { get; set; }
[Option("disable-error-logs", Required = false, HelpText = "Disables printing error log messages.")]
- public bool LoggingEnableError { get; set; }
+ public bool LoggingDisableError { get; set; }
[Option("enable-trace-logs", Required = false, Default = false, HelpText = "Enables printing trace log messages.")]
public bool LoggingEnableTrace { get; set; }
diff --git a/src/Ryujinx/Headless/Ryujinx.bmp b/src/Ryujinx/Headless/Ryujinx.bmp
new file mode 100644
index 000000000..36bf2f8ac
Binary files /dev/null and b/src/Ryujinx/Headless/Ryujinx.bmp differ
diff --git a/src/Ryujinx.Headless.SDL2/StatusUpdatedEventArgs.cs b/src/Ryujinx/Headless/StatusUpdatedEventArgs.cs
similarity index 94%
rename from src/Ryujinx.Headless.SDL2/StatusUpdatedEventArgs.cs
rename to src/Ryujinx/Headless/StatusUpdatedEventArgs.cs
index c1dd3805f..6c76a43a1 100644
--- a/src/Ryujinx.Headless.SDL2/StatusUpdatedEventArgs.cs
+++ b/src/Ryujinx/Headless/StatusUpdatedEventArgs.cs
@@ -1,6 +1,6 @@
using System;
-namespace Ryujinx.Headless.SDL2
+namespace Ryujinx.Headless
{
class StatusUpdatedEventArgs(
string vSyncMode,
diff --git a/src/Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs b/src/Ryujinx/Headless/Vulkan/VulkanWindow.cs
similarity index 98%
rename from src/Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs
rename to src/Ryujinx/Headless/Vulkan/VulkanWindow.cs
index b88e0fe83..92caad34e 100644
--- a/src/Ryujinx.Headless.SDL2/Vulkan/VulkanWindow.cs
+++ b/src/Ryujinx/Headless/Vulkan/VulkanWindow.cs
@@ -6,7 +6,7 @@ using System;
using System.Runtime.InteropServices;
using static SDL2.SDL;
-namespace Ryujinx.Headless.SDL2.Vulkan
+namespace Ryujinx.Headless
{
class VulkanWindow : WindowBase
{
diff --git a/src/Ryujinx.Headless.SDL2/WindowBase.cs b/src/Ryujinx/Headless/WindowBase.cs
similarity index 98%
rename from src/Ryujinx.Headless.SDL2/WindowBase.cs
rename to src/Ryujinx/Headless/WindowBase.cs
index fbe7cb49c..21bee368a 100644
--- a/src/Ryujinx.Headless.SDL2/WindowBase.cs
+++ b/src/Ryujinx/Headless/WindowBase.cs
@@ -1,5 +1,6 @@
using Humanizer;
using LibHac.Tools.Fs;
+using Ryujinx.Ava;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Logging;
@@ -26,7 +27,7 @@ using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
using Switch = Ryujinx.HLE.Switch;
-namespace Ryujinx.Headless.SDL2
+namespace Ryujinx.Headless
{
abstract partial class WindowBase : IHostUIHandler, IDisposable
{
@@ -136,7 +137,7 @@ namespace Ryujinx.Headless.SDL2
private void SetWindowIcon()
{
- Stream iconStream = typeof(WindowBase).Assembly.GetManifestResourceStream("Ryujinx.Headless.SDL2.Ryujinx.bmp");
+ Stream iconStream = typeof(Program).Assembly.GetManifestResourceStream("HeadlessLogo");
byte[] iconBytes = new byte[iconStream!.Length];
if (iconStream.Read(iconBytes, 0, iconBytes.Length) != iconBytes.Length)
@@ -318,7 +319,7 @@ namespace Ryujinx.Headless.SDL2
Device.VSyncMode.ToString(),
dockedMode,
Device.Configuration.AspectRatio.ToText(),
- $"Game: {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
+ $"{Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
$"FIFO: {Device.Statistics.GetFifoPercent():0.00} %",
$"GPU: {_gpuDriverName}"));
diff --git a/src/Ryujinx/Program.cs b/src/Ryujinx/Program.cs
index 2ec60ac70..bde08a372 100644
--- a/src/Ryujinx/Program.cs
+++ b/src/Ryujinx/Program.cs
@@ -14,6 +14,7 @@ using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Logging;
using Ryujinx.Common.SystemInterop;
using Ryujinx.Graphics.Vulkan.MoltenVK;
+using Ryujinx.Headless;
using Ryujinx.SDL2.Common;
using Ryujinx.UI.App.Common;
using Ryujinx.UI.Common;
@@ -52,9 +53,15 @@ namespace Ryujinx.Ava
}
PreviewerDetached = true;
+
+ if (args.Length > 0 && args[0] is "--no-gui" or "nogui")
+ {
+ HeadlessRyujinx.Entrypoint(args[1..]);
+ return 0;
+ }
Initialize(args);
-
+
LoggerAdapter.Register();
IconProvider.Current
@@ -106,7 +113,7 @@ namespace Ryujinx.Ava
AppDomain.CurrentDomain.UnhandledException += (sender, e)
=> ProcessUnhandledException(sender, e.ExceptionObject as Exception, e.IsTerminating);
AppDomain.CurrentDomain.ProcessExit += (_, _) => Exit();
-
+
// Setup base data directory.
AppDataManager.Initialize(CommandLineState.BaseDirPathArg);
@@ -223,7 +230,7 @@ namespace Ryujinx.Ava
UseHardwareAcceleration = CommandLineState.OverrideHardwareAcceleration.Value;
}
- private static void PrintSystemInfo()
+ internal static void PrintSystemInfo()
{
Logger.Notice.Print(LogClass.Application, $"{RyujinxApp.FullAppName} Version: {Version}");
SystemInfo.Gather().Print();
@@ -240,7 +247,7 @@ namespace Ryujinx.Ava
: $"Launch Mode: {AppDataManager.Mode}");
}
- private static void ProcessUnhandledException(object sender, Exception ex, bool isTerminating)
+ internal static void ProcessUnhandledException(object sender, Exception ex, bool isTerminating)
{
Logger.Log log = Logger.Error ?? Logger.Notice;
string message = $"Unhandled exception caught: {ex}";
@@ -255,7 +262,7 @@ namespace Ryujinx.Ava
Exit();
}
- public static void Exit()
+ internal static void Exit()
{
DiscordIntegrationModule.Exit();
diff --git a/src/Ryujinx/Ryujinx.csproj b/src/Ryujinx/Ryujinx.csproj
index d5bad2ee6..d98e499c2 100644
--- a/src/Ryujinx/Ryujinx.csproj
+++ b/src/Ryujinx/Ryujinx.csproj
@@ -47,6 +47,7 @@
+
@@ -66,6 +67,7 @@
+
@@ -74,7 +76,6 @@
-
@@ -133,6 +134,7 @@
+