UI: Fix UpdateWaitWindow.axaml windows being too big on windows #314
3
.gitignore
vendored
3
.gitignore
vendored
@ -175,3 +175,6 @@ PublishProfiles/
|
|||||||
|
|
||||||
# Glade backup files
|
# Glade backup files
|
||||||
*.glade~
|
*.glade~
|
||||||
|
|
||||||
|
# Ignore MacOS Attribute Files
|
||||||
|
._*
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.3-build14" />
|
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.3-build14" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
|
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
|
||||||
<PackageVersion Include="Gommon" Version="2.6.6" />
|
<PackageVersion Include="Gommon" Version="2.6.8" />
|
||||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||||
|
@ -14,7 +14,7 @@ if [ -z "$RYUJINX_BIN" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
COMMAND="env DOTNET_EnableAlternateStackCheck=1"
|
COMMAND="env LANG=C.UTF-8 DOTNET_EnableAlternateStackCheck=1"
|
||||||
|
|
||||||
if command -v gamemoderun > /dev/null 2>&1; then
|
if command -v gamemoderun > /dev/null 2>&1; then
|
||||||
COMMAND="$COMMAND gamemoderun"
|
COMMAND="$COMMAND gamemoderun"
|
||||||
|
@ -40,11 +40,11 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.1</string>
|
<string>1.2</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.1.0</string>
|
<string>1.2.0</string>
|
||||||
<key>NSHighResolutionCapable</key>
|
<key>NSHighResolutionCapable</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>CSResourcesFileMapped</key>
|
<key>CSResourcesFileMapped</key>
|
||||||
|
@ -17,7 +17,7 @@ error_handler() {
|
|||||||
set the button_pressed to the button returned of the result
|
set the button_pressed to the button returned of the result
|
||||||
|
|
||||||
if the button_pressed is \"Open Download Page\" then
|
if the button_pressed is \"Open Download Page\" then
|
||||||
open location \"https://ryujinx.org/download\"
|
open location \"https://ryujinx.app/download\"
|
||||||
end if
|
end if
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -36,9 +36,9 @@ namespace ARMeilleure.Common
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="address">Guest address</param>
|
/// <param name="address">Guest address</param>
|
||||||
/// <returns>Value of the <see cref="AddressTableLevel"/> from the specified guest <paramref name="address"/></returns>
|
/// <returns>Value of the <see cref="AddressTableLevel"/> from the specified guest <paramref name="address"/></returns>
|
||||||
public int GetValue(ulong address)
|
public long GetValue(ulong address)
|
||||||
{
|
{
|
||||||
return (int)((address & Mask) >> Index);
|
return (long)((address & Mask) >> Index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ namespace ARMeilleure.Instructions
|
|||||||
EmitSetTpidrEl0(context);
|
EmitSetTpidrEl0(context);
|
||||||
return;
|
return;
|
||||||
case 0b11_011_1101_0000_101:
|
case 0b11_011_1101_0000_101:
|
||||||
EmitGetTpidr2El0(context);
|
EmitSetTpidr2El0(context);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -291,5 +291,16 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
context.Store(context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrEl0Offset())), value);
|
context.Store(context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrEl0Offset())), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EmitSetTpidr2El0(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||||
|
|
||||||
|
Operand value = GetIntOrZR(context, op.Rt);
|
||||||
|
|
||||||
|
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||||
|
|
||||||
|
context.Store(context.Add(nativeContext, Const((ulong)NativeContext.GetTpidr2El0Offset())), value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 6992; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 6997; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
namespace Ryujinx.Common.Configuration.Hid.Controller
|
namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||||
{
|
{
|
||||||
public class JoyconConfigControllerStick<TButton, TStick> where TButton : unmanaged where TStick : unmanaged
|
public class JoyconConfigControllerStick<TButton, TStick>
|
||||||
|
where TButton : unmanaged
|
||||||
|
where TStick : unmanaged
|
||||||
{
|
{
|
||||||
public TStick Joystick { get; set; }
|
public TStick Joystick { get; set; }
|
||||||
public bool InvertStickX { get; set; }
|
public bool InvertStickX { get; set; }
|
||||||
|
@ -2,7 +2,7 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||||||
{
|
{
|
||||||
public class KeyboardHotkeys
|
public class KeyboardHotkeys
|
||||||
{
|
{
|
||||||
public Key ToggleVsync { get; set; }
|
public Key ToggleVSyncMode { get; set; }
|
||||||
public Key Screenshot { get; set; }
|
public Key Screenshot { get; set; }
|
||||||
public Key ShowUI { get; set; }
|
public Key ShowUI { get; set; }
|
||||||
public Key Pause { get; set; }
|
public Key Pause { get; set; }
|
||||||
@ -11,5 +11,7 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||||||
public Key ResScaleDown { get; set; }
|
public Key ResScaleDown { get; set; }
|
||||||
public Key VolumeUp { get; set; }
|
public Key VolumeUp { get; set; }
|
||||||
public Key VolumeDown { get; set; }
|
public Key VolumeDown { get; set; }
|
||||||
|
public Key CustomVSyncIntervalIncrement { get; set; }
|
||||||
|
public Key CustomVSyncIntervalDecrement { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
src/Ryujinx.Common/Configuration/VSyncMode.cs
Normal file
9
src/Ryujinx.Common/Configuration/VSyncMode.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Ryujinx.Common.Configuration
|
||||||
|
{
|
||||||
|
public enum VSyncMode
|
||||||
|
{
|
||||||
|
Switch,
|
||||||
|
Unbounded,
|
||||||
|
Custom
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
|
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -238,7 +238,7 @@ namespace ARMeilleure.Common
|
|||||||
{
|
{
|
||||||
TEntry* page = GetPage(address);
|
TEntry* page = GetPage(address);
|
||||||
|
|
||||||
int index = Levels[^1].GetValue(address);
|
long index = Levels[^1].GetValue(address);
|
||||||
|
|
||||||
EnsureMapped((IntPtr)(page + index));
|
EnsureMapped((IntPtr)(page + index));
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
|
|
||||||
void SetSize(int width, int height);
|
void SetSize(int width, int height);
|
||||||
|
|
||||||
void ChangeVSyncMode(bool vsyncEnabled);
|
void ChangeVSyncMode(VSyncMode vSyncMode);
|
||||||
|
|
||||||
void SetAntiAliasing(AntiAliasing antialiasing);
|
void SetAntiAliasing(AntiAliasing antialiasing);
|
||||||
void SetScalingFilter(ScalingFilter type);
|
void SetScalingFilter(ScalingFilter type);
|
||||||
|
@ -31,7 +31,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
_impl.Window.SetSize(width, height);
|
_impl.Window.SetSize(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ChangeVSyncMode(bool vsyncEnabled) { }
|
public void ChangeVSyncMode(VSyncMode vSyncMode) { }
|
||||||
|
|
||||||
public void SetAntiAliasing(AntiAliasing effect) { }
|
public void SetAntiAliasing(AntiAliasing effect) { }
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
9
src/Ryujinx.Graphics.GAL/VSyncMode.cs
Normal file
9
src/Ryujinx.Graphics.GAL/VSyncMode.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Ryujinx.Graphics.GAL
|
||||||
|
{
|
||||||
|
public enum VSyncMode
|
||||||
|
{
|
||||||
|
Switch,
|
||||||
|
Unbounded,
|
||||||
|
Custom
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -54,7 +54,7 @@ namespace Ryujinx.Graphics.OpenGL
|
|||||||
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 4);
|
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ChangeVSyncMode(bool vsyncEnabled) { }
|
public void ChangeVSyncMode(VSyncMode vSyncMode) { }
|
||||||
|
|
||||||
public void SetSize(int width, int height)
|
public void SetSize(int width, int height)
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
@ -183,6 +183,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Prevent the sum of descriptors from exceeding MaxPushDescriptors
|
||||||
|
int totalDescriptors = 0;
|
||||||
|
foreach (ResourceDescriptor desc in layout.Sets.First().Descriptors)
|
||||||
|
{
|
||||||
|
if (!reserved.Contains(desc.Binding))
|
||||||
|
totalDescriptors += desc.Count;
|
||||||
|
}
|
||||||
|
if (totalDescriptors > gd.Capabilities.MaxPushDescriptors)
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private int _width;
|
private int _width;
|
||||||
private int _height;
|
private int _height;
|
||||||
private bool _vsyncEnabled;
|
private VSyncMode _vSyncMode;
|
||||||
private bool _swapchainIsDirty;
|
private bool _swapchainIsDirty;
|
||||||
private VkFormat _format;
|
private VkFormat _format;
|
||||||
private AntiAliasing _currentAntiAliasing;
|
private AntiAliasing _currentAntiAliasing;
|
||||||
@ -139,7 +139,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
ImageArrayLayers = 1,
|
ImageArrayLayers = 1,
|
||||||
PreTransform = capabilities.CurrentTransform,
|
PreTransform = capabilities.CurrentTransform,
|
||||||
CompositeAlpha = ChooseCompositeAlpha(capabilities.SupportedCompositeAlpha),
|
CompositeAlpha = ChooseCompositeAlpha(capabilities.SupportedCompositeAlpha),
|
||||||
PresentMode = ChooseSwapPresentMode(presentModes, _vsyncEnabled),
|
PresentMode = ChooseSwapPresentMode(presentModes, _vSyncMode),
|
||||||
Clipped = true,
|
Clipped = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -279,9 +279,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PresentModeKHR ChooseSwapPresentMode(PresentModeKHR[] availablePresentModes, bool vsyncEnabled)
|
private static PresentModeKHR ChooseSwapPresentMode(PresentModeKHR[] availablePresentModes, VSyncMode vSyncMode)
|
||||||
{
|
{
|
||||||
if (!vsyncEnabled && availablePresentModes.Contains(PresentModeKHR.ImmediateKhr))
|
if (vSyncMode == VSyncMode.Unbounded && availablePresentModes.Contains(PresentModeKHR.ImmediateKhr))
|
||||||
{
|
{
|
||||||
return PresentModeKHR.ImmediateKhr;
|
return PresentModeKHR.ImmediateKhr;
|
||||||
}
|
}
|
||||||
@ -634,9 +634,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_swapchainIsDirty = true;
|
_swapchainIsDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ChangeVSyncMode(bool vsyncEnabled)
|
public override void ChangeVSyncMode(VSyncMode vSyncMode)
|
||||||
{
|
{
|
||||||
_vsyncEnabled = vsyncEnabled;
|
_vSyncMode = vSyncMode;
|
||||||
|
//present mode may change, so mark the swapchain for recreation
|
||||||
_swapchainIsDirty = true;
|
_swapchainIsDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
public abstract void Dispose();
|
public abstract void Dispose();
|
||||||
public abstract void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback);
|
public abstract void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback);
|
||||||
public abstract void SetSize(int width, int height);
|
public abstract void SetSize(int width, int height);
|
||||||
public abstract void ChangeVSyncMode(bool vsyncEnabled);
|
public abstract void ChangeVSyncMode(VSyncMode vSyncMode);
|
||||||
public abstract void SetAntiAliasing(AntiAliasing effect);
|
public abstract void SetAntiAliasing(AntiAliasing effect);
|
||||||
public abstract void SetScalingFilter(ScalingFilter scalerType);
|
public abstract void SetScalingFilter(ScalingFilter scalerType);
|
||||||
public abstract void SetScalingFilterLevel(float scale);
|
public abstract void SetScalingFilterLevel(float scale);
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||||
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
|
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
|
||||||
<IsRoslynComponent>true</IsRoslynComponent>
|
<IsRoslynComponent>true</IsRoslynComponent>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -21,6 +21,7 @@ using System.IO;
|
|||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.FileSystem
|
namespace Ryujinx.HLE.FileSystem
|
||||||
@ -474,6 +475,74 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
FinishInstallation(temporaryDirectory, registeredDirectory);
|
FinishInstallation(temporaryDirectory, registeredDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void InstallKeys(string keysSource, string installDirectory)
|
||||||
|
{
|
||||||
|
if (Directory.Exists(keysSource))
|
||||||
|
{
|
||||||
|
foreach (var filePath in Directory.EnumerateFiles(keysSource, "*.keys"))
|
||||||
|
{
|
||||||
|
VerifyKeysFile(filePath);
|
||||||
|
File.Copy(filePath, Path.Combine(installDirectory, Path.GetFileName(filePath)), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(keysSource))
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException("Keys file does not exist.");
|
||||||
|
}
|
||||||
|
|
||||||
|
FileInfo info = new(keysSource);
|
||||||
|
|
||||||
|
using FileStream file = File.OpenRead(keysSource);
|
||||||
|
|
||||||
|
switch (info.Extension)
|
||||||
|
{
|
||||||
|
case ".zip":
|
||||||
|
using (ZipArchive archive = ZipFile.OpenRead(keysSource))
|
||||||
|
{
|
||||||
|
InstallKeysFromZip(archive, installDirectory);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ".keys":
|
||||||
|
VerifyKeysFile(keysSource);
|
||||||
|
File.Copy(keysSource, Path.Combine(installDirectory, info.Name), true);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidFirmwarePackageException("Input file is not a valid key package");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InstallKeysFromZip(ZipArchive archive, string installDirectory)
|
||||||
|
{
|
||||||
|
string temporaryDirectory = Path.Combine(installDirectory, "temp");
|
||||||
|
if (Directory.Exists(temporaryDirectory))
|
||||||
|
{
|
||||||
|
Directory.Delete(temporaryDirectory, true);
|
||||||
|
}
|
||||||
|
Directory.CreateDirectory(temporaryDirectory);
|
||||||
|
foreach (var entry in archive.Entries)
|
||||||
|
{
|
||||||
|
if (Path.GetExtension(entry.FullName).Equals(".keys", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
string extractDestination = Path.Combine(temporaryDirectory, entry.Name);
|
||||||
|
entry.ExtractToFile(extractDestination, overwrite: true);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
VerifyKeysFile(extractDestination);
|
||||||
|
File.Move(extractDestination, Path.Combine(installDirectory, entry.Name), true);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
Directory.Delete(temporaryDirectory, true);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Directory.Delete(temporaryDirectory, true);
|
||||||
|
}
|
||||||
|
|
||||||
private void FinishInstallation(string temporaryDirectory, string registeredDirectory)
|
private void FinishInstallation(string temporaryDirectory, string registeredDirectory)
|
||||||
{
|
{
|
||||||
if (Directory.Exists(registeredDirectory))
|
if (Directory.Exists(registeredDirectory))
|
||||||
@ -947,5 +1016,70 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void VerifyKeysFile(string filePath)
|
||||||
|
{
|
||||||
|
// Verify the keys file format refers to https://github.com/Thealexbarney/LibHac/blob/master/KEYS.md
|
||||||
|
string genericPattern = @"^[a-z0-9_]+ = [a-z0-9]+$";
|
||||||
|
string titlePattern = @"^[a-z0-9]{32} = [a-z0-9]{32}$";
|
||||||
|
|
||||||
|
if (File.Exists(filePath))
|
||||||
|
{
|
||||||
|
// Read all lines from the file
|
||||||
|
string fileName = Path.GetFileName(filePath);
|
||||||
|
string[] lines = File.ReadAllLines(filePath);
|
||||||
|
|
||||||
|
bool verified = false;
|
||||||
|
switch (fileName)
|
||||||
|
{
|
||||||
|
case "prod.keys":
|
||||||
|
verified = verifyKeys(lines, genericPattern);
|
||||||
|
break;
|
||||||
|
case "title.keys":
|
||||||
|
verified = verifyKeys(lines, titlePattern);
|
||||||
|
break;
|
||||||
|
case "console.keys":
|
||||||
|
verified = verifyKeys(lines, genericPattern);
|
||||||
|
break;
|
||||||
|
case "dev.keys":
|
||||||
|
verified = verifyKeys(lines, genericPattern);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new FormatException($"Keys file name \"{fileName}\" not supported. Only \"prod.keys\", \"title.keys\", \"console.keys\", \"dev.keys\" are supported.");
|
||||||
|
}
|
||||||
|
if (!verified)
|
||||||
|
{
|
||||||
|
throw new FormatException($"Invalid \"{filePath}\" file format.");
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException($"Keys file not found at \"{filePath}\".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool verifyKeys(string[] lines, string regex)
|
||||||
|
{
|
||||||
|
foreach (string line in lines)
|
||||||
|
{
|
||||||
|
if (!Regex.IsMatch(line, regex))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AreKeysAlredyPresent(string pathToCheck)
|
||||||
|
{
|
||||||
|
string[] fileNames = { "prod.keys", "title.keys", "console.keys", "dev.keys" };
|
||||||
|
foreach (var file in fileNames)
|
||||||
|
{
|
||||||
|
if (File.Exists(Path.Combine(pathToCheck, file)))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,9 +223,10 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
KeySet ??= KeySet.CreateDefaultKeySet();
|
KeySet ??= KeySet.CreateDefaultKeySet();
|
||||||
|
|
||||||
string keyFile = null;
|
string prodKeyFile = null;
|
||||||
string titleKeyFile = null;
|
string titleKeyFile = null;
|
||||||
string consoleKeyFile = null;
|
string consoleKeyFile = null;
|
||||||
|
string devKeyFile = null;
|
||||||
|
|
||||||
if (AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile)
|
if (AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile)
|
||||||
{
|
{
|
||||||
@ -236,13 +237,14 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
|
|
||||||
void LoadSetAtPath(string basePath)
|
void LoadSetAtPath(string basePath)
|
||||||
{
|
{
|
||||||
string localKeyFile = Path.Combine(basePath, "prod.keys");
|
string localProdKeyFile = Path.Combine(basePath, "prod.keys");
|
||||||
string localTitleKeyFile = Path.Combine(basePath, "title.keys");
|
string localTitleKeyFile = Path.Combine(basePath, "title.keys");
|
||||||
string localConsoleKeyFile = Path.Combine(basePath, "console.keys");
|
string localConsoleKeyFile = Path.Combine(basePath, "console.keys");
|
||||||
|
string localDevKeyFile = Path.Combine(basePath, "dev.keys");
|
||||||
|
|
||||||
if (File.Exists(localKeyFile))
|
if (File.Exists(localProdKeyFile))
|
||||||
{
|
{
|
||||||
keyFile = localKeyFile;
|
prodKeyFile = localProdKeyFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (File.Exists(localTitleKeyFile))
|
if (File.Exists(localTitleKeyFile))
|
||||||
@ -254,9 +256,14 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
consoleKeyFile = localConsoleKeyFile;
|
consoleKeyFile = localConsoleKeyFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (File.Exists(localDevKeyFile))
|
||||||
|
{
|
||||||
|
devKeyFile = localDevKeyFile;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExternalKeyReader.ReadKeyFile(KeySet, keyFile, titleKeyFile, consoleKeyFile, null);
|
ExternalKeyReader.ReadKeyFile(KeySet, prodKeyFile, devKeyFile, titleKeyFile, consoleKeyFile, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ImportTickets(IFileSystem fs)
|
public void ImportTickets(IFileSystem fs)
|
||||||
|
@ -9,6 +9,7 @@ using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|||||||
using Ryujinx.HLE.HOS.SystemState;
|
using Ryujinx.HLE.HOS.SystemState;
|
||||||
using Ryujinx.HLE.UI;
|
using Ryujinx.HLE.UI;
|
||||||
using System;
|
using System;
|
||||||
|
using VSyncMode = Ryujinx.Common.Configuration.VSyncMode;
|
||||||
|
|
||||||
namespace Ryujinx.HLE
|
namespace Ryujinx.HLE
|
||||||
{
|
{
|
||||||
@ -84,9 +85,14 @@ namespace Ryujinx.HLE
|
|||||||
internal readonly RegionCode Region;
|
internal readonly RegionCode Region;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Control the initial state of the vertical sync in the SurfaceFlinger service.
|
/// Control the initial state of the present interval in the SurfaceFlinger service (previously Vsync).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly bool EnableVsync;
|
internal readonly VSyncMode VSyncMode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Control the custom VSync interval, if enabled and active.
|
||||||
|
/// </summary>
|
||||||
|
internal readonly int CustomVSyncInterval;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Control the initial state of the docked mode.
|
/// Control the initial state of the docked mode.
|
||||||
@ -195,7 +201,7 @@ namespace Ryujinx.HLE
|
|||||||
IHostUIHandler hostUIHandler,
|
IHostUIHandler hostUIHandler,
|
||||||
SystemLanguage systemLanguage,
|
SystemLanguage systemLanguage,
|
||||||
RegionCode region,
|
RegionCode region,
|
||||||
bool enableVsync,
|
VSyncMode vSyncMode,
|
||||||
bool enableDockedMode,
|
bool enableDockedMode,
|
||||||
bool enablePtc,
|
bool enablePtc,
|
||||||
bool enableInternetAccess,
|
bool enableInternetAccess,
|
||||||
@ -212,7 +218,8 @@ namespace Ryujinx.HLE
|
|||||||
MultiplayerMode multiplayerMode,
|
MultiplayerMode multiplayerMode,
|
||||||
bool multiplayerDisableP2p,
|
bool multiplayerDisableP2p,
|
||||||
string multiplayerLdnPassphrase,
|
string multiplayerLdnPassphrase,
|
||||||
string multiplayerLdnServer)
|
string multiplayerLdnServer,
|
||||||
|
int customVSyncInterval)
|
||||||
{
|
{
|
||||||
VirtualFileSystem = virtualFileSystem;
|
VirtualFileSystem = virtualFileSystem;
|
||||||
LibHacHorizonManager = libHacHorizonManager;
|
LibHacHorizonManager = libHacHorizonManager;
|
||||||
@ -225,7 +232,8 @@ namespace Ryujinx.HLE
|
|||||||
HostUIHandler = hostUIHandler;
|
HostUIHandler = hostUIHandler;
|
||||||
SystemLanguage = systemLanguage;
|
SystemLanguage = systemLanguage;
|
||||||
Region = region;
|
Region = region;
|
||||||
EnableVsync = enableVsync;
|
VSyncMode = vSyncMode;
|
||||||
|
CustomVSyncInterval = customVSyncInterval;
|
||||||
EnableDockedMode = enableDockedMode;
|
EnableDockedMode = enableDockedMode;
|
||||||
EnablePtc = enablePtc;
|
EnablePtc = enablePtc;
|
||||||
EnableInternetAccess = enableInternetAccess;
|
EnableInternetAccess = enableInternetAccess;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.HOS.Applets.Browser;
|
using Ryujinx.HLE.HOS.Applets.Browser;
|
||||||
|
using Ryujinx.HLE.HOS.Applets.Cabinet;
|
||||||
using Ryujinx.HLE.HOS.Applets.Dummy;
|
using Ryujinx.HLE.HOS.Applets.Dummy;
|
||||||
using Ryujinx.HLE.HOS.Applets.Error;
|
using Ryujinx.HLE.HOS.Applets.Error;
|
||||||
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
||||||
@ -23,14 +24,14 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
case AppletId.SoftwareKeyboard:
|
case AppletId.SoftwareKeyboard:
|
||||||
return new SoftwareKeyboardApplet(system);
|
return new SoftwareKeyboardApplet(system);
|
||||||
case AppletId.LibAppletWeb:
|
case AppletId.LibAppletWeb:
|
||||||
return new BrowserApplet(system);
|
|
||||||
case AppletId.LibAppletShop:
|
case AppletId.LibAppletShop:
|
||||||
return new BrowserApplet(system);
|
|
||||||
case AppletId.LibAppletOff:
|
case AppletId.LibAppletOff:
|
||||||
return new BrowserApplet(system);
|
return new BrowserApplet();
|
||||||
case AppletId.MiiEdit:
|
case AppletId.MiiEdit:
|
||||||
Logger.Warning?.Print(LogClass.Application, $"Please use the MiiEdit inside File/Open Applet");
|
Logger.Warning?.Print(LogClass.Application, $"Please use the MiiEdit inside File/Open Applet");
|
||||||
return new DummyApplet(system);
|
return new DummyApplet(system);
|
||||||
|
case AppletId.Cabinet:
|
||||||
|
return new CabinetApplet(system);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Warning?.Print(LogClass.Application, $"Applet {applet} not implemented!");
|
Logger.Warning?.Print(LogClass.Application, $"Applet {applet} not implemented!");
|
||||||
|
@ -18,13 +18,6 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
|
|||||||
private List<BrowserArgument> _arguments;
|
private List<BrowserArgument> _arguments;
|
||||||
private ShimKind _shimKind;
|
private ShimKind _shimKind;
|
||||||
|
|
||||||
public BrowserApplet(Horizon system) { }
|
|
||||||
|
|
||||||
public ResultCode GetResult()
|
|
||||||
{
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
|
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
|
||||||
{
|
{
|
||||||
_normalSession = normalSession;
|
_normalSession = normalSession;
|
||||||
|
182
src/Ryujinx.HLE/HOS/Applets/Cabinet/CabinetApplet.cs
Normal file
182
src/Ryujinx.HLE/HOS/Applets/Cabinet/CabinetApplet.cs
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Hid.HidServer;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Hid;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Nfc.Nfp;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Applets.Cabinet
|
||||||
|
{
|
||||||
|
internal unsafe class CabinetApplet : IApplet
|
||||||
|
{
|
||||||
|
private readonly Horizon _system;
|
||||||
|
private AppletSession _normalSession;
|
||||||
|
|
||||||
|
public event EventHandler AppletStateChanged;
|
||||||
|
|
||||||
|
public CabinetApplet(Horizon system)
|
||||||
|
{
|
||||||
|
_system = system;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
|
||||||
|
{
|
||||||
|
_normalSession = normalSession;
|
||||||
|
|
||||||
|
byte[] launchParams = _normalSession.Pop();
|
||||||
|
byte[] startParamBytes = _normalSession.Pop();
|
||||||
|
|
||||||
|
StartParamForAmiiboSettings startParam = IApplet.ReadStruct<StartParamForAmiiboSettings>(startParamBytes);
|
||||||
|
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceAm, $"CabinetApplet Start Type: {startParam.Type}");
|
||||||
|
|
||||||
|
switch (startParam.Type)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
StartNicknameAndOwnerSettings(ref startParam);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 3:
|
||||||
|
StartFormatter(ref startParam);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Logger.Error?.Print(LogClass.ServiceAm, $"Unknown AmiiboSettings type: {startParam.Type}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the response
|
||||||
|
ReturnValueForAmiiboSettings returnValue = new()
|
||||||
|
{
|
||||||
|
AmiiboSettingsReturnFlag = (byte)AmiiboSettingsReturnFlag.HasRegisterInfo,
|
||||||
|
DeviceHandle = new DeviceHandle
|
||||||
|
{
|
||||||
|
Handle = 0 // Dummy device handle
|
||||||
|
},
|
||||||
|
RegisterInfo = startParam.RegisterInfo
|
||||||
|
};
|
||||||
|
|
||||||
|
// Push the response
|
||||||
|
_normalSession.Push(BuildResponse(returnValue));
|
||||||
|
AppletStateChanged?.Invoke(this, null);
|
||||||
|
|
||||||
|
_system.ReturnFocus();
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResultCode GetResult()
|
||||||
|
{
|
||||||
|
_system.Device.System.NfpDevices.RemoveAt(0);
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartFormatter(ref StartParamForAmiiboSettings startParam)
|
||||||
|
{
|
||||||
|
// Initialize RegisterInfo
|
||||||
|
startParam.RegisterInfo = new RegisterInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartNicknameAndOwnerSettings(ref StartParamForAmiiboSettings startParam)
|
||||||
|
{
|
||||||
|
_system.Device.UIHandler.DisplayCabinetDialog(out string newName);
|
||||||
|
byte[] nameBytes = Encoding.UTF8.GetBytes(newName);
|
||||||
|
Array41<byte> nickName = new Array41<byte>();
|
||||||
|
nameBytes.CopyTo(nickName.AsSpan());
|
||||||
|
startParam.RegisterInfo.Nickname = nickName;
|
||||||
|
NfpDevice devicePlayer1 = new()
|
||||||
|
{
|
||||||
|
NpadIdType = NpadIdType.Player1,
|
||||||
|
Handle = HidUtils.GetIndexFromNpadIdType(NpadIdType.Player1),
|
||||||
|
State = NfpDeviceState.SearchingForTag,
|
||||||
|
};
|
||||||
|
_system.Device.System.NfpDevices.Add(devicePlayer1);
|
||||||
|
_system.Device.UIHandler.DisplayCabinetMessageDialog();
|
||||||
|
string amiiboId = string.Empty;
|
||||||
|
bool scanned = false;
|
||||||
|
while (!scanned)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _system.Device.System.NfpDevices.Count; i++)
|
||||||
|
{
|
||||||
|
if (_system.Device.System.NfpDevices[i].State == NfpDeviceState.TagFound)
|
||||||
|
{
|
||||||
|
amiiboId = _system.Device.System.NfpDevices[i].AmiiboId;
|
||||||
|
scanned = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VirtualAmiibo.UpdateNickName(amiiboId, newName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] BuildResponse(ReturnValueForAmiiboSettings returnValue)
|
||||||
|
{
|
||||||
|
int size = Unsafe.SizeOf<ReturnValueForAmiiboSettings>();
|
||||||
|
byte[] bytes = new byte[size];
|
||||||
|
|
||||||
|
fixed (byte* bytesPtr = bytes)
|
||||||
|
{
|
||||||
|
Unsafe.Write(bytesPtr, returnValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Structs
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
public unsafe struct TagInfo
|
||||||
|
{
|
||||||
|
public fixed byte Data[0x58];
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
public unsafe struct StartParamForAmiiboSettings
|
||||||
|
{
|
||||||
|
public byte ZeroValue; // Left at zero by sdknso
|
||||||
|
public byte Type;
|
||||||
|
public byte Flags;
|
||||||
|
public byte AmiiboSettingsStartParamOffset28;
|
||||||
|
public ulong AmiiboSettingsStartParam0;
|
||||||
|
|
||||||
|
public TagInfo TagInfo; // Only enabled when flags bit 1 is set
|
||||||
|
public RegisterInfo RegisterInfo; // Only enabled when flags bit 2 is set
|
||||||
|
|
||||||
|
public fixed byte StartParamExtraData[0x20];
|
||||||
|
|
||||||
|
public fixed byte Reserved[0x24];
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
public unsafe struct ReturnValueForAmiiboSettings
|
||||||
|
{
|
||||||
|
public byte AmiiboSettingsReturnFlag;
|
||||||
|
private byte Padding1;
|
||||||
|
private byte Padding2;
|
||||||
|
private byte Padding3;
|
||||||
|
public DeviceHandle DeviceHandle;
|
||||||
|
public TagInfo TagInfo;
|
||||||
|
public RegisterInfo RegisterInfo;
|
||||||
|
public fixed byte IgnoredBySdknso[0x24];
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
public struct DeviceHandle
|
||||||
|
{
|
||||||
|
public ulong Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AmiiboSettingsReturnFlag : byte
|
||||||
|
{
|
||||||
|
Cancel = 0,
|
||||||
|
HasTagInfo = 2,
|
||||||
|
HasRegisterInfo = 4,
|
||||||
|
HasTagInfoAndRegisterInfo = 6
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -117,11 +117,6 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode GetResult()
|
|
||||||
{
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte[] BuildResponse(ControllerSupportResultInfo result)
|
private static byte[] BuildResponse(ControllerSupportResultInfo result)
|
||||||
{
|
{
|
||||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||||
|
@ -11,11 +11,14 @@ namespace Ryujinx.HLE.HOS.Applets.Dummy
|
|||||||
{
|
{
|
||||||
private readonly Horizon _system;
|
private readonly Horizon _system;
|
||||||
private AppletSession _normalSession;
|
private AppletSession _normalSession;
|
||||||
|
|
||||||
public event EventHandler AppletStateChanged;
|
public event EventHandler AppletStateChanged;
|
||||||
|
|
||||||
public DummyApplet(Horizon system)
|
public DummyApplet(Horizon system)
|
||||||
{
|
{
|
||||||
_system = system;
|
_system = system;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
|
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
|
||||||
{
|
{
|
||||||
_normalSession = normalSession;
|
_normalSession = normalSession;
|
||||||
@ -24,10 +27,7 @@ namespace Ryujinx.HLE.HOS.Applets.Dummy
|
|||||||
_system.ReturnFocus();
|
_system.ReturnFocus();
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
private static T ReadStruct<T>(byte[] data) where T : struct
|
|
||||||
{
|
|
||||||
return MemoryMarshal.Read<T>(data.AsSpan());
|
|
||||||
}
|
|
||||||
private static byte[] BuildResponse()
|
private static byte[] BuildResponse()
|
||||||
{
|
{
|
||||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||||
@ -35,9 +35,5 @@ namespace Ryujinx.HLE.HOS.Applets.Dummy
|
|||||||
writer.Write((ulong)ResultCode.Success);
|
writer.Write((ulong)ResultCode.Success);
|
||||||
return stream.ToArray();
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
public ResultCode GetResult()
|
|
||||||
{
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,10 +203,5 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
_horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Number: {applicationErrorArg.ErrorNumber} (Details)", "\n" + detailsText, buttons.ToArray());
|
_horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Number: {applicationErrorArg.ErrorNumber} (Details)", "\n" + detailsText, buttons.ToArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode GetResult()
|
|
||||||
{
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
ResultCode Start(AppletSession normalSession,
|
ResultCode Start(AppletSession normalSession,
|
||||||
AppletSession interactiveSession);
|
AppletSession interactiveSession);
|
||||||
|
|
||||||
ResultCode GetResult();
|
ResultCode GetResult() => ResultCode.Success;
|
||||||
|
|
||||||
bool DrawTo(RenderingSurfaceInfo surfaceInfo, IVirtualMemoryManager destination, ulong position) => false;
|
bool DrawTo(RenderingSurfaceInfo surfaceInfo, IVirtualMemoryManager destination, ulong position) => false;
|
||||||
|
|
||||||
|
@ -37,11 +37,6 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode GetResult()
|
|
||||||
{
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] BuildResponse()
|
private byte[] BuildResponse()
|
||||||
{
|
{
|
||||||
UserProfile currentUser = _system.AccountManager.LastOpenedUser;
|
UserProfile currentUser = _system.AccountManager.LastOpenedUser;
|
||||||
|
@ -144,11 +144,6 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResultCode GetResult()
|
|
||||||
{
|
|
||||||
return ResultCode.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsKeyboardActive()
|
private bool IsKeyboardActive()
|
||||||
{
|
{
|
||||||
return _backgroundState >= InlineKeyboardState.Appearing && _backgroundState < InlineKeyboardState.Disappearing;
|
return _backgroundState >= InlineKeyboardState.Appearing && _backgroundState < InlineKeyboardState.Disappearing;
|
||||||
|
@ -2,7 +2,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wraps a type in a class so it gets stored in the GC managed heap. This is used as communication mechanism
|
/// Wraps a type in a class so it gets stored in the GC managed heap. This is used as communication mechanism
|
||||||
/// between classed that need to be disposed and, thus, can't share their references.
|
/// between classes that need to be disposed and, thus, can't share their references.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The internal type.</typeparam>
|
/// <typeparam name="T">The internal type.</typeparam>
|
||||||
class TRef<T>
|
class TRef<T>
|
||||||
|
@ -5,5 +5,23 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.Lp2p
|
|||||||
class IServiceCreator : IpcService
|
class IServiceCreator : IpcService
|
||||||
{
|
{
|
||||||
public IServiceCreator(ServiceCtx context) { }
|
public IServiceCreator(ServiceCtx context) { }
|
||||||
|
|
||||||
|
[CommandCmif(0)]
|
||||||
|
// CreateNetworkService(pid, u64, u32) -> object<nn::ldn::detail::ISfService>
|
||||||
|
public ResultCode CreateNetworkService(ServiceCtx context)
|
||||||
|
{
|
||||||
|
MakeObject(context, new ISfService(context));
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandCmif(8)]
|
||||||
|
// CreateNetworkServiceMonitor(pid, u64) -> object<nn::ldn::detail::ISfServiceMonitor>
|
||||||
|
public ResultCode CreateNetworkServiceMonitor(ServiceCtx context)
|
||||||
|
{
|
||||||
|
MakeObject(context, new ISfServiceMonitor(context));
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
src/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/ISfService.cs
Normal file
54
src/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/ISfService.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Ldn.Lp2p
|
||||||
|
{
|
||||||
|
class ISfService : IpcService
|
||||||
|
{
|
||||||
|
public ISfService(ServiceCtx context) { }
|
||||||
|
|
||||||
|
[CommandCmif(0)]
|
||||||
|
// Initialize()
|
||||||
|
public ResultCode Initialize(ServiceCtx context)
|
||||||
|
{
|
||||||
|
context.ResponseData.Write(0);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandCmif(768)]
|
||||||
|
// CreateGroup(buffer<nn::lp2p::GroupInfo, 0x31)
|
||||||
|
public ResultCode CreateGroup(ServiceCtx context)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceLdn);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandCmif(776)]
|
||||||
|
// DestroyGroup()
|
||||||
|
public ResultCode DestroyGroup(ServiceCtx context)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceLdn);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandCmif(1536)]
|
||||||
|
// SendToOtherGroup(nn::lp2p::MacAddress, nn::lp2p::GroupId, s16, s16, u32, buffer<unknown, 0x21>)
|
||||||
|
public ResultCode SendToOtherGroup(ServiceCtx context)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceLdn);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandCmif(1544)]
|
||||||
|
// RecvFromOtherGroup(u32, buffer<unknown, 0x22>) -> (nn::lp2p::MacAddress, u16, s16, u32, s32)
|
||||||
|
public ResultCode RecvFromOtherGroup(ServiceCtx context)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceLdn);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
86
src/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/ISfServiceMonitor.cs
Normal file
86
src/Ryujinx.HLE/HOS/Services/Ldn/Lp2p/ISfServiceMonitor.cs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.HLE.HOS.Ipc;
|
||||||
|
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Ldn.Lp2p
|
||||||
|
{
|
||||||
|
class ISfServiceMonitor : IpcService
|
||||||
|
{
|
||||||
|
private readonly KEvent _stateChangeEvent;
|
||||||
|
private readonly KEvent _jointEvent;
|
||||||
|
private int _stateChangeEventHandle = 0;
|
||||||
|
private int _jointEventHandle = 0;
|
||||||
|
|
||||||
|
public ISfServiceMonitor(ServiceCtx context)
|
||||||
|
{
|
||||||
|
_stateChangeEvent = new KEvent(context.Device.System.KernelContext);
|
||||||
|
_jointEvent = new KEvent(context.Device.System.KernelContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandCmif(0)]
|
||||||
|
// Initialize()
|
||||||
|
public ResultCode Initialize(ServiceCtx context)
|
||||||
|
{
|
||||||
|
context.ResponseData.Write(0);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandCmif(256)]
|
||||||
|
// AttachNetworkInterfaceStateChangeEvent() -> handle<copy>
|
||||||
|
public ResultCode AttachNetworkInterfaceStateChangeEvent(ServiceCtx context)
|
||||||
|
{
|
||||||
|
if (context.Process.HandleTable.GenerateHandle(_stateChangeEvent.ReadableEvent, out _stateChangeEventHandle) != Result.Success)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Out of handles!");
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_stateChangeEventHandle);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandCmif(288)]
|
||||||
|
// GetGroupInfo(buffer<nn::lp2p::GroupInfo, 0x32>)
|
||||||
|
public ResultCode GetGroupInfo(ServiceCtx context)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceLdn);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandCmif(296)]
|
||||||
|
// GetGroupInfo2(buffer<nn::lp2p::GroupInfo, 0x32>, buffer<nn::lp2p::GroupInfo, 0x31>)
|
||||||
|
public ResultCode GetGroupInfo2(ServiceCtx context)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceLdn);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandCmif(312)]
|
||||||
|
// GetIpConfig(buffer<unknown<0x100>, 0x1a>)
|
||||||
|
public ResultCode GetIpConfig(ServiceCtx context)
|
||||||
|
{
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceLdn);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CommandCmif(328)]
|
||||||
|
// AttachNetworkInterfaceStateChangeEvent() -> handle<copy>
|
||||||
|
public ResultCode AttachJoinEvent(ServiceCtx context)
|
||||||
|
{
|
||||||
|
if (context.Process.HandleTable.GenerateHandle(_jointEvent.ReadableEvent, out _jointEventHandle) != Result.Success)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Out of handles!");
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_jointEventHandle);
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
using Gommon;
|
||||||
|
using Humanizer;
|
||||||
using NetCoreServer;
|
using NetCoreServer;
|
||||||
using Open.Nat;
|
using Open.Nat;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
@ -153,7 +155,10 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||||||
|
|
||||||
if (_publicPort != 0)
|
if (_publicPort != 0)
|
||||||
{
|
{
|
||||||
_ = Task.Delay(PortLeaseRenew * 1000, _disposedCancellation.Token).ContinueWith((task) => Task.Run(RefreshLease));
|
_ = Executor.ExecuteAfterDelayAsync(
|
||||||
|
PortLeaseRenew.Seconds(),
|
||||||
|
_disposedCancellation.Token,
|
||||||
|
RefreshLease);
|
||||||
}
|
}
|
||||||
|
|
||||||
_natDevice = device;
|
_natDevice = device;
|
||||||
@ -257,7 +262,10 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = Task.Delay(PortLeaseRenew, _disposedCancellation.Token).ContinueWith((task) => Task.Run(RefreshLease));
|
_ = Executor.ExecuteAfterDelayAsync(
|
||||||
|
PortLeaseRenew.Milliseconds(),
|
||||||
|
_disposedCancellation.Token,
|
||||||
|
RefreshLease);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryRegisterUser(P2pProxySession session, ExternalProxyConfig config)
|
public bool TryRegisterUser(P2pProxySession session, ExternalProxyConfig config)
|
||||||
|
@ -93,6 +93,13 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|||||||
return registerInfo;
|
return registerInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void UpdateNickName(string amiiboId, string newNickName)
|
||||||
|
{
|
||||||
|
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
|
||||||
|
virtualAmiiboFile.NickName = newNickName;
|
||||||
|
SaveAmiiboFile(virtualAmiiboFile);
|
||||||
|
}
|
||||||
|
|
||||||
public static bool OpenApplicationArea(string amiiboId, uint applicationAreaId)
|
public static bool OpenApplicationArea(string amiiboId, uint applicationAreaId)
|
||||||
{
|
{
|
||||||
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
|
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
|
||||||
|
@ -10,13 +10,12 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using VSyncMode = Ryujinx.Common.Configuration.VSyncMode;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
||||||
{
|
{
|
||||||
class SurfaceFlinger : IConsumerListener, IDisposable
|
class SurfaceFlinger : IConsumerListener, IDisposable
|
||||||
{
|
{
|
||||||
private const int TargetFps = 60;
|
|
||||||
|
|
||||||
private readonly Switch _device;
|
private readonly Switch _device;
|
||||||
|
|
||||||
private readonly Dictionary<long, Layer> _layers;
|
private readonly Dictionary<long, Layer> _layers;
|
||||||
@ -32,6 +31,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||||||
private readonly long _spinTicks;
|
private readonly long _spinTicks;
|
||||||
private readonly long _1msTicks;
|
private readonly long _1msTicks;
|
||||||
|
|
||||||
|
private VSyncMode _vSyncMode;
|
||||||
|
private long _targetVSyncInterval;
|
||||||
|
|
||||||
private int _swapInterval;
|
private int _swapInterval;
|
||||||
private int _swapIntervalDelay;
|
private int _swapIntervalDelay;
|
||||||
|
|
||||||
@ -88,7 +90,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_ticksPerFrame = Stopwatch.Frequency / TargetFps;
|
_ticksPerFrame = Stopwatch.Frequency / _device.TargetVSyncInterval;
|
||||||
|
_targetVSyncInterval = _device.TargetVSyncInterval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,15 +373,20 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||||||
|
|
||||||
if (acquireStatus == Status.Success)
|
if (acquireStatus == Status.Success)
|
||||||
{
|
{
|
||||||
// If device vsync is disabled, reflect the change.
|
if (_device.VSyncMode == VSyncMode.Unbounded)
|
||||||
if (!_device.EnableDeviceVsync)
|
|
||||||
{
|
{
|
||||||
if (_swapInterval != 0)
|
if (_swapInterval != 0)
|
||||||
{
|
{
|
||||||
UpdateSwapInterval(0);
|
UpdateSwapInterval(0);
|
||||||
|
_vSyncMode = _device.VSyncMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (item.SwapInterval != _swapInterval)
|
else if (_device.VSyncMode != _vSyncMode)
|
||||||
|
{
|
||||||
|
UpdateSwapInterval(_device.VSyncMode == VSyncMode.Unbounded ? 0 : item.SwapInterval);
|
||||||
|
_vSyncMode = _device.VSyncMode;
|
||||||
|
}
|
||||||
|
else if (item.SwapInterval != _swapInterval || _device.TargetVSyncInterval != _targetVSyncInterval)
|
||||||
{
|
{
|
||||||
UpdateSwapInterval(item.SwapInterval);
|
UpdateSwapInterval(item.SwapInterval);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
{
|
{
|
||||||
private static readonly TitleUpdateMetadataJsonSerializerContext _applicationSerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly TitleUpdateMetadataJsonSerializerContext _applicationSerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
public static ProcessResult Load(this Nca nca, Switch device, Nca patchNca, Nca controlNca)
|
public static ProcessResult Load(this Nca nca, Switch device, Nca patchNca, Nca controlNca, BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
||||||
{
|
{
|
||||||
// Extract RomFs and ExeFs from NCA.
|
// Extract RomFs and ExeFs from NCA.
|
||||||
IStorage romFs = nca.GetRomFs(device, patchNca);
|
IStorage romFs = nca.GetRomFs(device, patchNca);
|
||||||
@ -55,6 +55,10 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
{
|
{
|
||||||
nacpData = controlNca.GetNacp(device);
|
nacpData = controlNca.GetNacp(device);
|
||||||
}
|
}
|
||||||
|
else if (customNacpData != null) // if the Application doesn't provide a nacp file but the Application provides an override, use the provided nacp override
|
||||||
|
{
|
||||||
|
nacpData = (BlitStruct<ApplicationControlProperty>)customNacpData;
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO: Rework this since it's wrong and doesn't work as it takes the DisplayVersion from a "potential" non-existent update.
|
/* TODO: Rework this since it's wrong and doesn't work as it takes the DisplayVersion from a "potential" non-existent update.
|
||||||
|
|
||||||
|
@ -98,12 +98,12 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool LoadNca(string path)
|
public bool LoadNca(string path, BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
||||||
{
|
{
|
||||||
FileStream file = new(path, FileMode.Open, FileAccess.Read);
|
FileStream file = new(path, FileMode.Open, FileAccess.Read);
|
||||||
Nca nca = new(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false));
|
Nca nca = new(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false));
|
||||||
|
|
||||||
ProcessResult processResult = nca.Load(_device, null, null);
|
ProcessResult processResult = nca.Load(_device, null, null, customNacpData);
|
||||||
|
|
||||||
if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult))
|
if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult))
|
||||||
{
|
{
|
||||||
|
@ -84,12 +84,19 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isFirmware = ProgramId is >= 0x0100000000000819 and <= 0x010000000000081C;
|
||||||
|
bool isFirmwareApplication = ProgramId <= 0x0100000000007FFF;
|
||||||
|
|
||||||
|
string name = !isFirmware
|
||||||
|
? (isFirmwareApplication ? "Firmware Application " : "") + (!string.IsNullOrWhiteSpace(Name) ? Name : "<Unknown Name>")
|
||||||
|
: "Firmware";
|
||||||
|
|
||||||
// TODO: LibHac npdm currently doesn't support version field.
|
// TODO: LibHac npdm currently doesn't support version field.
|
||||||
string version = ProgramId > 0x0100000000007FFF
|
string version = !isFirmware
|
||||||
? DisplayVersion
|
? (!string.IsNullOrWhiteSpace(DisplayVersion) ? DisplayVersion : "<Unknown Version>")
|
||||||
: device.System.ContentManager.GetCurrentFirmwareVersion()?.VersionString ?? "?";
|
: device.System.ContentManager.GetCurrentFirmwareVersion()?.VersionString ?? "?";
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {Name} v{version} [{ProgramIdText}] [{(Is64Bit ? "64-bit" : "32-bit")}]");
|
Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {name} v{version} [{ProgramIdText}] [{(Is64Bit ? "64-bit" : "32-bit")}]");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
37
src/Ryujinx.HLE/StructHelpers.cs
Normal file
37
src/Ryujinx.HLE/StructHelpers.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Ns;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE
|
||||||
|
{
|
||||||
|
public static class StructHelpers
|
||||||
|
{
|
||||||
|
public static BlitStruct<ApplicationControlProperty> CreateCustomNacpData(string name, string version)
|
||||||
|
{
|
||||||
|
// https://switchbrew.org/wiki/NACP
|
||||||
|
const int OffsetOfDisplayVersion = 0x3060;
|
||||||
|
|
||||||
|
// https://switchbrew.org/wiki/NACP#ApplicationTitle
|
||||||
|
const int TotalApplicationTitles = 0x10;
|
||||||
|
const int SizeOfApplicationTitle = 0x300;
|
||||||
|
const int OffsetOfApplicationPublisherStrings = 0x200;
|
||||||
|
|
||||||
|
|
||||||
|
var nacpData = new BlitStruct<ApplicationControlProperty>(1);
|
||||||
|
|
||||||
|
// name and publisher buffer
|
||||||
|
// repeat once for each locale (the ApplicationControlProperty has 16 locales)
|
||||||
|
for (int i = 0; i < TotalApplicationTitles; i++)
|
||||||
|
{
|
||||||
|
Encoding.ASCII.GetBytes(name).AsSpan().CopyTo(nacpData.ByteSpan[(i * SizeOfApplicationTitle)..]);
|
||||||
|
"Ryujinx"u8.CopyTo(nacpData.ByteSpan[(i * SizeOfApplicationTitle + OffsetOfApplicationPublisherStrings)..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// version buffer
|
||||||
|
Encoding.ASCII.GetBytes(version).AsSpan().CopyTo(nacpData.ByteSpan[OffsetOfDisplayVersion..]);
|
||||||
|
|
||||||
|
return nacpData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Ns;
|
||||||
using Ryujinx.Audio.Backends.CompatLayer;
|
using Ryujinx.Audio.Backends.CompatLayer;
|
||||||
using Ryujinx.Audio.Integration;
|
using Ryujinx.Audio.Integration;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
@ -27,7 +29,11 @@ namespace Ryujinx.HLE
|
|||||||
public TamperMachine TamperMachine { get; }
|
public TamperMachine TamperMachine { get; }
|
||||||
public IHostUIHandler UIHandler { get; }
|
public IHostUIHandler UIHandler { get; }
|
||||||
|
|
||||||
public bool EnableDeviceVsync { get; set; }
|
public VSyncMode VSyncMode { get; set; } = VSyncMode.Switch;
|
||||||
|
public bool CustomVSyncIntervalEnabled { get; set; } = false;
|
||||||
|
public int CustomVSyncInterval { get; set; }
|
||||||
|
|
||||||
|
public long TargetVSyncInterval { get; set; } = 60;
|
||||||
|
|
||||||
public bool IsFrameAvailable => Gpu.Window.IsFrameAvailable;
|
public bool IsFrameAvailable => Gpu.Window.IsFrameAvailable;
|
||||||
|
|
||||||
@ -59,12 +65,14 @@ namespace Ryujinx.HLE
|
|||||||
System.State.SetLanguage(Configuration.SystemLanguage);
|
System.State.SetLanguage(Configuration.SystemLanguage);
|
||||||
System.State.SetRegion(Configuration.Region);
|
System.State.SetRegion(Configuration.Region);
|
||||||
|
|
||||||
EnableDeviceVsync = Configuration.EnableVsync;
|
VSyncMode = Configuration.VSyncMode;
|
||||||
|
CustomVSyncInterval = Configuration.CustomVSyncInterval;
|
||||||
System.State.DockedMode = Configuration.EnableDockedMode;
|
System.State.DockedMode = Configuration.EnableDockedMode;
|
||||||
System.PerformanceState.PerformanceMode = System.State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default;
|
System.PerformanceState.PerformanceMode = System.State.DockedMode ? PerformanceMode.Boost : PerformanceMode.Default;
|
||||||
System.EnablePtc = Configuration.EnablePtc;
|
System.EnablePtc = Configuration.EnablePtc;
|
||||||
System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel;
|
System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel;
|
||||||
System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode;
|
System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode;
|
||||||
|
UpdateVSyncInterval();
|
||||||
#pragma warning restore IDE0055
|
#pragma warning restore IDE0055
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,9 +83,37 @@ namespace Ryujinx.HLE
|
|||||||
Gpu.GPFifo.DispatchCalls();
|
Gpu.GPFifo.DispatchCalls();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void IncrementCustomVSyncInterval()
|
||||||
|
{
|
||||||
|
CustomVSyncInterval += 1;
|
||||||
|
UpdateVSyncInterval();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DecrementCustomVSyncInterval()
|
||||||
|
{
|
||||||
|
CustomVSyncInterval -= 1;
|
||||||
|
UpdateVSyncInterval();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateVSyncInterval()
|
||||||
|
{
|
||||||
|
switch (VSyncMode)
|
||||||
|
{
|
||||||
|
case VSyncMode.Custom:
|
||||||
|
TargetVSyncInterval = CustomVSyncInterval;
|
||||||
|
break;
|
||||||
|
case VSyncMode.Switch:
|
||||||
|
TargetVSyncInterval = 60;
|
||||||
|
break;
|
||||||
|
case VSyncMode.Unbounded:
|
||||||
|
TargetVSyncInterval = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool LoadCart(string exeFsDir, string romFsFile = null) => Processes.LoadUnpackedNca(exeFsDir, romFsFile);
|
public bool LoadCart(string exeFsDir, string romFsFile = null) => Processes.LoadUnpackedNca(exeFsDir, romFsFile);
|
||||||
public bool LoadXci(string xciFile, ulong applicationId = 0) => Processes.LoadXci(xciFile, applicationId);
|
public bool LoadXci(string xciFile, ulong applicationId = 0) => Processes.LoadXci(xciFile, applicationId);
|
||||||
public bool LoadNca(string ncaFile) => Processes.LoadNca(ncaFile);
|
public bool LoadNca(string ncaFile, BlitStruct<ApplicationControlProperty>? customNacpData = null) => Processes.LoadNca(ncaFile, customNacpData);
|
||||||
public bool LoadNsp(string nspFile, ulong applicationId = 0) => Processes.LoadNsp(nspFile, applicationId);
|
public bool LoadNsp(string nspFile, ulong applicationId = 0) => Processes.LoadNsp(nspFile, applicationId);
|
||||||
public bool LoadProgram(string fileName) => Processes.LoadNxo(fileName);
|
public bool LoadProgram(string fileName) => Processes.LoadNxo(fileName);
|
||||||
|
|
||||||
|
@ -24,6 +24,18 @@ namespace Ryujinx.HLE.UI
|
|||||||
/// <returns>True when OK is pressed, False otherwise.</returns>
|
/// <returns>True when OK is pressed, False otherwise.</returns>
|
||||||
bool DisplayMessageDialog(ControllerAppletUIArgs args);
|
bool DisplayMessageDialog(ControllerAppletUIArgs args);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Displays an Input Dialog box to the user so they can enter the Amiibo's new name
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userText">Text that the user entered. Set to `null` on internal errors</param>
|
||||||
|
/// <returns>True when OK is pressed, False otherwise. Also returns True on internal errors</returns>
|
||||||
|
bool DisplayCabinetDialog(out string userText);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Displays a Message Dialog box to the user to notify them to scan the Amiibo.
|
||||||
|
/// </summary>
|
||||||
|
void DisplayCabinetMessageDialog();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tell the UI that we need to transition to another program.
|
/// Tell the UI that we need to transition to another program.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -115,8 +115,11 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
[Option("fs-global-access-log-mode", Required = false, Default = 0, HelpText = "Enables FS access log output to the console.")]
|
[Option("fs-global-access-log-mode", Required = false, Default = 0, HelpText = "Enables FS access log output to the console.")]
|
||||||
public int FsGlobalAccessLogMode { get; set; }
|
public int FsGlobalAccessLogMode { get; set; }
|
||||||
|
|
||||||
[Option("disable-vsync", Required = false, HelpText = "Disables Vertical Sync.")]
|
[Option("vsync-mode", Required = false, Default = VSyncMode.Switch, HelpText = "Sets the emulated VSync mode (Switch, Unbounded, or Custom).")]
|
||||||
public bool DisableVSync { get; set; }
|
public VSyncMode VSyncMode { get; set; }
|
||||||
|
|
||||||
|
[Option("custom-refresh-rate", Required = false, Default = 90, HelpText = "Sets the custom refresh rate target value (integer).")]
|
||||||
|
public int CustomVSyncInterval { get; set; }
|
||||||
|
|
||||||
[Option("disable-shader-cache", Required = false, HelpText = "Disables Shader cache.")]
|
[Option("disable-shader-cache", Required = false, HelpText = "Disables Shader cache.")]
|
||||||
public bool DisableShaderCache { get; set; }
|
public bool DisableShaderCache { get; set; }
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using CommandLine;
|
using CommandLine;
|
||||||
|
using Gommon;
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using Ryujinx.Audio.Backends.SDL2;
|
using Ryujinx.Audio.Backends.SDL2;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
@ -96,8 +97,13 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
}
|
}
|
||||||
|
|
||||||
Parser.Default.ParseArguments<Options>(args)
|
Parser.Default.ParseArguments<Options>(args)
|
||||||
.WithParsed(Load)
|
.WithParsed(Load)
|
||||||
.WithNotParsed(errors => errors.Output());
|
.WithNotParsed(errors =>
|
||||||
|
{
|
||||||
|
Logger.Error?.PrintMsg(LogClass.Application, "Error parsing command-line arguments:");
|
||||||
|
|
||||||
|
errors.ForEach(err => Logger.Error?.PrintMsg(LogClass.Application, $" - {err.Tag}"));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
|
private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
|
||||||
@ -563,7 +569,7 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
window,
|
window,
|
||||||
options.SystemLanguage,
|
options.SystemLanguage,
|
||||||
options.SystemRegion,
|
options.SystemRegion,
|
||||||
!options.DisableVSync,
|
options.VSyncMode,
|
||||||
!options.DisableDockedMode,
|
!options.DisableDockedMode,
|
||||||
!options.DisablePTC,
|
!options.DisablePTC,
|
||||||
options.EnableInternetAccess,
|
options.EnableInternetAccess,
|
||||||
@ -579,8 +585,9 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
options.MultiplayerLanInterfaceId,
|
options.MultiplayerLanInterfaceId,
|
||||||
Common.Configuration.Multiplayer.MultiplayerMode.Disabled,
|
Common.Configuration.Multiplayer.MultiplayerMode.Disabled,
|
||||||
false,
|
false,
|
||||||
"",
|
string.Empty,
|
||||||
"");
|
string.Empty,
|
||||||
|
options.CustomVSyncInterval);
|
||||||
|
|
||||||
return new Switch(configuration);
|
return new Switch(configuration);
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
|
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
|
||||||
<SigningCertificate Condition=" '$(SigningCertificate)' == '' ">-</SigningCertificate>
|
<SigningCertificate Condition=" '$(SigningCertificate)' == '' ">-</SigningCertificate>
|
||||||
<TieredPGO>true</TieredPGO>
|
<TieredPGO>true</TieredPGO>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,7 +3,7 @@ using System;
|
|||||||
namespace Ryujinx.Headless.SDL2
|
namespace Ryujinx.Headless.SDL2
|
||||||
{
|
{
|
||||||
class StatusUpdatedEventArgs(
|
class StatusUpdatedEventArgs(
|
||||||
bool vSyncEnabled,
|
string vSyncMode,
|
||||||
string dockedMode,
|
string dockedMode,
|
||||||
string aspectRatio,
|
string aspectRatio,
|
||||||
string gameStatus,
|
string gameStatus,
|
||||||
@ -11,7 +11,7 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
string gpuName)
|
string gpuName)
|
||||||
: EventArgs
|
: EventArgs
|
||||||
{
|
{
|
||||||
public bool VSyncEnabled = vSyncEnabled;
|
public string VSyncMode = vSyncMode;
|
||||||
public string DockedMode = dockedMode;
|
public string DockedMode = dockedMode;
|
||||||
public string AspectRatio = aspectRatio;
|
public string AspectRatio = aspectRatio;
|
||||||
public string GameStatus = gameStatus;
|
public string GameStatus = gameStatus;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Humanizer;
|
using Humanizer;
|
||||||
|
using LibHac.Tools.Fs;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
@ -314,7 +315,7 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
}
|
}
|
||||||
|
|
||||||
StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
|
StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
|
||||||
Device.EnableDeviceVsync,
|
Device.VSyncMode.ToString(),
|
||||||
dockedMode,
|
dockedMode,
|
||||||
Device.Configuration.AspectRatio.ToText(),
|
Device.Configuration.AspectRatio.ToText(),
|
||||||
$"Game: {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
$"Game: {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
||||||
@ -485,6 +486,19 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool DisplayCabinetDialog(out string userText)
|
||||||
|
{
|
||||||
|
// SDL2 doesn't support input dialogs
|
||||||
|
userText = "Ryujinx";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisplayCabinetMessageDialog()
|
||||||
|
{
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MessageBoxFlags.SDL_MESSAGEBOX_INFORMATION, "Cabinet Dialog", "Please scan your Amiibo now.", WindowHandle);
|
||||||
|
}
|
||||||
|
|
||||||
public bool DisplayMessageDialog(ControllerAppletUIArgs args)
|
public bool DisplayMessageDialog(ControllerAppletUIArgs args)
|
||||||
{
|
{
|
||||||
if (_ignoreControllerApplet) return false;
|
if (_ignoreControllerApplet) return false;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
<TargetOS Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">linux</TargetOS>
|
<TargetOS Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">linux</TargetOS>
|
||||||
<Configurations>Debug;Release</Configurations>
|
<Configurations>Debug;Release</Configurations>
|
||||||
<RunSettingsFilePath>$(MSBuildProjectDirectory)\.runsettings</RunSettingsFilePath>
|
<RunSettingsFilePath>$(MSBuildProjectDirectory)\.runsettings</RunSettingsFilePath>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using DynamicData;
|
using DynamicData;
|
||||||
using DynamicData.Kernel;
|
|
||||||
using Gommon;
|
using Gommon;
|
||||||
using LibHac;
|
using LibHac;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
@ -37,14 +36,13 @@ using System.Threading.Tasks;
|
|||||||
using ContentType = LibHac.Ncm.ContentType;
|
using ContentType = LibHac.Ncm.ContentType;
|
||||||
using MissingKeyException = LibHac.Common.Keys.MissingKeyException;
|
using MissingKeyException = LibHac.Common.Keys.MissingKeyException;
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
using SpanHelpers = LibHac.Common.SpanHelpers;
|
|
||||||
using TimeSpan = System.TimeSpan;
|
using TimeSpan = System.TimeSpan;
|
||||||
|
|
||||||
namespace Ryujinx.UI.App.Common
|
namespace Ryujinx.UI.App.Common
|
||||||
{
|
{
|
||||||
public class ApplicationLibrary
|
public class ApplicationLibrary
|
||||||
{
|
{
|
||||||
public static string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com";
|
public const string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com";
|
||||||
public Language DesiredLanguage { get; set; }
|
public Language DesiredLanguage { get; set; }
|
||||||
public event EventHandler<ApplicationCountUpdatedEventArgs> ApplicationCountUpdated;
|
public event EventHandler<ApplicationCountUpdatedEventArgs> ApplicationCountUpdated;
|
||||||
public event EventHandler<LdnGameDataReceivedEventArgs> LdnGameDataReceived;
|
public event EventHandler<LdnGameDataReceivedEventArgs> LdnGameDataReceived;
|
||||||
@ -191,12 +189,9 @@ namespace Ryujinx.UI.App.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isExeFs)
|
return isExeFs
|
||||||
{
|
? GetApplicationFromExeFs(pfs, filePath)
|
||||||
return GetApplicationFromExeFs(pfs, filePath);
|
: null;
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <exception cref="LibHac.Common.Keys.MissingKeyException">The configured key set is missing a key.</exception>
|
/// <exception cref="LibHac.Common.Keys.MissingKeyException">The configured key set is missing a key.</exception>
|
||||||
@ -512,10 +507,6 @@ namespace Ryujinx.UI.App.Common
|
|||||||
case ".xci":
|
case ".xci":
|
||||||
case ".nsp":
|
case ".nsp":
|
||||||
{
|
{
|
||||||
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
|
|
||||||
? IntegrityCheckLevel.ErrorOnInvalid
|
|
||||||
: IntegrityCheckLevel.None;
|
|
||||||
|
|
||||||
using IFileSystem pfs = PartitionFileSystemUtils.OpenApplicationFileSystem(filePath, _virtualFileSystem);
|
using IFileSystem pfs = PartitionFileSystemUtils.OpenApplicationFileSystem(filePath, _virtualFileSystem);
|
||||||
|
|
||||||
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
||||||
@ -604,7 +595,7 @@ namespace Ryujinx.UI.App.Common
|
|||||||
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None)
|
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None)
|
||||||
.OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read)
|
.OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read)
|
||||||
.ThrowIfFailure();
|
.ThrowIfFailure();
|
||||||
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData),
|
nacpFile.Get.Read(out _, 0, LibHac.Common.SpanHelpers.AsByteSpan(ref controlData),
|
||||||
ReadOption.None).ThrowIfFailure();
|
ReadOption.None).ThrowIfFailure();
|
||||||
|
|
||||||
var displayVersion = controlData.DisplayVersionString.ToString();
|
var displayVersion = controlData.DisplayVersionString.ToString();
|
||||||
@ -827,7 +818,7 @@ namespace Ryujinx.UI.App.Common
|
|||||||
{
|
{
|
||||||
_downloadableContents.Edit(it =>
|
_downloadableContents.Edit(it =>
|
||||||
{
|
{
|
||||||
DownloadableContentsHelper.SaveDownloadableContentsJson(_virtualFileSystem, application.IdBase, dlcs);
|
DownloadableContentsHelper.SaveDownloadableContentsJson(application.IdBase, dlcs);
|
||||||
|
|
||||||
it.Remove(it.Items.Where(item => item.Dlc.TitleIdBase == application.IdBase));
|
it.Remove(it.Items.Where(item => item.Dlc.TitleIdBase == application.IdBase));
|
||||||
it.AddOrUpdate(dlcs);
|
it.AddOrUpdate(dlcs);
|
||||||
@ -839,7 +830,7 @@ namespace Ryujinx.UI.App.Common
|
|||||||
{
|
{
|
||||||
_titleUpdates.Edit(it =>
|
_titleUpdates.Edit(it =>
|
||||||
{
|
{
|
||||||
TitleUpdatesHelper.SaveTitleUpdatesJson(_virtualFileSystem, application.IdBase, updates);
|
TitleUpdatesHelper.SaveTitleUpdatesJson(application.IdBase, updates);
|
||||||
|
|
||||||
it.Remove(it.Items.Where(item => item.TitleUpdate.TitleIdBase == application.IdBase));
|
it.Remove(it.Items.Where(item => item.TitleUpdate.TitleIdBase == application.IdBase));
|
||||||
it.AddOrUpdate(updates);
|
it.AddOrUpdate(updates);
|
||||||
@ -1088,11 +1079,12 @@ namespace Ryujinx.UI.App.Common
|
|||||||
|
|
||||||
private bool AddAndAutoSelectUpdate(TitleUpdateModel update)
|
private bool AddAndAutoSelectUpdate(TitleUpdateModel update)
|
||||||
{
|
{
|
||||||
var currentlySelected = TitleUpdates.Items.FirstOrOptional(it =>
|
if (update == null) return false;
|
||||||
|
|
||||||
|
var currentlySelected = TitleUpdates.Items.FindFirst(it =>
|
||||||
it.TitleUpdate.TitleIdBase == update.TitleIdBase && it.IsSelected);
|
it.TitleUpdate.TitleIdBase == update.TitleIdBase && it.IsSelected);
|
||||||
|
|
||||||
var shouldSelect = !currentlySelected.HasValue ||
|
var shouldSelect = currentlySelected.Check(curr => curr.TitleUpdate?.Version < update.Version);
|
||||||
currentlySelected.Value.TitleUpdate.Version < update.Version;
|
|
||||||
|
|
||||||
_titleUpdates.AddOrUpdate((update, shouldSelect));
|
_titleUpdates.AddOrUpdate((update, shouldSelect));
|
||||||
|
|
||||||
@ -1464,7 +1456,7 @@ namespace Ryujinx.UI.App.Common
|
|||||||
if (addedNewDlc)
|
if (addedNewDlc)
|
||||||
{
|
{
|
||||||
var gameDlcs = it.Items.Where(dlc => dlc.Dlc.TitleIdBase == application.IdBase).ToList();
|
var gameDlcs = it.Items.Where(dlc => dlc.Dlc.TitleIdBase == application.IdBase).ToList();
|
||||||
DownloadableContentsHelper.SaveDownloadableContentsJson(_virtualFileSystem, application.IdBase,
|
DownloadableContentsHelper.SaveDownloadableContentsJson(application.IdBase,
|
||||||
gameDlcs);
|
gameDlcs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1483,11 +1475,11 @@ namespace Ryujinx.UI.App.Common
|
|||||||
TitleUpdatesHelper.LoadTitleUpdatesJson(_virtualFileSystem, application.IdBase);
|
TitleUpdatesHelper.LoadTitleUpdatesJson(_virtualFileSystem, application.IdBase);
|
||||||
it.AddOrUpdate(savedUpdates);
|
it.AddOrUpdate(savedUpdates);
|
||||||
|
|
||||||
var selectedUpdate = savedUpdates.FirstOrOptional(update => update.IsSelected);
|
var selectedUpdate = savedUpdates.FindFirst(update => update.IsSelected);
|
||||||
|
|
||||||
if (TryGetTitleUpdatesFromFile(application.Path, out var bundledUpdates))
|
if (TryGetTitleUpdatesFromFile(application.Path, out var bundledUpdates))
|
||||||
{
|
{
|
||||||
var savedUpdateLookup = savedUpdates.Select(update => update.Item1).ToHashSet();
|
var savedUpdateLookup = savedUpdates.Select(update => update.Update).ToHashSet();
|
||||||
bool updatesChanged = false;
|
bool updatesChanged = false;
|
||||||
|
|
||||||
foreach (var update in bundledUpdates.OrderByDescending(bundled => bundled.Version))
|
foreach (var update in bundledUpdates.OrderByDescending(bundled => bundled.Version))
|
||||||
@ -1495,12 +1487,11 @@ namespace Ryujinx.UI.App.Common
|
|||||||
if (!savedUpdateLookup.Contains(update))
|
if (!savedUpdateLookup.Contains(update))
|
||||||
{
|
{
|
||||||
bool shouldSelect = false;
|
bool shouldSelect = false;
|
||||||
if (!selectedUpdate.HasValue || selectedUpdate.Value.Item1.Version < update.Version)
|
if (selectedUpdate.Check(su => su.Update?.Version < update.Version))
|
||||||
{
|
{
|
||||||
shouldSelect = true;
|
shouldSelect = true;
|
||||||
if (selectedUpdate.HasValue)
|
_titleUpdates.AddOrUpdate((selectedUpdate.Value.Update, false));
|
||||||
_titleUpdates.AddOrUpdate((selectedUpdate.Value.Item1, false));
|
selectedUpdate = (update, true);
|
||||||
selectedUpdate = DynamicData.Kernel.Optional<(TitleUpdateModel, bool IsSelected)>.Create((update, true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
modifiedVersion = modifiedVersion || shouldSelect;
|
modifiedVersion = modifiedVersion || shouldSelect;
|
||||||
@ -1513,7 +1504,7 @@ namespace Ryujinx.UI.App.Common
|
|||||||
if (updatesChanged)
|
if (updatesChanged)
|
||||||
{
|
{
|
||||||
var gameUpdates = it.Items.Where(update => update.TitleUpdate.TitleIdBase == application.IdBase).ToList();
|
var gameUpdates = it.Items.Where(update => update.TitleUpdate.TitleIdBase == application.IdBase).ToList();
|
||||||
TitleUpdatesHelper.SaveTitleUpdatesJson(_virtualFileSystem, application.IdBase, gameUpdates);
|
TitleUpdatesHelper.SaveTitleUpdatesJson(application.IdBase, gameUpdates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1525,14 +1516,14 @@ namespace Ryujinx.UI.App.Common
|
|||||||
private void SaveDownloadableContentsForGame(ulong titleIdBase)
|
private void SaveDownloadableContentsForGame(ulong titleIdBase)
|
||||||
{
|
{
|
||||||
var dlcs = DownloadableContents.Items.Where(dlc => dlc.Dlc.TitleIdBase == titleIdBase).ToList();
|
var dlcs = DownloadableContents.Items.Where(dlc => dlc.Dlc.TitleIdBase == titleIdBase).ToList();
|
||||||
DownloadableContentsHelper.SaveDownloadableContentsJson(_virtualFileSystem, titleIdBase, dlcs);
|
DownloadableContentsHelper.SaveDownloadableContentsJson(titleIdBase, dlcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the _currently tracked_ update state for the game
|
// Save the _currently tracked_ update state for the game
|
||||||
private void SaveTitleUpdatesForGame(ulong titleIdBase)
|
private void SaveTitleUpdatesForGame(ulong titleIdBase)
|
||||||
{
|
{
|
||||||
var updates = TitleUpdates.Items.Where(update => update.TitleUpdate.TitleIdBase == titleIdBase).ToList();
|
var updates = TitleUpdates.Items.Where(update => update.TitleUpdate.TitleIdBase == titleIdBase).ToList();
|
||||||
TitleUpdatesHelper.SaveTitleUpdatesJson(_virtualFileSystem, titleIdBase, updates);
|
TitleUpdatesHelper.SaveTitleUpdatesJson(titleIdBase, updates);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplicationData isnt live-updating (e.g. when an update gets applied) and so this is meant to trigger a refresh
|
// ApplicationData isnt live-updating (e.g. when an update gets applied) and so this is meant to trigger a refresh
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
using Ryujinx.Common.Configuration.Multiplayer;
|
using Ryujinx.Common.Configuration.Multiplayer;
|
||||||
@ -16,7 +17,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current version of the file format
|
/// The current version of the file format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int CurrentVersion = 56;
|
public const int CurrentVersion = 57;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version of the configuration file format
|
/// Version of the configuration file format
|
||||||
@ -191,8 +192,25 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables or disables Vertical Sync
|
/// Enables or disables Vertical Sync
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>Kept for file format compatibility (to avoid possible failure when parsing configuration on old versions)</remarks>
|
||||||
|
/// TODO: Remove this when those older versions aren't in use anymore.
|
||||||
public bool EnableVsync { get; set; }
|
public bool EnableVsync { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current VSync mode; 60 (Switch), unbounded ("Vsync off"), or custom
|
||||||
|
/// </summary>
|
||||||
|
public VSyncMode VSyncMode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables the custom present interval
|
||||||
|
/// </summary>
|
||||||
|
public bool EnableCustomVSyncInterval { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The custom present interval value
|
||||||
|
/// </summary>
|
||||||
|
public int CustomVSyncInterval { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables or disables Shader cache
|
/// Enables or disables Shader cache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -82,7 +82,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
|
|
||||||
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
{
|
{
|
||||||
ToggleVsync = Key.F1,
|
ToggleVSyncMode = Key.F1,
|
||||||
};
|
};
|
||||||
|
|
||||||
configurationFileUpdated = true;
|
configurationFileUpdated = true;
|
||||||
@ -276,7 +276,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
|
|
||||||
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
{
|
{
|
||||||
ToggleVsync = Key.F1,
|
ToggleVSyncMode = Key.F1,
|
||||||
Screenshot = Key.F8,
|
Screenshot = Key.F8,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -289,7 +289,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
|
|
||||||
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
{
|
{
|
||||||
ToggleVsync = Key.F1,
|
ToggleVSyncMode = Key.F1,
|
||||||
Screenshot = Key.F8,
|
Screenshot = Key.F8,
|
||||||
ShowUI = Key.F4,
|
ShowUI = Key.F4,
|
||||||
};
|
};
|
||||||
@ -332,7 +332,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
|
|
||||||
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
{
|
{
|
||||||
ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
|
ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode,
|
||||||
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
||||||
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
|
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
|
||||||
Pause = Key.F5,
|
Pause = Key.F5,
|
||||||
@ -347,7 +347,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
|
|
||||||
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
{
|
{
|
||||||
ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
|
ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode,
|
||||||
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
||||||
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
|
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
|
||||||
Pause = configurationFileFormat.Hotkeys.Pause,
|
Pause = configurationFileFormat.Hotkeys.Pause,
|
||||||
@ -421,7 +421,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
|
|
||||||
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
{
|
{
|
||||||
ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
|
ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode,
|
||||||
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
||||||
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
|
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
|
||||||
Pause = configurationFileFormat.Hotkeys.Pause,
|
Pause = configurationFileFormat.Hotkeys.Pause,
|
||||||
@ -448,7 +448,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
|
|
||||||
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
{
|
{
|
||||||
ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
|
ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode,
|
||||||
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
||||||
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
|
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
|
||||||
Pause = configurationFileFormat.Hotkeys.Pause,
|
Pause = configurationFileFormat.Hotkeys.Pause,
|
||||||
@ -611,6 +611,33 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
configurationFileUpdated = true;
|
configurationFileUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 57)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 57.");
|
||||||
|
|
||||||
|
configurationFileFormat.VSyncMode = VSyncMode.Switch;
|
||||||
|
configurationFileFormat.EnableCustomVSyncInterval = false;
|
||||||
|
|
||||||
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
|
{
|
||||||
|
ToggleVSyncMode = Key.F1,
|
||||||
|
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
||||||
|
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
|
||||||
|
Pause = configurationFileFormat.Hotkeys.Pause,
|
||||||
|
ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
|
||||||
|
ResScaleUp = configurationFileFormat.Hotkeys.ResScaleUp,
|
||||||
|
ResScaleDown = configurationFileFormat.Hotkeys.ResScaleDown,
|
||||||
|
VolumeUp = configurationFileFormat.Hotkeys.VolumeUp,
|
||||||
|
VolumeDown = configurationFileFormat.Hotkeys.VolumeDown,
|
||||||
|
CustomVSyncIntervalIncrement = Key.Unbound,
|
||||||
|
CustomVSyncIntervalDecrement = Key.Unbound,
|
||||||
|
};
|
||||||
|
|
||||||
|
configurationFileFormat.CustomVSyncInterval = 120;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
|
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
|
||||||
Graphics.ResScale.Value = configurationFileFormat.ResScale;
|
Graphics.ResScale.Value = configurationFileFormat.ResScale;
|
||||||
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
|
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
|
||||||
@ -646,7 +673,9 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
ShowTitleBar.Value = configurationFileFormat.ShowTitleBar;
|
ShowTitleBar.Value = configurationFileFormat.ShowTitleBar;
|
||||||
EnableHardwareAcceleration.Value = configurationFileFormat.EnableHardwareAcceleration;
|
EnableHardwareAcceleration.Value = configurationFileFormat.EnableHardwareAcceleration;
|
||||||
HideCursor.Value = configurationFileFormat.HideCursor;
|
HideCursor.Value = configurationFileFormat.HideCursor;
|
||||||
Graphics.EnableVsync.Value = configurationFileFormat.EnableVsync;
|
Graphics.VSyncMode.Value = configurationFileFormat.VSyncMode;
|
||||||
|
Graphics.EnableCustomVSyncInterval.Value = configurationFileFormat.EnableCustomVSyncInterval;
|
||||||
|
Graphics.CustomVSyncInterval.Value = configurationFileFormat.CustomVSyncInterval;
|
||||||
Graphics.EnableShaderCache.Value = configurationFileFormat.EnableShaderCache;
|
Graphics.EnableShaderCache.Value = configurationFileFormat.EnableShaderCache;
|
||||||
Graphics.EnableTextureRecompression.Value = configurationFileFormat.EnableTextureRecompression;
|
Graphics.EnableTextureRecompression.Value = configurationFileFormat.EnableTextureRecompression;
|
||||||
Graphics.EnableMacroHLE.Value = configurationFileFormat.EnableMacroHLE;
|
Graphics.EnableMacroHLE.Value = configurationFileFormat.EnableMacroHLE;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using ARMeilleure;
|
using ARMeilleure;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
@ -474,9 +474,19 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
public ReactiveObject<string> ShadersDumpPath { get; private set; }
|
public ReactiveObject<string> ShadersDumpPath { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables or disables Vertical Sync
|
/// Toggles the present interval mode. Options are Switch (60Hz), Unbounded (previously Vsync off), and Custom, if enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ReactiveObject<bool> EnableVsync { get; private set; }
|
public ReactiveObject<VSyncMode> VSyncMode { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables the custom present interval mode.
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableCustomVSyncInterval { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the custom present interval.
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<int> CustomVSyncInterval { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables or disables Shader cache
|
/// Enables or disables Shader cache
|
||||||
@ -536,8 +546,12 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
AspectRatio = new ReactiveObject<AspectRatio>();
|
AspectRatio = new ReactiveObject<AspectRatio>();
|
||||||
AspectRatio.LogChangesToValue(nameof(AspectRatio));
|
AspectRatio.LogChangesToValue(nameof(AspectRatio));
|
||||||
ShadersDumpPath = new ReactiveObject<string>();
|
ShadersDumpPath = new ReactiveObject<string>();
|
||||||
EnableVsync = new ReactiveObject<bool>();
|
VSyncMode = new ReactiveObject<VSyncMode>();
|
||||||
EnableVsync.LogChangesToValue(nameof(EnableVsync));
|
VSyncMode.LogChangesToValue(nameof(VSyncMode));
|
||||||
|
EnableCustomVSyncInterval = new ReactiveObject<bool>();
|
||||||
|
EnableCustomVSyncInterval.LogChangesToValue(nameof(EnableCustomVSyncInterval));
|
||||||
|
CustomVSyncInterval = new ReactiveObject<int>();
|
||||||
|
CustomVSyncInterval.LogChangesToValue(nameof(CustomVSyncInterval));
|
||||||
EnableShaderCache = new ReactiveObject<bool>();
|
EnableShaderCache = new ReactiveObject<bool>();
|
||||||
EnableShaderCache.LogChangesToValue(nameof(EnableShaderCache));
|
EnableShaderCache.LogChangesToValue(nameof(EnableShaderCache));
|
||||||
EnableTextureRecompression = new ReactiveObject<bool>();
|
EnableTextureRecompression = new ReactiveObject<bool>();
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
using ARMeilleure;
|
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
|
||||||
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||||
using Ryujinx.Common.Configuration.Multiplayer;
|
using Ryujinx.Common.Configuration.Multiplayer;
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Graphics.Vulkan;
|
using Ryujinx.Graphics.Vulkan;
|
||||||
using Ryujinx.HLE;
|
using Ryujinx.HLE;
|
||||||
using Ryujinx.UI.Common.Configuration.System;
|
using Ryujinx.UI.Common.Configuration.System;
|
||||||
using Ryujinx.UI.Common.Configuration.UI;
|
using Ryujinx.UI.Common.Configuration.UI;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.UI.Common.Configuration
|
namespace Ryujinx.UI.Common.Configuration
|
||||||
{
|
{
|
||||||
@ -21,10 +17,10 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
if (Instance != null)
|
if (Instance != null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Configuration is already initialized");
|
throw new InvalidOperationException("Configuration is already initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
Instance = new ConfigurationState();
|
Instance = new ConfigurationState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigurationFileFormat ToFileFormat()
|
public ConfigurationFileFormat ToFileFormat()
|
||||||
{
|
{
|
||||||
@ -64,7 +60,9 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
ShowTitleBar = ShowTitleBar,
|
ShowTitleBar = ShowTitleBar,
|
||||||
EnableHardwareAcceleration = EnableHardwareAcceleration,
|
EnableHardwareAcceleration = EnableHardwareAcceleration,
|
||||||
HideCursor = HideCursor,
|
HideCursor = HideCursor,
|
||||||
EnableVsync = Graphics.EnableVsync,
|
VSyncMode = Graphics.VSyncMode,
|
||||||
|
EnableCustomVSyncInterval = Graphics.EnableCustomVSyncInterval,
|
||||||
|
CustomVSyncInterval = Graphics.CustomVSyncInterval,
|
||||||
EnableShaderCache = Graphics.EnableShaderCache,
|
EnableShaderCache = Graphics.EnableShaderCache,
|
||||||
EnableTextureRecompression = Graphics.EnableTextureRecompression,
|
EnableTextureRecompression = Graphics.EnableTextureRecompression,
|
||||||
EnableMacroHLE = Graphics.EnableMacroHLE,
|
EnableMacroHLE = Graphics.EnableMacroHLE,
|
||||||
@ -179,7 +177,9 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
ShowTitleBar.Value = !OperatingSystem.IsWindows();
|
ShowTitleBar.Value = !OperatingSystem.IsWindows();
|
||||||
EnableHardwareAcceleration.Value = true;
|
EnableHardwareAcceleration.Value = true;
|
||||||
HideCursor.Value = HideCursorMode.OnIdle;
|
HideCursor.Value = HideCursorMode.OnIdle;
|
||||||
Graphics.EnableVsync.Value = true;
|
Graphics.VSyncMode.Value = VSyncMode.Switch;
|
||||||
|
Graphics.CustomVSyncInterval.Value = 120;
|
||||||
|
Graphics.EnableCustomVSyncInterval.Value = false;
|
||||||
Graphics.EnableShaderCache.Value = true;
|
Graphics.EnableShaderCache.Value = true;
|
||||||
Graphics.EnableTextureRecompression.Value = false;
|
Graphics.EnableTextureRecompression.Value = false;
|
||||||
Graphics.EnableMacroHLE.Value = true;
|
Graphics.EnableMacroHLE.Value = true;
|
||||||
@ -240,7 +240,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
Hid.EnableMouse.Value = false;
|
Hid.EnableMouse.Value = false;
|
||||||
Hid.Hotkeys.Value = new KeyboardHotkeys
|
Hid.Hotkeys.Value = new KeyboardHotkeys
|
||||||
{
|
{
|
||||||
ToggleVsync = Key.F1,
|
ToggleVSyncMode = Key.F1,
|
||||||
ToggleMute = Key.F2,
|
ToggleMute = Key.F2,
|
||||||
Screenshot = Key.F8,
|
Screenshot = Key.F8,
|
||||||
ShowUI = Key.F4,
|
ShowUI = Key.F4,
|
||||||
|
@ -247,6 +247,7 @@ namespace Ryujinx.UI.Common
|
|||||||
"0100dbf01000a000", // Burnout Paradise Remastered
|
"0100dbf01000a000", // Burnout Paradise Remastered
|
||||||
"0100744001588000", // Cars 3: Driven to Win
|
"0100744001588000", // Cars 3: Driven to Win
|
||||||
"0100b41013c82000", // Cruis'n Blast
|
"0100b41013c82000", // Cruis'n Blast
|
||||||
|
"01001b300b9be000", // Diablo III: Eternal Collection
|
||||||
"01008c8012920000", // Dying Light Platinum Edition
|
"01008c8012920000", // Dying Light Platinum Edition
|
||||||
"010073c01af34000", // LEGO Horizon Adventures
|
"010073c01af34000", // LEGO Horizon Adventures
|
||||||
"0100770008dd8000", // Monster Hunter Generations Ultimate
|
"0100770008dd8000", // Monster Hunter Generations Ultimate
|
||||||
|
@ -7,6 +7,24 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
{
|
{
|
||||||
public static partial class ConsoleHelper
|
public static partial class ConsoleHelper
|
||||||
{
|
{
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
|
[LibraryImport("kernel32")]
|
||||||
|
private static partial nint GetConsoleWindow();
|
||||||
|
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
|
[LibraryImport("user32")]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
private static partial bool ShowWindow(nint hWnd, int nCmdShow);
|
||||||
|
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
|
[LibraryImport("user32")]
|
||||||
|
private static partial nint GetForegroundWindow();
|
||||||
|
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
|
[LibraryImport("user32")]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
private static partial bool SetForegroundWindow(nint hWnd);
|
||||||
|
|
||||||
public static bool SetConsoleWindowStateSupported => OperatingSystem.IsWindows();
|
public static bool SetConsoleWindowStateSupported => OperatingSystem.IsWindows();
|
||||||
|
|
||||||
public static void SetConsoleWindowState(bool show)
|
public static void SetConsoleWindowState(bool show)
|
||||||
@ -35,16 +53,11 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetForegroundWindow(hWnd);
|
||||||
|
|
||||||
|
hWnd = GetForegroundWindow();
|
||||||
|
|
||||||
ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE);
|
ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
|
||||||
[LibraryImport("kernel32")]
|
|
||||||
private static partial nint GetConsoleWindow();
|
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
|
||||||
[LibraryImport("user32")]
|
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
|
||||||
private static partial bool ShowWindow(nint hWnd, int nCmdShow);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SaveDownloadableContentsJson(VirtualFileSystem vfs, ulong applicationIdBase, List<(DownloadableContentModel, bool IsEnabled)> dlcs)
|
public static void SaveDownloadableContentsJson(ulong applicationIdBase, List<(DownloadableContentModel, bool IsEnabled)> dlcs)
|
||||||
{
|
{
|
||||||
DownloadableContentContainer container = default;
|
DownloadableContentContainer container = default;
|
||||||
List<DownloadableContentContainer> downloadableContentContainerList = new();
|
List<DownloadableContentContainer> downloadableContentContainerList = new();
|
||||||
|
@ -28,7 +28,7 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
{
|
{
|
||||||
private static readonly TitleUpdateMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly TitleUpdateMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
public static List<(TitleUpdateModel, bool IsSelected)> LoadTitleUpdatesJson(VirtualFileSystem vfs, ulong applicationIdBase)
|
public static List<(TitleUpdateModel Update, bool IsSelected)> LoadTitleUpdatesJson(VirtualFileSystem vfs, ulong applicationIdBase)
|
||||||
{
|
{
|
||||||
var titleUpdatesJsonPath = PathToGameUpdatesJson(applicationIdBase);
|
var titleUpdatesJsonPath = PathToGameUpdatesJson(applicationIdBase);
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SaveTitleUpdatesJson(VirtualFileSystem vfs, ulong applicationIdBase, List<(TitleUpdateModel, bool IsSelected)> updates)
|
public static void SaveTitleUpdatesJson(ulong applicationIdBase, List<(TitleUpdateModel, bool IsSelected)> updates)
|
||||||
{
|
{
|
||||||
var titleUpdateWindowData = new TitleUpdateMetadata
|
var titleUpdateWindowData = new TitleUpdateMetadata
|
||||||
{
|
{
|
||||||
@ -77,7 +77,7 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
JsonHelper.SerializeToFile(titleUpdatesJsonPath, titleUpdateWindowData, _serializerContext.TitleUpdateMetadata);
|
JsonHelper.SerializeToFile(titleUpdatesJsonPath, titleUpdateWindowData, _serializerContext.TitleUpdateMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<(TitleUpdateModel, bool IsSelected)> LoadTitleUpdates(VirtualFileSystem vfs, TitleUpdateMetadata titleUpdateMetadata, ulong applicationIdBase)
|
private static List<(TitleUpdateModel Update, bool IsSelected)> LoadTitleUpdates(VirtualFileSystem vfs, TitleUpdateMetadata titleUpdateMetadata, ulong applicationIdBase)
|
||||||
{
|
{
|
||||||
var result = new List<(TitleUpdateModel, bool IsSelected)>();
|
var result = new List<(TitleUpdateModel, bool IsSelected)>();
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
<Application.Styles>
|
<Application.Styles>
|
||||||
<sty:FluentAvaloniaTheme PreferSystemTheme="False" />
|
<sty:FluentAvaloniaTheme PreferUserAccentColor="True" PreferSystemTheme="False" />
|
||||||
<StyleInclude Source="/Assets/Styles/Styles.xaml" />
|
<StyleInclude Source="/Assets/Styles/Styles.xaml" />
|
||||||
</Application.Styles>
|
</Application.Styles>
|
||||||
</Application>
|
</Application>
|
||||||
|
@ -3,6 +3,8 @@ using Avalonia.Controls;
|
|||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Ns;
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using Ryujinx.Audio.Backends.Dummy;
|
using Ryujinx.Audio.Backends.Dummy;
|
||||||
using Ryujinx.Audio.Backends.OpenAL;
|
using Ryujinx.Audio.Backends.OpenAL;
|
||||||
@ -57,6 +59,8 @@ using Key = Ryujinx.Input.Key;
|
|||||||
using MouseButton = Ryujinx.Input.MouseButton;
|
using MouseButton = Ryujinx.Input.MouseButton;
|
||||||
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
|
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
|
||||||
using Size = Avalonia.Size;
|
using Size = Avalonia.Size;
|
||||||
|
using Switch = Ryujinx.HLE.Switch;
|
||||||
|
using VSyncMode = Ryujinx.Common.Configuration.VSyncMode;
|
||||||
|
|
||||||
namespace Ryujinx.Ava
|
namespace Ryujinx.Ava
|
||||||
{
|
{
|
||||||
@ -203,6 +207,9 @@ namespace Ryujinx.Ava
|
|||||||
ConfigurationState.Instance.Graphics.ScalingFilter.Event += UpdateScalingFilter;
|
ConfigurationState.Instance.Graphics.ScalingFilter.Event += UpdateScalingFilter;
|
||||||
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event += UpdateScalingFilterLevel;
|
ConfigurationState.Instance.Graphics.ScalingFilterLevel.Event += UpdateScalingFilterLevel;
|
||||||
ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event += UpdateColorSpacePassthrough;
|
ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Event += UpdateColorSpacePassthrough;
|
||||||
|
ConfigurationState.Instance.Graphics.VSyncMode.Event += UpdateVSyncMode;
|
||||||
|
ConfigurationState.Instance.Graphics.CustomVSyncInterval.Event += UpdateCustomVSyncIntervalValue;
|
||||||
|
ConfigurationState.Instance.Graphics.EnableCustomVSyncInterval.Event += UpdateCustomVSyncIntervalEnabled;
|
||||||
|
|
||||||
ConfigurationState.Instance.System.EnableInternetAccess.Event += UpdateEnableInternetAccessState;
|
ConfigurationState.Instance.System.EnableInternetAccess.Event += UpdateEnableInternetAccessState;
|
||||||
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Event += UpdateLanInterfaceIdState;
|
ConfigurationState.Instance.Multiplayer.LanInterfaceId.Event += UpdateLanInterfaceIdState;
|
||||||
@ -295,6 +302,66 @@ namespace Ryujinx.Ava
|
|||||||
_renderer.Window?.SetColorSpacePassthrough((bool)ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value);
|
_renderer.Window?.SetColorSpacePassthrough((bool)ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateVSyncMode(object sender, ReactiveEventArgs<VSyncMode> e)
|
||||||
|
{
|
||||||
|
if (Device != null)
|
||||||
|
{
|
||||||
|
Device.VSyncMode = e.NewValue;
|
||||||
|
Device.UpdateVSyncInterval();
|
||||||
|
}
|
||||||
|
_renderer.Window?.ChangeVSyncMode((Ryujinx.Graphics.GAL.VSyncMode)e.NewValue);
|
||||||
|
|
||||||
|
_viewModel.ShowCustomVSyncIntervalPicker = (e.NewValue == VSyncMode.Custom);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void VSyncModeToggle()
|
||||||
|
{
|
||||||
|
VSyncMode oldVSyncMode = Device.VSyncMode;
|
||||||
|
VSyncMode newVSyncMode = VSyncMode.Switch;
|
||||||
|
bool customVSyncIntervalEnabled = ConfigurationState.Instance.Graphics.EnableCustomVSyncInterval.Value;
|
||||||
|
|
||||||
|
switch (oldVSyncMode)
|
||||||
|
{
|
||||||
|
case VSyncMode.Switch:
|
||||||
|
newVSyncMode = VSyncMode.Unbounded;
|
||||||
|
break;
|
||||||
|
case VSyncMode.Unbounded:
|
||||||
|
if (customVSyncIntervalEnabled)
|
||||||
|
{
|
||||||
|
newVSyncMode = VSyncMode.Custom;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newVSyncMode = VSyncMode.Switch;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case VSyncMode.Custom:
|
||||||
|
newVSyncMode = VSyncMode.Switch;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateVSyncMode(this, new ReactiveEventArgs<VSyncMode>(oldVSyncMode, newVSyncMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateCustomVSyncIntervalValue(object sender, ReactiveEventArgs<int> e)
|
||||||
|
{
|
||||||
|
if (Device != null)
|
||||||
|
{
|
||||||
|
Device.TargetVSyncInterval = e.NewValue;
|
||||||
|
Device.UpdateVSyncInterval();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateCustomVSyncIntervalEnabled(object sender, ReactiveEventArgs<bool> e)
|
||||||
|
{
|
||||||
|
if (Device != null)
|
||||||
|
{
|
||||||
|
Device.CustomVSyncIntervalEnabled = e.NewValue;
|
||||||
|
Device.UpdateVSyncInterval();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ShowCursor()
|
private void ShowCursor()
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
@ -505,12 +572,6 @@ namespace Ryujinx.Ava
|
|||||||
Device.Configuration.MultiplayerDisableP2p = e.NewValue;
|
Device.Configuration.MultiplayerDisableP2p = e.NewValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToggleVSync()
|
|
||||||
{
|
|
||||||
Device.EnableDeviceVsync = !Device.EnableDeviceVsync;
|
|
||||||
_renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
_isActive = false;
|
_isActive = false;
|
||||||
@ -611,7 +672,7 @@ namespace Ryujinx.Ava
|
|||||||
_cursorState = CursorStates.ForceChangeCursor;
|
_cursorState = CursorStates.ForceChangeCursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> LoadGuestApplication()
|
public async Task<bool> LoadGuestApplication(BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
||||||
{
|
{
|
||||||
InitializeSwitchInstance();
|
InitializeSwitchInstance();
|
||||||
MainWindow.UpdateGraphicsConfig();
|
MainWindow.UpdateGraphicsConfig();
|
||||||
@ -681,7 +742,7 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
Logger.Info?.Print(LogClass.Application, "Loading as Firmware Title (NCA).");
|
Logger.Info?.Print(LogClass.Application, "Loading as Firmware Title (NCA).");
|
||||||
|
|
||||||
if (!Device.LoadNca(ApplicationPath))
|
if (!Device.LoadNca(ApplicationPath, customNacpData))
|
||||||
{
|
{
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
@ -864,7 +925,7 @@ namespace Ryujinx.Ava
|
|||||||
_viewModel.UiHandler,
|
_viewModel.UiHandler,
|
||||||
(SystemLanguage)ConfigurationState.Instance.System.Language.Value,
|
(SystemLanguage)ConfigurationState.Instance.System.Language.Value,
|
||||||
(RegionCode)ConfigurationState.Instance.System.Region.Value,
|
(RegionCode)ConfigurationState.Instance.System.Region.Value,
|
||||||
ConfigurationState.Instance.Graphics.EnableVsync,
|
ConfigurationState.Instance.Graphics.VSyncMode,
|
||||||
ConfigurationState.Instance.System.EnableDockedMode,
|
ConfigurationState.Instance.System.EnableDockedMode,
|
||||||
ConfigurationState.Instance.System.EnablePtc,
|
ConfigurationState.Instance.System.EnablePtc,
|
||||||
ConfigurationState.Instance.System.EnableInternetAccess,
|
ConfigurationState.Instance.System.EnableInternetAccess,
|
||||||
@ -881,7 +942,8 @@ namespace Ryujinx.Ava
|
|||||||
ConfigurationState.Instance.Multiplayer.Mode,
|
ConfigurationState.Instance.Multiplayer.Mode,
|
||||||
ConfigurationState.Instance.Multiplayer.DisableP2p,
|
ConfigurationState.Instance.Multiplayer.DisableP2p,
|
||||||
ConfigurationState.Instance.Multiplayer.LdnPassphrase,
|
ConfigurationState.Instance.Multiplayer.LdnPassphrase,
|
||||||
ConfigurationState.Instance.Multiplayer.LdnServer));
|
ConfigurationState.Instance.Multiplayer.LdnServer,
|
||||||
|
ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IHardwareDeviceDriver InitializeAudio()
|
private static IHardwareDeviceDriver InitializeAudio()
|
||||||
@ -1002,7 +1064,7 @@ namespace Ryujinx.Ava
|
|||||||
Device.Gpu.SetGpuThread();
|
Device.Gpu.SetGpuThread();
|
||||||
Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);
|
Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);
|
||||||
|
|
||||||
_renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync);
|
_renderer.Window.ChangeVSyncMode((Ryujinx.Graphics.GAL.VSyncMode)Device.VSyncMode);
|
||||||
|
|
||||||
while (_isActive)
|
while (_isActive)
|
||||||
{
|
{
|
||||||
@ -1063,6 +1125,7 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
// Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued.
|
// Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued.
|
||||||
string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance[LocaleKeys.Docked] : LocaleManager.Instance[LocaleKeys.Handheld];
|
string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance[LocaleKeys.Docked] : LocaleManager.Instance[LocaleKeys.Handheld];
|
||||||
|
string vSyncMode = Device.VSyncMode.ToString();
|
||||||
|
|
||||||
UpdateShaderCount();
|
UpdateShaderCount();
|
||||||
|
|
||||||
@ -1072,11 +1135,11 @@ namespace Ryujinx.Ava
|
|||||||
}
|
}
|
||||||
|
|
||||||
StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
|
StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
|
||||||
Device.EnableDeviceVsync,
|
vSyncMode,
|
||||||
LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%",
|
LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%",
|
||||||
dockedMode,
|
dockedMode,
|
||||||
ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(),
|
ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(),
|
||||||
LocaleManager.Instance[LocaleKeys.Game] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
$"{Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
||||||
$"FIFO: {Device.Statistics.GetFifoPercent():00.00} %",
|
$"FIFO: {Device.Statistics.GetFifoPercent():00.00} %",
|
||||||
_displayCount));
|
_displayCount));
|
||||||
}
|
}
|
||||||
@ -1175,8 +1238,16 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
switch (currentHotkeyState)
|
switch (currentHotkeyState)
|
||||||
{
|
{
|
||||||
case KeyboardHotkeyState.ToggleVSync:
|
case KeyboardHotkeyState.ToggleVSyncMode:
|
||||||
ToggleVSync();
|
VSyncModeToggle();
|
||||||
|
break;
|
||||||
|
case KeyboardHotkeyState.CustomVSyncIntervalDecrement:
|
||||||
|
Device.DecrementCustomVSyncInterval();
|
||||||
|
_viewModel.CustomVSyncInterval -= 1;
|
||||||
|
break;
|
||||||
|
case KeyboardHotkeyState.CustomVSyncIntervalIncrement:
|
||||||
|
Device.IncrementCustomVSyncInterval();
|
||||||
|
_viewModel.CustomVSyncInterval += 1;
|
||||||
break;
|
break;
|
||||||
case KeyboardHotkeyState.Screenshot:
|
case KeyboardHotkeyState.Screenshot:
|
||||||
ScreenshotRequested = true;
|
ScreenshotRequested = true;
|
||||||
@ -1263,9 +1334,9 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
KeyboardHotkeyState state = KeyboardHotkeyState.None;
|
KeyboardHotkeyState state = KeyboardHotkeyState.None;
|
||||||
|
|
||||||
if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ToggleVsync))
|
if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ToggleVSyncMode))
|
||||||
{
|
{
|
||||||
state = KeyboardHotkeyState.ToggleVSync;
|
state = KeyboardHotkeyState.ToggleVSyncMode;
|
||||||
}
|
}
|
||||||
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot))
|
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot))
|
||||||
{
|
{
|
||||||
@ -1299,6 +1370,14 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
state = KeyboardHotkeyState.VolumeDown;
|
state = KeyboardHotkeyState.VolumeDown;
|
||||||
}
|
}
|
||||||
|
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CustomVSyncIntervalIncrement))
|
||||||
|
{
|
||||||
|
state = KeyboardHotkeyState.CustomVSyncIntervalIncrement;
|
||||||
|
}
|
||||||
|
else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.CustomVSyncIntervalDecrement))
|
||||||
|
{
|
||||||
|
state = KeyboardHotkeyState.CustomVSyncIntervalDecrement;
|
||||||
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"Language": "اَلْعَرَبِيَّةُ",
|
"Language": "اَلْعَرَبِيَّةُ",
|
||||||
"MenuBarFileOpenApplet": "فتح التطبيق المصغر",
|
"MenuBarFileOpenApplet": "فتح التطبيق المصغر",
|
||||||
|
"MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet",
|
||||||
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "افتح تطبيق تحرير Mii في الوضع المستقل",
|
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "افتح تطبيق تحرير Mii في الوضع المستقل",
|
||||||
"SettingsTabInputDirectMouseAccess": "الوصول المباشر للفأرة",
|
"SettingsTabInputDirectMouseAccess": "الوصول المباشر للفأرة",
|
||||||
"SettingsTabSystemMemoryManagerMode": "وضع إدارة الذاكرة:",
|
"SettingsTabSystemMemoryManagerMode": "وضع إدارة الذاكرة:",
|
||||||
@ -30,6 +31,9 @@
|
|||||||
"MenuBarToolsInstallFirmware": "تثبيت البرنامج الثابت",
|
"MenuBarToolsInstallFirmware": "تثبيت البرنامج الثابت",
|
||||||
"MenuBarFileToolsInstallFirmwareFromFile": "تثبيت برنامج ثابت من XCI أو ZIP",
|
"MenuBarFileToolsInstallFirmwareFromFile": "تثبيت برنامج ثابت من XCI أو ZIP",
|
||||||
"MenuBarFileToolsInstallFirmwareFromDirectory": "تثبيت برنامج ثابت من مجلد",
|
"MenuBarFileToolsInstallFirmwareFromDirectory": "تثبيت برنامج ثابت من مجلد",
|
||||||
|
"MenuBarToolsInstallKeys": "Install Keys",
|
||||||
|
"MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP",
|
||||||
|
"MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory",
|
||||||
"MenuBarToolsManageFileTypes": "إدارة أنواع الملفات",
|
"MenuBarToolsManageFileTypes": "إدارة أنواع الملفات",
|
||||||
"MenuBarToolsInstallFileTypes": "تثبيت أنواع الملفات",
|
"MenuBarToolsInstallFileTypes": "تثبيت أنواع الملفات",
|
||||||
"MenuBarToolsUninstallFileTypes": "إزالة أنواع الملفات",
|
"MenuBarToolsUninstallFileTypes": "إزالة أنواع الملفات",
|
||||||
@ -505,6 +509,13 @@
|
|||||||
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\nهل تريد المتابعة؟",
|
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\nهل تريد المتابعة؟",
|
||||||
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "تثبيت البرنامج الثابت...",
|
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "تثبيت البرنامج الثابت...",
|
||||||
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "تم تثبيت إصدار النظام {0} بنجاح.",
|
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "تم تثبيت إصدار النظام {0} بنجاح.",
|
||||||
|
"DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}",
|
||||||
|
"DialogKeysInstallerKeysInstallTitle": "Install Keys",
|
||||||
|
"DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.",
|
||||||
|
"DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.",
|
||||||
|
"DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?",
|
||||||
|
"DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...",
|
||||||
|
"DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.",
|
||||||
"DialogUserProfileDeletionWarningMessage": "لن تكون هناك ملفات الشخصية أخرى لفتحها إذا تم حذف الملف الشخصي المحدد",
|
"DialogUserProfileDeletionWarningMessage": "لن تكون هناك ملفات الشخصية أخرى لفتحها إذا تم حذف الملف الشخصي المحدد",
|
||||||
"DialogUserProfileDeletionConfirmMessage": "هل تريد حذف الملف الشخصي المحدد",
|
"DialogUserProfileDeletionConfirmMessage": "هل تريد حذف الملف الشخصي المحدد",
|
||||||
"DialogUserProfileUnsavedChangesTitle": "تحذير - التغييرات غير محفوظة",
|
"DialogUserProfileUnsavedChangesTitle": "تحذير - التغييرات غير محفوظة",
|
||||||
@ -691,6 +702,9 @@
|
|||||||
"Never": "مطلقا",
|
"Never": "مطلقا",
|
||||||
"SwkbdMinCharacters": "يجب أن يبلغ طوله {0} حرفا على الأقل",
|
"SwkbdMinCharacters": "يجب أن يبلغ طوله {0} حرفا على الأقل",
|
||||||
"SwkbdMinRangeCharacters": "يجب أن يتكون من {0}-{1} حرفا",
|
"SwkbdMinRangeCharacters": "يجب أن يتكون من {0}-{1} حرفا",
|
||||||
|
"CabinetTitle": "Cabinet Dialog",
|
||||||
|
"CabinetDialog": "Enter your Amiibo's new name",
|
||||||
|
"CabinetScanDialog": "Please scan your Amiibo now.",
|
||||||
"SoftwareKeyboard": "لوحة المفاتيح البرمجية",
|
"SoftwareKeyboard": "لوحة المفاتيح البرمجية",
|
||||||
"SoftwareKeyboardModeNumeric": "يجب أن يكون 0-9 أو '.' فقط",
|
"SoftwareKeyboardModeNumeric": "يجب أن يكون 0-9 أو '.' فقط",
|
||||||
"SoftwareKeyboardModeAlphabet": "يجب أن تكون الأحرف غير CJK فقط",
|
"SoftwareKeyboardModeAlphabet": "يجب أن تكون الأحرف غير CJK فقط",
|
||||||
@ -704,7 +718,6 @@
|
|||||||
"UpdaterAddingFiles": "إضافة ملفات جديدة...",
|
"UpdaterAddingFiles": "إضافة ملفات جديدة...",
|
||||||
"UpdaterExtracting": "استخراج التحديث...",
|
"UpdaterExtracting": "استخراج التحديث...",
|
||||||
"UpdaterDownloading": "تحميل التحديث...",
|
"UpdaterDownloading": "تحميل التحديث...",
|
||||||
"Game": "لعبة",
|
|
||||||
"Docked": "تركيب بالمنصة",
|
"Docked": "تركيب بالمنصة",
|
||||||
"Handheld": "محمول",
|
"Handheld": "محمول",
|
||||||
"ConnectionError": "خطأ في الاتصال",
|
"ConnectionError": "خطأ في الاتصال",
|
||||||
@ -775,7 +788,7 @@
|
|||||||
"CheatWindowHeading": "الغش متوفر لـ {0} [{1}]",
|
"CheatWindowHeading": "الغش متوفر لـ {0} [{1}]",
|
||||||
"BuildId": "معرف البناء:",
|
"BuildId": "معرف البناء:",
|
||||||
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"DlcWindowHeading": "المحتويات القابلة للتنزيل {0}",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"Language": "Deutsch",
|
"Language": "Deutsch",
|
||||||
"MenuBarFileOpenApplet": "Öffne Anwendung",
|
"MenuBarFileOpenApplet": "Öffne Anwendung",
|
||||||
|
"MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet",
|
||||||
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Öffnet das Mii-Editor-Applet im Standalone-Modus",
|
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Öffnet das Mii-Editor-Applet im Standalone-Modus",
|
||||||
"SettingsTabInputDirectMouseAccess": "Direkter Mauszugriff",
|
"SettingsTabInputDirectMouseAccess": "Direkter Mauszugriff",
|
||||||
"SettingsTabSystemMemoryManagerMode": "Speichermanagermodus:",
|
"SettingsTabSystemMemoryManagerMode": "Speichermanagermodus:",
|
||||||
@ -30,6 +31,9 @@
|
|||||||
"MenuBarToolsInstallFirmware": "Firmware installieren",
|
"MenuBarToolsInstallFirmware": "Firmware installieren",
|
||||||
"MenuBarFileToolsInstallFirmwareFromFile": "Firmware von einer XCI- oder einer ZIP-Datei installieren",
|
"MenuBarFileToolsInstallFirmwareFromFile": "Firmware von einer XCI- oder einer ZIP-Datei installieren",
|
||||||
"MenuBarFileToolsInstallFirmwareFromDirectory": "Firmware aus einem Verzeichnis installieren",
|
"MenuBarFileToolsInstallFirmwareFromDirectory": "Firmware aus einem Verzeichnis installieren",
|
||||||
|
"MenuBarToolsInstallKeys": "Install Keys",
|
||||||
|
"MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP",
|
||||||
|
"MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory",
|
||||||
"MenuBarToolsManageFileTypes": "Dateitypen verwalten",
|
"MenuBarToolsManageFileTypes": "Dateitypen verwalten",
|
||||||
"MenuBarToolsInstallFileTypes": "Dateitypen installieren",
|
"MenuBarToolsInstallFileTypes": "Dateitypen installieren",
|
||||||
"MenuBarToolsUninstallFileTypes": "Dateitypen deinstallieren",
|
"MenuBarToolsUninstallFileTypes": "Dateitypen deinstallieren",
|
||||||
@ -505,6 +509,13 @@
|
|||||||
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nMöchtest du fortfahren?",
|
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nMöchtest du fortfahren?",
|
||||||
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "Firmware wird installiert...",
|
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "Firmware wird installiert...",
|
||||||
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Systemversion {0} wurde erfolgreich installiert.",
|
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Systemversion {0} wurde erfolgreich installiert.",
|
||||||
|
"DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}",
|
||||||
|
"DialogKeysInstallerKeysInstallTitle": "Install Keys",
|
||||||
|
"DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.",
|
||||||
|
"DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.",
|
||||||
|
"DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?",
|
||||||
|
"DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...",
|
||||||
|
"DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.",
|
||||||
"DialogUserProfileDeletionWarningMessage": "Es können keine anderen Profile geöffnet werden, wenn das ausgewählte Profil gelöscht wird.",
|
"DialogUserProfileDeletionWarningMessage": "Es können keine anderen Profile geöffnet werden, wenn das ausgewählte Profil gelöscht wird.",
|
||||||
"DialogUserProfileDeletionConfirmMessage": "Möchtest du das ausgewählte Profil löschen?",
|
"DialogUserProfileDeletionConfirmMessage": "Möchtest du das ausgewählte Profil löschen?",
|
||||||
"DialogUserProfileUnsavedChangesTitle": "Warnung - Nicht gespeicherte Änderungen",
|
"DialogUserProfileUnsavedChangesTitle": "Warnung - Nicht gespeicherte Änderungen",
|
||||||
@ -691,6 +702,9 @@
|
|||||||
"Never": "Niemals",
|
"Never": "Niemals",
|
||||||
"SwkbdMinCharacters": "Muss mindestens {0} Zeichen lang sein",
|
"SwkbdMinCharacters": "Muss mindestens {0} Zeichen lang sein",
|
||||||
"SwkbdMinRangeCharacters": "Muss {0}-{1} Zeichen lang sein",
|
"SwkbdMinRangeCharacters": "Muss {0}-{1} Zeichen lang sein",
|
||||||
|
"CabinetTitle": "Cabinet Dialog",
|
||||||
|
"CabinetDialog": "Enter your Amiibo's new name",
|
||||||
|
"CabinetScanDialog": "Please scan your Amiibo now.",
|
||||||
"SoftwareKeyboard": "Software-Tastatur",
|
"SoftwareKeyboard": "Software-Tastatur",
|
||||||
"SoftwareKeyboardModeNumeric": "Darf nur 0-9 oder \".\" sein",
|
"SoftwareKeyboardModeNumeric": "Darf nur 0-9 oder \".\" sein",
|
||||||
"SoftwareKeyboardModeAlphabet": "Keine CJK-Zeichen",
|
"SoftwareKeyboardModeAlphabet": "Keine CJK-Zeichen",
|
||||||
@ -704,7 +718,6 @@
|
|||||||
"UpdaterAddingFiles": "Neue Dateien hinzufügen...",
|
"UpdaterAddingFiles": "Neue Dateien hinzufügen...",
|
||||||
"UpdaterExtracting": "Update extrahieren...",
|
"UpdaterExtracting": "Update extrahieren...",
|
||||||
"UpdaterDownloading": "Update herunterladen...",
|
"UpdaterDownloading": "Update herunterladen...",
|
||||||
"Game": "Spiel",
|
|
||||||
"Docked": "Docked",
|
"Docked": "Docked",
|
||||||
"Handheld": "Handheld",
|
"Handheld": "Handheld",
|
||||||
"ConnectionError": "Verbindungsfehler.",
|
"ConnectionError": "Verbindungsfehler.",
|
||||||
@ -775,7 +788,7 @@
|
|||||||
"CheatWindowHeading": "Cheats verfügbar für {0} [{1}]",
|
"CheatWindowHeading": "Cheats verfügbar für {0} [{1}]",
|
||||||
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"BuildId": "BuildId:",
|
"BuildId": "BuildId:",
|
||||||
"DlcWindowHeading": "DLC verfügbar für {0} [{1}]",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"Language": "Ελληνικά",
|
"Language": "Ελληνικά",
|
||||||
"MenuBarFileOpenApplet": "Άνοιγμα Applet",
|
"MenuBarFileOpenApplet": "Άνοιγμα Applet",
|
||||||
|
"MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet",
|
||||||
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Άνοιγμα του Mii Editor Applet σε Αυτόνομη λειτουργία",
|
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Άνοιγμα του Mii Editor Applet σε Αυτόνομη λειτουργία",
|
||||||
"SettingsTabInputDirectMouseAccess": "Άμεση Πρόσβαση Ποντικιού",
|
"SettingsTabInputDirectMouseAccess": "Άμεση Πρόσβαση Ποντικιού",
|
||||||
"SettingsTabSystemMemoryManagerMode": "Λειτουργία Διαχείρισης Μνήμης:",
|
"SettingsTabSystemMemoryManagerMode": "Λειτουργία Διαχείρισης Μνήμης:",
|
||||||
@ -30,6 +31,9 @@
|
|||||||
"MenuBarToolsInstallFirmware": "Εγκατάσταση Firmware",
|
"MenuBarToolsInstallFirmware": "Εγκατάσταση Firmware",
|
||||||
"MenuBarFileToolsInstallFirmwareFromFile": "Εγκατάσταση Firmware από XCI ή ZIP",
|
"MenuBarFileToolsInstallFirmwareFromFile": "Εγκατάσταση Firmware από XCI ή ZIP",
|
||||||
"MenuBarFileToolsInstallFirmwareFromDirectory": "Εγκατάσταση Firmware από τοποθεσία",
|
"MenuBarFileToolsInstallFirmwareFromDirectory": "Εγκατάσταση Firmware από τοποθεσία",
|
||||||
|
"MenuBarToolsInstallKeys": "Install Keys",
|
||||||
|
"MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP",
|
||||||
|
"MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory",
|
||||||
"MenuBarToolsManageFileTypes": "Διαχείριση τύπων αρχείων",
|
"MenuBarToolsManageFileTypes": "Διαχείριση τύπων αρχείων",
|
||||||
"MenuBarToolsInstallFileTypes": "Εγκαταστήσετε τύπους αρχείων.",
|
"MenuBarToolsInstallFileTypes": "Εγκαταστήσετε τύπους αρχείων.",
|
||||||
"MenuBarToolsUninstallFileTypes": "Απεγκαταστήσετε τύπους αρχείων",
|
"MenuBarToolsUninstallFileTypes": "Απεγκαταστήσετε τύπους αρχείων",
|
||||||
@ -505,6 +509,13 @@
|
|||||||
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nΘέλετε να συνεχίσετε;",
|
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nΘέλετε να συνεχίσετε;",
|
||||||
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "Εγκατάσταση Firmware...",
|
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "Εγκατάσταση Firmware...",
|
||||||
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Η έκδοση συστήματος {0} εγκαταστάθηκε με επιτυχία.",
|
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Η έκδοση συστήματος {0} εγκαταστάθηκε με επιτυχία.",
|
||||||
|
"DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}",
|
||||||
|
"DialogKeysInstallerKeysInstallTitle": "Install Keys",
|
||||||
|
"DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.",
|
||||||
|
"DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.",
|
||||||
|
"DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?",
|
||||||
|
"DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...",
|
||||||
|
"DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.",
|
||||||
"DialogUserProfileDeletionWarningMessage": "Δεν θα υπάρχουν άλλα προφίλ εάν διαγραφεί το επιλεγμένο",
|
"DialogUserProfileDeletionWarningMessage": "Δεν θα υπάρχουν άλλα προφίλ εάν διαγραφεί το επιλεγμένο",
|
||||||
"DialogUserProfileDeletionConfirmMessage": "Θέλετε να διαγράψετε το επιλεγμένο προφίλ",
|
"DialogUserProfileDeletionConfirmMessage": "Θέλετε να διαγράψετε το επιλεγμένο προφίλ",
|
||||||
"DialogUserProfileUnsavedChangesTitle": "Προσοχή - Μην Αποθηκευμένες Αλλαγές.",
|
"DialogUserProfileUnsavedChangesTitle": "Προσοχή - Μην Αποθηκευμένες Αλλαγές.",
|
||||||
@ -691,6 +702,9 @@
|
|||||||
"Never": "Ποτέ",
|
"Never": "Ποτέ",
|
||||||
"SwkbdMinCharacters": "Πρέπει να έχει μήκος τουλάχιστον {0} χαρακτήρες",
|
"SwkbdMinCharacters": "Πρέπει να έχει μήκος τουλάχιστον {0} χαρακτήρες",
|
||||||
"SwkbdMinRangeCharacters": "Πρέπει να έχει μήκος {0}-{1} χαρακτήρες",
|
"SwkbdMinRangeCharacters": "Πρέπει να έχει μήκος {0}-{1} χαρακτήρες",
|
||||||
|
"CabinetTitle": "Cabinet Dialog",
|
||||||
|
"CabinetDialog": "Enter your Amiibo's new name",
|
||||||
|
"CabinetScanDialog": "Please scan your Amiibo now.",
|
||||||
"SoftwareKeyboard": "Εικονικό Πληκτρολόγιο",
|
"SoftwareKeyboard": "Εικονικό Πληκτρολόγιο",
|
||||||
"SoftwareKeyboardModeNumeric": "Πρέπει να είναι 0-9 ή '.' μόνο",
|
"SoftwareKeyboardModeNumeric": "Πρέπει να είναι 0-9 ή '.' μόνο",
|
||||||
"SoftwareKeyboardModeAlphabet": "Πρέπει να μην είναι μόνο χαρακτήρες CJK",
|
"SoftwareKeyboardModeAlphabet": "Πρέπει να μην είναι μόνο χαρακτήρες CJK",
|
||||||
@ -704,7 +718,6 @@
|
|||||||
"UpdaterAddingFiles": "Προσθήκη Νέων Αρχείων...",
|
"UpdaterAddingFiles": "Προσθήκη Νέων Αρχείων...",
|
||||||
"UpdaterExtracting": "Εξαγωγή Ενημέρωσης...",
|
"UpdaterExtracting": "Εξαγωγή Ενημέρωσης...",
|
||||||
"UpdaterDownloading": "Λήψη Ενημέρωσης...",
|
"UpdaterDownloading": "Λήψη Ενημέρωσης...",
|
||||||
"Game": "Παιχνίδι",
|
|
||||||
"Docked": "Προσκολλημένο",
|
"Docked": "Προσκολλημένο",
|
||||||
"Handheld": "Χειροκίνητο",
|
"Handheld": "Χειροκίνητο",
|
||||||
"ConnectionError": "Σφάλμα Σύνδεσης.",
|
"ConnectionError": "Σφάλμα Σύνδεσης.",
|
||||||
@ -775,7 +788,7 @@
|
|||||||
"CheatWindowHeading": "Διαθέσιμα Cheats για {0} [{1}]",
|
"CheatWindowHeading": "Διαθέσιμα Cheats για {0} [{1}]",
|
||||||
"BuildId": "BuildId:",
|
"BuildId": "BuildId:",
|
||||||
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"Language": "English (US)",
|
"Language": "English (US)",
|
||||||
"MenuBarFileOpenApplet": "Open Applet",
|
"MenuBarFileOpenApplet": "Open Applet",
|
||||||
|
"MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet",
|
||||||
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Open Mii Editor Applet in Standalone mode",
|
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Open Mii Editor Applet in Standalone mode",
|
||||||
"SettingsTabInputDirectMouseAccess": "Direct Mouse Access",
|
"SettingsTabInputDirectMouseAccess": "Direct Mouse Access",
|
||||||
"SettingsTabSystemMemoryManagerMode": "Memory Manager Mode:",
|
"SettingsTabSystemMemoryManagerMode": "Memory Manager Mode:",
|
||||||
@ -30,6 +31,9 @@
|
|||||||
"MenuBarToolsInstallFirmware": "Install Firmware",
|
"MenuBarToolsInstallFirmware": "Install Firmware",
|
||||||
"MenuBarFileToolsInstallFirmwareFromFile": "Install a firmware from XCI or ZIP",
|
"MenuBarFileToolsInstallFirmwareFromFile": "Install a firmware from XCI or ZIP",
|
||||||
"MenuBarFileToolsInstallFirmwareFromDirectory": "Install a firmware from a directory",
|
"MenuBarFileToolsInstallFirmwareFromDirectory": "Install a firmware from a directory",
|
||||||
|
"MenuBarToolsInstallKeys": "Install Keys",
|
||||||
|
"MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP",
|
||||||
|
"MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory",
|
||||||
"MenuBarToolsManageFileTypes": "Manage file types",
|
"MenuBarToolsManageFileTypes": "Manage file types",
|
||||||
"MenuBarToolsInstallFileTypes": "Install file types",
|
"MenuBarToolsInstallFileTypes": "Install file types",
|
||||||
"MenuBarToolsUninstallFileTypes": "Uninstall file types",
|
"MenuBarToolsUninstallFileTypes": "Uninstall file types",
|
||||||
@ -142,9 +146,20 @@
|
|||||||
"SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Latin American Spanish",
|
"SettingsTabSystemSystemLanguageLatinAmericanSpanish": "Latin American Spanish",
|
||||||
"SettingsTabSystemSystemLanguageSimplifiedChinese": "Simplified Chinese",
|
"SettingsTabSystemSystemLanguageSimplifiedChinese": "Simplified Chinese",
|
||||||
"SettingsTabSystemSystemLanguageTraditionalChinese": "Traditional Chinese",
|
"SettingsTabSystemSystemLanguageTraditionalChinese": "Traditional Chinese",
|
||||||
"SettingsTabSystemSystemTimeZone": "System TimeZone:",
|
"SettingsTabSystemSystemTimeZone": "System Time Zone:",
|
||||||
"SettingsTabSystemSystemTime": "System Time:",
|
"SettingsTabSystemSystemTime": "System Time:",
|
||||||
"SettingsTabSystemEnableVsync": "VSync",
|
"SettingsTabSystemVSyncMode": "VSync:",
|
||||||
|
"SettingsTabSystemEnableCustomVSyncInterval": "Enable custom refresh rate (Experimental)",
|
||||||
|
"SettingsTabSystemVSyncModeSwitch": "Switch",
|
||||||
|
"SettingsTabSystemVSyncModeUnbounded": "Unbounded",
|
||||||
|
"SettingsTabSystemVSyncModeCustom": "Custom Refresh Rate",
|
||||||
|
"SettingsTabSystemVSyncModeTooltip": "Emulated Vertical Sync. 'Switch' emulates the Switch's refresh rate of 60Hz. 'Unbounded' is an unbounded refresh rate.",
|
||||||
|
"SettingsTabSystemVSyncModeTooltipCustom": "Emulated Vertical Sync. 'Switch' emulates the Switch's refresh rate of 60Hz. 'Unbounded' is an unbounded refresh rate. 'Custom' emulates the specified custom refresh rate.",
|
||||||
|
"SettingsTabSystemEnableCustomVSyncIntervalTooltip": "Allows the user to specify an emulated refresh rate. In some titles, this may speed up or slow down the rate of gameplay logic. In other titles, it may allow for capping FPS at some multiple of the refresh rate, or lead to unpredictable behavior. This is an experimental feature, with no guarantees for how gameplay will be affected. \n\nLeave OFF if unsure.",
|
||||||
|
"SettingsTabSystemCustomVSyncIntervalValueTooltip": "The custom refresh rate target value.",
|
||||||
|
"SettingsTabSystemCustomVSyncIntervalSliderTooltip": "The custom refresh rate, as a percentage of the normal Switch refresh rate.",
|
||||||
|
"SettingsTabSystemCustomVSyncIntervalPercentage": "Custom Refresh Rate %:",
|
||||||
|
"SettingsTabSystemCustomVSyncIntervalValue": "Custom Refresh Rate Value:",
|
||||||
"SettingsTabSystemEnablePptc": "PPTC (Profiled Persistent Translation Cache)",
|
"SettingsTabSystemEnablePptc": "PPTC (Profiled Persistent Translation Cache)",
|
||||||
"SettingsTabSystemEnableLowPowerPptc": "Low-power PPTC cache",
|
"SettingsTabSystemEnableLowPowerPptc": "Low-power PPTC cache",
|
||||||
"SettingsTabSystemEnableFsIntegrityChecks": "FS Integrity Checks",
|
"SettingsTabSystemEnableFsIntegrityChecks": "FS Integrity Checks",
|
||||||
@ -153,6 +168,7 @@
|
|||||||
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
|
"SettingsTabSystemAudioBackendOpenAL": "OpenAL",
|
||||||
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
|
"SettingsTabSystemAudioBackendSoundIO": "SoundIO",
|
||||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||||
|
"SettingsTabSystemCustomVSyncInterval": "Interval",
|
||||||
"SettingsTabSystemHacks": "Hacks",
|
"SettingsTabSystemHacks": "Hacks",
|
||||||
"SettingsTabSystemHacksNote": "May cause instability",
|
"SettingsTabSystemHacksNote": "May cause instability",
|
||||||
"SettingsTabSystemDramSize": "DRAM size:",
|
"SettingsTabSystemDramSize": "DRAM size:",
|
||||||
@ -505,6 +521,13 @@
|
|||||||
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nDo you want to continue?",
|
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\nDo you want to continue?",
|
||||||
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installing firmware...",
|
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "Installing firmware...",
|
||||||
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "System version {0} successfully installed.",
|
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "System version {0} successfully installed.",
|
||||||
|
"DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}",
|
||||||
|
"DialogKeysInstallerKeysInstallTitle": "Install Keys",
|
||||||
|
"DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.",
|
||||||
|
"DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.",
|
||||||
|
"DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?",
|
||||||
|
"DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...",
|
||||||
|
"DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.",
|
||||||
"DialogUserProfileDeletionWarningMessage": "There would be no other profiles to be opened if selected profile is deleted",
|
"DialogUserProfileDeletionWarningMessage": "There would be no other profiles to be opened if selected profile is deleted",
|
||||||
"DialogUserProfileDeletionConfirmMessage": "Do you want to delete the selected profile",
|
"DialogUserProfileDeletionConfirmMessage": "Do you want to delete the selected profile",
|
||||||
"DialogUserProfileUnsavedChangesTitle": "Warning - Unsaved Changes",
|
"DialogUserProfileUnsavedChangesTitle": "Warning - Unsaved Changes",
|
||||||
@ -691,6 +714,9 @@
|
|||||||
"Never": "Never",
|
"Never": "Never",
|
||||||
"SwkbdMinCharacters": "Must be at least {0} characters long",
|
"SwkbdMinCharacters": "Must be at least {0} characters long",
|
||||||
"SwkbdMinRangeCharacters": "Must be {0}-{1} characters long",
|
"SwkbdMinRangeCharacters": "Must be {0}-{1} characters long",
|
||||||
|
"CabinetTitle": "Cabinet Dialog",
|
||||||
|
"CabinetDialog": "Enter your Amiibo's new name",
|
||||||
|
"CabinetScanDialog": "Please scan your Amiibo now.",
|
||||||
"SoftwareKeyboard": "Software Keyboard",
|
"SoftwareKeyboard": "Software Keyboard",
|
||||||
"SoftwareKeyboardModeNumeric": "Must be 0-9 or '.' only",
|
"SoftwareKeyboardModeNumeric": "Must be 0-9 or '.' only",
|
||||||
"SoftwareKeyboardModeAlphabet": "Must be non CJK-characters only",
|
"SoftwareKeyboardModeAlphabet": "Must be non CJK-characters only",
|
||||||
@ -704,7 +730,6 @@
|
|||||||
"UpdaterAddingFiles": "Adding New Files...",
|
"UpdaterAddingFiles": "Adding New Files...",
|
||||||
"UpdaterExtracting": "Extracting Update...",
|
"UpdaterExtracting": "Extracting Update...",
|
||||||
"UpdaterDownloading": "Downloading Update...",
|
"UpdaterDownloading": "Downloading Update...",
|
||||||
"Game": "Game",
|
|
||||||
"Docked": "Docked",
|
"Docked": "Docked",
|
||||||
"Handheld": "Handheld",
|
"Handheld": "Handheld",
|
||||||
"ConnectionError": "Connection Error.",
|
"ConnectionError": "Connection Error.",
|
||||||
@ -720,11 +745,13 @@
|
|||||||
"RyujinxUpdater": "Ryujinx Updater",
|
"RyujinxUpdater": "Ryujinx Updater",
|
||||||
"SettingsTabHotkeys": "Keyboard Hotkeys",
|
"SettingsTabHotkeys": "Keyboard Hotkeys",
|
||||||
"SettingsTabHotkeysHotkeys": "Keyboard Hotkeys",
|
"SettingsTabHotkeysHotkeys": "Keyboard Hotkeys",
|
||||||
"SettingsTabHotkeysToggleVsyncHotkey": "Toggle VSync:",
|
"SettingsTabHotkeysToggleVSyncModeHotkey": "Toggle VSync mode:",
|
||||||
"SettingsTabHotkeysScreenshotHotkey": "Screenshot:",
|
"SettingsTabHotkeysScreenshotHotkey": "Screenshot:",
|
||||||
"SettingsTabHotkeysShowUiHotkey": "Show UI:",
|
"SettingsTabHotkeysShowUiHotkey": "Show UI:",
|
||||||
"SettingsTabHotkeysPauseHotkey": "Pause:",
|
"SettingsTabHotkeysPauseHotkey": "Pause:",
|
||||||
"SettingsTabHotkeysToggleMuteHotkey": "Mute:",
|
"SettingsTabHotkeysToggleMuteHotkey": "Mute:",
|
||||||
|
"SettingsTabHotkeysIncrementCustomVSyncIntervalHotkey": "Raise custom refresh rate",
|
||||||
|
"SettingsTabHotkeysDecrementCustomVSyncIntervalHotkey": "Lower custom refresh rate",
|
||||||
"ControllerMotionTitle": "Motion Control Settings",
|
"ControllerMotionTitle": "Motion Control Settings",
|
||||||
"ControllerRumbleTitle": "Rumble Settings",
|
"ControllerRumbleTitle": "Rumble Settings",
|
||||||
"SettingsSelectThemeFileDialogTitle": "Select Theme File",
|
"SettingsSelectThemeFileDialogTitle": "Select Theme File",
|
||||||
@ -775,7 +802,7 @@
|
|||||||
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
|
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
|
||||||
"BuildId": "BuildId:",
|
"BuildId": "BuildId:",
|
||||||
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user