mirror of
https://git.zaroz.cloud/nintendo-back-up/Ryujinx.git
synced 2025-12-16 07:22:42 +00:00
Compare commits
4 Commits
dependabot
...
1.1.1103
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f50b9bdb0 | ||
|
|
f11d663df7 | ||
|
|
19a949d0bf | ||
|
|
feec5ef7b3 |
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'
|
if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest'
|
||||||
|
|
||||||
- name: Upload Ryujinx artifact
|
- name: Upload Ryujinx artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||||
path: publish
|
path: publish
|
||||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||||
|
|
||||||
- name: Upload Ryujinx.Headless.SDL2 artifact
|
- name: Upload Ryujinx.Headless.SDL2 artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
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
|
path: publish_sdl2_headless
|
||||||
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest'
|
||||||
|
|
||||||
- name: Upload Ryujinx.Ava artifact
|
- name: Upload Ryujinx.Ava artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||||
path: publish_ava
|
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"
|
./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
|
- name: Upload Ryujinx.Ava artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
||||||
path: "publish_ava/*.tar.gz"
|
path: "publish_ava/*.tar.gz"
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
|
|
||||||
- name: Upload Ryujinx.Headless.SDL2 artifact
|
- name: Upload Ryujinx.Headless.SDL2 artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
||||||
path: "publish_headless/*.tar.gz"
|
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
|
- name: Upload report
|
||||||
if: failure()
|
if: failure()
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: dotnet-format
|
name: dotnet-format
|
||||||
path: ./*-report.json
|
path: ./*-report.json
|
||||||
|
|||||||
@@ -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();
|
_httpClient.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoadContentAsync()
|
private bool TryGetAmiiboJson(string json, out AmiiboJson amiiboJson)
|
||||||
{
|
|
||||||
string amiiboJsonString = DefaultJson;
|
|
||||||
|
|
||||||
if (File.Exists(_amiiboJsonPath))
|
|
||||||
{
|
|
||||||
amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath);
|
|
||||||
|
|
||||||
if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).LastUpdated))
|
|
||||||
{
|
|
||||||
amiiboJsonString = await DownloadAmiiboJson();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
amiiboJsonString = await DownloadAmiiboJson();
|
amiiboJson = JsonHelper.Deserialize<AmiiboJson>(json, _serializerContext.AmiiboJson);
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data: {ex}");
|
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
remoteIsValid = TryGetAmiiboJson(await DownloadAmiiboJson(), out amiiboJson);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
if (!(localIsValid || remoteIsValid))
|
||||||
|
{
|
||||||
|
// 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();
|
ShowInfoDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_amiiboList = JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).Amiibo;
|
return amiiboJson;
|
||||||
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
}
|
||||||
|
|
||||||
|
private async Task LoadContentAsync()
|
||||||
|
{
|
||||||
|
AmiiboJson amiiboJson = await GetMostRecentAmiiboListOrDefaultJson();
|
||||||
|
|
||||||
|
_amiiboList = amiiboJson.Amiibo.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
||||||
|
|
||||||
ParseAmiiboData();
|
ParseAmiiboData();
|
||||||
}
|
}
|
||||||
@@ -362,27 +388,15 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
private async Task<bool> NeedsUpdate(DateTime oldLastModified)
|
private async Task<bool> NeedsUpdate(DateTime oldLastModified)
|
||||||
{
|
{
|
||||||
try
|
HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/"));
|
||||||
{
|
|
||||||
HttpResponseMessage response =
|
|
||||||
await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/"));
|
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return response.Content.Headers.LastModified != new DateTimeOffset(oldLastModified.Ticks - (oldLastModified.Ticks % TimeSpan.TicksPerSecond), TimeSpan.Zero);
|
return response.Content.Headers.LastModified != oldLastModified;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.Error?.Print(LogClass.Application, $"Failed to check for amiibo updates: {ex}");
|
|
||||||
|
|
||||||
ShowInfoDialog();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> DownloadAmiiboJson()
|
private async Task<string> DownloadAmiiboJson()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -86,28 +86,16 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</Styles>
|
</Styles>
|
||||||
</TreeView.Styles>
|
</TreeView.Styles>
|
||||||
<TreeView.DataTemplates>
|
<TreeView.ItemTemplate>
|
||||||
<TreeDataTemplate DataType="model:CheatsList" ItemsSource="{Binding}">
|
<TreeDataTemplate ItemsSource="{Binding SubNodes}">
|
||||||
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
|
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
|
||||||
<CheckBox MinWidth="20" IsChecked="{Binding IsEnabled}" />
|
<CheckBox MinWidth="20" IsChecked="{Binding IsEnabled}" />
|
||||||
<TextBlock Width="150" Text="{Binding BuildId}" />
|
<TextBlock Width="150" Text="{Binding CleanName}" IsVisible="{Binding !IsRootNode}" />
|
||||||
<TextBlock Text="{Binding Path}" />
|
<TextBlock Width="150" Text="{Binding BuildId}" IsVisible="{Binding IsRootNode}" />
|
||||||
|
<TextBlock Text="{Binding Path}" IsVisible="{Binding IsRootNode}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</TreeDataTemplate>
|
</TreeDataTemplate>
|
||||||
<DataTemplate x:DataType="model:CheatModel">
|
</TreeView.ItemTemplate>
|
||||||
<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>
|
</TreeView>
|
||||||
</Border>
|
</Border>
|
||||||
<DockPanel
|
<DockPanel
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
private readonly string _enabledCheatsPath;
|
private readonly string _enabledCheatsPath;
|
||||||
public bool NoCheatsFound { get; }
|
public bool NoCheatsFound { get; }
|
||||||
|
|
||||||
public AvaloniaList<CheatsList> LoadedCheats { get; }
|
public AvaloniaList<CheatNode> LoadedCheats { get; }
|
||||||
|
|
||||||
public string Heading { get; }
|
public string Heading { get; }
|
||||||
public string BuildId { get; }
|
public string BuildId { get; }
|
||||||
@@ -33,7 +33,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
public CheatWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName, string titlePath)
|
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());
|
Heading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.CheatWindowHeading, titleName, titleId.ToUpper());
|
||||||
BuildId = ApplicationData.GetApplicationBuildId(virtualFileSystem, titlePath);
|
BuildId = ApplicationData.GetApplicationBuildId(virtualFileSystem, titlePath);
|
||||||
@@ -62,7 +62,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
string currentCheatFile = string.Empty;
|
string currentCheatFile = string.Empty;
|
||||||
string buildId = string.Empty;
|
string buildId = string.Empty;
|
||||||
|
|
||||||
CheatsList currentGroup = null;
|
CheatNode currentGroup = null;
|
||||||
|
|
||||||
foreach (var cheat in mods.Cheats)
|
foreach (var cheat in mods.Cheats)
|
||||||
{
|
{
|
||||||
@@ -72,13 +72,13 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
string parentPath = currentCheatFile.Replace(titleModsPath, "");
|
string parentPath = currentCheatFile.Replace(titleModsPath, "");
|
||||||
|
|
||||||
buildId = Path.GetFileNameWithoutExtension(currentCheatFile).ToUpper();
|
buildId = Path.GetFileNameWithoutExtension(currentCheatFile).ToUpper();
|
||||||
currentGroup = new CheatsList(buildId, parentPath);
|
currentGroup = new CheatNode("", buildId, parentPath, true);
|
||||||
|
|
||||||
LoadedCheats.Add(currentGroup);
|
LoadedCheats.Add(currentGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
var model = new CheatModel(cheat.Name, buildId, enabled.Contains($"{buildId}-{cheat.Name}"));
|
var model = new CheatNode(cheat.Name, buildId, "", false, enabled.Contains($"{buildId}-{cheat.Name}"));
|
||||||
currentGroup?.Add(model);
|
currentGroup?.SubNodes.Add(model);
|
||||||
|
|
||||||
cheatAdded++;
|
cheatAdded++;
|
||||||
}
|
}
|
||||||
@@ -104,7 +104,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
foreach (var cheats in LoadedCheats)
|
foreach (var cheats in LoadedCheats)
|
||||||
{
|
{
|
||||||
foreach (var cheat in cheats)
|
foreach (var cheat in cheats.SubNodes)
|
||||||
{
|
{
|
||||||
if (cheat.IsEnabled)
|
if (cheat.IsEnabled)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -675,7 +675,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
KMemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask,
|
||||||
MemoryAttribute.None,
|
MemoryAttribute.None,
|
||||||
MemoryAttribute.IpcAndDeviceMapped,
|
MemoryAttribute.IpcAndDeviceMapped | MemoryAttribute.PermissionLocked,
|
||||||
out MemoryState state,
|
out MemoryState state,
|
||||||
out _,
|
out _,
|
||||||
out _);
|
out _);
|
||||||
@@ -687,7 +687,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
state,
|
state,
|
||||||
KMemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
KMemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.Mask,
|
MemoryAttribute.Mask & ~MemoryAttribute.PermissionLocked,
|
||||||
MemoryAttribute.None);
|
MemoryAttribute.None);
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
@@ -913,19 +913,27 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
return Result.Success;
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result SetMemoryAttribute(
|
public Result SetMemoryAttribute(ulong address, ulong size, MemoryAttribute attributeMask, MemoryAttribute attributeValue)
|
||||||
ulong address,
|
|
||||||
ulong size,
|
|
||||||
MemoryAttribute attributeMask,
|
|
||||||
MemoryAttribute attributeValue)
|
|
||||||
{
|
{
|
||||||
lock (_blockManager)
|
lock (_blockManager)
|
||||||
{
|
{
|
||||||
|
MemoryState stateCheckMask = 0;
|
||||||
|
|
||||||
|
if (attributeMask.HasFlag(MemoryAttribute.Uncached))
|
||||||
|
{
|
||||||
|
stateCheckMask = MemoryState.AttributeChangeAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attributeMask.HasFlag(MemoryAttribute.PermissionLocked))
|
||||||
|
{
|
||||||
|
stateCheckMask |= MemoryState.PermissionLockAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
if (CheckRange(
|
if (CheckRange(
|
||||||
address,
|
address,
|
||||||
size,
|
size,
|
||||||
MemoryState.AttributeChangeAllowed,
|
stateCheckMask,
|
||||||
MemoryState.AttributeChangeAllowed,
|
stateCheckMask,
|
||||||
KMemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
KMemoryPermission.None,
|
KMemoryPermission.None,
|
||||||
MemoryAttribute.BorrowedAndIpcMapped,
|
MemoryAttribute.BorrowedAndIpcMapped,
|
||||||
|
|||||||
@@ -12,11 +12,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
IpcMapped = 1 << 1,
|
IpcMapped = 1 << 1,
|
||||||
DeviceMapped = 1 << 2,
|
DeviceMapped = 1 << 2,
|
||||||
Uncached = 1 << 3,
|
Uncached = 1 << 3,
|
||||||
|
PermissionLocked = 1 << 4,
|
||||||
|
|
||||||
IpcAndDeviceMapped = IpcMapped | DeviceMapped,
|
IpcAndDeviceMapped = IpcMapped | DeviceMapped,
|
||||||
|
|
||||||
BorrowedAndIpcMapped = Borrowed | IpcMapped,
|
BorrowedAndIpcMapped = Borrowed | IpcMapped,
|
||||||
|
|
||||||
DeviceMappedAndUncached = DeviceMapped | Uncached,
|
DeviceMappedAndUncached = DeviceMapped | Uncached,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,35 +5,155 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
[Flags]
|
[Flags]
|
||||||
enum MemoryState : uint
|
enum MemoryState : uint
|
||||||
{
|
{
|
||||||
Unmapped = 0x00000000,
|
Unmapped = 0x0,
|
||||||
Io = 0x00002001,
|
Io = Mapped | 0x1,
|
||||||
Normal = 0x00042002,
|
Normal = Mapped | QueryPhysicalAddressAllowed | 0x2,
|
||||||
CodeStatic = 0x00DC7E03,
|
CodeStatic = ForceReadWritableByDebugSyscalls |
|
||||||
CodeMutable = 0x03FEBD04,
|
IpcSendAllowedType0 |
|
||||||
Heap = 0x037EBD05,
|
IpcSendAllowedType3 |
|
||||||
SharedMemory = 0x00402006,
|
IpcSendAllowedType1 |
|
||||||
ModCodeStatic = 0x00DD7E08,
|
Mapped |
|
||||||
ModCodeMutable = 0x03FFBD09,
|
ProcessPermissionChangeAllowed |
|
||||||
IpcBuffer0 = 0x005C3C0A,
|
QueryPhysicalAddressAllowed |
|
||||||
Stack = 0x005C3C0B,
|
MapDeviceAllowed |
|
||||||
ThreadLocal = 0x0040200C,
|
MapDeviceAlignedAllowed |
|
||||||
TransferMemoryIsolated = 0x015C3C0D,
|
IsPoolAllocated |
|
||||||
TransferMemory = 0x005C380E,
|
MapProcessAllowed |
|
||||||
ProcessMemory = 0x0040380F,
|
LinearMapped |
|
||||||
Reserved = 0x00000010,
|
0x3,
|
||||||
IpcBuffer1 = 0x005C3811,
|
CodeMutable = PermissionChangeAllowed |
|
||||||
IpcBuffer3 = 0x004C2812,
|
IpcSendAllowedType0 |
|
||||||
KernelStack = 0x00002013,
|
IpcSendAllowedType3 |
|
||||||
CodeReadOnly = 0x00402214,
|
IpcSendAllowedType1 |
|
||||||
CodeWritable = 0x00402015,
|
Mapped |
|
||||||
UserMask = 0xff,
|
MapAllowed |
|
||||||
Mask = 0xffffffff,
|
TransferMemoryAllowed |
|
||||||
|
QueryPhysicalAddressAllowed |
|
||||||
|
MapDeviceAllowed |
|
||||||
|
MapDeviceAlignedAllowed |
|
||||||
|
IpcBufferAllowed |
|
||||||
|
IsPoolAllocated |
|
||||||
|
MapProcessAllowed |
|
||||||
|
AttributeChangeAllowed |
|
||||||
|
CodeMemoryAllowed |
|
||||||
|
LinearMapped |
|
||||||
|
PermissionLockAllowed |
|
||||||
|
0x4,
|
||||||
|
Heap = PermissionChangeAllowed |
|
||||||
|
IpcSendAllowedType0 |
|
||||||
|
IpcSendAllowedType3 |
|
||||||
|
IpcSendAllowedType1 |
|
||||||
|
Mapped |
|
||||||
|
MapAllowed |
|
||||||
|
TransferMemoryAllowed |
|
||||||
|
QueryPhysicalAddressAllowed |
|
||||||
|
MapDeviceAllowed |
|
||||||
|
MapDeviceAlignedAllowed |
|
||||||
|
IpcBufferAllowed |
|
||||||
|
IsPoolAllocated |
|
||||||
|
AttributeChangeAllowed |
|
||||||
|
CodeMemoryAllowed |
|
||||||
|
LinearMapped |
|
||||||
|
0x5,
|
||||||
|
SharedMemory = Mapped | IsPoolAllocated | LinearMapped | 0x6,
|
||||||
|
ModCodeStatic = ForceReadWritableByDebugSyscalls |
|
||||||
|
IpcSendAllowedType0 |
|
||||||
|
IpcSendAllowedType3 |
|
||||||
|
IpcSendAllowedType1 |
|
||||||
|
Mapped |
|
||||||
|
ProcessPermissionChangeAllowed |
|
||||||
|
UnmapProcessCodeMemoryAllowed |
|
||||||
|
QueryPhysicalAddressAllowed |
|
||||||
|
MapDeviceAllowed |
|
||||||
|
MapDeviceAlignedAllowed |
|
||||||
|
IsPoolAllocated |
|
||||||
|
MapProcessAllowed |
|
||||||
|
LinearMapped |
|
||||||
|
0x8,
|
||||||
|
ModCodeMutable = PermissionChangeAllowed |
|
||||||
|
IpcSendAllowedType0 |
|
||||||
|
IpcSendAllowedType3 |
|
||||||
|
IpcSendAllowedType1 |
|
||||||
|
Mapped |
|
||||||
|
MapAllowed |
|
||||||
|
UnmapProcessCodeMemoryAllowed |
|
||||||
|
TransferMemoryAllowed |
|
||||||
|
QueryPhysicalAddressAllowed |
|
||||||
|
MapDeviceAllowed |
|
||||||
|
MapDeviceAlignedAllowed |
|
||||||
|
IpcBufferAllowed |
|
||||||
|
IsPoolAllocated |
|
||||||
|
MapProcessAllowed |
|
||||||
|
AttributeChangeAllowed |
|
||||||
|
CodeMemoryAllowed |
|
||||||
|
LinearMapped |
|
||||||
|
PermissionLockAllowed |
|
||||||
|
0x9,
|
||||||
|
IpcBuffer0 = IpcSendAllowedType0 |
|
||||||
|
IpcSendAllowedType3 |
|
||||||
|
IpcSendAllowedType1 |
|
||||||
|
Mapped |
|
||||||
|
QueryPhysicalAddressAllowed |
|
||||||
|
MapDeviceAllowed |
|
||||||
|
MapDeviceAlignedAllowed |
|
||||||
|
IsPoolAllocated |
|
||||||
|
LinearMapped |
|
||||||
|
0xA,
|
||||||
|
Stack = IpcSendAllowedType0 |
|
||||||
|
IpcSendAllowedType3 |
|
||||||
|
IpcSendAllowedType1 |
|
||||||
|
Mapped |
|
||||||
|
QueryPhysicalAddressAllowed |
|
||||||
|
MapDeviceAllowed |
|
||||||
|
MapDeviceAlignedAllowed |
|
||||||
|
IsPoolAllocated |
|
||||||
|
LinearMapped |
|
||||||
|
0xB,
|
||||||
|
ThreadLocal = Mapped | IsPoolAllocated | LinearMapped | 0xC,
|
||||||
|
TransferMemoryIsolated = IpcSendAllowedType0 |
|
||||||
|
IpcSendAllowedType3 |
|
||||||
|
IpcSendAllowedType1 |
|
||||||
|
Mapped |
|
||||||
|
QueryPhysicalAddressAllowed |
|
||||||
|
MapDeviceAllowed |
|
||||||
|
MapDeviceAlignedAllowed |
|
||||||
|
IsPoolAllocated |
|
||||||
|
AttributeChangeAllowed |
|
||||||
|
LinearMapped |
|
||||||
|
0xD,
|
||||||
|
TransferMemory = IpcSendAllowedType3 |
|
||||||
|
IpcSendAllowedType1 |
|
||||||
|
Mapped |
|
||||||
|
QueryPhysicalAddressAllowed |
|
||||||
|
MapDeviceAllowed |
|
||||||
|
MapDeviceAlignedAllowed |
|
||||||
|
IsPoolAllocated |
|
||||||
|
LinearMapped |
|
||||||
|
0xE,
|
||||||
|
ProcessMemory = IpcSendAllowedType3 | IpcSendAllowedType1 | Mapped | IsPoolAllocated | LinearMapped | 0xF,
|
||||||
|
Reserved = 0x10,
|
||||||
|
IpcBuffer1 = IpcSendAllowedType3 |
|
||||||
|
IpcSendAllowedType1 |
|
||||||
|
Mapped |
|
||||||
|
QueryPhysicalAddressAllowed |
|
||||||
|
MapDeviceAllowed |
|
||||||
|
MapDeviceAlignedAllowed |
|
||||||
|
IsPoolAllocated |
|
||||||
|
LinearMapped |
|
||||||
|
0x11,
|
||||||
|
IpcBuffer3 = IpcSendAllowedType3 | Mapped | QueryPhysicalAddressAllowed | MapDeviceAllowed | IsPoolAllocated | LinearMapped | 0x12,
|
||||||
|
KernelStack = Mapped | 0x13,
|
||||||
|
CodeReadOnly = ForceReadWritableByDebugSyscalls | Mapped | IsPoolAllocated | LinearMapped | 0x14,
|
||||||
|
CodeWritable = Mapped | IsPoolAllocated | LinearMapped | 0x15,
|
||||||
|
UserMask = 0xFF,
|
||||||
|
Mask = 0xFFFFFFFF,
|
||||||
|
|
||||||
PermissionChangeAllowed = 1 << 8,
|
PermissionChangeAllowed = 1 << 8,
|
||||||
ForceReadWritableByDebugSyscalls = 1 << 9,
|
ForceReadWritableByDebugSyscalls = 1 << 9,
|
||||||
IpcSendAllowedType0 = 1 << 10,
|
IpcSendAllowedType0 = 1 << 10,
|
||||||
IpcSendAllowedType3 = 1 << 11,
|
IpcSendAllowedType3 = 1 << 11,
|
||||||
IpcSendAllowedType1 = 1 << 12,
|
IpcSendAllowedType1 = 1 << 12,
|
||||||
|
Mapped = 1 << 13,
|
||||||
ProcessPermissionChangeAllowed = 1 << 14,
|
ProcessPermissionChangeAllowed = 1 << 14,
|
||||||
MapAllowed = 1 << 15,
|
MapAllowed = 1 << 15,
|
||||||
UnmapProcessCodeMemoryAllowed = 1 << 16,
|
UnmapProcessCodeMemoryAllowed = 1 << 16,
|
||||||
@@ -46,5 +166,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||||||
MapProcessAllowed = 1 << 23,
|
MapProcessAllowed = 1 << 23,
|
||||||
AttributeChangeAllowed = 1 << 24,
|
AttributeChangeAllowed = 1 << 24,
|
||||||
CodeMemoryAllowed = 1 << 25,
|
CodeMemoryAllowed = 1 << 25,
|
||||||
|
LinearMapped = 1 << 26,
|
||||||
|
PermissionLockAllowed = 1 << 27,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -949,8 +949,16 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||||||
|
|
||||||
MemoryAttribute attributes = attributeMask | attributeValue;
|
MemoryAttribute attributes = attributeMask | attributeValue;
|
||||||
|
|
||||||
|
const MemoryAttribute SupportedAttributes = MemoryAttribute.Uncached | MemoryAttribute.PermissionLocked;
|
||||||
|
|
||||||
if (attributes != attributeMask ||
|
if (attributes != attributeMask ||
|
||||||
(attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached)
|
(attributes | SupportedAttributes) != SupportedAttributes)
|
||||||
|
{
|
||||||
|
return KernelResult.InvalidCombination;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The permission locked attribute can't be unset.
|
||||||
|
if ((attributeMask & MemoryAttribute.PermissionLocked) != (attributeValue & MemoryAttribute.PermissionLocked))
|
||||||
{
|
{
|
||||||
return KernelResult.InvalidCombination;
|
return KernelResult.InvalidCombination;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,37 +72,61 @@ namespace Ryujinx.Ui.Windows
|
|||||||
_ = LoadContentAsync();
|
_ = LoadContentAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoadContentAsync()
|
private bool TryGetAmiiboJson(string json, out AmiiboJson amiiboJson)
|
||||||
{
|
|
||||||
string amiiboJsonString = DefaultJson;
|
|
||||||
|
|
||||||
if (File.Exists(_amiiboJsonPath))
|
|
||||||
{
|
|
||||||
amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath);
|
|
||||||
|
|
||||||
if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, _serializerContext.AmiiboJson).LastUpdated))
|
|
||||||
{
|
|
||||||
amiiboJsonString = await DownloadAmiiboJson();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
amiiboJsonString = await DownloadAmiiboJson();
|
amiiboJson = JsonHelper.Deserialize<AmiiboJson>(json, _serializerContext.AmiiboJson);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data: {ex}");
|
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))
|
||||||
|
{
|
||||||
|
remoteIsValid = TryGetAmiiboJson(await DownloadAmiiboJson(), out amiiboJson);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
if (!(localIsValid || remoteIsValid))
|
||||||
|
{
|
||||||
|
// Neither local or remote files are valid JSON, close window.
|
||||||
ShowInfoDialog();
|
ShowInfoDialog();
|
||||||
|
|
||||||
Close();
|
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;
|
return amiiboJson;
|
||||||
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
}
|
||||||
|
|
||||||
|
private async Task LoadContentAsync()
|
||||||
|
{
|
||||||
|
AmiiboJson amiiboJson = await GetMostRecentAmiiboListOrDefaultJson();
|
||||||
|
|
||||||
|
_amiiboList = amiiboJson.Amiibo.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
||||||
|
|
||||||
if (LastScannedAmiiboShowAll)
|
if (LastScannedAmiiboShowAll)
|
||||||
{
|
{
|
||||||
@@ -171,27 +195,16 @@ namespace Ryujinx.Ui.Windows
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> NeedsUpdate(DateTime oldLastModified)
|
private async Task<bool> NeedsUpdate(DateTime oldLastModified)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/"));
|
HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/"));
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return response.Content.Headers.LastModified != new DateTimeOffset(oldLastModified.Ticks - (oldLastModified.Ticks % TimeSpan.TicksPerSecond), TimeSpan.Zero);
|
return response.Content.Headers.LastModified != oldLastModified;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.Error?.Print(LogClass.Application, $"Failed to check for amiibo updates: {ex}");
|
|
||||||
|
|
||||||
ShowInfoDialog();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> DownloadAmiiboJson()
|
private async Task<string> DownloadAmiiboJson()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user