mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-04-24 06:47:44 +02:00
Merge branch 'master' into Master_PR
This commit is contained in:
commit
9dc36646c1
37 changed files with 1340 additions and 233 deletions
|
@ -97,7 +97,7 @@ If you are planning to contribute or just want to learn more about this project
|
||||||
|
|
||||||
- **Input**
|
- **Input**
|
||||||
|
|
||||||
We currently have support for keyboard, mouse, touch input, JoyCon input support, and nearly all controllers.
|
We currently have support for keyboard, mouse, touch input, Joy-Con input support, and nearly all controllers.
|
||||||
Motion controls are natively supported in most cases; for dual-JoyCon motion support, DS4Windows or BetterJoy are currently required.
|
Motion controls are natively supported in most cases; for dual-JoyCon motion support, DS4Windows or BetterJoy are currently required.
|
||||||
In all scenarios, you can set up everything inside the input configuration menu.
|
In all scenarios, you can set up everything inside the input configuration menu.
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace ARMeilleure.Translation.Cache
|
||||||
|
|
||||||
private static JitCacheInvalidation _jitCacheInvalidator;
|
private static JitCacheInvalidation _jitCacheInvalidator;
|
||||||
|
|
||||||
private static CacheMemoryAllocator _cacheAllocator;
|
private static List<CacheMemoryAllocator> _cacheAllocators = [];
|
||||||
|
|
||||||
private static readonly List<CacheEntry> _cacheEntries = [];
|
private static readonly List<CacheEntry> _cacheEntries = [];
|
||||||
|
|
||||||
|
@ -40,37 +40,48 @@ namespace ARMeilleure.Translation.Cache
|
||||||
|
|
||||||
public static void Initialize(IJitMemoryAllocator allocator)
|
public static void Initialize(IJitMemoryAllocator allocator)
|
||||||
{
|
{
|
||||||
if (_initialized)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (_initialized)
|
if (_initialized)
|
||||||
{
|
{
|
||||||
return;
|
if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
JitUnwindWindows.RemoveFunctionTableHandler(
|
||||||
|
_jitRegions[0].Pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < _jitRegions.Count; i++)
|
||||||
|
{
|
||||||
|
_jitRegions[i].Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_jitRegions.Clear();
|
||||||
|
_cacheAllocators.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_activeRegionIndex = 0;
|
||||||
|
|
||||||
ReservedRegion firstRegion = new(allocator, CacheSize);
|
ReservedRegion firstRegion = new(allocator, CacheSize);
|
||||||
_jitRegions.Add(firstRegion);
|
_jitRegions.Add(firstRegion);
|
||||||
_activeRegionIndex = 0;
|
|
||||||
|
CacheMemoryAllocator firstCacheAllocator = new(CacheSize);
|
||||||
|
_cacheAllocators.Add(firstCacheAllocator);
|
||||||
|
|
||||||
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
|
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
_jitCacheInvalidator = new JitCacheInvalidation(allocator);
|
_jitCacheInvalidator = new JitCacheInvalidation(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
_cacheAllocator = new CacheMemoryAllocator(CacheSize);
|
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
{
|
{
|
||||||
JitUnwindWindows.InstallFunctionTableHandler(
|
JitUnwindWindows.InstallFunctionTableHandler(
|
||||||
firstRegion.Pointer, CacheSize, firstRegion.Pointer + Allocate(_pageSize)
|
firstRegion.Pointer, CacheSize, firstRegion.Pointer + Allocate(_pageSize)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_initialized = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +147,7 @@ namespace ARMeilleure.Translation.Cache
|
||||||
|
|
||||||
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
|
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
|
||||||
{
|
{
|
||||||
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
|
_cacheAllocators[_activeRegionIndex].Free(funcOffset, AlignCodeSize(entry.Size));
|
||||||
_cacheEntries.RemoveAt(entryIndex);
|
_cacheEntries.RemoveAt(entryIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,30 +178,24 @@ namespace ARMeilleure.Translation.Cache
|
||||||
{
|
{
|
||||||
codeSize = AlignCodeSize(codeSize);
|
codeSize = AlignCodeSize(codeSize);
|
||||||
|
|
||||||
for (int i = _activeRegionIndex; i < _jitRegions.Count; i++)
|
int allocOffset = _cacheAllocators[_activeRegionIndex].Allocate(codeSize);
|
||||||
{
|
|
||||||
int allocOffset = _cacheAllocator.Allocate(codeSize);
|
|
||||||
|
|
||||||
if (allocOffset >= 0)
|
if (allocOffset >= 0)
|
||||||
{
|
{
|
||||||
_jitRegions[i].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
|
_jitRegions[_activeRegionIndex].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
|
||||||
_activeRegionIndex = i;
|
|
||||||
return allocOffset;
|
return allocOffset;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int exhaustedRegion = _activeRegionIndex;
|
int exhaustedRegion = _activeRegionIndex;
|
||||||
ReservedRegion newRegion = new(_jitRegions[0].Allocator, CacheSize);
|
ReservedRegion newRegion = new(_jitRegions[0].Allocator, CacheSize);
|
||||||
_jitRegions.Add(newRegion);
|
_jitRegions.Add(newRegion);
|
||||||
_activeRegionIndex = _jitRegions.Count - 1;
|
_activeRegionIndex = _jitRegions.Count - 1;
|
||||||
|
|
||||||
int newRegionNumber = _activeRegionIndex;
|
Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {_activeRegionIndex} ({((long)(_activeRegionIndex + 1) * CacheSize).Bytes()} Total Allocation).");
|
||||||
|
|
||||||
Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {newRegionNumber} ({((long)(newRegionNumber + 1) * CacheSize).Bytes()} Total Allocation).");
|
_cacheAllocators.Add(new CacheMemoryAllocator(CacheSize));
|
||||||
|
|
||||||
_cacheAllocator = new CacheMemoryAllocator(CacheSize);
|
int allocOffsetNew = _cacheAllocators[_activeRegionIndex].Allocate(codeSize);
|
||||||
|
|
||||||
int allocOffsetNew = _cacheAllocator.Allocate(codeSize);
|
|
||||||
if (allocOffsetNew < 0)
|
if (allocOffsetNew < 0)
|
||||||
{
|
{
|
||||||
throw new OutOfMemoryException("Failed to allocate in new Cache Region!");
|
throw new OutOfMemoryException("Failed to allocate in new Cache Region!");
|
||||||
|
|
|
@ -52,6 +52,11 @@ namespace ARMeilleure.Translation.Cache
|
||||||
nint context,
|
nint context,
|
||||||
[MarshalAs(UnmanagedType.LPWStr)] string outOfProcessCallbackDll);
|
[MarshalAs(UnmanagedType.LPWStr)] string outOfProcessCallbackDll);
|
||||||
|
|
||||||
|
[LibraryImport("kernel32.dll")]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
private static unsafe partial bool RtlDeleteFunctionTable(
|
||||||
|
ulong tableIdentifier);
|
||||||
|
|
||||||
private static GetRuntimeFunctionCallback _getRuntimeFunctionCallback;
|
private static GetRuntimeFunctionCallback _getRuntimeFunctionCallback;
|
||||||
|
|
||||||
private static int _sizeOfRuntimeFunction;
|
private static int _sizeOfRuntimeFunction;
|
||||||
|
@ -91,6 +96,23 @@ namespace ARMeilleure.Translation.Cache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void RemoveFunctionTableHandler(nint codeCachePointer)
|
||||||
|
{
|
||||||
|
ulong codeCachePtr = (ulong)codeCachePointer.ToInt64();
|
||||||
|
|
||||||
|
bool result;
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
result = RtlDeleteFunctionTable(codeCachePtr | 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Failure removing function table callback.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, nint context)
|
private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, nint context)
|
||||||
{
|
{
|
||||||
int offset = (int)((long)controlPc - context.ToInt64());
|
int offset = (int)((long)controlPc - context.ToInt64());
|
||||||
|
|
|
@ -5,15 +5,34 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Common.Helper
|
namespace Ryujinx.Common.Helper
|
||||||
{
|
{
|
||||||
|
public enum OperatingSystemType
|
||||||
|
{
|
||||||
|
MacOS,
|
||||||
|
Linux,
|
||||||
|
Windows
|
||||||
|
}
|
||||||
|
|
||||||
public static class RunningPlatform
|
public static class RunningPlatform
|
||||||
{
|
{
|
||||||
|
public static readonly OperatingSystemType CurrentOS
|
||||||
|
= IsMacOS
|
||||||
|
? OperatingSystemType.MacOS
|
||||||
|
: IsWindows
|
||||||
|
? OperatingSystemType.Windows
|
||||||
|
: IsLinux
|
||||||
|
? OperatingSystemType.Linux
|
||||||
|
: throw new PlatformNotSupportedException();
|
||||||
|
|
||||||
|
public static Architecture Architecture => RuntimeInformation.OSArchitecture;
|
||||||
|
public static Architecture CurrentProcessArchitecture => RuntimeInformation.ProcessArchitecture;
|
||||||
|
|
||||||
public static bool IsMacOS => OperatingSystem.IsMacOS();
|
public static bool IsMacOS => OperatingSystem.IsMacOS();
|
||||||
public static bool IsWindows => OperatingSystem.IsWindows();
|
public static bool IsWindows => OperatingSystem.IsWindows();
|
||||||
public static bool IsLinux => OperatingSystem.IsLinux();
|
public static bool IsLinux => OperatingSystem.IsLinux();
|
||||||
|
|
||||||
public static bool IsArm => RuntimeInformation.OSArchitecture is Architecture.Arm64;
|
public static bool IsArm => Architecture is Architecture.Arm64;
|
||||||
|
|
||||||
public static bool IsX64 => RuntimeInformation.OSArchitecture is Architecture.X64;
|
public static bool IsX64 => Architecture is Architecture.X64;
|
||||||
|
|
||||||
public static bool IsIntelMac => IsMacOS && IsX64;
|
public static bool IsIntelMac => IsMacOS && IsX64;
|
||||||
public static bool IsArmMac => IsMacOS && IsArm;
|
public static bool IsArmMac => IsMacOS && IsArm;
|
||||||
|
|
|
@ -71,16 +71,24 @@ namespace Ryujinx.HLE.Loaders.Mods
|
||||||
int patchOffset = (int)offset;
|
int patchOffset = (int)offset;
|
||||||
int patchSize = patch.Length;
|
int patchSize = patch.Length;
|
||||||
|
|
||||||
if (patchOffset < protectedOffset || patchOffset > memory.Length)
|
if (patchOffset < protectedOffset)
|
||||||
{
|
{
|
||||||
continue; // Add warning?
|
Logger.Warning?.Print(LogClass.ModLoader, $"Attempted to patch protected memory ({patchOffset:x} is within protected boundary of {protectedOffset:x}).");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patchOffset > memory.Length)
|
||||||
|
{
|
||||||
|
Logger.Warning?.Print(LogClass.ModLoader, $"Attempted to patch out of bounds memory (offset {patchOffset} ({patchOffset:x}) exceeds memory buffer length {memory.Length}).");
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
patchOffset -= protectedOffset;
|
patchOffset -= protectedOffset;
|
||||||
|
|
||||||
if (patchOffset + patchSize > memory.Length)
|
if (patchOffset + patchSize > memory.Length)
|
||||||
{
|
{
|
||||||
patchSize = memory.Length - patchOffset; // Add warning?
|
Logger.Warning?.Print(LogClass.ModLoader, $"Patch offset ({patchOffset:x}) + size ({patchSize}) is greater than the size of the memory buffer ({memory.Length}). Attempting to fix this...");
|
||||||
|
patchSize = memory.Length - patchOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.ModLoader, $"Patching address offset {patchOffset:x} <= {BitConverter.ToString(patch).Replace('-', ' ')} len={patchSize}");
|
Logger.Info?.Print(LogClass.ModLoader, $"Patching address offset {patchOffset:x} <= {BitConverter.ToString(patch).Replace('-', ' ')} len={patchSize}");
|
||||||
|
|
|
@ -1113,6 +1113,13 @@ namespace Ryujinx.Ava
|
||||||
});
|
});
|
||||||
|
|
||||||
(RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(true);
|
(RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(true);
|
||||||
|
|
||||||
|
// Reload settings when the game is turned off
|
||||||
|
// (resets custom settings if there were any)
|
||||||
|
Program.ReloadConfig();
|
||||||
|
|
||||||
|
// Reload application list (changes the status of the user setting if it was added or removed during the game)
|
||||||
|
Dispatcher.UIThread.Post(() => RyujinxApp.MainWindow.LoadApplications());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InitStatus()
|
public void InitStatus()
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
|
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
|
||||||
xmlns:windowing="clr-namespace:FluentAvalonia.UI.Windowing;assembly=FluentAvalonia">
|
xmlns:windowing="clr-namespace:FluentAvalonia.UI.Windowing;assembly=FluentAvalonia">
|
||||||
<Design.PreviewWith>
|
<Design.PreviewWith>
|
||||||
<Border Height="2000"
|
<Border Height="2000"
|
||||||
|
@ -30,7 +31,8 @@
|
||||||
<Button
|
<Button
|
||||||
Name="btnRem"
|
Name="btnRem"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Content="Add" />
|
Content="Add"
|
||||||
|
Classes="red"/>
|
||||||
<TextBox
|
<TextBox
|
||||||
Width="100"
|
Width="100"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
@ -41,6 +43,11 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
<ui:NumberBox Value="1" />
|
<ui:NumberBox Value="1" />
|
||||||
|
<MenuItem
|
||||||
|
Header="123 0000"
|
||||||
|
ToolTip.Tip="What this"/>
|
||||||
|
<TextBlock
|
||||||
|
Classes="globalConfigMarker"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</Design.PreviewWith>
|
</Design.PreviewWith>
|
||||||
|
@ -331,12 +338,11 @@
|
||||||
<Setter Property="Margin"
|
<Setter Property="Margin"
|
||||||
Value="0,5,0,0" />
|
Value="0,5,0,0" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="TextBlock.pending" >
|
<Style Selector="TextBlock.globalConfigMarker" >
|
||||||
<Setter Property="Foreground" Value="SlateGray"/>
|
<Setter Property="Foreground" Value="SeaGreen"/>
|
||||||
|
<Setter Property="Margin" Value="5,0,0,0"/>
|
||||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
<Setter Property="Text" Value="{ext:Locale GameSpecificConfigurationGlobal}"/>
|
||||||
<Setter Property="FontSize" Value="12"/>
|
|
||||||
<Setter Property="Text" Value="(pending!)"/>
|
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="StackPanel.globalConfigMarker">
|
<Style Selector="StackPanel.globalConfigMarker">
|
||||||
</Style>
|
</Style>
|
||||||
|
@ -382,6 +388,19 @@
|
||||||
<Setter Property="Background"
|
<Setter Property="Background"
|
||||||
Value="{DynamicResource AppListHoverBackgroundColor}" />
|
Value="{DynamicResource AppListHoverBackgroundColor}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style Selector="Button.red /template/ ContentPresenter">
|
||||||
|
<Setter Property="CornerRadius" Value="4"/>
|
||||||
|
<Setter Property="Background" Value="red"/>
|
||||||
|
<Setter Property="Foreground" Value="White"/>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="Button.red:pointerover /template/ ContentPresenter">
|
||||||
|
<Setter Property="CornerRadius" Value="4"/>
|
||||||
|
<Setter Property="Background" Value="{DynamicResource WarningBackgroundColor}" />
|
||||||
|
<Setter Property="Foreground" Value="White"/>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Styles.Resources>
|
<Styles.Resources>
|
||||||
<SolidColorBrush x:Key="ThemeAccentColorBrush"
|
<SolidColorBrush x:Key="ThemeAccentColorBrush"
|
||||||
Color="{DynamicResource SystemAccentColor}" />
|
Color="{DynamicResource SystemAccentColor}" />
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
<ResourceDictionary.ThemeDictionaries>
|
<ResourceDictionary.ThemeDictionaries>
|
||||||
<ResourceDictionary x:Key="Default">
|
<ResourceDictionary x:Key="Default">
|
||||||
|
@ -12,11 +12,13 @@
|
||||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
||||||
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
|
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
|
||||||
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
|
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
|
||||||
|
<Color x:Key="WarningBackgroundColor">#FF6347</Color>
|
||||||
<Color x:Key="SecondaryTextColor">#A0000000</Color>
|
<Color x:Key="SecondaryTextColor">#A0000000</Color>
|
||||||
<Color x:Key="FavoriteApplicationIconColor">#fffcd12a</Color>
|
<Color x:Key="FavoriteApplicationIconColor">#fffcd12a</Color>
|
||||||
<Color x:Key="Switch">#FF2EEAC9</Color>
|
<Color x:Key="Switch">#FF2EEAC9</Color>
|
||||||
<Color x:Key="Unbounded">#FFFF4554</Color>
|
<Color x:Key="Unbounded">#FFFF4554</Color>
|
||||||
<Color x:Key="Custom">#6483F5</Color>
|
<Color x:Key="Custom">#6483F5</Color>
|
||||||
|
<Color x:Key="Warning">#800080</Color>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
<ResourceDictionary x:Key="Light">
|
<ResourceDictionary x:Key="Light">
|
||||||
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
|
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
|
||||||
|
@ -29,11 +31,13 @@
|
||||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
||||||
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
|
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
|
||||||
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
|
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
|
||||||
|
<Color x:Key="WarningBackgroundColor">#FF6347</Color>
|
||||||
<Color x:Key="SecondaryTextColor">#A0000000</Color>
|
<Color x:Key="SecondaryTextColor">#A0000000</Color>
|
||||||
<Color x:Key="FavoriteApplicationIconColor">#fffcd12a</Color>
|
<Color x:Key="FavoriteApplicationIconColor">#fffcd12a</Color>
|
||||||
<Color x:Key="Switch">#13c3a4</Color>
|
<Color x:Key="Switch">#13c3a4</Color>
|
||||||
<Color x:Key="Unbounded">#FFFF4554</Color>
|
<Color x:Key="Unbounded">#FFFF4554</Color>
|
||||||
<Color x:Key="Custom">#6483F5</Color>
|
<Color x:Key="Custom">#6483F5</Color>
|
||||||
|
<Color x:Key="Warning">#800080</Color>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
<ResourceDictionary x:Key="Dark">
|
<ResourceDictionary x:Key="Dark">
|
||||||
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
|
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
|
||||||
|
@ -46,11 +50,13 @@
|
||||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#3D3D3D</Color>
|
<Color x:Key="MenuFlyoutPresenterBorderColor">#3D3D3D</Color>
|
||||||
<Color x:Key="AppListBackgroundColor">#0FFFFFFF</Color>
|
<Color x:Key="AppListBackgroundColor">#0FFFFFFF</Color>
|
||||||
<Color x:Key="AppListHoverBackgroundColor">#1EFFFFFF</Color>
|
<Color x:Key="AppListHoverBackgroundColor">#1EFFFFFF</Color>
|
||||||
|
<Color x:Key="WarningBackgroundColor">#FF6347</Color>
|
||||||
<Color x:Key="SecondaryTextColor">#A0FFFFFF</Color>
|
<Color x:Key="SecondaryTextColor">#A0FFFFFF</Color>
|
||||||
<Color x:Key="FavoriteApplicationIconColor">#fffcd12a</Color>
|
<Color x:Key="FavoriteApplicationIconColor">#fffcd12a</Color>
|
||||||
<Color x:Key="Switch">#FF2EEAC9</Color>
|
<Color x:Key="Switch">#FF2EEAC9</Color>
|
||||||
<Color x:Key="Unbounded">#FFFF4554</Color>
|
<Color x:Key="Unbounded">#FFFF4554</Color>
|
||||||
<Color x:Key="Custom">#6483F5</Color>
|
<Color x:Key="Custom">#6483F5</Color>
|
||||||
|
<Color x:Key="Warning">#FFA500</Color>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</ResourceDictionary.ThemeDictionaries>
|
</ResourceDictionary.ThemeDictionaries>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
|
|
@ -464,7 +464,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Abrir Pasta de Capturas de Tela",
|
"pt_BR": "Abrir Pasta de Capturas de Tela",
|
||||||
"ru_RU": "Открыть папку со скриншотами",
|
"ru_RU": "Открыть папку со скриншотами",
|
||||||
"sv_SE": "",
|
"sv_SE": "Öppna skärmbildsmappen",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Відкрити теку скріншотів",
|
"uk_UA": "Відкрити теку скріншотів",
|
||||||
|
@ -1564,7 +1564,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Desenvolvido por {0}",
|
"pt_BR": "Desenvolvido por {0}",
|
||||||
"ru_RU": "Разработана {0}",
|
"ru_RU": "Разработана {0}",
|
||||||
"sv_SE": "",
|
"sv_SE": "Utvecklat av {0}",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Розроблено: {0}",
|
"uk_UA": "Розроблено: {0}",
|
||||||
|
@ -1864,7 +1864,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Compatibilidade:",
|
"pt_BR": "Compatibilidade:",
|
||||||
"ru_RU": "Совместимость:",
|
"ru_RU": "Совместимость:",
|
||||||
"sv_SE": "",
|
"sv_SE": "Kompatibilitet:",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Сумісність:",
|
"uk_UA": "Сумісність:",
|
||||||
|
@ -1889,7 +1889,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "ID do Título:",
|
"pt_BR": "ID do Título:",
|
||||||
"ru_RU": "ID приложения",
|
"ru_RU": "ID приложения",
|
||||||
"sv_SE": "",
|
"sv_SE": "Titel-id:",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "ID гри:",
|
"uk_UA": "ID гри:",
|
||||||
|
@ -1914,7 +1914,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Jogos Hospedados: {0}",
|
"pt_BR": "Jogos Hospedados: {0}",
|
||||||
"ru_RU": "Запущенно игр: {0}",
|
"ru_RU": "Запущенно игр: {0}",
|
||||||
"sv_SE": "",
|
"sv_SE": "Värdskap för spel: {0}",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Розміщені ігри: {0}",
|
"uk_UA": "Розміщені ігри: {0}",
|
||||||
|
@ -1939,7 +1939,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Jogadores Online: {0}",
|
"pt_BR": "Jogadores Online: {0}",
|
||||||
"ru_RU": "Игроков онлайн: {0}",
|
"ru_RU": "Игроков онлайн: {0}",
|
||||||
"sv_SE": "",
|
"sv_SE": "Online-spelare: {0}",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Гравців онлайн: {0}",
|
"uk_UA": "Гравців онлайн: {0}",
|
||||||
|
@ -2289,7 +2289,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Limpar Cache PPTC",
|
"pt_BR": "Limpar Cache PPTC",
|
||||||
"ru_RU": "Очистить кэш PPTC",
|
"ru_RU": "Очистить кэш PPTC",
|
||||||
"sv_SE": "",
|
"sv_SE": "Rensa PPTC-cache",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Очистити кеш PPTC",
|
"uk_UA": "Очистити кеш PPTC",
|
||||||
|
@ -2314,7 +2314,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Apaga os arquivos de cache PPTC do aplicativo",
|
"pt_BR": "Apaga os arquivos de cache PPTC do aplicativo",
|
||||||
"ru_RU": "Удаляет все файлы кэша PPTC для приложения",
|
"ru_RU": "Удаляет все файлы кэша PPTC для приложения",
|
||||||
"sv_SE": "",
|
"sv_SE": "Tar bort alla PPTC-cachefiler för applikationen",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Видаляє всі файли кешу PPTC для застосунку",
|
"uk_UA": "Видаляє всі файли кешу PPTC для застосунку",
|
||||||
|
@ -2747,6 +2747,56 @@
|
||||||
"zh_TW": "建立桌面捷徑,啟動選取的應用程式"
|
"zh_TW": "建立桌面捷徑,啟動選取的應用程式"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ID": "GameListContextMenuCreateCustomConfiguration",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "",
|
||||||
|
"de_DE": "",
|
||||||
|
"el_GR": "",
|
||||||
|
"en_US": "Create Custom Configuration",
|
||||||
|
"es_ES": "",
|
||||||
|
"fr_FR": "",
|
||||||
|
"he_IL": "",
|
||||||
|
"it_IT": "",
|
||||||
|
"ja_JP": "",
|
||||||
|
"ko_KR": "",
|
||||||
|
"no_NO": "",
|
||||||
|
"pl_PL": "",
|
||||||
|
"pt_BR": "",
|
||||||
|
"ru_RU": "Создать пользовательскую конфигурацию",
|
||||||
|
"sv_SE": "",
|
||||||
|
"th_TH": "",
|
||||||
|
"tr_TR": "",
|
||||||
|
"uk_UA": "",
|
||||||
|
"zh_CN": "",
|
||||||
|
"zh_TW": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "GameListContextMenuEditCustomConfiguration",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "",
|
||||||
|
"de_DE": "",
|
||||||
|
"el_GR": "",
|
||||||
|
"en_US": "Edit Custom Configuration",
|
||||||
|
"es_ES": "",
|
||||||
|
"fr_FR": "",
|
||||||
|
"he_IL": "",
|
||||||
|
"it_IT": "",
|
||||||
|
"ja_JP": "",
|
||||||
|
"ko_KR": "",
|
||||||
|
"no_NO": "",
|
||||||
|
"pl_PL": "",
|
||||||
|
"pt_BR": "",
|
||||||
|
"ru_RU": "Изменить пользовательскую конфигурацию",
|
||||||
|
"sv_SE": "",
|
||||||
|
"th_TH": "",
|
||||||
|
"tr_TR": "",
|
||||||
|
"uk_UA": "",
|
||||||
|
"zh_CN": "",
|
||||||
|
"zh_TW": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ID": "GameListContextMenuCreateShortcutToolTipMacOS",
|
"ID": "GameListContextMenuCreateShortcutToolTipMacOS",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
|
@ -2772,6 +2822,56 @@
|
||||||
"zh_TW": "在 macOS 的應用程式資料夾中建立捷徑,啟動選取的應用程式"
|
"zh_TW": "在 macOS 的應用程式資料夾中建立捷徑,啟動選取的應用程式"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ID": "CreateCustomConfigurationToolTip",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "ينشئ تكوينًا مستقلًا للعبة الحالية",
|
||||||
|
"de_DE": "Erstellt eine unabhängige Konfiguration für das aktuelle Spiel",
|
||||||
|
"el_GR": "Δημιουργεί μια ανεξάρτητη διαμόρφωση για το τρέχον παιχνίδι",
|
||||||
|
"en_US": "Creates an independent configuration for the selected game",
|
||||||
|
"es_ES": "Crea una configuración independiente para el juego actual",
|
||||||
|
"fr_FR": "Crée une configuration indépendante pour le jeu en cours",
|
||||||
|
"he_IL": "יוצר תצורה עצמאית למשחק הנוכחי",
|
||||||
|
"it_IT": "Crea una configurazione indipendente per il gioco attuale",
|
||||||
|
"ja_JP": "現在のゲーム用の独立した設定を作成します",
|
||||||
|
"ko_KR": "현재 게임에 대한 독립적인 설정을 생성합니다",
|
||||||
|
"no_NO": "Oppretter en uavhengig konfigurasjon for det gjeldende spillet",
|
||||||
|
"pl_PL": "Tworzy niezależną konfigurację dla bieżącej gry",
|
||||||
|
"pt_BR": "Cria uma configuração independente para o jogo atual",
|
||||||
|
"ru_RU": "Создает независимую конфигурацию для текущей игры",
|
||||||
|
"sv_SE": "Skapar en oberoende konfiguration för det aktuella spelet",
|
||||||
|
"th_TH": "สร้างการกำหนดค่าที่เป็นอิสระสำหรับเกมปัจจุบัน",
|
||||||
|
"tr_TR": "Mevcut oyun için bağımsız bir yapılandırma oluşturur",
|
||||||
|
"uk_UA": "Створює незалежну конфігурацію для поточної гри",
|
||||||
|
"zh_CN": "为当前游戏创建独立的配置",
|
||||||
|
"zh_TW": "為當前遊戲創建獨立的配置"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "EditCustomConfigurationToolTip",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "",
|
||||||
|
"de_DE": "",
|
||||||
|
"el_GR": "",
|
||||||
|
"en_US": "Edit your existing independent configuration for the selected game",
|
||||||
|
"es_ES": "",
|
||||||
|
"fr_FR": "",
|
||||||
|
"he_IL": "",
|
||||||
|
"it_IT": "",
|
||||||
|
"ja_JP": "",
|
||||||
|
"ko_KR": "",
|
||||||
|
"no_NO": "",
|
||||||
|
"pl_PL": "",
|
||||||
|
"pt_BR": "",
|
||||||
|
"ru_RU": "Отредактировать существующую независимую конфигурацию для выбранной игры.",
|
||||||
|
"sv_SE": "",
|
||||||
|
"th_TH": "",
|
||||||
|
"tr_TR": "",
|
||||||
|
"uk_UA": "",
|
||||||
|
"zh_CN": "",
|
||||||
|
"zh_TW": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ID": "GameListContextMenuShowCompatEntry",
|
"ID": "GameListContextMenuShowCompatEntry",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
|
@ -2789,7 +2889,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Mostrar Dados de Compatibilidade",
|
"pt_BR": "Mostrar Dados de Compatibilidade",
|
||||||
"ru_RU": "Показать записи о совместимости",
|
"ru_RU": "Показать записи о совместимости",
|
||||||
"sv_SE": "",
|
"sv_SE": "Visa kompatibilitetspost",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Iнформація про сумісність",
|
"uk_UA": "Iнформація про сумісність",
|
||||||
|
@ -2814,7 +2914,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Exibe o jogo selecionado na Lista de Compatibilidade, que normalmente pode ser acessada pelo menu Ajuda.",
|
"pt_BR": "Exibe o jogo selecionado na Lista de Compatibilidade, que normalmente pode ser acessada pelo menu Ajuda.",
|
||||||
"ru_RU": "Отобразить выбранную игру в списке совместимости, доступ к которому вы обычно можете получить через меню Справки.",
|
"ru_RU": "Отобразить выбранную игру в списке совместимости, доступ к которому вы обычно можете получить через меню Справки.",
|
||||||
"sv_SE": "",
|
"sv_SE": "Visa valt spel i kompatibilitetslistan som du normalt sett kan komma åt via hjälpmenyn.",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Показати цю гру в Списку Сумісності. Список сумісності також можна зайти в меню Довідки.",
|
"uk_UA": "Показати цю гру в Списку Сумісності. Список сумісності також можна зайти в меню Довідки.",
|
||||||
|
@ -2839,7 +2939,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Mostrar Informações do Jogo",
|
"pt_BR": "Mostrar Informações do Jogo",
|
||||||
"ru_RU": "Показать информацию об игре",
|
"ru_RU": "Показать информацию об игре",
|
||||||
"sv_SE": "",
|
"sv_SE": "Visa spelinformation",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Інформація про гру",
|
"uk_UA": "Інформація про гру",
|
||||||
|
@ -2864,7 +2964,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Exibe estatísticas e detalhes sobre o jogo selecionado.",
|
"pt_BR": "Exibe estatísticas e detalhes sobre o jogo selecionado.",
|
||||||
"ru_RU": "Показывать статистику и подробную информацию о выбранной игре.",
|
"ru_RU": "Показывать статистику и подробную информацию о выбранной игре.",
|
||||||
"sv_SE": "",
|
"sv_SE": "Visa statistik och detaljer om det aktuella spelet.",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Показати статистику та деталі обраної гри.",
|
"uk_UA": "Показати статистику та деталі обраної гри.",
|
||||||
|
@ -3297,6 +3397,31 @@
|
||||||
"zh_TW": "設定"
|
"zh_TW": "設定"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ID": "SettingsWithInfo",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "{0} - إعدادات",
|
||||||
|
"de_DE": "Einstellungen - {0}",
|
||||||
|
"el_GR": "Ρυθμίσεις - {0}",
|
||||||
|
"en_US": "Settings - {0}",
|
||||||
|
"es_ES": "Configuración - {0}",
|
||||||
|
"fr_FR": "Paramètres - {0}",
|
||||||
|
"he_IL": "{0} - הגדרות",
|
||||||
|
"it_IT": "Impostazioni - {0}",
|
||||||
|
"ja_JP": "設定 - {0}",
|
||||||
|
"ko_KR": "설정 - {0}",
|
||||||
|
"no_NO": "Innstillinger - {0}",
|
||||||
|
"pl_PL": "Ustawienia - {0}",
|
||||||
|
"pt_BR": "Configurações - {0}",
|
||||||
|
"ru_RU": "Параметры - {0}",
|
||||||
|
"sv_SE": "Inställningar - {0}",
|
||||||
|
"th_TH": "ตั้งค่า - {0}",
|
||||||
|
"tr_TR": "Ayarlar - {0}",
|
||||||
|
"uk_UA": "Налаштування - {0}",
|
||||||
|
"zh_CN": "设置 - {0}",
|
||||||
|
"zh_TW": "設定 - {0}"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ID": "SettingsTabGeneral",
|
"ID": "SettingsTabGeneral",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
|
@ -3389,7 +3514,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Verificar Atualizações:",
|
"pt_BR": "Verificar Atualizações:",
|
||||||
"ru_RU": "Проверка наличия обновлений",
|
"ru_RU": "Проверка наличия обновлений",
|
||||||
"sv_SE": "",
|
"sv_SE": "Leta efter uppdateringar:",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Перевірка оновлень:",
|
"uk_UA": "Перевірка оновлень:",
|
||||||
|
@ -3414,7 +3539,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Desligado",
|
"pt_BR": "Desligado",
|
||||||
"ru_RU": "Отключить",
|
"ru_RU": "Отключить",
|
||||||
"sv_SE": "",
|
"sv_SE": "Av",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Вимкнути",
|
"uk_UA": "Вимкнути",
|
||||||
|
@ -3439,7 +3564,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Ao Abrir",
|
"pt_BR": "Ao Abrir",
|
||||||
"ru_RU": "При запуске",
|
"ru_RU": "При запуске",
|
||||||
"sv_SE": "",
|
"sv_SE": "Fråga",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Запитувати щоразу",
|
"uk_UA": "Запитувати щоразу",
|
||||||
|
@ -3464,7 +3589,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "2° Plano",
|
"pt_BR": "2° Plano",
|
||||||
"ru_RU": "В фоне",
|
"ru_RU": "В фоне",
|
||||||
"sv_SE": "",
|
"sv_SE": "Bakgrund",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Оновлювати в фоні",
|
"uk_UA": "Оновлювати в фоні",
|
||||||
|
@ -3489,7 +3614,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Ao Perder o Foco:",
|
"pt_BR": "Ao Perder o Foco:",
|
||||||
"ru_RU": "При выходе эмулятора из фокуса",
|
"ru_RU": "При выходе эмулятора из фокуса",
|
||||||
"sv_SE": "",
|
"sv_SE": "När emulatorn tappar fokus:",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "При втраті фокуса емулятором:",
|
"uk_UA": "При втраті фокуса емулятором:",
|
||||||
|
@ -3514,7 +3639,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Não Fazer Nada",
|
"pt_BR": "Não Fazer Nada",
|
||||||
"ru_RU": "Ничего не делать",
|
"ru_RU": "Ничего не делать",
|
||||||
"sv_SE": "",
|
"sv_SE": "Gör ingenting",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Нічого не робити",
|
"uk_UA": "Нічого не робити",
|
||||||
|
@ -3539,7 +3664,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Bloquear Controles",
|
"pt_BR": "Bloquear Controles",
|
||||||
"ru_RU": "Блокировать управление",
|
"ru_RU": "Блокировать управление",
|
||||||
"sv_SE": "",
|
"sv_SE": "Blockera inmatning",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Блокувати введення",
|
"uk_UA": "Блокувати введення",
|
||||||
|
@ -3564,7 +3689,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Ficar Mudo",
|
"pt_BR": "Ficar Mudo",
|
||||||
"ru_RU": "Отключить звук",
|
"ru_RU": "Отключить звук",
|
||||||
"sv_SE": "",
|
"sv_SE": "Stäng av ljudet",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Вимкнути звук",
|
"uk_UA": "Вимкнути звук",
|
||||||
|
@ -3589,7 +3714,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Bloquear Controles & Ficar Mudo",
|
"pt_BR": "Bloquear Controles & Ficar Mudo",
|
||||||
"ru_RU": "Блокировать управление и отключить звук",
|
"ru_RU": "Блокировать управление и отключить звук",
|
||||||
"sv_SE": "",
|
"sv_SE": "Blockera inmatningar och stäng av ljudet",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Блокувати введення та Вимкнути звук",
|
"uk_UA": "Блокувати введення та Вимкнути звук",
|
||||||
|
@ -3614,7 +3739,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Pausar a Emulação",
|
"pt_BR": "Pausar a Emulação",
|
||||||
"ru_RU": "Поставить паузу",
|
"ru_RU": "Поставить паузу",
|
||||||
"sv_SE": "",
|
"sv_SE": "Pausa emuleringen",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Поставити на паузу",
|
"uk_UA": "Поставити на паузу",
|
||||||
|
@ -3689,7 +3814,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Desativar Controles Quando Estiver Fora de Foco",
|
"pt_BR": "Desativar Controles Quando Estiver Fora de Foco",
|
||||||
"ru_RU": "Отключает управление при выходе из фокуса",
|
"ru_RU": "Отключает управление при выходе из фокуса",
|
||||||
"sv_SE": "",
|
"sv_SE": "Inaktivera inmatning när fokus tappas",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "",
|
"uk_UA": "",
|
||||||
|
@ -4714,7 +4839,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Sincronizar com o Sistema PC",
|
"pt_BR": "Sincronizar com o Sistema PC",
|
||||||
"ru_RU": "Соответствовать времени в системе",
|
"ru_RU": "Соответствовать времени в системе",
|
||||||
"sv_SE": "",
|
"sv_SE": "Matcha systemtid",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "",
|
"uk_UA": "",
|
||||||
|
@ -4888,7 +5013,7 @@
|
||||||
"no_NO": "Lyd Inn/Ut",
|
"no_NO": "Lyd Inn/Ut",
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "",
|
"pt_BR": "",
|
||||||
"ru_RU": "",
|
"ru_RU": "Выход/Вход звука",
|
||||||
"sv_SE": "",
|
"sv_SE": "",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
|
@ -5139,7 +5264,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Ignorar Applet do Controlador",
|
"pt_BR": "Ignorar Applet do Controlador",
|
||||||
"ru_RU": "Игнорировать апплет контроллера",
|
"ru_RU": "Игнорировать апплет контроллера",
|
||||||
"sv_SE": "",
|
"sv_SE": "Ignorera kontroller-applet",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Ігнорувати Аплет Контролера",
|
"uk_UA": "Ігнорувати Аплет Контролера",
|
||||||
|
@ -5989,7 +6114,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Habilitar Logs da IU",
|
"pt_BR": "Habilitar Logs da IU",
|
||||||
"ru_RU": "Включить журнал интерфейса",
|
"ru_RU": "Включить журнал интерфейса",
|
||||||
"sv_SE": "",
|
"sv_SE": "Aktivera gränssnittsloggar",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Увімкнути журнали інтерфейсу",
|
"uk_UA": "Увімкнути журнали інтерфейсу",
|
||||||
|
@ -6389,7 +6514,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Redefinir Configurações",
|
"pt_BR": "Redefinir Configurações",
|
||||||
"ru_RU": "Сбросить настройки",
|
"ru_RU": "Сбросить настройки",
|
||||||
"sv_SE": "",
|
"sv_SE": "Nollställ inställningar",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Скинути налаштування",
|
"uk_UA": "Скинути налаштування",
|
||||||
|
@ -6414,7 +6539,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Quero redefinir minhas configurações.",
|
"pt_BR": "Quero redefinir minhas configurações.",
|
||||||
"ru_RU": "Я хочу сбросить свои настройки.",
|
"ru_RU": "Я хочу сбросить свои настройки.",
|
||||||
"sv_SE": "",
|
"sv_SE": "Jag vill nollställa mina inställningar.",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Я хочу скинути налаштування.",
|
"uk_UA": "Я хочу скинути налаштування.",
|
||||||
|
@ -6438,7 +6563,7 @@
|
||||||
"no_NO": "",
|
"no_NO": "",
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "",
|
"pt_BR": "",
|
||||||
"ru_RU": "",
|
"ru_RU": "Ок",
|
||||||
"sv_SE": "Ok",
|
"sv_SE": "Ok",
|
||||||
"th_TH": "ตกลง",
|
"th_TH": "ตกลง",
|
||||||
"tr_TR": "Tamam",
|
"tr_TR": "Tamam",
|
||||||
|
@ -6888,7 +7013,7 @@
|
||||||
"no_NO": "",
|
"no_NO": "",
|
||||||
"pl_PL": "Pro Kontroler",
|
"pl_PL": "Pro Kontroler",
|
||||||
"pt_BR": "",
|
"pt_BR": "",
|
||||||
"ru_RU": "",
|
"ru_RU": "Pro контроллер",
|
||||||
"sv_SE": "",
|
"sv_SE": "",
|
||||||
"th_TH": "โปรคอนโทรลเลอร์",
|
"th_TH": "โปรคอนโทรลเลอร์",
|
||||||
"tr_TR": "Profesyonel Kumanda",
|
"tr_TR": "Profesyonel Kumanda",
|
||||||
|
@ -8464,7 +8589,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Velocidade do Arco-íris",
|
"pt_BR": "Velocidade do Arco-íris",
|
||||||
"ru_RU": "Скорость переливания",
|
"ru_RU": "Скорость переливания",
|
||||||
"sv_SE": "",
|
"sv_SE": "Regnbågshastighet",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "",
|
"uk_UA": "",
|
||||||
|
@ -12747,6 +12872,31 @@
|
||||||
"zh_TW": "正在下載更新..."
|
"zh_TW": "正在下載更新..."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ID": "DialogRebooterMessage",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "من فضلك انتظر، المحاكي في طور إعادة التشغيل",
|
||||||
|
"de_DE": "Bitte warten Sie, der Emulator wird neu gestartet",
|
||||||
|
"el_GR": "Παρακαλώ περιμένετε, ο εξομοιωτής επανεκκινείται",
|
||||||
|
"en_US": "Please wait, the emulator is restarting",
|
||||||
|
"es_ES": "Por favor, espere, el emulador se está reiniciando",
|
||||||
|
"fr_FR": "Veuillez patienter, l'émulateur est en train de redémarrer",
|
||||||
|
"he_IL": "אנא המתן, המחקה מתארגן מחדש",
|
||||||
|
"it_IT": "Attendere prego, l'emulatore si sta riavviando",
|
||||||
|
"ja_JP": "お待ちください、エミュレーターが再起動しています",
|
||||||
|
"ko_KR": "잠시만 기다려 주세요, 에뮬레이터가 재시작 중입니다",
|
||||||
|
"no_NO": "Vennligst vent, emulatoren starter på nytt",
|
||||||
|
"pl_PL": "Proszę czekać, emulator jest w trakcie ponownego uruchamiania",
|
||||||
|
"pt_BR": "Por favor, aguarde, o emulador está reiniciando",
|
||||||
|
"ru_RU": "Пожалуйста, подождите, эмулятор перезапускается",
|
||||||
|
"sv_SE": "Vänligen vänta, emulatorn startar om",
|
||||||
|
"th_TH": "กรุณารอสักครู่, ตัวจำลองกำลังเริ่มใหม่",
|
||||||
|
"tr_TR": "Lütfen bekleyin, emülatör yeniden başlatılıyor",
|
||||||
|
"uk_UA": "Будь ласка, зачекайте, емулятор перезавантажується",
|
||||||
|
"zh_CN": "请稍等,模拟器正在重新启动",
|
||||||
|
"zh_TW": "請稍候,模擬器正在重新啟動"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ID": "DialogUpdaterExtractionMessage",
|
"ID": "DialogUpdaterExtractionMessage",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
|
@ -13764,7 +13914,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Você está prestes a limpar todos os dados PPTC de:\n\n{0}\n\nTem certeza de que deseja continuar?",
|
"pt_BR": "Você está prestes a limpar todos os dados PPTC de:\n\n{0}\n\nTem certeza de que deseja continuar?",
|
||||||
"ru_RU": "Вы собираетесь удалить все данные PPTC из:\n\n{0}\n\nВы уверены, что хотите продолжить?",
|
"ru_RU": "Вы собираетесь удалить все данные PPTC из:\n\n{0}\n\nВы уверены, что хотите продолжить?",
|
||||||
"sv_SE": "",
|
"sv_SE": "Du är på väg att ta bort allt PPTC-data från:\n\n{0}\n\nÄr du säker på att du vill fortsätta?",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Ви збираєтесь видалити всі дані PPTC з:\n\n{0}\n\nБажаєте продовжити цю операцію?",
|
"uk_UA": "Ви збираєтесь видалити всі дані PPTC з:\n\n{0}\n\nБажаєте продовжити цю операцію?",
|
||||||
|
@ -16614,7 +16764,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "A caixa de diálogo do Applet do controlador não aparecerá se o controle for desconectado enquanto um aplicativo estiver em execução.\n\nDeixe a opção DESLIGADO se não tiver certeza.",
|
"pt_BR": "A caixa de diálogo do Applet do controlador não aparecerá se o controle for desconectado enquanto um aplicativo estiver em execução.\n\nDeixe a opção DESLIGADO se não tiver certeza.",
|
||||||
"ru_RU": "Диалоговое окно апплета контроллера не будет отображаться, если геймпад отключен во время работы приложения.\n\nОставьте выключенным, если не уверены.",
|
"ru_RU": "Диалоговое окно апплета контроллера не будет отображаться, если геймпад отключен во время работы приложения.\n\nОставьте выключенным, если не уверены.",
|
||||||
"sv_SE": "",
|
"sv_SE": "Handkontroller-appleten kommer inte att visas om gamepaden är frånkopplad under tiden en applikation körs.\n\nLämna AV om du är osäker.",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Діалогове вікно Аплету Контролера не з'явиться, якщо геймпад було відключено під час роботи програми.\n\nЗалиште вимкненим якщо не впевнені.",
|
"uk_UA": "Діалогове вікно Аплету Контролера не з'явиться, якщо геймпад було відключено під час роботи програми.\n\nЗалиште вимкненим якщо не впевнені.",
|
||||||
|
@ -17089,7 +17239,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Imprime mensagens de log do Avalonia (UI) no console.",
|
"pt_BR": "Imprime mensagens de log do Avalonia (UI) no console.",
|
||||||
"ru_RU": "Выводит сообщения журнала Avalonia (интерфейс) в консоли.",
|
"ru_RU": "Выводит сообщения журнала Avalonia (интерфейс) в консоли.",
|
||||||
"sv_SE": "",
|
"sv_SE": "Skriver ut loggmeddelanden från Avalonia (användargränssnittet) i konsollen.",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Виводити повідомлення журналу Avalonia (UI) в консоль",
|
"uk_UA": "Виводити повідомлення журналу Avalonia (UI) в консоль",
|
||||||
|
@ -17289,7 +17439,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Abre a pasta de capturas de tela do Ryujinx",
|
"pt_BR": "Abre a pasta de capturas de tela do Ryujinx",
|
||||||
"ru_RU": "Открывает папку скриншотов Ryujinx",
|
"ru_RU": "Открывает папку скриншотов Ryujinx",
|
||||||
"sv_SE": "",
|
"sv_SE": "Öppna Ryujinx skärmbildsmapp",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Відкрити теку куди зберігаються скріншоти Ryujinx",
|
"uk_UA": "Відкрити теку куди зберігаються скріншоти Ryujinx",
|
||||||
|
@ -18039,7 +18189,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Atualização Disponível!",
|
"pt_BR": "Atualização Disponível!",
|
||||||
"ru_RU": "Доступно обновление!",
|
"ru_RU": "Доступно обновление!",
|
||||||
"sv_SE": "",
|
"sv_SE": "Uppdatering finns tillgänglig!",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Доступне оновлення!",
|
"uk_UA": "Доступне оновлення!",
|
||||||
|
@ -19622,6 +19772,31 @@
|
||||||
"zh_TW": "{0} 更新程式"
|
"zh_TW": "{0} 更新程式"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ID": "RyujinxRebooter",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "إعادة تشغيل {0}",
|
||||||
|
"de_DE": "Neustart von {0}",
|
||||||
|
"el_GR": "Επανεκκίνηση {0}",
|
||||||
|
"en_US": "{0} Reboot",
|
||||||
|
"es_ES": "Reinicio de {0}",
|
||||||
|
"fr_FR": "Redémarrage de {0}",
|
||||||
|
"he_IL": "אתחול {0}",
|
||||||
|
"it_IT": "Riavvio di {0}",
|
||||||
|
"ja_JP": "{0} 再起動",
|
||||||
|
"ko_KR": "{0} 재부팅",
|
||||||
|
"no_NO": "Omstart av {0}",
|
||||||
|
"pl_PL": "Ponowne uruchomienie {0}",
|
||||||
|
"pt_BR": "Reinício de {0}",
|
||||||
|
"ru_RU": "{0} Перезагрузка",
|
||||||
|
"sv_SE": "Ominläsning av {0}",
|
||||||
|
"th_TH": "เริ่มต้นใหม่ {0}",
|
||||||
|
"tr_TR": "{0} Yeniden Başlatma",
|
||||||
|
"uk_UA": "Перезавантаження {0}",
|
||||||
|
"zh_CN": "{0} 重启",
|
||||||
|
"zh_TW": "{0} 重新啟動"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ID": "SettingsTabHotkeys",
|
"ID": "SettingsTabHotkeys",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
|
@ -19938,7 +20113,7 @@
|
||||||
"no_NO": "",
|
"no_NO": "",
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "",
|
"pt_BR": "",
|
||||||
"ru_RU": "",
|
"ru_RU": "Амибо",
|
||||||
"sv_SE": "",
|
"sv_SE": "",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
|
@ -23989,7 +24164,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Inicializa e roda sem travamentos ou bugs de GPU de qualquer tipo, e em uma velocidade rápida o suficiente para ser aproveitado em um PC comum.",
|
"pt_BR": "Inicializa e roda sem travamentos ou bugs de GPU de qualquer tipo, e em uma velocidade rápida o suficiente para ser aproveitado em um PC comum.",
|
||||||
"ru_RU": "Запускается и работает без любого рода сбоев или графисечких ошибок и на скорости, достаточной для работы на обычном ПК.",
|
"ru_RU": "Запускается и работает без любого рода сбоев или графисечких ошибок и на скорости, достаточной для работы на обычном ПК.",
|
||||||
"sv_SE": "",
|
"sv_SE": "Startar upp och spelas utan några krascher eller GPU-fel av några slag och med en hastighet som är snabb nog för bra upplevelse på en genomsnittlig PC.",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Запускається та оптимально працює (без збоїв або графічних багів) на середньостатистичному комп'ютері.",
|
"uk_UA": "Запускається та оптимально працює (без збоїв або графічних багів) на середньостатистичному комп'ютері.",
|
||||||
|
@ -24014,7 +24189,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Inicializa e entra no jogo, mas sofre de um ou mais dos seguintes: travamentos, deadlocks, bugs de GPU, áudio ruim que distrai ou é simplesmente muito lento. O jogo ainda pode ser jogado até o fim, mas não da forma como foi criado para ser jogado.",
|
"pt_BR": "Inicializa e entra no jogo, mas sofre de um ou mais dos seguintes: travamentos, deadlocks, bugs de GPU, áudio ruim que distrai ou é simplesmente muito lento. O jogo ainda pode ser jogado até o fim, mas não da forma como foi criado para ser jogado.",
|
||||||
"ru_RU": "Запускается и работает, но возникает одна или несколько из следующих проблем: сбои, взаимоблокировки, ошибки GPU, отвлекающие звуки или просто слишком медленная работа. Возможно, игру всё же удастся пройти до конца, но не так, как она задумана.",
|
"ru_RU": "Запускается и работает, но возникает одна или несколько из следующих проблем: сбои, взаимоблокировки, ошибки GPU, отвлекающие звуки или просто слишком медленная работа. Возможно, игру всё же удастся пройти до конца, но не так, как она задумана.",
|
||||||
"sv_SE": "",
|
"sv_SE": "Startar och går in i spelet men lider av ett eller flera av följande: kraschar, deadlocks, GPU-buggar, distraherande dåligt ljud eller är helt enkelt för långsamt. Spelet kan fortfarande spelas hela vägen igenom, men inte så som spelet är avsett att spelas.",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Запускається, але в грі на вас чекатимуть одна або декілька наступних проблем: збої, зависання, графічні баги, спотворений звук або ж гра загалом працюватиме надто повільно. Можливо, її все ще можна пройти, але досвід буде не найкращим.",
|
"uk_UA": "Запускається, але в грі на вас чекатимуть одна або декілька наступних проблем: збої, зависання, графічні баги, спотворений звук або ж гра загалом працюватиме надто повільно. Можливо, її все ще можна пройти, але досвід буде не найкращим.",
|
||||||
|
@ -24039,7 +24214,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Inicializa e passa da tela de título, mas não entra no jogo principal.",
|
"pt_BR": "Inicializa e passa da tela de título, mas não entra no jogo principal.",
|
||||||
"ru_RU": "Загружается титульный экран и можно перейти дальше, но сама игра не работает.",
|
"ru_RU": "Загружается титульный экран и можно перейти дальше, но сама игра не работает.",
|
||||||
"sv_SE": "",
|
"sv_SE": "Startar upp och går förbi titelskärmen men tar sig inte in i huvudspelet.",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Запускається та проходить початковий екран, але пограти не вийде.",
|
"uk_UA": "Запускається та проходить початковий екран, але пограти не вийде.",
|
||||||
|
@ -24064,7 +24239,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Inizializa, mas não passa da tela de título.",
|
"pt_BR": "Inizializa, mas não passa da tela de título.",
|
||||||
"ru_RU": "Загружается, но не проходит дальше титульного экрана.",
|
"ru_RU": "Загружается, но не проходит дальше титульного экрана.",
|
||||||
"sv_SE": "",
|
"sv_SE": "Startar upp men tar sig inte förbi titelskärmen.",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Запускається, але не відображає навіть початкового екрану.",
|
"uk_UA": "Запускається, але не відображає навіть початкового екрану.",
|
||||||
|
@ -24089,7 +24264,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Não inicializa ou não mostra sinais de atividade.",
|
"pt_BR": "Não inicializa ou não mostra sinais de atividade.",
|
||||||
"ru_RU": "Не запускается или не подаёт признаков жизни.",
|
"ru_RU": "Не запускается или не подаёт признаков жизни.",
|
||||||
"sv_SE": "",
|
"sv_SE": "Startar inte upp eller visar någon form av aktivitet.",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Взагалі не запускається.",
|
"uk_UA": "Взагалі не запускається.",
|
||||||
|
@ -24097,6 +24272,56 @@
|
||||||
"zh_TW": ""
|
"zh_TW": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ID": "GameSpecificConfigurationHeader",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "",
|
||||||
|
"de_DE": "",
|
||||||
|
"el_GR": "",
|
||||||
|
"en_US": "Custom Config",
|
||||||
|
"es_ES": "",
|
||||||
|
"fr_FR": "",
|
||||||
|
"he_IL": "",
|
||||||
|
"it_IT": "",
|
||||||
|
"ja_JP": "",
|
||||||
|
"ko_KR": "",
|
||||||
|
"no_NO": "",
|
||||||
|
"pl_PL": "",
|
||||||
|
"pt_BR": "",
|
||||||
|
"ru_RU": "",
|
||||||
|
"sv_SE": "",
|
||||||
|
"th_TH": "",
|
||||||
|
"tr_TR": "",
|
||||||
|
"uk_UA": "",
|
||||||
|
"zh_CN": "",
|
||||||
|
"zh_TW": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ID": "GameSpecificConfigurationGlobal",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "",
|
||||||
|
"de_DE": "",
|
||||||
|
"el_GR": "",
|
||||||
|
"en_US": "(Global)",
|
||||||
|
"es_ES": "",
|
||||||
|
"fr_FR": "",
|
||||||
|
"he_IL": "",
|
||||||
|
"it_IT": "",
|
||||||
|
"ja_JP": "",
|
||||||
|
"ko_KR": "",
|
||||||
|
"no_NO": "",
|
||||||
|
"pl_PL": "",
|
||||||
|
"pt_BR": "",
|
||||||
|
"ru_RU": "",
|
||||||
|
"sv_SE": "",
|
||||||
|
"th_TH": "",
|
||||||
|
"tr_TR": "",
|
||||||
|
"uk_UA": "",
|
||||||
|
"zh_CN": "",
|
||||||
|
"zh_TW": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ID": "ExtractAocListHeader",
|
"ID": "ExtractAocListHeader",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
|
@ -24139,7 +24364,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Imagem da Presença do Discord",
|
"pt_BR": "Imagem da Presença do Discord",
|
||||||
"ru_RU": "Изображение для статуса активности",
|
"ru_RU": "Изображение для статуса активности",
|
||||||
"sv_SE": "",
|
"sv_SE": "Bild för Rich Presence",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Зображення картки активності Discord",
|
"uk_UA": "Зображення картки активності Discord",
|
||||||
|
@ -24164,7 +24389,7 @@
|
||||||
"pl_PL": "",
|
"pl_PL": "",
|
||||||
"pt_BR": "Presença Dinâmica do Discord",
|
"pt_BR": "Presença Dinâmica do Discord",
|
||||||
"ru_RU": "Динамический статус активности",
|
"ru_RU": "Динамический статус активности",
|
||||||
"sv_SE": "",
|
"sv_SE": "Dynamisk Rich Presence",
|
||||||
"th_TH": "",
|
"th_TH": "",
|
||||||
"tr_TR": "",
|
"tr_TR": "",
|
||||||
"uk_UA": "Динамічна картка активності Discord",
|
"uk_UA": "Динамічна картка активності Discord",
|
||||||
|
|
|
@ -54,6 +54,7 @@ namespace Ryujinx.Ava.Common.Locale
|
||||||
SetDynamicValues(LocaleKeys.RyujinxInfo, RyujinxApp.FullAppName);
|
SetDynamicValues(LocaleKeys.RyujinxInfo, RyujinxApp.FullAppName);
|
||||||
SetDynamicValues(LocaleKeys.RyujinxConfirm, RyujinxApp.FullAppName);
|
SetDynamicValues(LocaleKeys.RyujinxConfirm, RyujinxApp.FullAppName);
|
||||||
SetDynamicValues(LocaleKeys.RyujinxUpdater, RyujinxApp.FullAppName);
|
SetDynamicValues(LocaleKeys.RyujinxUpdater, RyujinxApp.FullAppName);
|
||||||
|
SetDynamicValues(LocaleKeys.RyujinxRebooter, RyujinxApp.FullAppName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string this[LocaleKeys key]
|
public string this[LocaleKeys key]
|
||||||
|
|
|
@ -32,8 +32,10 @@ namespace Ryujinx.Ava
|
||||||
public static double DesktopScaleFactor { get; set; } = 1.0;
|
public static double DesktopScaleFactor { get; set; } = 1.0;
|
||||||
public static string Version { get; private set; }
|
public static string Version { get; private set; }
|
||||||
public static string ConfigurationPath { get; private set; }
|
public static string ConfigurationPath { get; private set; }
|
||||||
|
public static string GlobalConfigurationPath { get; private set; }
|
||||||
public static bool PreviewerDetached { get; private set; }
|
public static bool PreviewerDetached { get; private set; }
|
||||||
public static bool UseHardwareAcceleration { get; private set; }
|
public static bool UseHardwareAcceleration { get; private set; }
|
||||||
|
public static string BackendThreadingArg { get; private set; }
|
||||||
|
|
||||||
[LibraryImport("user32.dll", SetLastError = true)]
|
[LibraryImport("user32.dll", SetLastError = true)]
|
||||||
public static partial int MessageBoxA(nint hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type);
|
public static partial int MessageBoxA(nint hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type);
|
||||||
|
@ -156,11 +158,38 @@ namespace Ryujinx.Ava
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetDirGameUserConfig(string gameId, bool rememberGlobalDir = false, bool changeFolderForGame = false)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(gameId))
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
string gameDir = Path.Combine(AppDataManager.GamesDirPath, gameId, ReleaseInformation.ConfigName);
|
||||||
|
|
||||||
|
// Should load with the game if there is a custom setting for the game
|
||||||
|
if (rememberGlobalDir)
|
||||||
|
{
|
||||||
|
GlobalConfigurationPath = ConfigurationPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changeFolderForGame)
|
||||||
|
{
|
||||||
|
ConfigurationPath = gameDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gameDir;
|
||||||
|
}
|
||||||
|
|
||||||
public static void ReloadConfig()
|
public static void ReloadConfig()
|
||||||
{
|
{
|
||||||
|
//It is necessary that when a user setting appears, the global setting remains available
|
||||||
|
GlobalConfigurationPath = null;
|
||||||
|
|
||||||
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName);
|
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName);
|
||||||
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName);
|
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName);
|
||||||
|
|
||||||
|
|
||||||
// Now load the configuration as the other subsystems are now registered
|
// Now load the configuration as the other subsystems are now registered
|
||||||
if (File.Exists(localConfigurationPath))
|
if (File.Exists(localConfigurationPath))
|
||||||
{
|
{
|
||||||
|
@ -217,6 +246,11 @@ namespace Ryujinx.Ava
|
||||||
_ => ConfigurationState.Instance.Graphics.BackendThreading
|
_ => ConfigurationState.Instance.Graphics.BackendThreading
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (CommandLineState.OverrideBackendThreadingAfterReboot is not null)
|
||||||
|
{
|
||||||
|
BackendThreadingArg = CommandLineState.OverrideBackendThreadingAfterReboot;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if docked mode was overriden.
|
// Check if docked mode was overriden.
|
||||||
if (CommandLineState.OverrideDockedMode.HasValue)
|
if (CommandLineState.OverrideDockedMode.HasValue)
|
||||||
ConfigurationState.Instance.System.EnableDockedMode.Value = CommandLineState.OverrideDockedMode.Value;
|
ConfigurationState.Instance.System.EnableDockedMode.Value = CommandLineState.OverrideDockedMode.Value;
|
||||||
|
@ -232,6 +266,33 @@ namespace Ryujinx.Ava
|
||||||
_ => ConfigurationState.Instance.HideCursor,
|
_ => ConfigurationState.Instance.HideCursor,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Check if memoryManagerMode was overridden.
|
||||||
|
if (CommandLineState.OverrideMemoryManagerMode is not null)
|
||||||
|
if (Enum.TryParse(CommandLineState.OverrideMemoryManagerMode, true, out MemoryManagerMode result))
|
||||||
|
{
|
||||||
|
ConfigurationState.Instance.System.MemoryManagerMode.Value = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if PPTC was overridden.
|
||||||
|
if (CommandLineState.OverridePPTC is not null)
|
||||||
|
if (Enum.TryParse(CommandLineState.OverridePPTC, true, out bool result))
|
||||||
|
{
|
||||||
|
ConfigurationState.Instance.System.EnablePtc.Value = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if region was overridden.
|
||||||
|
if (CommandLineState.OverrideSystemRegion is not null)
|
||||||
|
if (Enum.TryParse(CommandLineState.OverrideSystemRegion, true, out Ryujinx.HLE.HOS.SystemState.RegionCode result))
|
||||||
|
{
|
||||||
|
ConfigurationState.Instance.System.Region.Value = (Utilities.Configuration.System.Region)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if language was overridden.
|
||||||
|
if (CommandLineState.OverrideSystemLanguage is not null)
|
||||||
|
if (Enum.TryParse(CommandLineState.OverrideSystemLanguage, true, out Ryujinx.HLE.HOS.SystemState.SystemLanguage result))
|
||||||
|
{
|
||||||
|
ConfigurationState.Instance.System.Language.Value = (Utilities.Configuration.System.Language)result;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if hardware-acceleration was overridden.
|
// Check if hardware-acceleration was overridden.
|
||||||
if (CommandLineState.OverrideHardwareAcceleration != null)
|
if (CommandLineState.OverrideHardwareAcceleration != null)
|
||||||
|
|
76
src/Ryujinx/Rebooter.cs
Normal file
76
src/Ryujinx/Rebooter.cs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
using FluentAvalonia.UI.Controls;
|
||||||
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
|
using Ryujinx.Ava.Utilities;
|
||||||
|
using SkiaSharp;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava
|
||||||
|
{
|
||||||
|
internal static class Rebooter
|
||||||
|
{
|
||||||
|
|
||||||
|
private static readonly string _updateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update");
|
||||||
|
|
||||||
|
|
||||||
|
public static void RebootAppWithGame(string gamePath, List<string> args)
|
||||||
|
{
|
||||||
|
_ = Reboot(gamePath, args);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task Reboot(string gamePath, List<string> args)
|
||||||
|
{
|
||||||
|
|
||||||
|
bool shouldRestart = true;
|
||||||
|
|
||||||
|
TaskDialog taskDialog = new()
|
||||||
|
{
|
||||||
|
Header = LocaleManager.Instance[LocaleKeys.RyujinxRebooter],
|
||||||
|
SubHeader = LocaleManager.Instance[LocaleKeys.DialogRebooterMessage],
|
||||||
|
IconSource = new SymbolIconSource { Symbol = Symbol.Games },
|
||||||
|
XamlRoot = RyujinxApp.MainWindow,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (shouldRestart)
|
||||||
|
{
|
||||||
|
List<string> arguments = CommandLineState.Arguments.ToList();
|
||||||
|
string executableDirectory = AppDomain.CurrentDomain.BaseDirectory;
|
||||||
|
|
||||||
|
var dialogTask = taskDialog.ShowAsync(true);
|
||||||
|
await Task.Delay(500);
|
||||||
|
|
||||||
|
// Find the process name.
|
||||||
|
string ryuName = Path.GetFileName(Environment.ProcessPath) ?? string.Empty;
|
||||||
|
|
||||||
|
// Fallback if the executable could not be found.
|
||||||
|
if (ryuName.Length == 0 || !Path.Exists(Path.Combine(executableDirectory, ryuName)))
|
||||||
|
{
|
||||||
|
ryuName = OperatingSystem.IsWindows() ? "Ryujinx.exe" : "Ryujinx";
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessStartInfo processStart = new(ryuName)
|
||||||
|
{
|
||||||
|
UseShellExecute = true,
|
||||||
|
WorkingDirectory = executableDirectory,
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var arg in args)
|
||||||
|
{
|
||||||
|
processStart.ArgumentList.Add(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
processStart.ArgumentList.Add(gamePath);
|
||||||
|
|
||||||
|
Process.Start(processStart);
|
||||||
|
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -95,7 +95,7 @@ namespace Ryujinx.Ava.UI.Applet
|
||||||
_parent.SettingsWindow =
|
_parent.SettingsWindow =
|
||||||
new SettingsWindow(_parent.VirtualFileSystem, _parent.ContentManager);
|
new SettingsWindow(_parent.VirtualFileSystem, _parent.ContentManager);
|
||||||
|
|
||||||
await _parent.SettingsWindow.ShowDialog(window);
|
await StyleableAppWindow.ShowAsync(_parent.SettingsWindow, window);
|
||||||
|
|
||||||
_parent.SettingsWindow = null;
|
_parent.SettingsWindow = null;
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,18 @@
|
||||||
Header="{ext:Locale GameListContextMenuCreateShortcut}"
|
Header="{ext:Locale GameListContextMenuCreateShortcut}"
|
||||||
Icon="{ext:Icon fa-solid fa-bookmark}"
|
Icon="{ext:Icon fa-solid fa-bookmark}"
|
||||||
ToolTip.Tip="{OnPlatform Default={ext:Locale GameListContextMenuCreateShortcutToolTip}, macOS={ext:Locale GameListContextMenuCreateShortcutToolTipMacOS}}" />
|
ToolTip.Tip="{OnPlatform Default={ext:Locale GameListContextMenuCreateShortcutToolTip}, macOS={ext:Locale GameListContextMenuCreateShortcutToolTipMacOS}}" />
|
||||||
|
<MenuItem
|
||||||
|
Click="EditGameConfiguration_Click"
|
||||||
|
IsVisible="{Binding SelectedApplication.HasIndependentConfiguration}"
|
||||||
|
Header="{ext:Locale GameListContextMenuEditCustomConfiguration}"
|
||||||
|
Icon="{ext:Icon fa-solid fa-gear}"
|
||||||
|
ToolTip.Tip="{ext:Locale EditCustomConfigurationToolTip}" />
|
||||||
|
<MenuItem
|
||||||
|
Click="EditGameConfiguration_Click"
|
||||||
|
IsVisible="{Binding !SelectedApplication.HasIndependentConfiguration}"
|
||||||
|
Header="{ext:Locale GameListContextMenuCreateCustomConfiguration}"
|
||||||
|
Icon="{ext:Icon fa-solid fa-gear}"
|
||||||
|
ToolTip.Tip="{ext:Locale CreateCustomConfigurationToolTip}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
IsVisible="{Binding HasCompatibilityEntry}"
|
IsVisible="{Binding HasCompatibilityEntry}"
|
||||||
Click="OpenApplicationCompatibility_Click"
|
Click="OpenApplicationCompatibility_Click"
|
||||||
|
|
|
@ -91,11 +91,14 @@ namespace Ryujinx.Ava.UI.Controls
|
||||||
public async void OpenCheatManager_Click(object sender, RoutedEventArgs args)
|
public async void OpenCheatManager_Click(object sender, RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||||
await new CheatWindow(
|
await StyleableAppWindow.ShowAsync(
|
||||||
|
new CheatWindow(
|
||||||
viewModel.VirtualFileSystem,
|
viewModel.VirtualFileSystem,
|
||||||
viewModel.SelectedApplication.IdString,
|
viewModel.SelectedApplication.IdString,
|
||||||
viewModel.SelectedApplication.Name,
|
viewModel.SelectedApplication.Name,
|
||||||
viewModel.SelectedApplication.Path).ShowDialog((Window)viewModel.TopLevel);
|
viewModel.SelectedApplication.Path
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OpenModsDirectory_Click(object sender, RoutedEventArgs args)
|
public void OpenModsDirectory_Click(object sender, RoutedEventArgs args)
|
||||||
|
@ -200,7 +203,7 @@ namespace Ryujinx.Ava.UI.Controls
|
||||||
if (backupDir.Exists)
|
if (backupDir.Exists)
|
||||||
{
|
{
|
||||||
cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache"));
|
cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache"));
|
||||||
cacheFiles.AddRange(mainDir.EnumerateFiles("*.info"));
|
cacheFiles.AddRange(backupDir.EnumerateFiles("*.info"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cacheFiles.Count > 0)
|
if (cacheFiles.Count > 0)
|
||||||
|
@ -387,6 +390,19 @@ namespace Ryujinx.Ava.UI.Controls
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async void EditGameConfiguration_Click(object sender, RoutedEventArgs args)
|
||||||
|
{
|
||||||
|
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||||
|
{
|
||||||
|
await StyleableAppWindow.ShowAsync(new GameSpecificSettingsWindow(viewModel));
|
||||||
|
|
||||||
|
// just checking for file presence
|
||||||
|
viewModel.SelectedApplication.HasIndependentConfiguration = File.Exists(Program.GetDirGameUserConfig(viewModel.SelectedApplication.IdString,false,false));
|
||||||
|
|
||||||
|
viewModel.RefreshView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async void OpenApplicationCompatibility_Click(object sender, RoutedEventArgs args)
|
public async void OpenApplicationCompatibility_Click(object sender, RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
|
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
Focusable="True"
|
Focusable="True"
|
||||||
|
@ -73,12 +74,18 @@
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
IsVisible="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).ShowNames}">
|
IsVisible="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).ShowNames}">
|
||||||
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="{Binding Name}"
|
Text="{Binding Name}"
|
||||||
TextAlignment="Center"
|
TextAlignment="Center"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
<TextBlock
|
||||||
|
IsVisible="{Binding HasIndependentConfiguration}"
|
||||||
|
Text="{ext:Locale GameSpecificConfigurationHeader}"
|
||||||
|
TextAlignment="Center"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Foreground="{DynamicResource Warning}" />
|
||||||
|
</StackPanel>
|
||||||
</Panel>
|
</Panel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
@ -86,10 +93,28 @@
|
||||||
Margin="5,5,0,0"
|
Margin="5,5,0,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
FontSize="16"
|
FontSize="18"
|
||||||
Foreground="{DynamicResource FavoriteApplicationIconColor}"
|
Foreground="{DynamicResource FavoriteApplicationIconColor}"
|
||||||
IsVisible="{Binding Favorite}"
|
IsVisible="{Binding Favorite}"
|
||||||
Symbol="StarFilled" />
|
Symbol="StarFilled" />
|
||||||
|
<Grid IsVisible="{Binding !$parent[UserControl].((viewModels:MainWindowViewModel)DataContext).ShowNames}">
|
||||||
|
<Border
|
||||||
|
Margin="15,35,5,15"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Width="90"
|
||||||
|
Height="20"
|
||||||
|
CornerRadius="4"
|
||||||
|
IsVisible="{Binding HasIndependentConfiguration}"
|
||||||
|
Background="{DynamicResource ThemeContentBackgroundColor}">
|
||||||
|
<TextBlock
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{ext:Locale GameSpecificConfigurationHeader}"
|
||||||
|
TextAlignment="Center"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
Focusable="True"
|
Focusable="True"
|
||||||
|
@ -156,6 +157,13 @@
|
||||||
Text="{Binding Converter={x:Static helpers:MultiplayerInfoConverter.Instance}}"
|
Text="{Binding Converter={x:Static helpers:MultiplayerInfoConverter.Instance}}"
|
||||||
TextAlignment="Start"
|
TextAlignment="Start"
|
||||||
TextWrapping="Wrap"/>
|
TextWrapping="Wrap"/>
|
||||||
|
<TextBlock
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
IsVisible="{Binding HasIndependentConfiguration}"
|
||||||
|
Text="{ext:Locale GameSpecificConfigurationHeader}"
|
||||||
|
TextAlignment="Start"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Foreground="{DynamicResource Warning}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Column="4"
|
Grid.Column="4"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
|
using Avalonia.Input;
|
||||||
using Avalonia.Layout;
|
using Avalonia.Layout;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
@ -385,6 +386,10 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||||
ShowInTaskbar = false,
|
ShowInTaskbar = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
_contentDialogOverlayWindow.AttachDevTools(new KeyGesture(Key.F12, KeyModifiers.Control));
|
||||||
|
#endif
|
||||||
|
|
||||||
parent.PositionChanged += OverlayOnPositionChanged;
|
parent.PositionChanged += OverlayOnPositionChanged;
|
||||||
|
|
||||||
void OverlayOnPositionChanged(object sender, PixelPointEventArgs e)
|
void OverlayOnPositionChanged(object sender, PixelPointEventArgs e)
|
||||||
|
|
|
@ -356,6 +356,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ListSelectedApplication = value;
|
||||||
|
GridSelectedApplication = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasCompatibilityEntry => SelectedApplication.HasPlayabilityInfo;
|
public bool HasCompatibilityEntry => SelectedApplication.HasPlayabilityInfo;
|
||||||
|
@ -1551,8 +1556,50 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool InitializeUserConfig(ApplicationData application)
|
||||||
|
{
|
||||||
|
// Code where conditions will be met before loading the user configuration (Global Config)
|
||||||
|
BackendThreading backendThreadingValue = ConfigurationState.Instance.Graphics.BackendThreading.Value;
|
||||||
|
string BackendThreadingInit = Program.BackendThreadingArg;
|
||||||
|
|
||||||
|
if (BackendThreadingInit is null)
|
||||||
|
{
|
||||||
|
BackendThreadingInit = ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a configuration is found in the "/games/xxxxxxxxxxxxxx" folder, the program will load the user setting.
|
||||||
|
string idGame = application.IdBaseString;
|
||||||
|
if (ConfigurationFileFormat.TryLoad(Program.GetDirGameUserConfig(idGame), out ConfigurationFileFormat configurationFileFormat))
|
||||||
|
{
|
||||||
|
// Loads the user configuration, having previously changed the global configuration to the user configuration
|
||||||
|
ConfigurationState.Instance.Load(configurationFileFormat, Program.GetDirGameUserConfig(idGame, true, true), idGame);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code where conditions will be executed after loading user configuration
|
||||||
|
if (ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString() != BackendThreadingInit)
|
||||||
|
{
|
||||||
|
|
||||||
|
List<string> Arguments = new List<string>
|
||||||
|
{
|
||||||
|
"--bt", ConfigurationState.Instance.Graphics.BackendThreading.Value.ToString() // BackendThreading
|
||||||
|
};
|
||||||
|
|
||||||
|
Rebooter.RebootAppWithGame(application.Path, Arguments);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task LoadApplication(ApplicationData application, bool startFullscreen = false, BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
public async Task LoadApplication(ApplicationData application, bool startFullscreen = false, BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (InitializeUserConfig(application))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (AppHost != null)
|
if (AppHost != null)
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateInfoDialog(
|
await ContentDialogHelper.CreateInfoDialog(
|
||||||
|
@ -1613,6 +1660,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
Thread gameThread = new(InitializeGame) { Name = "GUI.WindowThread" };
|
Thread gameThread = new(InitializeGame) { Name = "GUI.WindowThread" };
|
||||||
gameThread.Start();
|
gameThread.Start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SwitchToRenderer(bool startFullscreen) =>
|
public void SwitchToRenderer(bool startFullscreen) =>
|
||||||
|
@ -1699,7 +1747,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
string titleId = AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper();
|
string titleId = AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper();
|
||||||
AmiiboWindow window = new(ShowAll, LastScannedAmiiboId, titleId);
|
AmiiboWindow window = new(ShowAll, LastScannedAmiiboId, titleId);
|
||||||
|
|
||||||
await window.ShowDialog(Window);
|
await StyleableAppWindow.ShowAsync(window);
|
||||||
|
|
||||||
if (window.IsScanned)
|
if (window.IsScanned)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
@ -27,6 +28,7 @@ using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -68,6 +70,19 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
public SettingsHacksViewModel DirtyHacks { get; }
|
public SettingsHacksViewModel DirtyHacks { get; }
|
||||||
|
|
||||||
|
private readonly bool _isGameRunning;
|
||||||
|
private Bitmap _gameIcon;
|
||||||
|
private string _gameTitle;
|
||||||
|
private string _gamePath;
|
||||||
|
private string _gameId;
|
||||||
|
public bool IsGameRunning => _isGameRunning;
|
||||||
|
public Bitmap GameIcon => _gameIcon;
|
||||||
|
public string GamePath => _gamePath;
|
||||||
|
public string GameTitle => _gameTitle;
|
||||||
|
public string GameId => _gameId;
|
||||||
|
public bool IsGameTitleNotNull => !string.IsNullOrEmpty(GameTitle);
|
||||||
|
public double PanelOpacity => IsGameTitleNotNull ? 0.5 : 1;
|
||||||
|
|
||||||
public int ResolutionScale
|
public int ResolutionScale
|
||||||
{
|
{
|
||||||
get => _resolutionScale;
|
get => _resolutionScale;
|
||||||
|
@ -335,7 +350,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
public bool IsInvalidLdnPassphraseVisible { get; set; }
|
public bool IsInvalidLdnPassphraseVisible { get; set; }
|
||||||
|
|
||||||
public SettingsViewModel(VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this()
|
public SettingsViewModel(VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this(false)
|
||||||
{
|
{
|
||||||
_virtualFileSystem = virtualFileSystem;
|
_virtualFileSystem = virtualFileSystem;
|
||||||
_contentManager = contentManager;
|
_contentManager = contentManager;
|
||||||
|
@ -348,7 +363,51 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SettingsViewModel()
|
public SettingsViewModel(
|
||||||
|
VirtualFileSystem virtualFileSystem,
|
||||||
|
ContentManager contentManager,
|
||||||
|
bool gameRunning,
|
||||||
|
string gamePath,
|
||||||
|
string gameName,
|
||||||
|
string gameId,
|
||||||
|
byte[] gameIconData,
|
||||||
|
bool enableToLoadCustomConfig) : this(enableToLoadCustomConfig)
|
||||||
|
{
|
||||||
|
_virtualFileSystem = virtualFileSystem;
|
||||||
|
_contentManager = contentManager;
|
||||||
|
|
||||||
|
if (gameIconData != null && gameIconData.Length > 0)
|
||||||
|
{
|
||||||
|
using (var ms = new MemoryStream(gameIconData))
|
||||||
|
{
|
||||||
|
_gameIcon = new Bitmap(ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_isGameRunning = gameRunning;
|
||||||
|
_gamePath = gamePath;
|
||||||
|
_gameTitle = gameName;
|
||||||
|
_gameId = gameId;
|
||||||
|
|
||||||
|
if (enableToLoadCustomConfig) // During the game. If there is no user config, then load the global config window
|
||||||
|
{
|
||||||
|
string gameDir = Program.GetDirGameUserConfig(gameId, false, true);
|
||||||
|
if (ConfigurationFileFormat.TryLoad(gameDir, out ConfigurationFileFormat configurationFileFormat))
|
||||||
|
{
|
||||||
|
ConfigurationState.Instance.Load(configurationFileFormat, gameDir, gameId);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadCurrentConfiguration(); // Needed to load custom configuration
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Program.PreviewerDetached)
|
||||||
|
{
|
||||||
|
Task.Run(LoadTimeZones);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SettingsViewModel(bool noLoadGlobalConfig = false)
|
||||||
{
|
{
|
||||||
GameDirectories = [];
|
GameDirectories = [];
|
||||||
AutoloadDirectories = [];
|
AutoloadDirectories = [];
|
||||||
|
@ -363,6 +422,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
if (Program.PreviewerDetached)
|
if (Program.PreviewerDetached)
|
||||||
{
|
{
|
||||||
Task.Run(LoadAvailableGpus);
|
Task.Run(LoadAvailableGpus);
|
||||||
|
|
||||||
|
// if (!noLoadGlobalConfig)// Default is false, but loading custom config avoids double call
|
||||||
LoadCurrentConfiguration();
|
LoadCurrentConfiguration();
|
||||||
|
|
||||||
DirtyHacks = new SettingsHacksViewModel(this);
|
DirtyHacks = new SettingsHacksViewModel(this);
|
||||||
|
@ -711,15 +772,39 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RevertIfNotSaved()
|
private static void RevertIfNotSaved()
|
||||||
|
{
|
||||||
|
// maybe this is an unnecessary check(all options need to be tested)
|
||||||
|
if (string.IsNullOrEmpty(Program.GlobalConfigurationPath))
|
||||||
{
|
{
|
||||||
Program.ReloadConfig();
|
Program.ReloadConfig();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void ApplyButton()
|
public void ApplyButton()
|
||||||
{
|
{
|
||||||
SaveSettings();
|
SaveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DeleteConfigGame()
|
||||||
|
{
|
||||||
|
string gameDir = Program.GetDirGameUserConfig(GameId,false,false);
|
||||||
|
|
||||||
|
if (File.Exists(gameDir))
|
||||||
|
{
|
||||||
|
File.Delete(gameDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
RevertIfNotSaved();
|
||||||
|
CloseWindow?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveUserConfig()
|
||||||
|
{
|
||||||
|
SaveSettings();
|
||||||
|
RevertIfNotSaved(); // Revert global configuration after saving user configuration
|
||||||
|
CloseWindow?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
public void OkButton()
|
public void OkButton()
|
||||||
{
|
{
|
||||||
SaveSettings();
|
SaveSettings();
|
||||||
|
|
|
@ -19,6 +19,7 @@ using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption;
|
using Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
@ -131,7 +132,24 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||||
|
|
||||||
Rainbow.Enable();
|
Rainbow.Enable();
|
||||||
|
|
||||||
await Window.SettingsWindow.ShowDialog(Window);
|
if (ViewModel.SelectedApplication is null) // Checks if game data exists
|
||||||
|
{
|
||||||
|
await StyleableAppWindow.ShowAsync(Window.SettingsWindow);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool customConfigExists = File.Exists(Program.GetDirGameUserConfig(ViewModel.SelectedApplication.IdString));
|
||||||
|
|
||||||
|
if (!ViewModel.IsGameRunning || !customConfigExists)
|
||||||
|
{
|
||||||
|
await Window.SettingsWindow.ShowDialog(Window); // The game is not running, or if the user configuration does not exist
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If there is a custom configuration in the folder
|
||||||
|
await StyleableAppWindow.ShowAsync(new GameSpecificSettingsWindow(ViewModel, customConfigExists));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rainbow.Disable();
|
Rainbow.Disable();
|
||||||
Rainbow.Reset();
|
Rainbow.Reset();
|
||||||
|
@ -158,11 +176,13 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||||
|
|
||||||
string name = ViewModel.AppHost.Device.Processes.ActiveApplication.ApplicationControlProperties.Title[(int)ViewModel.AppHost.Device.System.State.DesiredTitleLanguage].NameString.ToString();
|
string name = ViewModel.AppHost.Device.Processes.ActiveApplication.ApplicationControlProperties.Title[(int)ViewModel.AppHost.Device.System.State.DesiredTitleLanguage].NameString.ToString();
|
||||||
|
|
||||||
await new CheatWindow(
|
await StyleableAppWindow.ShowAsync(
|
||||||
|
new CheatWindow(
|
||||||
Window.VirtualFileSystem,
|
Window.VirtualFileSystem,
|
||||||
ViewModel.AppHost.Device.Processes.ActiveApplication.ProgramIdText,
|
ViewModel.AppHost.Device.Processes.ActiveApplication.ProgramIdText,
|
||||||
name,
|
name,
|
||||||
ViewModel.SelectedApplication.Path).ShowDialog(Window);
|
ViewModel.SelectedApplication.Path)
|
||||||
|
);
|
||||||
|
|
||||||
ViewModel.AppHost.Device.EnableCheats();
|
ViewModel.AppHost.Device.EnableCheats();
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,6 +156,8 @@
|
||||||
ValueMemberBinding="{Binding Mode=OneWay, Converter={x:Static helpers:TimeZoneConverter.Instance}}" />
|
ValueMemberBinding="{Binding Mode=OneWay, Converter={x:Static helpers:TimeZoneConverter.Instance}}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
IsEnabled="{Binding !IsGameTitleNotNull}"
|
||||||
|
Opacity="{Binding PanelOpacity}"
|
||||||
Margin="0,0,0,10"
|
Margin="0,0,0,10"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
@ -169,8 +171,11 @@
|
||||||
SelectedDate="{Binding CurrentDate}"
|
SelectedDate="{Binding CurrentDate}"
|
||||||
ToolTip.Tip="{ext:Locale TimeTooltip}"
|
ToolTip.Tip="{ext:Locale TimeTooltip}"
|
||||||
Width="350" />
|
Width="350" />
|
||||||
|
<TextBlock Classes="globalConfigMarker" IsVisible="{Binding IsGameTitleNotNull}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
IsEnabled="{Binding !IsGameTitleNotNull}"
|
||||||
|
Opacity="{Binding PanelOpacity}"
|
||||||
Margin="250,0,0,10"
|
Margin="250,0,0,10"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<TimePicker
|
<TimePicker
|
||||||
|
@ -180,8 +185,12 @@
|
||||||
SelectedTime="{Binding CurrentTime}"
|
SelectedTime="{Binding CurrentTime}"
|
||||||
Width="350"
|
Width="350"
|
||||||
ToolTip.Tip="{ext:Locale TimeTooltip}" />
|
ToolTip.Tip="{ext:Locale TimeTooltip}" />
|
||||||
|
<TextBlock Classes="globalConfigMarker" IsVisible="{Binding IsGameTitleNotNull}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel
|
||||||
|
IsEnabled="{Binding !IsGameTitleNotNull}"
|
||||||
|
Opacity="{Binding PanelOpacity}"
|
||||||
|
Orientation="Horizontal">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{ext:Locale SettingsTabSystemSystemTimeMatch}"
|
Text="{ext:Locale SettingsTabSystemSystemTimeMatch}"
|
||||||
|
@ -191,6 +200,7 @@
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
IsChecked="{Binding MatchSystemTime}"
|
IsChecked="{Binding MatchSystemTime}"
|
||||||
ToolTip.Tip="{ext:Locale MatchTimeTooltip}"/>
|
ToolTip.Tip="{ext:Locale MatchTimeTooltip}"/>
|
||||||
|
<TextBlock Classes="globalConfigMarker" IsVisible="{Binding IsGameTitleNotNull}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Separator />
|
<Separator />
|
||||||
<StackPanel Margin="0,10,0,10"
|
<StackPanel Margin="0,10,0,10"
|
||||||
|
|
|
@ -27,20 +27,42 @@
|
||||||
<TextBlock Classes="h1" Text="{ext:Locale SettingsTabGeneralGeneral}" />
|
<TextBlock Classes="h1" Text="{ext:Locale SettingsTabGeneralGeneral}" />
|
||||||
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
<StackPanel Margin="10,0,0,0" Orientation="Vertical">
|
||||||
<CheckBox IsChecked="{Binding EnableDiscordIntegration}">
|
<CheckBox IsChecked="{Binding EnableDiscordIntegration}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock VerticalAlignment="Center"
|
<TextBlock VerticalAlignment="Center"
|
||||||
ToolTip.Tip="{ext:Locale ToggleDiscordTooltip}"
|
ToolTip.Tip="{ext:Locale ToggleDiscordTooltip}"
|
||||||
Text="{ext:Locale SettingsTabGeneralEnableDiscordRichPresence}" />
|
Text="{ext:Locale SettingsTabGeneralEnableDiscordRichPresence}" />
|
||||||
|
</StackPanel>
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<CheckBox IsChecked="{Binding ShowConfirmExit}">
|
<CheckBox
|
||||||
|
IsEnabled="{Binding !IsGameTitleNotNull}"
|
||||||
|
Opacity="{Binding PanelOpacity}"
|
||||||
|
IsChecked="{Binding ShowConfirmExit}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Text="{ext:Locale SettingsTabGeneralShowConfirmExitDialog}" />
|
<TextBlock Text="{ext:Locale SettingsTabGeneralShowConfirmExitDialog}" />
|
||||||
|
<TextBlock Classes="globalConfigMarker" IsVisible="{Binding IsGameTitleNotNull}" />
|
||||||
|
</StackPanel>
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<CheckBox IsChecked="{Binding RememberWindowState}">
|
<CheckBox
|
||||||
|
IsEnabled="{Binding !IsGameTitleNotNull}"
|
||||||
|
Opacity="{Binding PanelOpacity}"
|
||||||
|
IsChecked="{Binding RememberWindowState}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Text="{ext:Locale SettingsTabGeneralRememberWindowState}" />
|
<TextBlock Text="{ext:Locale SettingsTabGeneralRememberWindowState}" />
|
||||||
|
<TextBlock Classes="globalConfigMarker" IsVisible="{Binding IsGameTitleNotNull}" />
|
||||||
|
</StackPanel>
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<CheckBox IsChecked="{Binding ShowTitleBar}" IsVisible="{x:Static helper:RunningPlatform.IsWindows}">
|
<CheckBox
|
||||||
|
IsEnabled="{Binding !IsGameTitleNotNull}"
|
||||||
|
Opacity="{Binding PanelOpacity}"
|
||||||
|
IsChecked="{Binding ShowTitleBar}" IsVisible="{x:Static helper:RunningPlatform.IsWindows}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Text="{ext:Locale SettingsTabGeneralShowTitleBar}" />
|
<TextBlock Text="{ext:Locale SettingsTabGeneralShowTitleBar}" />
|
||||||
|
<TextBlock Classes="globalConfigMarker" IsVisible="{Binding IsGameTitleNotNull}" />
|
||||||
|
</StackPanel>
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<StackPanel Margin="0, 15, 0, 0" Orientation="Horizontal">
|
<StackPanel
|
||||||
|
Margin="0, 15, 0, 0"
|
||||||
|
Orientation="Horizontal">
|
||||||
<TextBlock VerticalAlignment="Center"
|
<TextBlock VerticalAlignment="Center"
|
||||||
Text="{ext:Locale SettingsTabGeneralFocusLossType}"
|
Text="{ext:Locale SettingsTabGeneralFocusLossType}"
|
||||||
Width="150" />
|
Width="150" />
|
||||||
|
@ -64,7 +86,11 @@
|
||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Margin="0, 15, 0, 0" Orientation="Horizontal">
|
<StackPanel
|
||||||
|
IsEnabled="{Binding !IsGameTitleNotNull}"
|
||||||
|
Opacity="{Binding PanelOpacity}"
|
||||||
|
Margin="0, 15, 0, 0"
|
||||||
|
Orientation="Horizontal">
|
||||||
<TextBlock VerticalAlignment="Center"
|
<TextBlock VerticalAlignment="Center"
|
||||||
Text="{ext:Locale SettingsTabGeneralCheckUpdatesOnLaunch}"
|
Text="{ext:Locale SettingsTabGeneralCheckUpdatesOnLaunch}"
|
||||||
Width="150" />
|
Width="150" />
|
||||||
|
@ -81,8 +107,11 @@
|
||||||
<TextBlock Text="{ext:Locale SettingsTabGeneralCheckUpdatesOnLaunchBackground}" />
|
<TextBlock Text="{ext:Locale SettingsTabGeneralCheckUpdatesOnLaunchBackground}" />
|
||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
|
<TextBlock Classes="globalConfigMarker" IsVisible="{Binding IsGameTitleNotNull}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Margin="0, 15, 0, 0" Orientation="Horizontal">
|
<StackPanel
|
||||||
|
Margin="0, 15, 0, 0"
|
||||||
|
Orientation="Horizontal">
|
||||||
<TextBlock VerticalAlignment="Center"
|
<TextBlock VerticalAlignment="Center"
|
||||||
Text="{ext:Locale SettingsTabGeneralHideCursor}"
|
Text="{ext:Locale SettingsTabGeneralHideCursor}"
|
||||||
Width="150" />
|
Width="150" />
|
||||||
|
@ -100,7 +129,11 @@
|
||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Margin="0, 15, 0, 10" Orientation="Horizontal">
|
<StackPanel
|
||||||
|
IsEnabled="{Binding !IsGameTitleNotNull}"
|
||||||
|
Opacity="{Binding PanelOpacity}"
|
||||||
|
Margin="0, 15, 0, 10"
|
||||||
|
Orientation="Horizontal">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Text="{ext:Locale SettingsTabGeneralTheme}"
|
Text="{ext:Locale SettingsTabGeneralTheme}"
|
||||||
|
@ -118,11 +151,17 @@
|
||||||
<TextBlock Text="{ext:Locale SettingsTabGeneralThemeDark}" />
|
<TextBlock Text="{ext:Locale SettingsTabGeneralThemeDark}" />
|
||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
|
<TextBlock Classes="globalConfigMarker" IsVisible="{Binding IsGameTitleNotNull}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Separator Height="1" />
|
<Separator Height="1" />
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Classes="h1" Text="{ext:Locale SettingsTabGeneralGameDirectories}" />
|
<TextBlock Classes="h1" Text="{ext:Locale SettingsTabGeneralGameDirectories}" />
|
||||||
|
<TextBlock Classes="globalConfigMarker" IsVisible="{Binding IsGameTitleNotNull}"/>
|
||||||
|
</StackPanel>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
IsEnabled="{Binding !IsGameTitleNotNull}"
|
||||||
|
Opacity="{Binding PanelOpacity}"
|
||||||
Margin="10,0,0,0"
|
Margin="10,0,0,0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Orientation="Vertical"
|
Orientation="Vertical"
|
||||||
|
@ -172,10 +211,15 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Separator Height="1" />
|
<Separator Height="1" />
|
||||||
<StackPanel Orientation="Vertical" Spacing="5">
|
<StackPanel Orientation="Vertical" Spacing="5">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Classes="h1" Text="{ext:Locale SettingsTabGeneralAutoloadDirectories}" />
|
<TextBlock Classes="h1" Text="{ext:Locale SettingsTabGeneralAutoloadDirectories}" />
|
||||||
|
<TextBlock Classes="globalConfigMarker" IsVisible="{Binding IsGameTitleNotNull}"/>
|
||||||
|
</StackPanel>
|
||||||
<TextBlock Foreground="{DynamicResource SecondaryTextColor}" Text="{ext:Locale SettingsTabGeneralAutoloadNote}" />
|
<TextBlock Foreground="{DynamicResource SecondaryTextColor}" Text="{ext:Locale SettingsTabGeneralAutoloadNote}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
IsEnabled="{Binding !IsGameTitleNotNull}"
|
||||||
|
Opacity="{Binding PanelOpacity}"
|
||||||
Margin="10,0,0,0"
|
Margin="10,0,0,0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Orientation="Vertical"
|
Orientation="Vertical"
|
||||||
|
|
155
src/Ryujinx/UI/Windows/GameSpecificSettingsWindow.axaml
Normal file
155
src/Ryujinx/UI/Windows/GameSpecificSettingsWindow.axaml
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
<window:StyleableAppWindow
|
||||||
|
x:Class="Ryujinx.Ava.UI.Windows.GameSpecificSettingsWindow"
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows"
|
||||||
|
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||||
|
xmlns:settings="clr-namespace:Ryujinx.Ava.UI.Views.Settings"
|
||||||
|
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||||
|
xmlns:helper="clr-namespace:Ryujinx.Common.Helper;assembly=Ryujinx.Common"
|
||||||
|
Width="1100"
|
||||||
|
Height="910"
|
||||||
|
MinWidth="800"
|
||||||
|
MinHeight="480"
|
||||||
|
WindowStartupLocation="CenterOwner"
|
||||||
|
x:DataType="viewModels:SettingsViewModel"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Focusable="True">
|
||||||
|
<Design.DataContext>
|
||||||
|
<viewModels:SettingsViewModel />
|
||||||
|
</Design.DataContext>
|
||||||
|
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinWidth="600" RowDefinitions="Auto,*,Auto">
|
||||||
|
<ContentPresenter
|
||||||
|
x:Name="ContentPresenter"
|
||||||
|
Grid.Row="1"
|
||||||
|
IsVisible="False"
|
||||||
|
KeyboardNavigation.IsTabStop="False"/>
|
||||||
|
<Grid Name="Pages" IsVisible="False" Grid.Row="2">
|
||||||
|
<settings:SettingsUiView Name="UiPage" />
|
||||||
|
<settings:SettingsInputView Name="InputPage" />
|
||||||
|
<settings:SettingsSystemView Name="SystemPage" />
|
||||||
|
<settings:SettingsCPUView Name="CpuPage" />
|
||||||
|
<settings:SettingsGraphicsView Name="GraphicsPage" />
|
||||||
|
<settings:SettingsAudioView Name="AudioPage" />
|
||||||
|
<settings:SettingsNetworkView Name="NetworkPage" />
|
||||||
|
<settings:SettingsLoggingView Name="LoggingPage" />
|
||||||
|
<settings:SettingsHacksView Name="HacksPage" />
|
||||||
|
</Grid>
|
||||||
|
<ui:NavigationView
|
||||||
|
Grid.Row="1"
|
||||||
|
IsSettingsVisible="False"
|
||||||
|
Name="NavPanel"
|
||||||
|
IsBackEnabled="False"
|
||||||
|
PaneDisplayMode="Left"
|
||||||
|
Margin="2,10,10,0"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
OpenPaneLength="200"
|
||||||
|
IsPaneToggleButtonVisible="False">
|
||||||
|
|
||||||
|
<!-- For image -->
|
||||||
|
<ui:NavigationView.PaneHeader>
|
||||||
|
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="5"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TextBlock Text="{Binding GameId}"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0,0,0,10"
|
||||||
|
TextAlignment="Center" Grid.Row="0" />
|
||||||
|
<Image Source="{Binding GameIcon}"
|
||||||
|
Width="160"
|
||||||
|
Height="160"
|
||||||
|
Grid.Row="1"
|
||||||
|
Margin="0,0,0,10"
|
||||||
|
HorizontalAlignment="Center" />
|
||||||
|
<TextBlock Text="{Binding GameTitle}"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0,0,0,10"
|
||||||
|
TextAlignment="Center" Grid.Row="2" />
|
||||||
|
<Separator Height="1" Grid.Row="3" Margin="0,0,0,10" HorizontalAlignment="Stretch"/>
|
||||||
|
</Grid>
|
||||||
|
</ui:NavigationView.PaneHeader>
|
||||||
|
|
||||||
|
<ui:NavigationView.MenuItems>
|
||||||
|
<ui:NavigationViewItem
|
||||||
|
IsSelected="True"
|
||||||
|
Content="{ext:Locale SettingsTabGeneral}"
|
||||||
|
Tag="UiPage"
|
||||||
|
IconSource="New" />
|
||||||
|
<ui:NavigationViewItem
|
||||||
|
Content="{ext:Locale SettingsTabInput}"
|
||||||
|
Tag="InputPage"
|
||||||
|
IconSource="Games" />
|
||||||
|
<ui:NavigationViewItem
|
||||||
|
Content="{ext:Locale SettingsTabSystem}"
|
||||||
|
Tag="SystemPage"
|
||||||
|
IconSource="Settings" />
|
||||||
|
<ui:NavigationViewItem
|
||||||
|
Content="{ext:Locale SettingsTabCpu}"
|
||||||
|
Tag="CpuPage">
|
||||||
|
<ui:NavigationViewItem.IconSource>
|
||||||
|
<ui:FontIconSource
|
||||||
|
FontFamily="avares://Ryujinx/Assets/Fonts#Segoe Fluent Icons"
|
||||||
|
Glyph="{helpers:GlyphValueConverter Chip}" />
|
||||||
|
</ui:NavigationViewItem.IconSource>
|
||||||
|
</ui:NavigationViewItem>
|
||||||
|
<ui:NavigationViewItem
|
||||||
|
Content="{ext:Locale SettingsTabGraphics}"
|
||||||
|
Tag="GraphicsPage"
|
||||||
|
IconSource="Image" />
|
||||||
|
<ui:NavigationViewItem
|
||||||
|
Content="{ext:Locale SettingsTabAudio}"
|
||||||
|
IconSource="Audio"
|
||||||
|
Tag="AudioPage" />
|
||||||
|
<ui:NavigationViewItem
|
||||||
|
Content="{ext:Locale SettingsTabNetwork}"
|
||||||
|
Tag="NetworkPage"
|
||||||
|
IconSource="Globe" />
|
||||||
|
<ui:NavigationViewItem
|
||||||
|
Content="{ext:Locale SettingsTabLogging}"
|
||||||
|
Tag="LoggingPage"
|
||||||
|
IconSource="Document" />
|
||||||
|
<ui:NavigationViewItem
|
||||||
|
IsVisible="{Binding ShowDirtyHacks}"
|
||||||
|
Content="Dirty Hacks"
|
||||||
|
Tag="HacksPage"
|
||||||
|
IconSource="Code" />
|
||||||
|
</ui:NavigationView.MenuItems>
|
||||||
|
</ui:NavigationView>
|
||||||
|
|
||||||
|
<ReversibleStackPanel
|
||||||
|
Grid.Row="2"
|
||||||
|
Margin="10"
|
||||||
|
Spacing="10"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
ReverseOrder="{x:Static helper:RunningPlatform.IsMacOS}">
|
||||||
|
<Button
|
||||||
|
Content="{ext:Locale SettingsButtonSave}"
|
||||||
|
Command="{Binding SaveUserConfig}" />
|
||||||
|
<Button
|
||||||
|
HotKey="Escape"
|
||||||
|
Content="{ext:Locale SettingsButtonClose}"
|
||||||
|
Command="{Binding CancelButton}" />
|
||||||
|
<Button
|
||||||
|
IsVisible="{Binding IsGameRunning}"
|
||||||
|
Content="{ext:Locale SettingsButtonApply}"
|
||||||
|
Command="{Binding ApplyButton}" />
|
||||||
|
<Button
|
||||||
|
IsVisible="{Binding !IsGameRunning}"
|
||||||
|
Content="{ext:Locale UserProfilesDelete}"
|
||||||
|
Command="{Binding DeleteConfigGame}"
|
||||||
|
Classes="red"/>
|
||||||
|
</ReversibleStackPanel>
|
||||||
|
</Grid>
|
||||||
|
</window:StyleableAppWindow>
|
115
src/Ryujinx/UI/Windows/GameSpecificSettingsWindow.axaml.cs
Normal file
115
src/Ryujinx/UI/Windows/GameSpecificSettingsWindow.axaml.cs
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Shapes;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
|
using FluentAvalonia.Core;
|
||||||
|
using FluentAvalonia.UI.Controls;
|
||||||
|
using Projektanker.Icons.Avalonia;
|
||||||
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using Ryujinx.Ava.UI.Models;
|
||||||
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
|
using Ryujinx.Ava.UI.ViewModels.Input;
|
||||||
|
using Ryujinx.Ava.Utilities;
|
||||||
|
using Ryujinx.Ava.Utilities.Configuration;
|
||||||
|
using Ryujinx.Common.Configuration;
|
||||||
|
using Ryujinx.HLE.FileSystem;
|
||||||
|
using Ryujinx.HLE.HOS.SystemState;
|
||||||
|
using Ryujinx.Input;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Key = Avalonia.Input.Key;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Windows
|
||||||
|
{
|
||||||
|
public partial class GameSpecificSettingsWindow : StyleableAppWindow
|
||||||
|
{
|
||||||
|
internal readonly SettingsViewModel ViewModel;
|
||||||
|
|
||||||
|
public GameSpecificSettingsWindow(MainWindowViewModel viewModel, bool findUserConfigDir = true)
|
||||||
|
{
|
||||||
|
Title = string.Format(LocaleManager.Instance[LocaleKeys.SettingsWithInfo], viewModel.SelectedApplication.Name, viewModel.SelectedApplication.IdString);
|
||||||
|
|
||||||
|
DataContext = ViewModel = new SettingsViewModel(
|
||||||
|
viewModel.VirtualFileSystem,
|
||||||
|
viewModel.ContentManager,
|
||||||
|
viewModel.IsGameRunning,
|
||||||
|
viewModel.SelectedApplication.Path,
|
||||||
|
viewModel.SelectedApplication.Name,
|
||||||
|
viewModel.SelectedApplication.IdString,
|
||||||
|
viewModel.SelectedApplication.Icon,
|
||||||
|
findUserConfigDir);
|
||||||
|
|
||||||
|
ViewModel.CloseWindow += Close;
|
||||||
|
ViewModel.SaveSettingsEvent += SaveSettings;
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
|
Load();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveSettings()
|
||||||
|
{
|
||||||
|
InputPage.InputView?.SaveCurrentProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void Load()
|
||||||
|
{
|
||||||
|
Pages.Children.Clear();
|
||||||
|
NavPanel.SelectionChanged += NavPanelOnSelectionChanged;
|
||||||
|
NavPanel.SelectedItem = NavPanel.MenuItems.ElementAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NavPanelOnSelectionChanged(object sender, NavigationViewSelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (e.SelectedItem is NavigationViewItem navItem && navItem.Tag is not null)
|
||||||
|
{
|
||||||
|
switch (navItem.Tag.ToString())
|
||||||
|
{
|
||||||
|
case nameof(UiPage):
|
||||||
|
UiPage.ViewModel = ViewModel;
|
||||||
|
NavPanel.Content = UiPage;
|
||||||
|
break;
|
||||||
|
case nameof(InputPage):
|
||||||
|
NavPanel.Content = InputPage;
|
||||||
|
break;
|
||||||
|
case nameof(SystemPage):
|
||||||
|
SystemPage.ViewModel = ViewModel;
|
||||||
|
NavPanel.Content = SystemPage;
|
||||||
|
break;
|
||||||
|
case nameof(CpuPage):
|
||||||
|
NavPanel.Content = CpuPage;
|
||||||
|
break;
|
||||||
|
case nameof(GraphicsPage):
|
||||||
|
NavPanel.Content = GraphicsPage;
|
||||||
|
break;
|
||||||
|
case nameof(AudioPage):
|
||||||
|
NavPanel.Content = AudioPage;
|
||||||
|
break;
|
||||||
|
case nameof(NetworkPage):
|
||||||
|
NetworkPage.ViewModel = ViewModel;
|
||||||
|
NavPanel.Content = NetworkPage;
|
||||||
|
break;
|
||||||
|
case nameof(LoggingPage):
|
||||||
|
NavPanel.Content = LoggingPage;
|
||||||
|
break;
|
||||||
|
case nameof(HacksPage):
|
||||||
|
HacksPage.DataContext = ViewModel;
|
||||||
|
NavPanel.Content = HacksPage;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnClosing(WindowClosingEventArgs e)
|
||||||
|
{
|
||||||
|
InputPage.Dispose(); // You need to unload the gamepad settings, otherwise the controls will be blocked
|
||||||
|
base.OnClosing(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -385,6 +385,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
|
|
||||||
if (applicationData != null)
|
if (applicationData != null)
|
||||||
{
|
{
|
||||||
|
ViewModel.SelectedApplication = applicationData;
|
||||||
await ViewModel.LoadApplication(applicationData, _startFullscreen);
|
await ViewModel.LoadApplication(applicationData, _startFullscreen);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -396,6 +397,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
applicationData = applications[0];
|
applicationData = applications[0];
|
||||||
|
ViewModel.SelectedApplication = applicationData;
|
||||||
await ViewModel.LoadApplication(applicationData, _startFullscreen);
|
await ViewModel.LoadApplication(applicationData, _startFullscreen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||||
xmlns:helper="clr-namespace:Ryujinx.Common.Helper;assembly=Ryujinx.Common"
|
xmlns:helper="clr-namespace:Ryujinx.Common.Helper;assembly=Ryujinx.Common"
|
||||||
Width="1100"
|
Width="1100"
|
||||||
Height="768"
|
Height="918"
|
||||||
MinWidth="800"
|
MinWidth="800"
|
||||||
MinHeight="480"
|
MinHeight="480"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
|
@ -8,7 +6,6 @@ using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.Input;
|
using Ryujinx.Input;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Key = Avalonia.Input.Key;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Windows
|
namespace Ryujinx.Ava.UI.Windows
|
||||||
{
|
{
|
||||||
|
@ -27,10 +24,6 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Load();
|
Load();
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
this.AttachDevTools(new KeyGesture(Key.F12, KeyModifiers.Alt));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SettingsWindow()
|
public SettingsWindow()
|
||||||
|
|
|
@ -1,15 +1,26 @@
|
||||||
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Controls.Primitives;
|
||||||
|
using Avalonia.Input;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.Platform;
|
using Avalonia.Platform;
|
||||||
using FluentAvalonia.UI.Windowing;
|
using FluentAvalonia.UI.Windowing;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Windows
|
namespace Ryujinx.Ava.UI.Windows
|
||||||
{
|
{
|
||||||
public abstract class StyleableAppWindow : AppWindow
|
public abstract class StyleableAppWindow : AppWindow
|
||||||
{
|
{
|
||||||
|
public static async Task ShowAsync(StyleableAppWindow appWindow, Window owner = null)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
appWindow.AttachDevTools(new KeyGesture(Key.F12, KeyModifiers.Control));
|
||||||
|
#endif
|
||||||
|
await appWindow.ShowDialog(owner ?? RyujinxApp.MainWindow);
|
||||||
|
}
|
||||||
|
|
||||||
protected StyleableAppWindow()
|
protected StyleableAppWindow()
|
||||||
{
|
{
|
||||||
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||||
|
@ -36,6 +47,14 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
|
|
||||||
public abstract class StyleableWindow : Window
|
public abstract class StyleableWindow : Window
|
||||||
{
|
{
|
||||||
|
public static async Task ShowAsync(StyleableWindow window, Window owner = null)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
window.AttachDevTools(new KeyGesture(Key.F12, KeyModifiers.Control));
|
||||||
|
#endif
|
||||||
|
await window.ShowDialog(owner ?? RyujinxApp.MainWindow);
|
||||||
|
}
|
||||||
|
|
||||||
protected StyleableWindow()
|
protected StyleableWindow()
|
||||||
{
|
{
|
||||||
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||||
|
|
|
@ -44,16 +44,8 @@ namespace Ryujinx.Ava
|
||||||
|
|
||||||
private static string _buildVer;
|
private static string _buildVer;
|
||||||
|
|
||||||
private static readonly string _platformExt =
|
|
||||||
RunningPlatform.IsMacOS
|
private static readonly string _platformExt = BuildPlatformExtension();
|
||||||
? "macos_universal.app.tar.gz"
|
|
||||||
: RunningPlatform.IsWindows
|
|
||||||
? "win_x64.zip"
|
|
||||||
: RunningPlatform.IsX64Linux
|
|
||||||
? "linux_x64.tar.gz"
|
|
||||||
: RunningPlatform.IsArmLinux
|
|
||||||
? "linux_arm64.tar.gz"
|
|
||||||
: throw new PlatformNotSupportedException();
|
|
||||||
|
|
||||||
private static string _buildUrl;
|
private static string _buildUrl;
|
||||||
private static long _buildSize;
|
private static long _buildSize;
|
||||||
|
@ -780,5 +772,34 @@ namespace Ryujinx.Ava
|
||||||
public static void CleanupUpdate() =>
|
public static void CleanupUpdate() =>
|
||||||
Directory.GetFiles(_homeDir, "*.ryuold", SearchOption.AllDirectories)
|
Directory.GetFiles(_homeDir, "*.ryuold", SearchOption.AllDirectories)
|
||||||
.ForEach(File.Delete);
|
.ForEach(File.Delete);
|
||||||
|
|
||||||
|
private static string BuildPlatformExtension()
|
||||||
|
{
|
||||||
|
if (RunningPlatform.IsMacOS)
|
||||||
|
return "macos_universal.app.tar.gz";
|
||||||
|
|
||||||
|
#pragma warning disable CS8509 // It is exhaustive for any values this can contain.
|
||||||
|
string osPrefix = RunningPlatform.CurrentOS switch
|
||||||
|
{
|
||||||
|
OperatingSystemType.Linux => "linux",
|
||||||
|
OperatingSystemType.Windows => "win"
|
||||||
|
};
|
||||||
|
|
||||||
|
string archSuffix = RunningPlatform.Architecture switch
|
||||||
|
{
|
||||||
|
Architecture.Arm64 => "arm64",
|
||||||
|
Architecture.X64 => "x64",
|
||||||
|
_ => throw new PlatformNotSupportedException($"Unknown architecture {Enum.GetName(RunningPlatform.Architecture)}."),
|
||||||
|
};
|
||||||
|
|
||||||
|
string fileExtension = RunningPlatform.CurrentOS switch
|
||||||
|
#pragma warning restore CS8509
|
||||||
|
{
|
||||||
|
OperatingSystemType.Linux => "tar.gz",
|
||||||
|
OperatingSystemType.Windows => "zip"
|
||||||
|
};
|
||||||
|
|
||||||
|
return $"{osPrefix}_{archSuffix}.{fileExtension}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
||||||
public class ApplicationData
|
public class ApplicationData
|
||||||
{
|
{
|
||||||
public bool Favorite { get; set; }
|
public bool Favorite { get; set; }
|
||||||
|
public bool HasIndependentConfiguration { get; set; }
|
||||||
public byte[] Icon { get; set; }
|
public byte[] Icon { get; set; }
|
||||||
public string Name { get; set; } = "Unknown";
|
public string Name { get; set; } = "Unknown";
|
||||||
|
|
||||||
|
|
|
@ -532,6 +532,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
||||||
data.Favorite = appMetadata.Favorite;
|
data.Favorite = appMetadata.Favorite;
|
||||||
data.TimePlayed = appMetadata.TimePlayed;
|
data.TimePlayed = appMetadata.TimePlayed;
|
||||||
data.LastPlayed = appMetadata.LastPlayed;
|
data.LastPlayed = appMetadata.LastPlayed;
|
||||||
|
data.HasIndependentConfiguration = File.Exists(Program.GetDirGameUserConfig(data.IdBaseString, false, false)); // Just check user config
|
||||||
}
|
}
|
||||||
|
|
||||||
data.FileExtension = Path.GetExtension(applicationPath).TrimStart('.').ToUpper();
|
data.FileExtension = Path.GetExtension(applicationPath).TrimStart('.').ToUpper();
|
||||||
|
|
|
@ -7,11 +7,16 @@ namespace Ryujinx.Ava.Utilities
|
||||||
public static class CommandLineState
|
public static class CommandLineState
|
||||||
{
|
{
|
||||||
public static string[] Arguments { get; private set; }
|
public static string[] Arguments { get; private set; }
|
||||||
|
public static int CountArguments { get; private set; }
|
||||||
public static bool? OverrideDockedMode { get; private set; }
|
public static bool? OverrideDockedMode { get; private set; }
|
||||||
public static bool? OverrideHardwareAcceleration { get; private set; }
|
public static bool? OverrideHardwareAcceleration { get; private set; }
|
||||||
public static string OverrideGraphicsBackend { get; private set; }
|
public static string OverrideGraphicsBackend { get; private set; }
|
||||||
public static string OverrideBackendThreading { get; private set; }
|
public static string OverrideBackendThreading { get; private set; }
|
||||||
|
public static string OverrideBackendThreadingAfterReboot { get; private set; }
|
||||||
|
public static string OverridePPTC { get; private set; }
|
||||||
|
public static string OverrideMemoryManagerMode { get; private set; }
|
||||||
|
public static string OverrideSystemRegion { get; private set; }
|
||||||
|
public static string OverrideSystemLanguage { get; private set; }
|
||||||
public static string OverrideHideCursor { get; private set; }
|
public static string OverrideHideCursor { get; private set; }
|
||||||
public static string BaseDirPathArg { get; private set; }
|
public static string BaseDirPathArg { get; private set; }
|
||||||
public static FilePath FirmwareToInstallPathArg { get; set; }
|
public static FilePath FirmwareToInstallPathArg { get; set; }
|
||||||
|
@ -21,6 +26,7 @@ namespace Ryujinx.Ava.Utilities
|
||||||
public static bool StartFullscreenArg { get; private set; }
|
public static bool StartFullscreenArg { get; private set; }
|
||||||
public static bool HideAvailableUpdates { get; private set; }
|
public static bool HideAvailableUpdates { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
public static void ParseArguments(string[] args)
|
public static void ParseArguments(string[] args)
|
||||||
{
|
{
|
||||||
List<string> arguments = [];
|
List<string> arguments = [];
|
||||||
|
@ -30,6 +36,11 @@ namespace Ryujinx.Ava.Utilities
|
||||||
{
|
{
|
||||||
string arg = args[i];
|
string arg = args[i];
|
||||||
|
|
||||||
|
if (arg.Contains("-") || arg.Contains("--"))
|
||||||
|
{
|
||||||
|
CountArguments++;
|
||||||
|
}
|
||||||
|
|
||||||
switch (arg)
|
switch (arg)
|
||||||
{
|
{
|
||||||
case "-r":
|
case "-r":
|
||||||
|
@ -100,6 +111,57 @@ namespace Ryujinx.Ava.Utilities
|
||||||
|
|
||||||
OverrideBackendThreading = args[++i];
|
OverrideBackendThreading = args[++i];
|
||||||
break;
|
break;
|
||||||
|
case "--bt":
|
||||||
|
if (i + 1 >= args.Length)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
OverrideBackendThreadingAfterReboot = args[++i];
|
||||||
|
break;
|
||||||
|
case "--pptc":
|
||||||
|
if (i + 1 >= args.Length)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
OverridePPTC = args[++i];
|
||||||
|
break;
|
||||||
|
case "-m":
|
||||||
|
case "--memory-manager-mode":
|
||||||
|
if (i + 1 >= args.Length)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
OverrideMemoryManagerMode = args[++i];
|
||||||
|
break;
|
||||||
|
case "--system-region":
|
||||||
|
if (i + 1 >= args.Length)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
OverrideSystemRegion = args[++i];
|
||||||
|
break;
|
||||||
|
case "--system-language":
|
||||||
|
if (i + 1 >= args.Length)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
OverrideSystemLanguage = args[++i];
|
||||||
|
break;
|
||||||
case "-i":
|
case "-i":
|
||||||
case "--application-id":
|
case "--application-id":
|
||||||
LaunchApplicationId = args[++i];
|
LaunchApplicationId = args[++i];
|
||||||
|
|
|
@ -18,9 +18,10 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||||
{
|
{
|
||||||
public partial class ConfigurationState
|
public partial class ConfigurationState
|
||||||
{
|
{
|
||||||
public void Load(ConfigurationFileFormat cff, string configurationFilePath)
|
public void Load(ConfigurationFileFormat cff, string configurationFilePath, string titleId = "")
|
||||||
{
|
{
|
||||||
bool configurationFileUpdated = false;
|
bool configurationFileUpdated = false;
|
||||||
|
bool shouldLoadFromFile = string.IsNullOrEmpty(titleId);
|
||||||
|
|
||||||
if (cff.Version is < 0 or > ConfigurationFileFormat.CurrentVersion)
|
if (cff.Version is < 0 or > ConfigurationFileFormat.CurrentVersion)
|
||||||
{
|
{
|
||||||
|
@ -43,14 +44,15 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||||
configurationFileUpdated = true;
|
configurationFileUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EnableDiscordIntegration.Value = cff.EnableDiscordIntegration;
|
EnableDiscordIntegration.Value = cff.EnableDiscordIntegration;
|
||||||
CheckUpdatesOnStart.Value = cff.CheckUpdatesOnStart;
|
CheckUpdatesOnStart.Value = shouldLoadFromFile ? cff.CheckUpdatesOnStart : CheckUpdatesOnStart.Value; // Get from global config only
|
||||||
UpdateCheckerType.Value = cff.UpdateCheckerType;
|
UpdateCheckerType.Value = shouldLoadFromFile ? cff.UpdateCheckerType : UpdateCheckerType.Value; // Get from global config only
|
||||||
FocusLostActionType.Value = cff.FocusLostActionType;
|
FocusLostActionType.Value = cff.FocusLostActionType;
|
||||||
ShowConfirmExit.Value = cff.ShowConfirmExit;
|
ShowConfirmExit.Value = shouldLoadFromFile ? cff.ShowConfirmExit : ShowConfirmExit.Value; // Get from global config only
|
||||||
RememberWindowState.Value = cff.RememberWindowState;
|
RememberWindowState.Value = shouldLoadFromFile ? cff.RememberWindowState : RememberWindowState.Value; // Get from global config only
|
||||||
ShowTitleBar.Value = cff.ShowTitleBar;
|
ShowTitleBar.Value = shouldLoadFromFile ? cff.ShowTitleBar : ShowTitleBar.Value; // Get from global config only
|
||||||
EnableHardwareAcceleration.Value = cff.EnableHardwareAcceleration;
|
EnableHardwareAcceleration.Value = shouldLoadFromFile ? cff.EnableHardwareAcceleration : EnableHardwareAcceleration.Value; // Get from global config only
|
||||||
HideCursor.Value = cff.HideCursor;
|
HideCursor.Value = cff.HideCursor;
|
||||||
|
|
||||||
Logger.EnableFileLog.Value = cff.EnableFileLog;
|
Logger.EnableFileLog.Value = cff.EnableFileLog;
|
||||||
|
@ -87,8 +89,8 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||||
System.Language.Value = cff.SystemLanguage;
|
System.Language.Value = cff.SystemLanguage;
|
||||||
System.Region.Value = cff.SystemRegion;
|
System.Region.Value = cff.SystemRegion;
|
||||||
System.TimeZone.Value = cff.SystemTimeZone;
|
System.TimeZone.Value = cff.SystemTimeZone;
|
||||||
System.SystemTimeOffset.Value = cff.SystemTimeOffset;
|
System.SystemTimeOffset.Value = shouldLoadFromFile ? cff.SystemTimeOffset : System.SystemTimeOffset.Value; // Get from global config only
|
||||||
System.MatchSystemTime.Value = cff.MatchSystemTime;
|
System.MatchSystemTime.Value = shouldLoadFromFile ? cff.MatchSystemTime : System.MatchSystemTime.Value; // Get from global config only
|
||||||
System.EnableDockedMode.Value = cff.DockedMode;
|
System.EnableDockedMode.Value = cff.DockedMode;
|
||||||
System.EnablePtc.Value = cff.EnablePtc;
|
System.EnablePtc.Value = cff.EnablePtc;
|
||||||
System.EnableLowPowerPtc.Value = cff.EnableLowPowerPtc;
|
System.EnableLowPowerPtc.Value = cff.EnableLowPowerPtc;
|
||||||
|
@ -103,46 +105,47 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||||
System.IgnoreControllerApplet.Value = cff.IgnoreApplet;
|
System.IgnoreControllerApplet.Value = cff.IgnoreApplet;
|
||||||
System.UseHypervisor.Value = cff.UseHypervisor;
|
System.UseHypervisor.Value = cff.UseHypervisor;
|
||||||
|
|
||||||
UI.GuiColumns.FavColumn.Value = cff.GuiColumns.FavColumn;
|
UI.GuiColumns.FavColumn.Value = shouldLoadFromFile ? cff.GuiColumns.FavColumn : UI.GuiColumns.FavColumn.Value;
|
||||||
UI.GuiColumns.IconColumn.Value = cff.GuiColumns.IconColumn;
|
UI.GuiColumns.IconColumn.Value = shouldLoadFromFile ? cff.GuiColumns.IconColumn : UI.GuiColumns.IconColumn.Value;
|
||||||
UI.GuiColumns.AppColumn.Value = cff.GuiColumns.AppColumn;
|
UI.GuiColumns.AppColumn.Value = shouldLoadFromFile ? cff.GuiColumns.AppColumn : UI.GuiColumns.AppColumn.Value;
|
||||||
UI.GuiColumns.DevColumn.Value = cff.GuiColumns.DevColumn;
|
UI.GuiColumns.DevColumn.Value = shouldLoadFromFile ? cff.GuiColumns.DevColumn : UI.GuiColumns.DevColumn.Value;
|
||||||
UI.GuiColumns.VersionColumn.Value = cff.GuiColumns.VersionColumn;
|
UI.GuiColumns.VersionColumn.Value = shouldLoadFromFile ? cff.GuiColumns.VersionColumn : UI.GuiColumns.VersionColumn.Value;
|
||||||
UI.GuiColumns.TimePlayedColumn.Value = cff.GuiColumns.TimePlayedColumn;
|
UI.GuiColumns.TimePlayedColumn.Value = shouldLoadFromFile ? cff.GuiColumns.TimePlayedColumn : UI.GuiColumns.TimePlayedColumn.Value;
|
||||||
UI.GuiColumns.LastPlayedColumn.Value = cff.GuiColumns.LastPlayedColumn;
|
UI.GuiColumns.LastPlayedColumn.Value = shouldLoadFromFile ? cff.GuiColumns.LastPlayedColumn : UI.GuiColumns.LastPlayedColumn.Value;
|
||||||
UI.GuiColumns.FileExtColumn.Value = cff.GuiColumns.FileExtColumn;
|
UI.GuiColumns.FileExtColumn.Value = shouldLoadFromFile ? cff.GuiColumns.FileExtColumn : UI.GuiColumns.FileExtColumn.Value;
|
||||||
UI.GuiColumns.FileSizeColumn.Value = cff.GuiColumns.FileSizeColumn;
|
UI.GuiColumns.FileSizeColumn.Value = shouldLoadFromFile ? cff.GuiColumns.FileSizeColumn : UI.GuiColumns.FileSizeColumn.Value;
|
||||||
UI.GuiColumns.PathColumn.Value = cff.GuiColumns.PathColumn;
|
UI.GuiColumns.PathColumn.Value = shouldLoadFromFile ? cff.GuiColumns.PathColumn : UI.GuiColumns.PathColumn.Value;
|
||||||
UI.ColumnSort.SortColumnId.Value = cff.ColumnSort.SortColumnId;
|
UI.ColumnSort.SortColumnId.Value = shouldLoadFromFile ? cff.ColumnSort.SortColumnId : UI.ColumnSort.SortColumnId.Value;
|
||||||
UI.ColumnSort.SortAscending.Value = cff.ColumnSort.SortAscending;
|
UI.ColumnSort.SortAscending.Value = shouldLoadFromFile ? cff.ColumnSort.SortAscending : UI.ColumnSort.SortAscending.Value;
|
||||||
UI.GameDirs.Value = cff.GameDirs;
|
UI.GameDirs.Value = shouldLoadFromFile ? cff.GameDirs : UI.GameDirs.Value;
|
||||||
UI.AutoloadDirs.Value = cff.AutoloadDirs ?? [];
|
UI.AutoloadDirs.Value = shouldLoadFromFile ? (cff.AutoloadDirs ?? []) : UI.AutoloadDirs.Value;
|
||||||
UI.ShownFileTypes.NSP.Value = cff.ShownFileTypes.NSP;
|
UI.ShownFileTypes.NSP.Value = shouldLoadFromFile ? cff.ShownFileTypes.NSP : UI.ShownFileTypes.NSP.Value;
|
||||||
UI.ShownFileTypes.PFS0.Value = cff.ShownFileTypes.PFS0;
|
UI.ShownFileTypes.PFS0.Value = shouldLoadFromFile ? cff.ShownFileTypes.PFS0 : UI.ShownFileTypes.PFS0.Value;
|
||||||
UI.ShownFileTypes.XCI.Value = cff.ShownFileTypes.XCI;
|
UI.ShownFileTypes.XCI.Value = shouldLoadFromFile ? cff.ShownFileTypes.XCI : UI.ShownFileTypes.XCI.Value;
|
||||||
UI.ShownFileTypes.NCA.Value = cff.ShownFileTypes.NCA;
|
UI.ShownFileTypes.NCA.Value = shouldLoadFromFile ? cff.ShownFileTypes.NCA : UI.ShownFileTypes.NCA.Value;
|
||||||
UI.ShownFileTypes.NRO.Value = cff.ShownFileTypes.NRO;
|
UI.ShownFileTypes.NRO.Value = shouldLoadFromFile ? cff.ShownFileTypes.NRO : UI.ShownFileTypes.NRO.Value;
|
||||||
UI.ShownFileTypes.NSO.Value = cff.ShownFileTypes.NSO;
|
UI.ShownFileTypes.NSO.Value = shouldLoadFromFile ? cff.ShownFileTypes.NSO : UI.ShownFileTypes.NSO.Value;
|
||||||
UI.LanguageCode.Value = cff.LanguageCode;
|
UI.LanguageCode.Value = shouldLoadFromFile ? cff.LanguageCode : UI.LanguageCode.Value;
|
||||||
UI.BaseStyle.Value = cff.BaseStyle;
|
UI.BaseStyle.Value = shouldLoadFromFile ? cff.BaseStyle : UI.BaseStyle.Value;
|
||||||
UI.GameListViewMode.Value = cff.GameListViewMode;
|
UI.GameListViewMode.Value = shouldLoadFromFile ? cff.GameListViewMode : UI.GameListViewMode.Value;
|
||||||
UI.ShowNames.Value = cff.ShowNames;
|
UI.ShowNames.Value = shouldLoadFromFile ? cff.ShowNames : UI.ShowNames.Value;
|
||||||
UI.IsAscendingOrder.Value = cff.IsAscendingOrder;
|
UI.IsAscendingOrder.Value = shouldLoadFromFile ? cff.IsAscendingOrder : UI.IsAscendingOrder.Value;
|
||||||
UI.GridSize.Value = cff.GridSize;
|
UI.GridSize.Value = shouldLoadFromFile ? cff.GridSize : UI.GridSize.Value;
|
||||||
UI.ApplicationSort.Value = cff.ApplicationSort;
|
UI.ApplicationSort.Value = shouldLoadFromFile ? cff.ApplicationSort : UI.ApplicationSort.Value;
|
||||||
UI.StartFullscreen.Value = cff.StartFullscreen;
|
UI.StartFullscreen.Value = shouldLoadFromFile ? cff.StartFullscreen : UI.StartFullscreen.Value;
|
||||||
UI.StartNoUI.Value = cff.StartNoUI;
|
UI.StartNoUI.Value = shouldLoadFromFile ? cff.StartNoUI : UI.StartNoUI.Value;
|
||||||
UI.ShowConsole.Value = cff.ShowConsole;
|
UI.ShowConsole.Value = shouldLoadFromFile ? cff.ShowConsole : UI.ShowConsole.Value;
|
||||||
UI.WindowStartup.WindowSizeWidth.Value = cff.WindowStartup.WindowSizeWidth;
|
UI.WindowStartup.WindowSizeWidth.Value = shouldLoadFromFile ? cff.WindowStartup.WindowSizeWidth : UI.WindowStartup.WindowSizeWidth.Value;
|
||||||
UI.WindowStartup.WindowSizeHeight.Value = cff.WindowStartup.WindowSizeHeight;
|
UI.WindowStartup.WindowSizeHeight.Value = shouldLoadFromFile ? cff.WindowStartup.WindowSizeHeight : UI.WindowStartup.WindowSizeHeight.Value;
|
||||||
UI.WindowStartup.WindowPositionX.Value = cff.WindowStartup.WindowPositionX;
|
UI.WindowStartup.WindowPositionX.Value = shouldLoadFromFile ? cff.WindowStartup.WindowPositionX : UI.WindowStartup.WindowPositionX.Value;
|
||||||
UI.WindowStartup.WindowPositionY.Value = cff.WindowStartup.WindowPositionY;
|
UI.WindowStartup.WindowPositionY.Value = shouldLoadFromFile ? cff.WindowStartup.WindowPositionY : UI.WindowStartup.WindowPositionY.Value;
|
||||||
UI.WindowStartup.WindowMaximized.Value = cff.WindowStartup.WindowMaximized;
|
UI.WindowStartup.WindowMaximized.Value = shouldLoadFromFile ? cff.WindowStartup.WindowMaximized : UI.WindowStartup.WindowMaximized.Value;
|
||||||
|
|
||||||
|
|
||||||
Hid.EnableKeyboard.Value = cff.EnableKeyboard;
|
Hid.EnableKeyboard.Value = cff.EnableKeyboard;
|
||||||
Hid.EnableMouse.Value = cff.EnableMouse;
|
Hid.EnableMouse.Value = cff.EnableMouse;
|
||||||
Hid.DisableInputWhenOutOfFocus.Value = cff.DisableInputWhenOutOfFocus;
|
Hid.DisableInputWhenOutOfFocus.Value = shouldLoadFromFile ? cff.DisableInputWhenOutOfFocus: Hid.DisableInputWhenOutOfFocus.Value; // Get from global config only
|
||||||
Hid.Hotkeys.Value = cff.Hotkeys;
|
Hid.Hotkeys.Value = shouldLoadFromFile ? cff.Hotkeys : Hid.Hotkeys.Value; // Get from global config only
|
||||||
Hid.InputConfig.Value = cff.InputConfig ?? [];
|
Hid.InputConfig.Value = cff.InputConfig ?? [];
|
||||||
Hid.RainbowSpeed.Value = cff.RainbowSpeed;
|
Hid.RainbowSpeed.Value = cff.RainbowSpeed;
|
||||||
|
|
||||||
|
|
|
@ -60,11 +60,12 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||||
_ => FormattedValue.ForceReset
|
_ => FormattedValue.ForceReset
|
||||||
};
|
};
|
||||||
|
|
||||||
private static FormattedValue PokemonSVUnionCircle(SingleValue value)
|
private static FormattedValue PokemonSV(MultiValue values)
|
||||||
=> value.Matched.BoxedValue is 0 ? "Playing Alone" : "Playing in a group";
|
{
|
||||||
|
|
||||||
private static FormattedValue PokemonSVArea(SingleValue value)
|
string playStatus = values.Matched[0].BoxedValue is 0 ? "Playing Alone" : "Playing in a group";
|
||||||
=> value.Matched.StringValue switch
|
|
||||||
|
FormattedValue locations = values.Matched[1].ToString() switch
|
||||||
{
|
{
|
||||||
// Base Game Locations
|
// Base Game Locations
|
||||||
"a_w01" => "South Area One",
|
"a_w01" => "South Area One",
|
||||||
|
@ -92,11 +93,14 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||||
"a_w24" => "South Paldean Sea",
|
"a_w24" => "South Paldean Sea",
|
||||||
"a_w25" => "West Paldean Sea",
|
"a_w25" => "West Paldean Sea",
|
||||||
"a_w26" => "East Paldean Sea",
|
"a_w26" => "East Paldean Sea",
|
||||||
"a_w27" => "Nouth Paldean Sea",
|
"a_w27" => "North Paldean Sea",
|
||||||
//TODO DLC Locations
|
//TODO DLC Locations
|
||||||
_ => FormattedValue.ForceReset
|
_ => FormattedValue.ForceReset
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return$"{playStatus} in {locations}";
|
||||||
|
}
|
||||||
|
|
||||||
private static FormattedValue SuperSmashBrosUltimate_Mode(SparseMultiValue values)
|
private static FormattedValue SuperSmashBrosUltimate_Mode(SparseMultiValue values)
|
||||||
{
|
{
|
||||||
// Check if the PlayReport is for a challenger approach or an achievement.
|
// Check if the PlayReport is for a challenger approach or an achievement.
|
||||||
|
@ -115,6 +119,11 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||||
return $"Achievement Unlocked - ID: {anniversary}";
|
return $"Achievement Unlocked - ID: {anniversary}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (values.Matched.ContainsKey("is_created"))
|
||||||
|
{
|
||||||
|
return "Edited a Custom Stage!";
|
||||||
|
}
|
||||||
|
|
||||||
if (values.Matched.ContainsKey("adv_slot"))
|
if (values.Matched.ContainsKey("adv_slot"))
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
|
|
|
@ -59,9 +59,8 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||||
.AddSpec(
|
.AddSpec(
|
||||||
["0100a3d008c5c000", "01008f6008c5e000"],
|
["0100a3d008c5c000", "01008f6008c5e000"],
|
||||||
spec => spec
|
spec => spec
|
||||||
.WithDescription("based on what area of Paldea you're exploring.")
|
.WithDescription("based on if you're playing alone or in a group and what area of Paldea you're exploring.")
|
||||||
.AddValueFormatter("area_no", PokemonSVArea)
|
.AddMultiValueFormatter(["team_circle", "area_no"], PokemonSV)
|
||||||
.AddValueFormatter("team_circle", PokemonSVUnionCircle)
|
|
||||||
)
|
)
|
||||||
.AddSpec(
|
.AddSpec(
|
||||||
"01006a800016e000",
|
"01006a800016e000",
|
||||||
|
@ -71,7 +70,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||||
[
|
[
|
||||||
// Metadata to figure out what PlayReport we have.
|
// Metadata to figure out what PlayReport we have.
|
||||||
"match_mode", "match_submode", "anniversary", "fighter", "reason", "challenge_count",
|
"match_mode", "match_submode", "anniversary", "fighter", "reason", "challenge_count",
|
||||||
"adv_slot",
|
"adv_slot", "is_created",
|
||||||
// List of Fighters
|
// List of Fighters
|
||||||
"player_1_fighter", "player_2_fighter", "player_3_fighter", "player_4_fighter",
|
"player_1_fighter", "player_2_fighter", "player_3_fighter", "player_4_fighter",
|
||||||
"player_5_fighter", "player_6_fighter", "player_7_fighter", "player_8_fighter",
|
"player_5_fighter", "player_6_fighter", "player_7_fighter", "player_8_fighter",
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Ryujinx.Ava.Utilities
|
||||||
public static class ShortcutHelper
|
public static class ShortcutHelper
|
||||||
{
|
{
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
private static void CreateShortcutWindows(string applicationFilePath, string applicationId, byte[] iconData, string iconPath, string cleanedAppName, string desktopPath)
|
private static void CreateShortcutWindows(string applicationFilePath, string applicationId, byte[] iconData, string iconPath, string cleanedAppName, string desktopPath, string args = "")
|
||||||
{
|
{
|
||||||
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, AppDomain.CurrentDomain.FriendlyName + ".exe");
|
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, AppDomain.CurrentDomain.FriendlyName + ".exe");
|
||||||
iconPath += ".ico";
|
iconPath += ".ico";
|
||||||
|
@ -22,13 +22,13 @@ namespace Ryujinx.Ava.Utilities
|
||||||
image.Resize(new SKImageInfo(128, 128), SKFilterQuality.High);
|
image.Resize(new SKImageInfo(128, 128), SKFilterQuality.High);
|
||||||
SaveBitmapAsIcon(image, iconPath);
|
SaveBitmapAsIcon(image, iconPath);
|
||||||
|
|
||||||
Shortcut shortcut = Shortcut.CreateShortcut(basePath, GetArgsString(applicationFilePath, applicationId), iconPath, 0);
|
Shortcut shortcut = Shortcut.CreateShortcut(basePath, GetArgsString(applicationFilePath, applicationId, args), iconPath, 0);
|
||||||
shortcut.StringData.NameString = cleanedAppName;
|
shortcut.StringData.NameString = cleanedAppName;
|
||||||
shortcut.WriteToFile(Path.Combine(desktopPath, cleanedAppName + ".lnk"));
|
shortcut.WriteToFile(Path.Combine(desktopPath, cleanedAppName + ".lnk"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("linux")]
|
[SupportedOSPlatform("linux")]
|
||||||
private static void CreateShortcutLinux(string applicationFilePath, string applicationId, byte[] iconData, string iconPath, string desktopPath, string cleanedAppName)
|
private static void CreateShortcutLinux(string applicationFilePath, string applicationId, byte[] iconData, string iconPath, string desktopPath, string cleanedAppName, string args = "")
|
||||||
{
|
{
|
||||||
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx.sh");
|
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx.sh");
|
||||||
string desktopFile = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-template.desktop");
|
string desktopFile = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-template.desktop");
|
||||||
|
@ -40,11 +40,11 @@ namespace Ryujinx.Ava.Utilities
|
||||||
data.SaveTo(file);
|
data.SaveTo(file);
|
||||||
|
|
||||||
using StreamWriter outputFile = new(Path.Combine(desktopPath, cleanedAppName + ".desktop"));
|
using StreamWriter outputFile = new(Path.Combine(desktopPath, cleanedAppName + ".desktop"));
|
||||||
outputFile.Write(desktopFile, cleanedAppName, iconPath, $"{basePath} {GetArgsString(applicationFilePath, applicationId)}");
|
outputFile.Write(desktopFile, cleanedAppName, iconPath, $"{basePath} {GetArgsString(applicationFilePath, applicationId, args)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("macos")]
|
[SupportedOSPlatform("macos")]
|
||||||
private static void CreateShortcutMacos(string appFilePath, string applicationId, byte[] iconData, string desktopPath, string cleanedAppName)
|
private static void CreateShortcutMacos(string appFilePath, string applicationId, byte[] iconData, string desktopPath, string cleanedAppName, string args = "")
|
||||||
{
|
{
|
||||||
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx");
|
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx");
|
||||||
string plistFile = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-template.plist");
|
string plistFile = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-template.plist");
|
||||||
|
@ -63,7 +63,7 @@ namespace Ryujinx.Ava.Utilities
|
||||||
string scriptPath = Path.Combine(scriptFolderPath, ScriptName);
|
string scriptPath = Path.Combine(scriptFolderPath, ScriptName);
|
||||||
using StreamWriter scriptFile = new(scriptPath);
|
using StreamWriter scriptFile = new(scriptPath);
|
||||||
|
|
||||||
scriptFile.Write(shortcutScript, basePath, GetArgsString(appFilePath, applicationId));
|
scriptFile.Write(shortcutScript, basePath, GetArgsString(appFilePath, applicationId, args));
|
||||||
|
|
||||||
// Set execute permission
|
// Set execute permission
|
||||||
FileInfo fileInfo = new(scriptPath);
|
FileInfo fileInfo = new(scriptPath);
|
||||||
|
@ -87,7 +87,7 @@ namespace Ryujinx.Ava.Utilities
|
||||||
outputFile.Write(plistFile, ScriptName, cleanedAppName, IconName);
|
outputFile.Write(plistFile, ScriptName, cleanedAppName, IconName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CreateAppShortcut(string applicationFilePath, string applicationName, string applicationId, byte[] iconData)
|
public static void CreateAppShortcut(string applicationFilePath, string applicationName, string applicationId, byte[] iconData, string args = "")
|
||||||
{
|
{
|
||||||
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
|
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
|
||||||
string cleanedAppName = string.Join("_", applicationName.Split(Path.GetInvalidFileNameChars()));
|
string cleanedAppName = string.Join("_", applicationName.Split(Path.GetInvalidFileNameChars()));
|
||||||
|
@ -96,7 +96,7 @@ namespace Ryujinx.Ava.Utilities
|
||||||
{
|
{
|
||||||
string iconPath = Path.Combine(AppDataManager.BaseDirPath, "games", applicationId, "app");
|
string iconPath = Path.Combine(AppDataManager.BaseDirPath, "games", applicationId, "app");
|
||||||
|
|
||||||
CreateShortcutWindows(applicationFilePath, applicationId, iconData, iconPath, cleanedAppName, desktopPath);
|
CreateShortcutWindows(applicationFilePath, applicationId, iconData, iconPath, cleanedAppName, desktopPath, args);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -106,14 +106,14 @@ namespace Ryujinx.Ava.Utilities
|
||||||
string iconPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share", "icons", "Ryujinx");
|
string iconPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share", "icons", "Ryujinx");
|
||||||
|
|
||||||
Directory.CreateDirectory(iconPath);
|
Directory.CreateDirectory(iconPath);
|
||||||
CreateShortcutLinux(applicationFilePath, applicationId, iconData, Path.Combine(iconPath, applicationId), desktopPath, cleanedAppName);
|
CreateShortcutLinux(applicationFilePath, applicationId, iconData, Path.Combine(iconPath, applicationId), desktopPath, cleanedAppName, args);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OperatingSystem.IsMacOS())
|
if (OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
CreateShortcutMacos(applicationFilePath, applicationId, iconData, desktopPath, cleanedAppName);
|
CreateShortcutMacos(applicationFilePath, applicationId, iconData, desktopPath, cleanedAppName, args);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ namespace Ryujinx.Ava.Utilities
|
||||||
throw new NotImplementedException("Shortcut support has not been implemented yet for this OS.");
|
throw new NotImplementedException("Shortcut support has not been implemented yet for this OS.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetArgsString(string appFilePath, string applicationId)
|
private static string GetArgsString(string appFilePath, string applicationId, string config = "")
|
||||||
{
|
{
|
||||||
// args are first defined as a list, for easier adjustments in the future
|
// args are first defined as a list, for easier adjustments in the future
|
||||||
List<string> argsList = [];
|
List<string> argsList = [];
|
||||||
|
@ -132,6 +132,11 @@ namespace Ryujinx.Ava.Utilities
|
||||||
argsList.Add($"\"{CommandLineState.BaseDirPathArg}\"");
|
argsList.Add($"\"{CommandLineState.BaseDirPathArg}\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(config))
|
||||||
|
{
|
||||||
|
argsList.Add(config);
|
||||||
|
}
|
||||||
|
|
||||||
if (appFilePath.ToLower().EndsWith(".xci"))
|
if (appFilePath.ToLower().EndsWith(".xci"))
|
||||||
{
|
{
|
||||||
argsList.Add("--application-id");
|
argsList.Add("--application-id");
|
||||||
|
|
Loading…
Add table
Reference in a new issue