Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f11d663df7 | ||
|
19a949d0bf | ||
|
feec5ef7b3 | ||
|
9864675a0b | ||
|
06bff0159c | ||
|
04ed8c1f83 | ||
|
ad8d5b9b56 |
42
.github/labeler.yml
vendored
42
.github/labeler.yml
vendored
@@ -1,33 +1,35 @@
|
||||
audio: 'src/Ryujinx.Audio*/**'
|
||||
audio:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'src/Ryujinx.Audio*/**'
|
||||
|
||||
cpu:
|
||||
- 'src/ARMeilleure/**'
|
||||
- 'src/Ryujinx.Cpu/**'
|
||||
- 'src/Ryujinx.Memory/**'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/ARMeilleure/**', 'src/Ryujinx.Cpu/**', 'src/Ryujinx.Memory/**']
|
||||
|
||||
gpu:
|
||||
- 'src/Ryujinx.Graphics.*/**'
|
||||
- 'src/Spv.Generator/**'
|
||||
- 'src/Ryujinx.ShaderTools/**'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx.Graphics.*/**', 'src/Spv.Generator/**', 'src/Ryujinx.ShaderTools/**']
|
||||
|
||||
'graphics-backend:opengl':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'src/Ryujinx.Graphics.OpenGL/**'
|
||||
|
||||
'graphics-backend:opengl': 'src/Ryujinx.Graphics.OpenGL/**'
|
||||
'graphics-backend:vulkan':
|
||||
- 'src/Ryujinx.Graphics.Vulkan/**'
|
||||
- 'src/Spv.Generator/**'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx.Graphics.Vulkan/**', 'src/Spv.Generator/**']
|
||||
|
||||
gui:
|
||||
- 'src/Ryujinx/**'
|
||||
- 'src/Ryujinx.Ui.Common/**'
|
||||
- 'src/Ryujinx.Ui.LocaleGenerator/**'
|
||||
- 'src/Ryujinx.Ava/**'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.Ui.Common/**', 'src/Ryujinx.Ui.LocaleGenerator/**', 'src/Ryujinx.Ava/**']
|
||||
|
||||
horizon:
|
||||
- 'src/Ryujinx.HLE/**'
|
||||
- 'src/Ryujinx.Horizon*/**'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx.HLE/**', 'src/Ryujinx.Horizon/**']
|
||||
|
||||
kernel: 'src/Ryujinx.HLE/HOS/Kernel/**'
|
||||
kernel:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: 'src/Ryujinx.HLE/HOS/Kernel/**'
|
||||
|
||||
infra:
|
||||
- '.github/**'
|
||||
- 'distribution/**'
|
||||
- 'Directory.Packages.props'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['.github/**', 'distribution/**', 'Directory.Packages.props']
|
||||
|
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@@ -79,21 +79,21 @@ jobs:
|
||||
if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest'
|
||||
|
||||
- name: Upload Ryujinx artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||
path: publish
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
- name: Upload Ryujinx.Headless.SDL2 artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||
path: publish_sdl2_headless
|
||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||
|
||||
- name: Upload Ryujinx.Ava artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||
path: publish_ava
|
||||
@@ -144,14 +144,14 @@ jobs:
|
||||
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
|
||||
|
||||
- name: Upload Ryujinx.Ava artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
||||
path: "publish_ava/*.tar.gz"
|
||||
if: github.event_name == 'pull_request'
|
||||
|
||||
- name: Upload Ryujinx.Headless.SDL2 artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
||||
path: "publish_headless/*.tar.gz"
|
||||
|
2
.github/workflows/checks.yml
vendored
2
.github/workflows/checks.yml
vendored
@@ -63,7 +63,7 @@ jobs:
|
||||
|
||||
- name: Upload report
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: dotnet-format
|
||||
path: ./*-report.json
|
||||
|
2
.github/workflows/nightly_pr_comment.yml
vendored
2
.github/workflows/nightly_pr_comment.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }}
|
||||
steps:
|
||||
- uses: actions/github-script@v7
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const {owner, repo} = context.repo;
|
||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Create tag
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
github.rest.git.createRef({
|
||||
|
@@ -10,14 +10,25 @@
|
||||
<string>Ryujinx</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>Ryujinx.icns</string>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>nca</string>
|
||||
<string>nro</string>
|
||||
<string>nso</string>
|
||||
<string>nsp</string>
|
||||
<string>xci</string>
|
||||
</array>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>nca</string>
|
||||
<string>nro</string>
|
||||
<string>nso</string>
|
||||
<string>nsp</string>
|
||||
<string>xci</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Nintendo Switch File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Default</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.ryujinx.Ryujinx</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
|
@@ -1088,10 +1088,11 @@ namespace Ryujinx.Ava
|
||||
case KeyboardHotkeyState.ToggleMute:
|
||||
if (Device.IsAudioMuted())
|
||||
{
|
||||
Device.SetVolume(ConfigurationState.Instance.System.AudioVolume);
|
||||
Device.SetVolume(_viewModel.VolumeBeforeMute);
|
||||
}
|
||||
else
|
||||
{
|
||||
_viewModel.VolumeBeforeMute = Device.GetVolume();
|
||||
Device.SetVolume(0);
|
||||
}
|
||||
|
||||
|
@@ -1,40 +0,0 @@
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Models
|
||||
{
|
||||
public class CheatModel : BaseModel
|
||||
{
|
||||
private bool _isEnabled;
|
||||
|
||||
public event EventHandler<bool> EnableToggled;
|
||||
|
||||
public CheatModel(string name, string buildId, bool isEnabled)
|
||||
{
|
||||
Name = name;
|
||||
BuildId = buildId;
|
||||
IsEnabled = isEnabled;
|
||||
}
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get => _isEnabled;
|
||||
set
|
||||
{
|
||||
_isEnabled = value;
|
||||
|
||||
EnableToggled?.Invoke(this, _isEnabled);
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string BuildId { get; }
|
||||
|
||||
public string BuildIdKey => $"{BuildId}-{Name}";
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public string CleanName => Name[1..^7];
|
||||
}
|
||||
}
|
57
src/Ryujinx.Ava/UI/Models/CheatNode.cs
Normal file
57
src/Ryujinx.Ava/UI/Models/CheatNode.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Models
|
||||
{
|
||||
public class CheatNode : BaseModel
|
||||
{
|
||||
private bool _isEnabled = false;
|
||||
public ObservableCollection<CheatNode> SubNodes { get; } = new();
|
||||
public string CleanName => Name[1..^7];
|
||||
public string BuildIdKey => $"{BuildId}-{Name}";
|
||||
public bool IsRootNode { get; }
|
||||
public string Name { get; }
|
||||
public string BuildId { get; }
|
||||
public string Path { get; }
|
||||
public bool IsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SubNodes.Count > 0)
|
||||
{
|
||||
return SubNodes.ToList().TrueForAll(x => x.IsEnabled);
|
||||
}
|
||||
|
||||
return _isEnabled;
|
||||
}
|
||||
set
|
||||
{
|
||||
foreach (var cheat in SubNodes)
|
||||
{
|
||||
cheat.IsEnabled = value;
|
||||
cheat.OnPropertyChanged();
|
||||
}
|
||||
|
||||
_isEnabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
public CheatNode(string name, string buildId, string path, bool isRootNode, bool isEnabled = false)
|
||||
{
|
||||
Name = name;
|
||||
BuildId = buildId;
|
||||
Path = path;
|
||||
IsEnabled = isEnabled;
|
||||
IsRootNode = isRootNode;
|
||||
|
||||
SubNodes.CollectionChanged += CheatsList_CollectionChanged;
|
||||
}
|
||||
|
||||
private void CheatsList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(nameof(IsEnabled));
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,51 +0,0 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Models
|
||||
{
|
||||
public class CheatsList : ObservableCollection<CheatModel>
|
||||
{
|
||||
public CheatsList(string buildId, string path)
|
||||
{
|
||||
BuildId = buildId;
|
||||
Path = path;
|
||||
|
||||
CollectionChanged += CheatsList_CollectionChanged;
|
||||
}
|
||||
|
||||
public string BuildId { get; }
|
||||
public string Path { get; }
|
||||
|
||||
public bool IsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.ToList().TrueForAll(x => x.IsEnabled);
|
||||
}
|
||||
set
|
||||
{
|
||||
foreach (var cheat in this)
|
||||
{
|
||||
cheat.IsEnabled = value;
|
||||
}
|
||||
|
||||
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsEnabled)));
|
||||
}
|
||||
}
|
||||
|
||||
private void CheatsList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.Action == NotifyCollectionChangedAction.Add)
|
||||
{
|
||||
(e.NewItems[0] as CheatModel).EnableToggled += Item_EnableToggled;
|
||||
}
|
||||
}
|
||||
|
||||
private void Item_EnableToggled(object sender, bool e)
|
||||
{
|
||||
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsEnabled)));
|
||||
}
|
||||
}
|
||||
}
|
@@ -188,35 +188,61 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
_httpClient.Dispose();
|
||||
}
|
||||
|
||||
private async Task LoadContentAsync()
|
||||
private bool TryGetAmiiboJson(string json, out AmiiboJson amiiboJson)
|
||||
{
|
||||
string amiiboJsonString = DefaultJson;
|
||||
|
||||
if (File.Exists(_amiiboJsonPath))
|
||||
try
|
||||
{
|
||||
amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath);
|
||||
amiiboJson = JsonHelper.Deserialize<AmiiboJson>(json, _serializerContext.AmiiboJson);
|
||||
|
||||
if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).LastUpdated))
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
amiiboJson = JsonHelper.Deserialize<AmiiboJson>(DefaultJson, _serializerContext.AmiiboJson);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<AmiiboJson> GetMostRecentAmiiboListOrDefaultJson()
|
||||
{
|
||||
bool localIsValid = false;
|
||||
bool remoteIsValid = false;
|
||||
AmiiboJson amiiboJson = JsonHelper.Deserialize<AmiiboJson>(DefaultJson, _serializerContext.AmiiboJson);
|
||||
|
||||
try
|
||||
{
|
||||
localIsValid = TryGetAmiiboJson(File.ReadAllText(_amiiboJsonPath), out amiiboJson);
|
||||
|
||||
if (!localIsValid || await NeedsUpdate(amiiboJson.LastUpdated))
|
||||
{
|
||||
amiiboJsonString = await DownloadAmiiboJson();
|
||||
remoteIsValid = TryGetAmiiboJson(await DownloadAmiiboJson(), out amiiboJson);
|
||||
}
|
||||
}
|
||||
else
|
||||
catch
|
||||
{
|
||||
try
|
||||
if (!(localIsValid || remoteIsValid))
|
||||
{
|
||||
amiiboJsonString = await DownloadAmiiboJson();
|
||||
// Neither local or remote files are valid JSON, close window.
|
||||
ShowInfoDialog();
|
||||
Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
else if (!remoteIsValid)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data: {ex}");
|
||||
|
||||
// Only the local file is valid, the local one should be used
|
||||
// but the user should be warned.
|
||||
ShowInfoDialog();
|
||||
}
|
||||
}
|
||||
|
||||
_amiiboList = JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).Amiibo;
|
||||
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
||||
return amiiboJson;
|
||||
}
|
||||
|
||||
private async Task LoadContentAsync()
|
||||
{
|
||||
AmiiboJson amiiboJson = await GetMostRecentAmiiboListOrDefaultJson();
|
||||
|
||||
_amiiboList = amiiboJson.Amiibo.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
||||
|
||||
ParseAmiiboData();
|
||||
}
|
||||
@@ -362,26 +388,14 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
private async Task<bool> NeedsUpdate(DateTime oldLastModified)
|
||||
{
|
||||
try
|
||||
HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/"));
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
HttpResponseMessage response =
|
||||
await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/"));
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
return response.Content.Headers.LastModified != new DateTimeOffset(oldLastModified.Ticks - (oldLastModified.Ticks % TimeSpan.TicksPerSecond), TimeSpan.Zero);
|
||||
}
|
||||
|
||||
return false;
|
||||
return response.Content.Headers.LastModified != oldLastModified;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to check for amiibo updates: {ex}");
|
||||
|
||||
ShowInfoDialog();
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<string> DownloadAmiiboJson()
|
||||
|
@@ -90,6 +90,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
private string _pauseKey = "F5";
|
||||
private string _screenshotKey = "F8";
|
||||
private float _volume;
|
||||
private float _volumeBeforeMute;
|
||||
private string _backendText;
|
||||
|
||||
private bool _canUpdate = true;
|
||||
@@ -554,6 +555,17 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public float VolumeBeforeMute
|
||||
{
|
||||
get => _volumeBeforeMute;
|
||||
set
|
||||
{
|
||||
_volumeBeforeMute = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowStatusSeparator
|
||||
{
|
||||
get => _showStatusSeparator;
|
||||
|
@@ -86,28 +86,16 @@
|
||||
</Style>
|
||||
</Styles>
|
||||
</TreeView.Styles>
|
||||
<TreeView.DataTemplates>
|
||||
<TreeDataTemplate DataType="model:CheatsList" ItemsSource="{Binding}">
|
||||
<TreeView.ItemTemplate>
|
||||
<TreeDataTemplate ItemsSource="{Binding SubNodes}">
|
||||
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
|
||||
<CheckBox MinWidth="20" IsChecked="{Binding IsEnabled}" />
|
||||
<TextBlock Width="150" Text="{Binding BuildId}" />
|
||||
<TextBlock Text="{Binding Path}" />
|
||||
<TextBlock Width="150" Text="{Binding CleanName}" IsVisible="{Binding !IsRootNode}" />
|
||||
<TextBlock Width="150" Text="{Binding BuildId}" IsVisible="{Binding IsRootNode}" />
|
||||
<TextBlock Text="{Binding Path}" IsVisible="{Binding IsRootNode}" />
|
||||
</StackPanel>
|
||||
</TreeDataTemplate>
|
||||
<DataTemplate x:DataType="model:CheatModel">
|
||||
<StackPanel
|
||||
Margin="0"
|
||||
HorizontalAlignment="Left"
|
||||
Orientation="Horizontal">
|
||||
<CheckBox
|
||||
MinWidth="20"
|
||||
Margin="5,0"
|
||||
Padding="0"
|
||||
IsChecked="{Binding IsEnabled}" />
|
||||
<TextBlock VerticalAlignment="Center" Text="{Binding CleanName}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</TreeView.DataTemplates>
|
||||
</TreeView.ItemTemplate>
|
||||
</TreeView>
|
||||
</Border>
|
||||
<DockPanel
|
||||
|
@@ -17,7 +17,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
private readonly string _enabledCheatsPath;
|
||||
public bool NoCheatsFound { get; }
|
||||
|
||||
public AvaloniaList<CheatsList> LoadedCheats { get; }
|
||||
public AvaloniaList<CheatNode> LoadedCheats { get; }
|
||||
|
||||
public string Heading { get; }
|
||||
public string BuildId { get; }
|
||||
@@ -33,7 +33,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
public CheatWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName, string titlePath)
|
||||
{
|
||||
LoadedCheats = new AvaloniaList<CheatsList>();
|
||||
LoadedCheats = new AvaloniaList<CheatNode>();
|
||||
|
||||
Heading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.CheatWindowHeading, titleName, titleId.ToUpper());
|
||||
BuildId = ApplicationData.GetApplicationBuildId(virtualFileSystem, titlePath);
|
||||
@@ -62,7 +62,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
string currentCheatFile = string.Empty;
|
||||
string buildId = string.Empty;
|
||||
|
||||
CheatsList currentGroup = null;
|
||||
CheatNode currentGroup = null;
|
||||
|
||||
foreach (var cheat in mods.Cheats)
|
||||
{
|
||||
@@ -72,13 +72,13 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
string parentPath = currentCheatFile.Replace(titleModsPath, "");
|
||||
|
||||
buildId = Path.GetFileNameWithoutExtension(currentCheatFile).ToUpper();
|
||||
currentGroup = new CheatsList(buildId, parentPath);
|
||||
currentGroup = new CheatNode("", buildId, parentPath, true);
|
||||
|
||||
LoadedCheats.Add(currentGroup);
|
||||
}
|
||||
|
||||
var model = new CheatModel(cheat.Name, buildId, enabled.Contains($"{buildId}-{cheat.Name}"));
|
||||
currentGroup?.Add(model);
|
||||
var model = new CheatNode(cheat.Name, buildId, "", false, enabled.Contains($"{buildId}-{cheat.Name}"));
|
||||
currentGroup?.SubNodes.Add(model);
|
||||
|
||||
cheatAdded++;
|
||||
}
|
||||
@@ -104,7 +104,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
foreach (var cheats in LoadedCheats)
|
||||
{
|
||||
foreach (var cheat in cheats)
|
||||
foreach (var cheat in cheats.SubNodes)
|
||||
{
|
||||
if (cheat.IsEnabled)
|
||||
{
|
||||
|
@@ -436,10 +436,11 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
if (!volumeSplitButton.IsChecked)
|
||||
{
|
||||
ViewModel.AppHost.Device.SetVolume(ConfigurationState.Instance.System.AudioVolume);
|
||||
ViewModel.AppHost.Device.SetVolume(ViewModel.VolumeBeforeMute);
|
||||
}
|
||||
else
|
||||
{
|
||||
ViewModel.VolumeBeforeMute = ViewModel.AppHost.Device.GetVolume();
|
||||
ViewModel.AppHost.Device.SetVolume(0);
|
||||
}
|
||||
|
||||
|
@@ -72,37 +72,61 @@ namespace Ryujinx.Ui.Windows
|
||||
_ = LoadContentAsync();
|
||||
}
|
||||
|
||||
private async Task LoadContentAsync()
|
||||
private bool TryGetAmiiboJson(string json, out AmiiboJson amiiboJson)
|
||||
{
|
||||
string amiiboJsonString = DefaultJson;
|
||||
|
||||
if (File.Exists(_amiiboJsonPath))
|
||||
try
|
||||
{
|
||||
amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath);
|
||||
amiiboJson = JsonHelper.Deserialize<AmiiboJson>(json, _serializerContext.AmiiboJson);
|
||||
|
||||
if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).LastUpdated))
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
amiiboJson = JsonHelper.Deserialize<AmiiboJson>(DefaultJson, _serializerContext.AmiiboJson);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<AmiiboJson> GetMostRecentAmiiboListOrDefaultJson()
|
||||
{
|
||||
bool localIsValid = false;
|
||||
bool remoteIsValid = false;
|
||||
AmiiboJson amiiboJson = JsonHelper.Deserialize<AmiiboJson>(DefaultJson, _serializerContext.AmiiboJson);
|
||||
|
||||
try
|
||||
{
|
||||
localIsValid = TryGetAmiiboJson(File.ReadAllText(_amiiboJsonPath), out amiiboJson);
|
||||
|
||||
if (!localIsValid || await NeedsUpdate(amiiboJson.LastUpdated))
|
||||
{
|
||||
amiiboJsonString = await DownloadAmiiboJson();
|
||||
remoteIsValid = TryGetAmiiboJson(await DownloadAmiiboJson(), out amiiboJson);
|
||||
}
|
||||
}
|
||||
else
|
||||
catch
|
||||
{
|
||||
try
|
||||
if (!(localIsValid || remoteIsValid))
|
||||
{
|
||||
amiiboJsonString = await DownloadAmiiboJson();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data: {ex}");
|
||||
|
||||
// Neither local or remote files are valid JSON, close window.
|
||||
ShowInfoDialog();
|
||||
|
||||
Close();
|
||||
}
|
||||
else if (!remoteIsValid)
|
||||
{
|
||||
// Only the local file is valid, the local one should be used
|
||||
// but the user should be warned.
|
||||
ShowInfoDialog();
|
||||
}
|
||||
}
|
||||
|
||||
_amiiboList = JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).Amiibo;
|
||||
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
||||
return amiiboJson;
|
||||
}
|
||||
|
||||
private async Task LoadContentAsync()
|
||||
{
|
||||
AmiiboJson amiiboJson = await GetMostRecentAmiiboListOrDefaultJson();
|
||||
|
||||
_amiiboList = amiiboJson.Amiibo.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
||||
|
||||
if (LastScannedAmiiboShowAll)
|
||||
{
|
||||
@@ -172,25 +196,14 @@ namespace Ryujinx.Ui.Windows
|
||||
|
||||
private async Task<bool> NeedsUpdate(DateTime oldLastModified)
|
||||
{
|
||||
try
|
||||
HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/"));
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/"));
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
return response.Content.Headers.LastModified != new DateTimeOffset(oldLastModified.Ticks - (oldLastModified.Ticks % TimeSpan.TicksPerSecond), TimeSpan.Zero);
|
||||
}
|
||||
|
||||
return false;
|
||||
return response.Content.Headers.LastModified != oldLastModified;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to check for amiibo updates: {ex}");
|
||||
|
||||
ShowInfoDialog();
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<string> DownloadAmiiboJson()
|
||||
|
Reference in New Issue
Block a user