Compare commits
8 Commits
Canary-1.2
...
Canary-1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e5b2bda38 | ||
|
|
9bb50fc6dd | ||
|
|
e956864697 | ||
|
|
f43442f774 | ||
|
|
88d11d3d8d | ||
|
|
391f57bdd2 | ||
|
|
fd2b5a7fc1 | ||
|
|
37c165e9fc |
@@ -25,7 +25,7 @@ namespace Ryujinx.Common.Configuration
|
||||
{
|
||||
var unpackedFields = packedHack.UnpackBitFields(PackedFormat);
|
||||
if (unpackedFields is not [var hack, var value])
|
||||
throw new ArgumentException(nameof(packedHack));
|
||||
throw new Exception("The unpack operation on the integer resulted in an invalid unpacked result.");
|
||||
|
||||
return new EnabledDirtyHack((DirtyHack)hack, (int)value);
|
||||
}
|
||||
|
||||
@@ -171,6 +171,7 @@ namespace Ryujinx.Common
|
||||
"0100b41013c82000", // Cruis'n Blast
|
||||
"01001b300b9be000", // Diablo III: Eternal Collection
|
||||
"01008c8012920000", // Dying Light Platinum Edition
|
||||
"01001cc01b2d4000", // Goat Simulator 3
|
||||
"010073c01af34000", // LEGO Horizon Adventures
|
||||
"0100770008dd8000", // Monster Hunter Generations Ultimate
|
||||
"0100b04011742000", // Monster Hunter Rise
|
||||
|
||||
@@ -367,7 +367,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_context.DirtyHacks.IsEnabled(DirtyHack.ShaderTranslationDelay))
|
||||
if (_context.Capabilities.Api == TargetApi.Metal && _context.DirtyHacks.IsEnabled(DirtyHack.ShaderTranslationDelay))
|
||||
Thread.Sleep(_context.DirtyHacks[DirtyHack.ShaderTranslationDelay]);
|
||||
|
||||
AsyncProgramTranslation asyncTranslation = new(guestShaders, specState, programIndex, isCompute);
|
||||
|
||||
@@ -15,8 +15,10 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
||||
{
|
||||
_baseStorage = SharedRef<LibHac.FsSrv.Sf.IStorage>.CreateMove(ref baseStorage);
|
||||
}
|
||||
|
||||
private const string Xc2TitleId = "0100e95004038000";
|
||||
|
||||
private const string Xc2JpTitleId = "0100f3400332c000";
|
||||
private const string Xc2GlobalTitleId = "0100e95004038000";
|
||||
private static bool IsXc2 => TitleIDs.CurrentApplication.Value.OrDefault() is Xc2GlobalTitleId or Xc2JpTitleId;
|
||||
|
||||
[CommandCmif(0)]
|
||||
// Read(u64 offset, u64 length) -> buffer<u8, 0x46, 0> buffer
|
||||
@@ -39,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
||||
using var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true);
|
||||
Result result = _baseStorage.Get.Read((long)offset, new OutBuffer(region.Memory.Span), (long)size);
|
||||
|
||||
if (context.Device.DirtyHacks.IsEnabled(DirtyHack.Xc2MenuSoftlockFix) && TitleIDs.CurrentApplication.Value == Xc2TitleId)
|
||||
if (context.Device.DirtyHacks.IsEnabled(DirtyHack.Xc2MenuSoftlockFix) && IsXc2)
|
||||
{
|
||||
// Add a load-bearing sleep to avoid XC2 softlock
|
||||
// https://web.archive.org/web/20240728045136/https://github.com/Ryujinx/Ryujinx/issues/2357
|
||||
|
||||
@@ -3,7 +3,6 @@ using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Threading;
|
||||
using Gommon;
|
||||
using LibHac.Common;
|
||||
using LibHac.Ns;
|
||||
using LibHac.Tools.FsSystem;
|
||||
@@ -43,7 +42,6 @@ using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.Input;
|
||||
using Ryujinx.Input.HLE;
|
||||
using Silk.NET.Vulkan;
|
||||
using SkiaSharp;
|
||||
using SPB.Graphics.Vulkan;
|
||||
using System;
|
||||
|
||||
@@ -22598,4 +22598,4 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ namespace Ryujinx.Headless
|
||||
// Make process DPI aware for proper window sizing on high-res screens.
|
||||
ForceDpiAware.Windows();
|
||||
|
||||
Console.Title = $"Ryujinx Console {Program.Version} (Headless)";
|
||||
Console.Title = $"HeadlessRyujinx Console {Program.Version}";
|
||||
|
||||
if (OperatingSystem.IsMacOS() || OperatingSystem.IsLinux())
|
||||
{
|
||||
@@ -162,6 +162,11 @@ namespace Ryujinx.Headless
|
||||
}
|
||||
|
||||
ReloadConfig();
|
||||
|
||||
if (option.InheritConfig)
|
||||
{
|
||||
option.InheritMainConfigInput(originalArgs, ConfigurationState.Instance);
|
||||
}
|
||||
|
||||
_virtualFileSystem = VirtualFileSystem.CreateInstance();
|
||||
_libHacHorizonManager = new LibHacHorizonManager();
|
||||
@@ -224,15 +229,7 @@ namespace Ryujinx.Headless
|
||||
_enableKeyboard = option.EnableKeyboard;
|
||||
_enableMouse = option.EnableMouse;
|
||||
|
||||
static void LoadPlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
|
||||
{
|
||||
InputConfig inputConfig = HandlePlayerConfiguration(inputProfileName, inputId, index);
|
||||
|
||||
if (inputConfig != null)
|
||||
{
|
||||
_inputConfiguration.Add(inputConfig);
|
||||
}
|
||||
}
|
||||
|
||||
LoadPlayerConfiguration(option.InputProfile1Name, option.InputId1, PlayerIndex.Player1);
|
||||
LoadPlayerConfiguration(option.InputProfile2Name, option.InputId2, PlayerIndex.Player2);
|
||||
@@ -244,7 +241,6 @@ namespace Ryujinx.Headless
|
||||
LoadPlayerConfiguration(option.InputProfile8Name, option.InputId8, PlayerIndex.Player8);
|
||||
LoadPlayerConfiguration(option.InputProfileHandheldName, option.InputIdHandheld, PlayerIndex.Handheld);
|
||||
|
||||
|
||||
if (_inputConfiguration.Count == 0)
|
||||
{
|
||||
return;
|
||||
@@ -306,6 +302,24 @@ namespace Ryujinx.Headless
|
||||
}
|
||||
|
||||
_inputManager.Dispose();
|
||||
|
||||
return;
|
||||
|
||||
void LoadPlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
|
||||
{
|
||||
if (index == PlayerIndex.Handheld && _inputConfiguration.Count > 0)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.Configuration, "Skipping handheld configuration as there are already other players configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
InputConfig inputConfig = option.InheritedInputConfigs[index] ?? HandlePlayerConfiguration(inputProfileName, inputId, index);
|
||||
|
||||
if (inputConfig != null)
|
||||
{
|
||||
_inputConfiguration.Add(inputConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetupProgressHandler()
|
||||
|
||||
@@ -154,10 +154,37 @@ namespace Ryujinx.Headless
|
||||
return;
|
||||
|
||||
bool NeedsOverride(string argKey) => originalArgs.None(arg => arg.TrimStart('-').EqualsIgnoreCase(OptionName(argKey)));
|
||||
|
||||
string OptionName(string propertyName) =>
|
||||
typeof(Options)!.GetProperty(propertyName)!.GetCustomAttribute<OptionAttribute>()!.LongName;
|
||||
}
|
||||
|
||||
public void InheritMainConfigInput(string[] originalArgs, ConfigurationState configurationState)
|
||||
{
|
||||
Dictionary<PlayerIndex, (string InputId, string InputProfileName)> indicesToProperties = new()
|
||||
{
|
||||
{ PlayerIndex.Handheld, (nameof(InputIdHandheld), nameof(InputProfileHandheldName)) },
|
||||
{ PlayerIndex.Player1, (nameof(InputId1), nameof(InputProfile1Name)) },
|
||||
{ PlayerIndex.Player2, (nameof(InputId2), nameof(InputProfile2Name)) },
|
||||
{ PlayerIndex.Player3, (nameof(InputId3), nameof(InputProfile3Name)) },
|
||||
{ PlayerIndex.Player4, (nameof(InputId4), nameof(InputProfile4Name)) },
|
||||
{ PlayerIndex.Player5, (nameof(InputId5), nameof(InputProfile5Name)) },
|
||||
{ PlayerIndex.Player6, (nameof(InputId6), nameof(InputProfile6Name)) },
|
||||
{ PlayerIndex.Player7, (nameof(InputId7), nameof(InputProfile7Name)) },
|
||||
{ PlayerIndex.Player8, (nameof(InputId8), nameof(InputProfile8Name)) }
|
||||
};
|
||||
|
||||
foreach ((PlayerIndex playerIndex, _) in indicesToProperties
|
||||
.Where(it => NeedsOverride(it.Value.InputId) && NeedsOverride(it.Value.InputProfileName)))
|
||||
{
|
||||
configurationState.Hid.InputConfig.Value.FindFirst(x => x.PlayerIndex == playerIndex)
|
||||
.IfPresent(ic => InheritedInputConfigs[playerIndex] = ic);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
bool NeedsOverride(string argKey) => originalArgs.None(arg => arg.TrimStart('-').EqualsIgnoreCase(OptionName(argKey)));
|
||||
}
|
||||
|
||||
private static string OptionName(string propertyName) =>
|
||||
typeof(Options)!.GetProperty(propertyName)!.GetCustomAttribute<OptionAttribute>()!.LongName;
|
||||
|
||||
// General
|
||||
|
||||
@@ -391,5 +418,7 @@ namespace Ryujinx.Headless
|
||||
|
||||
[Value(0, MetaName = "input", HelpText = "Input to load.", Required = true)]
|
||||
public string InputPath { get; set; }
|
||||
|
||||
public SafeDictionary<PlayerIndex, InputConfig> InheritedInputConfigs = new();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<UserControl
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="800"
|
||||
d:DesignHeight="450"
|
||||
x:Class="Ryujinx.Ava.UI.Renderer.RendererHost"
|
||||
FlowDirection="LeftToRight"
|
||||
Focusable="True">
|
||||
</UserControl>
|
||||
@@ -1,16 +1,15 @@
|
||||
using Avalonia;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Gommon;
|
||||
using Avalonia.Media;
|
||||
using Ryujinx.Ava.Utilities.Configuration;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Renderer
|
||||
{
|
||||
public partial class RendererHost : UserControl, IDisposable
|
||||
public class RendererHost : UserControl, IDisposable
|
||||
{
|
||||
public readonly EmbeddedWindow EmbeddedWindow;
|
||||
|
||||
@@ -19,7 +18,8 @@ namespace Ryujinx.Ava.UI.Renderer
|
||||
|
||||
public RendererHost()
|
||||
{
|
||||
InitializeComponent();
|
||||
Focusable = true;
|
||||
FlowDirection = FlowDirection.LeftToRight;
|
||||
|
||||
EmbeddedWindow = ConfigurationState.Instance.Graphics.GraphicsBackend.Value switch
|
||||
{
|
||||
@@ -43,8 +43,6 @@ namespace Ryujinx.Ava.UI.Renderer
|
||||
|
||||
public RendererHost(string titleId)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
switch (TitleIDs.SelectGraphicsBackend(titleId, ConfigurationState.Instance.Graphics.GraphicsBackend))
|
||||
{
|
||||
case GraphicsBackend.OpenGl:
|
||||
@@ -109,3 +107,4 @@ namespace Ryujinx.Ava.UI.Renderer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,9 +106,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
// NOTE(jpr): this works around a bug where calling _views.Clear also clears SelectedDownloadableContents for
|
||||
// some reason. so we save the items here and add them back after
|
||||
var items = SelectedDownloadableContents.ToArray();
|
||||
|
||||
_views.Clear();
|
||||
_views.AddRange(view);
|
||||
|
||||
Views.Clear();
|
||||
Views.AddRange(view);
|
||||
|
||||
foreach (DownloadableContentModel item in items)
|
||||
{
|
||||
|
||||
@@ -80,7 +80,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
[ObservableProperty] private Brush _progressBarForegroundColor;
|
||||
[ObservableProperty] private Brush _progressBarBackgroundColor;
|
||||
[ObservableProperty] private Brush _vSyncModeColor;
|
||||
[ObservableProperty] private byte[] _selectedIcon;
|
||||
#nullable enable
|
||||
[ObservableProperty] private byte[]? _selectedIcon;
|
||||
#nullable disable
|
||||
[ObservableProperty] private int _statusBarProgressMaximum;
|
||||
[ObservableProperty] private int _statusBarProgressValue;
|
||||
[ObservableProperty] private string _statusBarProgressStatusText;
|
||||
@@ -125,43 +127,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
private ApplicationData _listSelectedApplication;
|
||||
private ApplicationData _gridSelectedApplication;
|
||||
|
||||
public ApplicationData ListSelectedApplication
|
||||
{
|
||||
get => _listSelectedApplication;
|
||||
set
|
||||
{
|
||||
_listSelectedApplication = value;
|
||||
|
||||
#pragma warning disable MVVMTK0034
|
||||
if (_listSelectedApplication != null && _listAppContextMenu == null)
|
||||
|
||||
ListAppContextMenu = new ApplicationContextMenu();
|
||||
else if (_listSelectedApplication == null && _listAppContextMenu != null)
|
||||
ListAppContextMenu = null!;
|
||||
#pragma warning restore MVVMTK0034
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationData GridSelectedApplication
|
||||
{
|
||||
get => _gridSelectedApplication;
|
||||
set
|
||||
{
|
||||
_gridSelectedApplication = value;
|
||||
|
||||
#pragma warning disable MVVMTK0034
|
||||
if (_gridSelectedApplication != null && _gridAppContextMenu == null)
|
||||
GridAppContextMenu = new ApplicationContextMenu();
|
||||
else if (_gridSelectedApplication == null && _gridAppContextMenu != null)
|
||||
GridAppContextMenu = null!;
|
||||
#pragma warning restore MVVMTK0034
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// Key is Title ID
|
||||
public SafeDictionary<string, LdnGameData.Array> LdnData = [];
|
||||
|
||||
@@ -182,8 +147,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
Applications.ToObservableChangeSet()
|
||||
.Filter(Filter)
|
||||
.Sort(GetComparer())
|
||||
.Bind(out _appsObservableList)
|
||||
.AsObservableList();
|
||||
.OnItemAdded(_ => OnPropertyChanged(nameof(AppsObservableList)))
|
||||
.OnItemRemoved(_ => OnPropertyChanged(nameof(AppsObservableList)))
|
||||
#pragma warning disable MVVMTK0034 // Event to update is fired below
|
||||
.Bind(out _appsObservableList);
|
||||
#pragma warning restore MVVMTK0034
|
||||
|
||||
_rendererWaitEvent = new AutoResetEvent(false);
|
||||
|
||||
@@ -192,8 +160,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
LoadConfigurableHotKeys();
|
||||
|
||||
Volume = ConfigurationState.Instance.System.AudioVolume;
|
||||
CustomVSyncInterval = ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value;
|
||||
}
|
||||
CustomVSyncInterval = ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value;
|
||||
}
|
||||
|
||||
public void Initialize(
|
||||
@@ -331,6 +299,43 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
OnPropertyChanged(nameof(ShowFirmwareStatus));
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationData ListSelectedApplication
|
||||
{
|
||||
get => _listSelectedApplication;
|
||||
set
|
||||
{
|
||||
_listSelectedApplication = value;
|
||||
|
||||
#pragma warning disable MVVMTK0034
|
||||
if (_listSelectedApplication != null && _listAppContextMenu == null)
|
||||
|
||||
ListAppContextMenu = new ApplicationContextMenu();
|
||||
else if (_listSelectedApplication == null && _listAppContextMenu != null)
|
||||
ListAppContextMenu = null!;
|
||||
#pragma warning restore MVVMTK0034
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationData GridSelectedApplication
|
||||
{
|
||||
get => _gridSelectedApplication;
|
||||
set
|
||||
{
|
||||
_gridSelectedApplication = value;
|
||||
|
||||
#pragma warning disable MVVMTK0034
|
||||
if (_gridSelectedApplication != null && _gridAppContextMenu == null)
|
||||
GridAppContextMenu = new ApplicationContextMenu();
|
||||
else if (_gridSelectedApplication == null && _gridAppContextMenu != null)
|
||||
GridAppContextMenu = null!;
|
||||
#pragma warning restore MVVMTK0034
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public ApplicationData SelectedApplication
|
||||
{
|
||||
@@ -1751,7 +1756,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public async void ProcessTrimResult(String filename, Ryujinx.Common.Utilities.XCIFileTrimmer.OperationOutcome operationOutcome)
|
||||
public async void ProcessTrimResult(String filename, XCIFileTrimmer.OperationOutcome operationOutcome)
|
||||
{
|
||||
string notifyUser = operationOutcome.ToLocalisedText();
|
||||
|
||||
@@ -1766,12 +1771,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
switch (operationOutcome)
|
||||
{
|
||||
case Ryujinx.Common.Utilities.XCIFileTrimmer.OperationOutcome.Successful:
|
||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||
{
|
||||
if (desktop.MainWindow is MainWindow mainWindow)
|
||||
mainWindow.LoadApplications();
|
||||
}
|
||||
case XCIFileTrimmer.OperationOutcome.Successful:
|
||||
RyujinxApp.MainWindow.LoadApplications();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user