Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
72634c80f4 | ||
|
bebd8eb822 | ||
|
f4b74e9ce1 | ||
|
4e19b36ad7 | ||
|
b16923a902 | ||
|
7e58b21f3d | ||
|
4fbc978e73 | ||
|
1a45dc8df8 |
18
.github/dependabot.yml
vendored
18
.github/dependabot.yml
vendored
@@ -13,7 +13,7 @@ updates:
|
||||
|
||||
- package-ecosystem: nuget
|
||||
directory: /
|
||||
open-pull-requests-limit: 5
|
||||
open-pull-requests-limit: 10
|
||||
schedule:
|
||||
interval: daily
|
||||
labels:
|
||||
@@ -22,3 +22,19 @@ updates:
|
||||
- marysaka
|
||||
commit-message:
|
||||
prefix: nuget
|
||||
groups:
|
||||
Avalonia:
|
||||
patterns:
|
||||
- "*Avalonia*"
|
||||
Silk.NET:
|
||||
patterns:
|
||||
- "Silk.NET*"
|
||||
OpenTK:
|
||||
patterns:
|
||||
- "OpenTK*"
|
||||
SixLabors:
|
||||
patterns:
|
||||
- "SixLabors*"
|
||||
NUnit:
|
||||
patterns:
|
||||
- "NUnit*"
|
||||
|
@@ -3,24 +3,25 @@
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia" Version="11.0.5" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.5" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.5" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.5" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.5" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.3" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.3" />
|
||||
<PackageVersion Include="Avalonia" Version="11.0.7" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.7" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.7" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.7" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.7" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.10" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.10" />
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="Concentus" Version="1.1.7" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageVersion Include="DynamicData" Version="7.14.2" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.4" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
|
||||
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.3.0-beta.4" />
|
||||
<PackageVersion Include="LibHac" Version="0.19.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.7.0" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.2.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
@@ -46,9 +47,8 @@
|
||||
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
||||
<PackageVersion Include="System.Drawing.Common" Version="8.0.0" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="7.0.3" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="8.0.0" />
|
||||
<PackageVersion Include="System.Management" Version="8.0.0" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
@@ -16,8 +16,10 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
private readonly Dictionary<LocaleKeys, string> _localeStrings;
|
||||
private Dictionary<LocaleKeys, string> _localeDefaultStrings;
|
||||
private readonly ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues;
|
||||
private string _localeLanguageCode;
|
||||
|
||||
public static LocaleManager Instance { get; } = new();
|
||||
public event Action LocaleChanged;
|
||||
|
||||
public LocaleManager()
|
||||
{
|
||||
@@ -104,6 +106,15 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRTL()
|
||||
{
|
||||
return _localeLanguageCode switch
|
||||
{
|
||||
"he_IL" => true,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
||||
public string UpdateAndGetDynamicValue(LocaleKeys key, params object[] values)
|
||||
{
|
||||
_dynamicValues[key] = values;
|
||||
@@ -124,6 +135,9 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
{
|
||||
this[item.Key] = item.Value;
|
||||
}
|
||||
|
||||
_localeLanguageCode = languageCode;
|
||||
LocaleChanged?.Invoke();
|
||||
}
|
||||
|
||||
private static Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode = DefaultLanguageCode)
|
||||
|
@@ -119,6 +119,7 @@
|
||||
<None Remove="Assets\Locales\en_US.json" />
|
||||
<None Remove="Assets\Locales\es_ES.json" />
|
||||
<None Remove="Assets\Locales\fr_FR.json" />
|
||||
<None Remove="Assets\Locales\he_IL.json" />
|
||||
<None Remove="Assets\Locales\de_DE.json" />
|
||||
<None Remove="Assets\Locales\it_IT.json" />
|
||||
<None Remove="Assets\Locales\ja_JP.json" />
|
||||
@@ -143,6 +144,7 @@
|
||||
<EmbeddedResource Include="Assets\Locales\en_US.json" />
|
||||
<EmbeddedResource Include="Assets\Locales\es_ES.json" />
|
||||
<EmbeddedResource Include="Assets\Locales\fr_FR.json" />
|
||||
<EmbeddedResource Include="Assets\Locales\he_IL.json" />
|
||||
<EmbeddedResource Include="Assets\Locales\de_DE.json" />
|
||||
<EmbeddedResource Include="Assets\Locales\it_IT.json" />
|
||||
<EmbeddedResource Include="Assets\Locales\ja_JP.json" />
|
||||
|
@@ -86,17 +86,17 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
FontWeight="Bold"
|
||||
Text="{Binding TitleName}"
|
||||
TextAlignment="Left"
|
||||
TextAlignment="Start"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding Developer}"
|
||||
TextAlignment="Left"
|
||||
TextAlignment="Start"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding Version}"
|
||||
TextAlignment="Left"
|
||||
TextAlignment="Start"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
@@ -110,12 +110,12 @@
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding TitleId}"
|
||||
TextAlignment="Left"
|
||||
TextAlignment="Start"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding FileExtension}"
|
||||
TextAlignment="Left"
|
||||
TextAlignment="Start"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
@@ -127,17 +127,17 @@
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding TimePlayedString}"
|
||||
TextAlignment="Right"
|
||||
TextAlignment="End"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding LastPlayedString, Converter={helpers:LocalizedNeverConverter}}"
|
||||
TextAlignment="Right"
|
||||
TextAlignment="End"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding FileSizeString}"
|
||||
TextAlignment="Right"
|
||||
TextAlignment="End"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
<ui:SymbolIcon
|
||||
|
@@ -1,11 +1,12 @@
|
||||
<UserControl
|
||||
<UserControl
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="800"
|
||||
d:DesignHeight="450"
|
||||
x:Class="Ryujinx.Ava.UI.Renderer.RendererHost"
|
||||
FlowDirection="LeftToRight"
|
||||
Focusable="True">
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
@@ -17,6 +17,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels
|
||||
@@ -188,17 +189,25 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
_httpClient.Dispose();
|
||||
}
|
||||
|
||||
private bool TryGetAmiiboJson(string json, out AmiiboJson amiiboJson)
|
||||
private static bool TryGetAmiiboJson(string json, out AmiiboJson amiiboJson)
|
||||
{
|
||||
if (string.IsNullOrEmpty(json))
|
||||
{
|
||||
amiiboJson = JsonHelper.Deserialize(DefaultJson, _serializerContext.AmiiboJson);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
amiiboJson = JsonHelper.Deserialize<AmiiboJson>(json, _serializerContext.AmiiboJson);
|
||||
amiiboJson = JsonHelper.Deserialize(json, _serializerContext.AmiiboJson);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
catch (JsonException exception)
|
||||
{
|
||||
amiiboJson = JsonHelper.Deserialize<AmiiboJson>(DefaultJson, _serializerContext.AmiiboJson);
|
||||
Logger.Error?.Print(LogClass.Application, $"Unable to deserialize amiibo data: {exception}");
|
||||
amiiboJson = JsonHelper.Deserialize(DefaultJson, _serializerContext.AmiiboJson);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -208,27 +217,41 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
bool localIsValid = false;
|
||||
bool remoteIsValid = false;
|
||||
AmiiboJson amiiboJson = JsonHelper.Deserialize<AmiiboJson>(DefaultJson, _serializerContext.AmiiboJson);
|
||||
AmiiboJson amiiboJson = new();
|
||||
|
||||
try
|
||||
{
|
||||
localIsValid = TryGetAmiiboJson(File.ReadAllText(_amiiboJsonPath), out amiiboJson);
|
||||
try
|
||||
{
|
||||
if (File.Exists(_amiiboJsonPath))
|
||||
{
|
||||
localIsValid = TryGetAmiiboJson(await File.ReadAllTextAsync(_amiiboJsonPath), out amiiboJson);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Unable to read data from '{_amiiboJsonPath}': {exception}");
|
||||
}
|
||||
|
||||
if (!localIsValid || await NeedsUpdate(amiiboJson.LastUpdated))
|
||||
{
|
||||
remoteIsValid = TryGetAmiiboJson(await DownloadAmiiboJson(), out amiiboJson);
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (!(localIsValid || remoteIsValid))
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Couldn't get valid amiibo data: {exception}");
|
||||
|
||||
// Neither local or remote files are valid JSON, close window.
|
||||
ShowInfoDialog();
|
||||
Close();
|
||||
}
|
||||
else if (!remoteIsValid)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Couldn't update amiibo data: {exception}");
|
||||
|
||||
// Only the local file is valid, the local one should be used
|
||||
// but the user should be warned.
|
||||
ShowInfoDialog();
|
||||
@@ -388,11 +411,18 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
private async Task<bool> NeedsUpdate(DateTime oldLastModified)
|
||||
{
|
||||
HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/"));
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
try
|
||||
{
|
||||
return response.Content.Headers.LastModified != oldLastModified;
|
||||
HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/"));
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
return response.Content.Headers.LastModified != oldLastModified;
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException exception)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Unable to check for amiibo data updates: {exception}");
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -400,21 +430,33 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
private async Task<string> DownloadAmiiboJson()
|
||||
{
|
||||
HttpResponseMessage response = await _httpClient.GetAsync("https://amiibo.ryujinx.org/");
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
try
|
||||
{
|
||||
string amiiboJsonString = await response.Content.ReadAsStringAsync();
|
||||
HttpResponseMessage response = await _httpClient.GetAsync("https://amiibo.ryujinx.org/");
|
||||
|
||||
using (FileStream amiiboJsonStream = File.Create(_amiiboJsonPath, 4096, FileOptions.WriteThrough))
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
amiiboJsonStream.Write(Encoding.UTF8.GetBytes(amiiboJsonString));
|
||||
string amiiboJsonString = await response.Content.ReadAsStringAsync();
|
||||
|
||||
try
|
||||
{
|
||||
using FileStream dlcJsonStream = File.Create(_amiiboJsonPath, 4096, FileOptions.WriteThrough);
|
||||
dlcJsonStream.Write(Encoding.UTF8.GetBytes(amiiboJsonString));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Couldn't write amiibo data to file '{_amiiboJsonPath}: {exception}'");
|
||||
}
|
||||
|
||||
return amiiboJsonString;
|
||||
}
|
||||
|
||||
return amiiboJsonString;
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data. Response status code: {response.StatusCode}");
|
||||
}
|
||||
catch (HttpRequestException exception)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to request amiibo data: {exception}");
|
||||
}
|
||||
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data. Response status code: {response.StatusCode}");
|
||||
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle],
|
||||
LocaleManager.Instance[LocaleKeys.DialogAmiiboApiFailFetchMessage],
|
||||
@@ -422,9 +464,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
"",
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
||||
|
||||
Close();
|
||||
|
||||
return DefaultJson;
|
||||
return null;
|
||||
}
|
||||
|
||||
private void Close()
|
||||
|
@@ -101,7 +101,7 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
SelectedIndex="0"
|
||||
ItemsSource="{Binding ProfilesList}"
|
||||
ItemsSource="{Binding ProfilesList}"
|
||||
Text="{Binding ProfileName, Mode=TwoWay}" />
|
||||
<Button
|
||||
Grid.Column="2"
|
||||
@@ -218,6 +218,7 @@
|
||||
<Grid
|
||||
Name="SettingButtons"
|
||||
MinHeight="450"
|
||||
FlowDirection="LeftToRight"
|
||||
IsVisible="{Binding ShowSettings}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
|
@@ -88,7 +88,7 @@
|
||||
IsVisible="{Binding !ShowLoadProgress}"
|
||||
PointerReleased="VsyncStatus_PointerReleased"
|
||||
Text="VSync"
|
||||
TextAlignment="Left" />
|
||||
TextAlignment="Start" />
|
||||
<Border
|
||||
Width="2"
|
||||
Height="12"
|
||||
@@ -105,7 +105,7 @@
|
||||
IsVisible="{Binding !ShowLoadProgress}"
|
||||
PointerReleased="DockedStatus_PointerReleased"
|
||||
Text="{Binding DockedStatusText}"
|
||||
TextAlignment="Left" />
|
||||
TextAlignment="Start" />
|
||||
<Border
|
||||
Width="2"
|
||||
Height="12"
|
||||
@@ -225,7 +225,7 @@
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding !ShowLoadProgress}"
|
||||
Text="{Binding GameStatusText}"
|
||||
TextAlignment="Left" />
|
||||
TextAlignment="Start" />
|
||||
<Border
|
||||
Width="2"
|
||||
Height="12"
|
||||
@@ -240,7 +240,7 @@
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding !ShowLoadProgress}"
|
||||
Text="{Binding FifoStatusText}"
|
||||
TextAlignment="Left" />
|
||||
TextAlignment="Start" />
|
||||
<Border
|
||||
Width="2"
|
||||
Height="12"
|
||||
@@ -255,7 +255,7 @@
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding !ShowLoadProgress}"
|
||||
Text="{Binding BackendText}"
|
||||
TextAlignment="Left" />
|
||||
TextAlignment="Start" />
|
||||
<Border
|
||||
Width="2"
|
||||
Height="12"
|
||||
@@ -270,7 +270,7 @@
|
||||
VerticalAlignment="Center"
|
||||
IsVisible="{Binding !ShowLoadProgress}"
|
||||
Text="{Binding GpuNameText}"
|
||||
TextAlignment="Left" />
|
||||
TextAlignment="Start" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Grid.Column="3"
|
||||
|
@@ -27,7 +27,7 @@
|
||||
Grid.Row="0"
|
||||
TextWrapping="Wrap"
|
||||
HorizontalAlignment="Left"
|
||||
TextAlignment="Left"
|
||||
TextAlignment="Start"
|
||||
Text="{locale:Locale ProfileImageSelectionNote}" />
|
||||
<StackPanel
|
||||
Grid.Row="2"
|
||||
@@ -59,4 +59,4 @@
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
@@ -49,7 +49,7 @@
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding UserId}"
|
||||
TextAlignment="Left"
|
||||
TextAlignment="Start"
|
||||
TextWrapping="Wrap" />
|
||||
<Button Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
@@ -79,4 +79,4 @@
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
@@ -238,7 +238,7 @@
|
||||
<TextBlock
|
||||
FontSize="10"
|
||||
Text="{locale:Locale AboutRyujinxContributorsButtonHeader}"
|
||||
TextAlignment="Right"
|
||||
TextAlignment="End"
|
||||
ToolTip.Tip="{locale:Locale AboutRyujinxMaintainersContentTooltipMessage}" />
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
@@ -72,4 +72,4 @@
|
||||
Click="CancelButton_Click" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</window:StyleableWindow>
|
||||
</window:StyleableWindow>
|
||||
|
@@ -158,7 +158,7 @@
|
||||
FontWeight="Bold"
|
||||
IsVisible="{Binding ShowLoadProgress}"
|
||||
Text="{Binding LoadHeading}"
|
||||
TextAlignment="Left"
|
||||
TextAlignment="Start"
|
||||
TextWrapping="Wrap"
|
||||
MaxWidth="500" />
|
||||
<Border
|
||||
@@ -192,7 +192,7 @@
|
||||
FontSize="18"
|
||||
IsVisible="{Binding ShowLoadProgress}"
|
||||
Text="{Binding CacheLoadStatus}"
|
||||
TextAlignment="Left"
|
||||
TextAlignment="Start"
|
||||
MaxWidth="500" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
@@ -202,4 +202,4 @@
|
||||
Grid.Row="2" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</window:StyleableWindow>
|
||||
</window:StyleableWindow>
|
||||
|
@@ -101,6 +101,9 @@
|
||||
<Style Selector="Grid#PlaceholderGrid">
|
||||
<Setter Property="Height" Value="40" />
|
||||
</Style>
|
||||
<Style Selector="ui|NavigationViewItem ui|SymbolIcon">
|
||||
<Setter Property="FlowDirection" Value="LeftToRight" />
|
||||
</Style>
|
||||
</ui:NavigationView.Styles>
|
||||
</ui:NavigationView>
|
||||
<ReversibleStackPanel
|
||||
|
@@ -1,7 +1,9 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Platform;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
@@ -22,6 +24,14 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
Icon = new WindowIcon(stream);
|
||||
stream.Position = 0;
|
||||
IconImage = new Bitmap(stream);
|
||||
|
||||
LocaleManager.Instance.LocaleChanged += LocaleChanged;
|
||||
LocaleChanged();
|
||||
}
|
||||
|
||||
private void LocaleChanged()
|
||||
{
|
||||
FlowDirection = LocaleManager.Instance.IsRTL() ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
|
@@ -130,4 +130,4 @@
|
||||
</StackPanel>
|
||||
</Panel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
|
@@ -1,62 +0,0 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
|
||||
namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
static class HvCodePatcher
|
||||
{
|
||||
private const uint XMask = 0x3f808000u;
|
||||
private const uint XValue = 0x8000000u;
|
||||
|
||||
private const uint ZrIndex = 31u;
|
||||
|
||||
public static void RewriteUnorderedExclusiveInstructions(Span<byte> code)
|
||||
{
|
||||
Span<uint> codeUint = MemoryMarshal.Cast<byte, uint>(code);
|
||||
Span<Vector128<uint>> codeVector = MemoryMarshal.Cast<byte, Vector128<uint>>(code);
|
||||
|
||||
Vector128<uint> mask = Vector128.Create(XMask);
|
||||
Vector128<uint> value = Vector128.Create(XValue);
|
||||
|
||||
for (int index = 0; index < codeVector.Length; index++)
|
||||
{
|
||||
Vector128<uint> v = codeVector[index];
|
||||
|
||||
if (Vector128.EqualsAny(Vector128.BitwiseAnd(v, mask), value))
|
||||
{
|
||||
int baseIndex = index * 4;
|
||||
|
||||
for (int instIndex = baseIndex; instIndex < baseIndex + 4; instIndex++)
|
||||
{
|
||||
ref uint inst = ref codeUint[instIndex];
|
||||
|
||||
if ((inst & XMask) != XValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isPair = (inst & (1u << 21)) != 0;
|
||||
bool isLoad = (inst & (1u << 22)) != 0;
|
||||
|
||||
uint rt2 = (inst >> 10) & 0x1fu;
|
||||
uint rs = (inst >> 16) & 0x1fu;
|
||||
|
||||
if (isLoad && rs != ZrIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isPair && rt2 != ZrIndex)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set the ordered flag.
|
||||
inst |= 1u << 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -724,18 +724,6 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
/// <inheritdoc/>
|
||||
public void Reprotect(ulong va, ulong size, MemoryPermission protection)
|
||||
{
|
||||
if (protection.HasFlag(MemoryPermission.Execute))
|
||||
{
|
||||
// Some applications use unordered exclusive memory access instructions
|
||||
// where it is not valid to do so, leading to memory re-ordering that
|
||||
// makes the code behave incorrectly on some CPUs.
|
||||
// To work around this, we force all such accesses to be ordered.
|
||||
|
||||
using WritableRegion writableRegion = GetWritableRegion(va, (int)size);
|
||||
|
||||
HvCodePatcher.RewriteUnorderedExclusiveInstructions(writableRegion.Memory.Span);
|
||||
}
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
@@ -103,6 +103,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// <param name="argument">Method call argument</param>
|
||||
public void DrawEnd(ThreedClass engine, int argument)
|
||||
{
|
||||
_drawState.DrawUsesEngineState = true;
|
||||
|
||||
DrawEnd(
|
||||
engine,
|
||||
_state.State.IndexBufferState.First,
|
||||
@@ -205,10 +207,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
}
|
||||
else
|
||||
{
|
||||
#pragma warning disable IDE0059 // Remove unnecessary value assignment
|
||||
var drawState = _state.State.VertexBufferDrawState;
|
||||
#pragma warning restore IDE0059
|
||||
|
||||
DrawImpl(engine, drawVertexCount, 1, 0, drawFirstVertex, firstInstance, indexed: false);
|
||||
}
|
||||
|
||||
@@ -379,6 +377,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
bool oldDrawIndexed = _drawState.DrawIndexed;
|
||||
|
||||
_drawState.DrawIndexed = true;
|
||||
_drawState.DrawUsesEngineState = false;
|
||||
engine.ForceStateDirty(IndexBufferCountMethodOffset * 4);
|
||||
|
||||
DrawEnd(engine, firstIndex, indexCount, 0, 0);
|
||||
@@ -424,6 +423,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
bool oldDrawIndexed = _drawState.DrawIndexed;
|
||||
|
||||
_drawState.DrawIndexed = false;
|
||||
_drawState.DrawUsesEngineState = false;
|
||||
engine.ForceStateDirty(VertexBufferFirstMethodOffset * 4);
|
||||
|
||||
DrawEnd(engine, 0, 0, firstVertex, vertexCount);
|
||||
@@ -544,6 +544,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_state.State.FirstInstance = (uint)firstInstance;
|
||||
|
||||
_drawState.DrawIndexed = indexed;
|
||||
_drawState.DrawUsesEngineState = true;
|
||||
_currentSpecState.SetHasConstantBufferDrawParameters(true);
|
||||
|
||||
engine.UpdateState();
|
||||
@@ -676,6 +677,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_drawState.DrawIndexed = indexed;
|
||||
_drawState.DrawIndirect = true;
|
||||
_drawState.DrawUsesEngineState = true;
|
||||
_currentSpecState.SetHasConstantBufferDrawParameters(true);
|
||||
|
||||
engine.UpdateState();
|
||||
|
@@ -38,6 +38,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
public bool DrawIndirect;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the draw is using the draw parameters on the 3D engine state, rather than inline parameters submitted with the draw command.
|
||||
/// </summary>
|
||||
public bool DrawUsesEngineState;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if any of the currently used vertex shaders reads the instance ID.
|
||||
/// </summary>
|
||||
@@ -48,11 +53,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
public bool IsAnyVbInstanced;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0.
|
||||
/// </summary>
|
||||
public bool HasConstantBufferDrawParameters;
|
||||
|
||||
/// <summary>
|
||||
/// Primitive topology for the next draw.
|
||||
/// </summary>
|
||||
|
@@ -47,7 +47,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
private uint _vbEnableMask;
|
||||
|
||||
private bool _prevDrawIndexed;
|
||||
private readonly bool _prevDrawIndirect;
|
||||
private bool _prevDrawIndirect;
|
||||
private bool _prevDrawUsesEngineState;
|
||||
private IndexType _prevIndexType;
|
||||
private uint _prevFirstVertex;
|
||||
private bool _prevTfEnable;
|
||||
@@ -236,7 +237,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
// method when doing indexed draws, so we need to make sure
|
||||
// to update the vertex buffers if we are doing a regular
|
||||
// draw after a indexed one and vice-versa.
|
||||
if (_drawState.DrawIndexed != _prevDrawIndexed)
|
||||
// Some draws also do not update the engine state, so it is possible for it
|
||||
// to not be dirty even if the vertex counts or other state changed. We need to force it to be dirty in this case.
|
||||
if (_drawState.DrawIndexed != _prevDrawIndexed || _drawState.DrawUsesEngineState != _prevDrawUsesEngineState)
|
||||
{
|
||||
_updateTracker.ForceDirty(VertexBufferStateIndex);
|
||||
|
||||
@@ -251,6 +254,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
}
|
||||
|
||||
_prevDrawIndexed = _drawState.DrawIndexed;
|
||||
_prevDrawUsesEngineState = _drawState.DrawUsesEngineState;
|
||||
}
|
||||
|
||||
// Some draw parameters are used to restrict the vertex buffer size,
|
||||
@@ -260,6 +264,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
if (_drawState.DrawIndirect != _prevDrawIndirect)
|
||||
{
|
||||
_updateTracker.ForceDirty(VertexBufferStateIndex);
|
||||
|
||||
_prevDrawIndirect = _drawState.DrawIndirect;
|
||||
}
|
||||
|
||||
// In some cases, the index type is also used to guess the
|
||||
|
@@ -520,7 +520,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
if (_gd.PipelineInternal.CurrentCommandBuffer.CommandBuffer.Handle == cbs.CommandBuffer.Handle)
|
||||
{
|
||||
SetData(rangeOffset, _pendingData.AsSpan(rangeOffset, rangeSize), cbs, _gd.PipelineInternal.EndRenderPass, false);
|
||||
SetData(rangeOffset, _pendingData.AsSpan(rangeOffset, rangeSize), cbs, _gd.PipelineInternal.EndRenderPassDelegate, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -30,6 +30,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public readonly PipelineCache PipelineCache;
|
||||
|
||||
public readonly AutoFlushCounter AutoFlush;
|
||||
public readonly Action EndRenderPassDelegate;
|
||||
|
||||
protected PipelineDynamicState DynamicState;
|
||||
private PipelineState _newState;
|
||||
@@ -92,6 +93,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Device = device;
|
||||
|
||||
AutoFlush = new AutoFlushCounter(gd);
|
||||
EndRenderPassDelegate = EndRenderPass;
|
||||
|
||||
var pipelineCacheCreateInfo = new PipelineCacheCreateInfo
|
||||
{
|
||||
|
@@ -784,7 +784,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data)
|
||||
{
|
||||
BufferManager.SetData(buffer, offset, data, _pipeline.CurrentCommandBuffer, _pipeline.EndRenderPass);
|
||||
BufferManager.SetData(buffer, offset, data, _pipeline.CurrentCommandBuffer, _pipeline.EndRenderPassDelegate);
|
||||
}
|
||||
|
||||
public void UpdateCounters()
|
||||
|
@@ -1,10 +1,12 @@
|
||||
using Microsoft.IdentityModel.JsonWebTokens;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc.AsyncContext;
|
||||
using System;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -37,11 +39,6 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
|
||||
|
||||
credentials.Key.KeyId = parameters.ToString();
|
||||
|
||||
var header = new JwtHeader(credentials)
|
||||
{
|
||||
{ "jku", "https://e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com/1.0.0/certificates" },
|
||||
};
|
||||
|
||||
byte[] rawUserId = new byte[0x10];
|
||||
RandomNumberGenerator.Fill(rawUserId);
|
||||
|
||||
@@ -51,23 +48,25 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
|
||||
byte[] deviceAccountId = new byte[0x10];
|
||||
RandomNumberGenerator.Fill(deviceId);
|
||||
|
||||
var payload = new JwtPayload
|
||||
var descriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
{ "sub", Convert.ToHexString(rawUserId).ToLower() },
|
||||
{ "aud", "ed9e2f05d286f7b8" },
|
||||
{ "di", Convert.ToHexString(deviceId).ToLower() },
|
||||
{ "sn", "XAW10000000000" },
|
||||
{ "bs:did", Convert.ToHexString(deviceAccountId).ToLower() },
|
||||
{ "iss", "https://e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com" },
|
||||
{ "typ", "id_token" },
|
||||
{ "iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds() },
|
||||
{ "jti", Guid.NewGuid().ToString() },
|
||||
{ "exp", (DateTimeOffset.UtcNow + TimeSpan.FromHours(3)).ToUnixTimeSeconds() },
|
||||
Subject = new GenericIdentity(Convert.ToHexString(rawUserId).ToLower()),
|
||||
SigningCredentials = credentials,
|
||||
Audience = "ed9e2f05d286f7b8",
|
||||
Issuer = "https://e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com",
|
||||
TokenType = "id_token",
|
||||
IssuedAt = DateTime.UtcNow,
|
||||
Expires = DateTime.UtcNow + TimeSpan.FromHours(3),
|
||||
Claims = new Dictionary<string, object>
|
||||
{
|
||||
{ "jku", "https://e0d67c509fb203858ebcb2fe3f88c2aa.baas.nintendo.com/1.0.0/certificates" },
|
||||
{ "di", Convert.ToHexString(deviceId).ToLower() },
|
||||
{ "sn", "XAW10000000000" },
|
||||
{ "bs:did", Convert.ToHexString(deviceAccountId).ToLower() }
|
||||
}
|
||||
};
|
||||
|
||||
JwtSecurityToken securityToken = new(header, payload);
|
||||
|
||||
return new JwtSecurityTokenHandler().WriteToken(securityToken);
|
||||
return new JsonWebTokenHandler().CreateToken(descriptor);
|
||||
}
|
||||
|
||||
public ResultCode CheckAvailability(ServiceCtx context)
|
||||
|
@@ -23,10 +23,10 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Concentus" />
|
||||
<PackageReference Include="LibHac" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" />
|
||||
<PackageReference Include="MsgPack.Cli" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" />
|
||||
<PackageReference Include="NetCoreServer" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
using Gdk;
|
||||
using Gtk;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
@@ -13,7 +14,9 @@ using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Window = Gtk.Window;
|
||||
|
||||
namespace Ryujinx.Ui.Windows
|
||||
{
|
||||
@@ -49,11 +52,11 @@ namespace Ryujinx.Ui.Windows
|
||||
|
||||
public AmiiboWindow() : base($"Ryujinx {Program.Version} - Amiibo")
|
||||
{
|
||||
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
|
||||
Icon = new Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
_httpClient = new HttpClient()
|
||||
_httpClient = new HttpClient
|
||||
{
|
||||
Timeout = TimeSpan.FromSeconds(30),
|
||||
};
|
||||
@@ -64,7 +67,7 @@ namespace Ryujinx.Ui.Windows
|
||||
_amiiboList = new List<AmiiboApi>();
|
||||
|
||||
_amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.Ui.Common/Resources/Logo_Amiibo.png");
|
||||
_amiiboImage.Pixbuf = new Gdk.Pixbuf(_amiiboLogoBytes);
|
||||
_amiiboImage.Pixbuf = new Pixbuf(_amiiboLogoBytes);
|
||||
|
||||
_scanButton.Sensitive = false;
|
||||
_randomUuidCheckBox.Sensitive = false;
|
||||
@@ -72,17 +75,25 @@ namespace Ryujinx.Ui.Windows
|
||||
_ = LoadContentAsync();
|
||||
}
|
||||
|
||||
private bool TryGetAmiiboJson(string json, out AmiiboJson amiiboJson)
|
||||
private static bool TryGetAmiiboJson(string json, out AmiiboJson amiiboJson)
|
||||
{
|
||||
if (string.IsNullOrEmpty(json))
|
||||
{
|
||||
amiiboJson = JsonHelper.Deserialize(DefaultJson, _serializerContext.AmiiboJson);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
amiiboJson = JsonHelper.Deserialize<AmiiboJson>(json, _serializerContext.AmiiboJson);
|
||||
amiiboJson = JsonHelper.Deserialize(json, _serializerContext.AmiiboJson);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
catch (JsonException exception)
|
||||
{
|
||||
amiiboJson = JsonHelper.Deserialize<AmiiboJson>(DefaultJson, _serializerContext.AmiiboJson);
|
||||
Logger.Error?.Print(LogClass.Application, $"Unable to deserialize amiibo data: {exception}");
|
||||
amiiboJson = JsonHelper.Deserialize(DefaultJson, _serializerContext.AmiiboJson);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -92,27 +103,41 @@ namespace Ryujinx.Ui.Windows
|
||||
{
|
||||
bool localIsValid = false;
|
||||
bool remoteIsValid = false;
|
||||
AmiiboJson amiiboJson = JsonHelper.Deserialize<AmiiboJson>(DefaultJson, _serializerContext.AmiiboJson);
|
||||
AmiiboJson amiiboJson = new();
|
||||
|
||||
try
|
||||
{
|
||||
localIsValid = TryGetAmiiboJson(File.ReadAllText(_amiiboJsonPath), out amiiboJson);
|
||||
try
|
||||
{
|
||||
if (File.Exists(_amiiboJsonPath))
|
||||
{
|
||||
localIsValid = TryGetAmiiboJson(await File.ReadAllTextAsync(_amiiboJsonPath), out amiiboJson);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Unable to read data from '{_amiiboJsonPath}': {exception}");
|
||||
}
|
||||
|
||||
if (!localIsValid || await NeedsUpdate(amiiboJson.LastUpdated))
|
||||
{
|
||||
remoteIsValid = TryGetAmiiboJson(await DownloadAmiiboJson(), out amiiboJson);
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (!(localIsValid || remoteIsValid))
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Couldn't get valid amiibo data: {exception}");
|
||||
|
||||
// Neither local or remote files are valid JSON, close window.
|
||||
ShowInfoDialog();
|
||||
Close();
|
||||
}
|
||||
else if (!remoteIsValid)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Couldn't update amiibo data: {exception}");
|
||||
|
||||
// Only the local file is valid, the local one should be used
|
||||
// but the user should be warned.
|
||||
ShowInfoDialog();
|
||||
@@ -196,11 +221,18 @@ namespace Ryujinx.Ui.Windows
|
||||
|
||||
private async Task<bool> NeedsUpdate(DateTime oldLastModified)
|
||||
{
|
||||
HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/"));
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
try
|
||||
{
|
||||
return response.Content.Headers.LastModified != oldLastModified;
|
||||
HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/"));
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
return response.Content.Headers.LastModified != oldLastModified;
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException exception)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Unable to check for amiibo data updates: {exception}");
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -208,29 +240,37 @@ namespace Ryujinx.Ui.Windows
|
||||
|
||||
private async Task<string> DownloadAmiiboJson()
|
||||
{
|
||||
HttpResponseMessage response = await _httpClient.GetAsync("https://amiibo.ryujinx.org/");
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
try
|
||||
{
|
||||
string amiiboJsonString = await response.Content.ReadAsStringAsync();
|
||||
HttpResponseMessage response = await _httpClient.GetAsync("https://amiibo.ryujinx.org/");
|
||||
|
||||
using (FileStream dlcJsonStream = File.Create(_amiiboJsonPath, 4096, FileOptions.WriteThrough))
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
dlcJsonStream.Write(Encoding.UTF8.GetBytes(amiiboJsonString));
|
||||
string amiiboJsonString = await response.Content.ReadAsStringAsync();
|
||||
|
||||
try
|
||||
{
|
||||
using FileStream dlcJsonStream = File.Create(_amiiboJsonPath, 4096, FileOptions.WriteThrough);
|
||||
dlcJsonStream.Write(Encoding.UTF8.GetBytes(amiiboJsonString));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Couldn't write amiibo data to file '{_amiiboJsonPath}: {exception}'");
|
||||
}
|
||||
|
||||
return amiiboJsonString;
|
||||
}
|
||||
|
||||
return amiiboJsonString;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data. Response status code: {response.StatusCode}");
|
||||
|
||||
GtkDialog.CreateInfoDialog($"Amiibo API", "An error occured while fetching information from the API.");
|
||||
|
||||
Close();
|
||||
}
|
||||
catch (HttpRequestException exception)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to request amiibo data: {exception}");
|
||||
}
|
||||
|
||||
return DefaultJson;
|
||||
GtkDialog.CreateInfoDialog("Amiibo API", "An error occured while fetching information from the API.");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task UpdateAmiiboPreview(string imageUrl)
|
||||
@@ -240,7 +280,7 @@ namespace Ryujinx.Ui.Windows
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
byte[] amiiboPreviewBytes = await response.Content.ReadAsByteArrayAsync();
|
||||
Gdk.Pixbuf amiiboPreview = new(amiiboPreviewBytes);
|
||||
Pixbuf amiiboPreview = new(amiiboPreviewBytes);
|
||||
|
||||
float ratio = Math.Min((float)_amiiboImage.AllocatedWidth / amiiboPreview.Width,
|
||||
(float)_amiiboImage.AllocatedHeight / amiiboPreview.Height);
|
||||
@@ -248,7 +288,7 @@ namespace Ryujinx.Ui.Windows
|
||||
int resizeHeight = (int)(amiiboPreview.Height * ratio);
|
||||
int resizeWidth = (int)(amiiboPreview.Width * ratio);
|
||||
|
||||
_amiiboImage.Pixbuf = amiiboPreview.ScaleSimple(resizeWidth, resizeHeight, Gdk.InterpType.Bilinear);
|
||||
_amiiboImage.Pixbuf = amiiboPreview.ScaleSimple(resizeWidth, resizeHeight, InterpType.Bilinear);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -258,7 +298,7 @@ namespace Ryujinx.Ui.Windows
|
||||
|
||||
private static void ShowInfoDialog()
|
||||
{
|
||||
GtkDialog.CreateInfoDialog($"Amiibo API", "Unable to connect to Amiibo API server. The service may be down or you may need to verify your internet connection is online.");
|
||||
GtkDialog.CreateInfoDialog("Amiibo API", "Unable to connect to Amiibo API server. The service may be down or you may need to verify your internet connection is online.");
|
||||
}
|
||||
|
||||
//
|
||||
@@ -314,7 +354,7 @@ namespace Ryujinx.Ui.Windows
|
||||
{
|
||||
AmiiboId = _amiiboCharsComboBox.ActiveId;
|
||||
|
||||
_amiiboImage.Pixbuf = new Gdk.Pixbuf(_amiiboLogoBytes);
|
||||
_amiiboImage.Pixbuf = new Pixbuf(_amiiboLogoBytes);
|
||||
|
||||
string imageUrl = _amiiboList.Find(amiibo => amiibo.Head + amiibo.Tail == _amiiboCharsComboBox.ActiveId).Image;
|
||||
|
||||
@@ -354,7 +394,7 @@ namespace Ryujinx.Ui.Windows
|
||||
|
||||
private void ShowAllCheckBox_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
_amiiboImage.Pixbuf = new Gdk.Pixbuf(_amiiboLogoBytes);
|
||||
_amiiboImage.Pixbuf = new Pixbuf(_amiiboLogoBytes);
|
||||
|
||||
_amiiboSeriesComboBox.Changed -= SeriesComboBox_Changed;
|
||||
_amiiboCharsComboBox.Changed -= CharacterComboBox_Changed;
|
||||
@@ -365,7 +405,7 @@ namespace Ryujinx.Ui.Windows
|
||||
_scanButton.Sensitive = false;
|
||||
_randomUuidCheckBox.Sensitive = false;
|
||||
|
||||
new Task(() => ParseAmiiboData()).Start();
|
||||
new Task(ParseAmiiboData).Start();
|
||||
}
|
||||
|
||||
private void ScanButton_Pressed(object sender, EventArgs args)
|
||||
|
Reference in New Issue
Block a user