mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-07-03 01:36:25 +02:00
This reverts commit 5c3cfb84c0
.
This commit is contained in:
parent
6228331fd1
commit
51065d9129
33 changed files with 819 additions and 1171 deletions
|
@ -7,7 +7,6 @@ using Ryujinx.Common.SystemInterop;
|
|||
using Ryujinx.Modules;
|
||||
using Ryujinx.SDL2.Common;
|
||||
using Ryujinx.Ui;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using Ryujinx.Ui.Common;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using Ryujinx.Ui.Common.Helper;
|
||||
|
@ -333,12 +332,7 @@ namespace Ryujinx
|
|||
|
||||
if (CommandLineState.LaunchPathArg != null)
|
||||
{
|
||||
ApplicationData applicationData = new()
|
||||
{
|
||||
Path = CommandLineState.LaunchPathArg,
|
||||
};
|
||||
|
||||
mainWindow.RunApplication(applicationData, CommandLineState.StartFullscreenArg);
|
||||
mainWindow.RunApplication(CommandLineState.LaunchPathArg, CommandLineState.StartFullscreenArg);
|
||||
}
|
||||
|
||||
if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false))
|
||||
|
|
|
@ -39,7 +39,6 @@ using Silk.NET.Vulkan;
|
|||
using SPB.Graphics.Vulkan;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
@ -71,7 +70,7 @@ namespace Ryujinx.Ui
|
|||
private bool _gameLoaded;
|
||||
private bool _ending;
|
||||
|
||||
private ApplicationData _currentApplicationData = null;
|
||||
private string _currentEmulatedGamePath = null;
|
||||
|
||||
private string _lastScannedAmiiboId = "";
|
||||
private bool _lastScannedAmiiboShowAll = false;
|
||||
|
@ -182,12 +181,8 @@ namespace Ryujinx.Ui
|
|||
_accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient, CommandLineState.Profile);
|
||||
_userChannelPersistence = new UserChannelPersistence();
|
||||
|
||||
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
|
||||
? IntegrityCheckLevel.ErrorOnInvalid
|
||||
: IntegrityCheckLevel.None;
|
||||
|
||||
// Instantiate GUI objects.
|
||||
_applicationLibrary = new ApplicationLibrary(_virtualFileSystem, checkLevel);
|
||||
_applicationLibrary = new ApplicationLibrary(_virtualFileSystem);
|
||||
_uiHandler = new GtkHostUiHandler(this);
|
||||
_deviceExitStatus = new AutoResetEvent(false);
|
||||
|
||||
|
@ -789,7 +784,7 @@ namespace Ryujinx.Ui
|
|||
}
|
||||
}
|
||||
|
||||
private bool LoadApplication(string path, ulong titleId, bool isFirmwareTitle)
|
||||
private bool LoadApplication(string path, bool isFirmwareTitle)
|
||||
{
|
||||
SystemVersion firmwareVersion = _contentManager.GetCurrentFirmwareVersion();
|
||||
|
||||
|
@ -863,7 +858,7 @@ namespace Ryujinx.Ui
|
|||
case ".xci":
|
||||
Logger.Info?.Print(LogClass.Application, "Loading as XCI.");
|
||||
|
||||
return _emulationContext.LoadXci(path, titleId);
|
||||
return _emulationContext.LoadXci(path);
|
||||
case ".nca":
|
||||
Logger.Info?.Print(LogClass.Application, "Loading as NCA.");
|
||||
|
||||
|
@ -872,7 +867,7 @@ namespace Ryujinx.Ui
|
|||
case ".pfs0":
|
||||
Logger.Info?.Print(LogClass.Application, "Loading as NSP.");
|
||||
|
||||
return _emulationContext.LoadNsp(path, titleId);
|
||||
return _emulationContext.LoadNsp(path);
|
||||
default:
|
||||
Logger.Info?.Print(LogClass.Application, "Loading as Homebrew.");
|
||||
try
|
||||
|
@ -893,7 +888,7 @@ namespace Ryujinx.Ui
|
|||
return false;
|
||||
}
|
||||
|
||||
public void RunApplication(ApplicationData application, bool startFullscreen = false)
|
||||
public void RunApplication(string path, bool startFullscreen = false)
|
||||
{
|
||||
if (_gameLoaded)
|
||||
{
|
||||
|
@ -915,14 +910,14 @@ namespace Ryujinx.Ui
|
|||
|
||||
bool isFirmwareTitle = false;
|
||||
|
||||
if (application.Path.StartsWith("@SystemContent"))
|
||||
if (path.StartsWith("@SystemContent"))
|
||||
{
|
||||
application.Path = VirtualFileSystem.SwitchPathToSystemPath(application.Path);
|
||||
path = VirtualFileSystem.SwitchPathToSystemPath(path);
|
||||
|
||||
isFirmwareTitle = true;
|
||||
}
|
||||
|
||||
if (!LoadApplication(application.Path, application.Id, isFirmwareTitle))
|
||||
if (!LoadApplication(path, isFirmwareTitle))
|
||||
{
|
||||
_emulationContext.Dispose();
|
||||
SwitchToGameTable();
|
||||
|
@ -932,7 +927,7 @@ namespace Ryujinx.Ui
|
|||
|
||||
SetupProgressUiHandlers();
|
||||
|
||||
_currentApplicationData = application;
|
||||
_currentEmulatedGamePath = path;
|
||||
|
||||
_deviceExitStatus.Reset();
|
||||
|
||||
|
@ -1173,7 +1168,7 @@ namespace Ryujinx.Ui
|
|||
_tableStore.AppendValues(
|
||||
args.AppData.Favorite,
|
||||
new Gdk.Pixbuf(args.AppData.Icon, 75, 75),
|
||||
$"{args.AppData.Name}\n{args.AppData.IdString.ToUpper()}",
|
||||
$"{args.AppData.TitleName}\n{args.AppData.TitleId.ToUpper()}",
|
||||
args.AppData.Developer,
|
||||
args.AppData.Version,
|
||||
args.AppData.TimePlayedString,
|
||||
|
@ -1261,22 +1256,9 @@ namespace Ryujinx.Ui
|
|||
{
|
||||
_gameTableSelection.GetSelected(out TreeIter treeIter);
|
||||
|
||||
ApplicationData application = new()
|
||||
{
|
||||
Favorite = (bool)_tableStore.GetValue(treeIter, 0),
|
||||
Name = ((string)_tableStore.GetValue(treeIter, 2)).Split('\n')[0],
|
||||
Id = ulong.Parse(((string)_tableStore.GetValue(treeIter, 2)).Split('\n')[1], NumberStyles.HexNumber),
|
||||
Developer = (string)_tableStore.GetValue(treeIter, 3),
|
||||
Version = (string)_tableStore.GetValue(treeIter, 4),
|
||||
TimePlayed = ValueFormatUtils.ParseTimeSpan((string)_tableStore.GetValue(treeIter, 5)),
|
||||
LastPlayed = ValueFormatUtils.ParseDateTime((string)_tableStore.GetValue(treeIter, 6)),
|
||||
FileExtension = (string)_tableStore.GetValue(treeIter, 7),
|
||||
FileSize = ValueFormatUtils.ParseFileSize((string)_tableStore.GetValue(treeIter, 8)),
|
||||
Path = (string)_tableStore.GetValue(treeIter, 9),
|
||||
ControlHolder = (BlitStruct<ApplicationControlProperty>)_tableStore.GetValue(treeIter, 10),
|
||||
};
|
||||
string path = (string)_tableStore.GetValue(treeIter, 9);
|
||||
|
||||
RunApplication(application);
|
||||
RunApplication(path);
|
||||
}
|
||||
|
||||
private void VSyncStatus_Clicked(object sender, ButtonReleaseEventArgs args)
|
||||
|
@ -1334,22 +1316,13 @@ namespace Ryujinx.Ui
|
|||
return;
|
||||
}
|
||||
|
||||
ApplicationData application = new()
|
||||
{
|
||||
Favorite = (bool)_tableStore.GetValue(treeIter, 0),
|
||||
Name = ((string)_tableStore.GetValue(treeIter, 2)).Split('\n')[0],
|
||||
Id = ulong.Parse(((string)_tableStore.GetValue(treeIter, 2)).Split('\n')[1], NumberStyles.HexNumber),
|
||||
Developer = (string)_tableStore.GetValue(treeIter, 3),
|
||||
Version = (string)_tableStore.GetValue(treeIter, 4),
|
||||
TimePlayed = ValueFormatUtils.ParseTimeSpan((string)_tableStore.GetValue(treeIter, 5)),
|
||||
LastPlayed = ValueFormatUtils.ParseDateTime((string)_tableStore.GetValue(treeIter, 6)),
|
||||
FileExtension = (string)_tableStore.GetValue(treeIter, 7),
|
||||
FileSize = ValueFormatUtils.ParseFileSize((string)_tableStore.GetValue(treeIter, 8)),
|
||||
Path = (string)_tableStore.GetValue(treeIter, 9),
|
||||
ControlHolder = (BlitStruct<ApplicationControlProperty>)_tableStore.GetValue(treeIter, 10),
|
||||
};
|
||||
string titleFilePath = _tableStore.GetValue(treeIter, 9).ToString();
|
||||
string titleName = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[0];
|
||||
string titleId = _tableStore.GetValue(treeIter, 2).ToString().Split("\n")[1].ToLower();
|
||||
|
||||
_ = new GameTableContextMenu(this, _virtualFileSystem, _accountManager, _libHacHorizonManager.RyujinxClient, application);
|
||||
BlitStruct<ApplicationControlProperty> controlData = (BlitStruct<ApplicationControlProperty>)_tableStore.GetValue(treeIter, 10);
|
||||
|
||||
_ = new GameTableContextMenu(this, _virtualFileSystem, _accountManager, _libHacHorizonManager.RyujinxClient, titleFilePath, titleName, titleId, controlData);
|
||||
}
|
||||
|
||||
private void Load_Application_File(object sender, EventArgs args)
|
||||
|
@ -1371,12 +1344,7 @@ namespace Ryujinx.Ui
|
|||
|
||||
if (fileChooser.Run() == (int)ResponseType.Accept)
|
||||
{
|
||||
ApplicationData applicationData = new()
|
||||
{
|
||||
Path = fileChooser.Filename,
|
||||
};
|
||||
|
||||
RunApplication(applicationData);
|
||||
RunApplication(fileChooser.Filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1386,13 +1354,7 @@ namespace Ryujinx.Ui
|
|||
|
||||
if (fileChooser.Run() == (int)ResponseType.Accept)
|
||||
{
|
||||
ApplicationData applicationData = new()
|
||||
{
|
||||
Name = System.IO.Path.GetFileNameWithoutExtension(fileChooser.Filename),
|
||||
Path = fileChooser.Filename,
|
||||
};
|
||||
|
||||
RunApplication(applicationData);
|
||||
RunApplication(fileChooser.Filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1407,14 +1369,7 @@ namespace Ryujinx.Ui
|
|||
{
|
||||
string contentPath = _contentManager.GetInstalledContentPath(0x0100000000001009, StorageId.BuiltInSystem, NcaContentType.Program);
|
||||
|
||||
ApplicationData applicationData = new()
|
||||
{
|
||||
Name = "miiEdit",
|
||||
Id = 0x0100000000001009ul,
|
||||
Path = contentPath,
|
||||
};
|
||||
|
||||
RunApplication(applicationData);
|
||||
RunApplication(contentPath);
|
||||
}
|
||||
|
||||
private void Open_Ryu_Folder(object sender, EventArgs args)
|
||||
|
@ -1690,13 +1645,13 @@ namespace Ryujinx.Ui
|
|||
{
|
||||
_userChannelPersistence.ShouldRestart = false;
|
||||
|
||||
RunApplication(_currentApplicationData);
|
||||
RunApplication(_currentEmulatedGamePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, clear state.
|
||||
_userChannelPersistence = new UserChannelPersistence();
|
||||
_currentApplicationData = null;
|
||||
_currentEmulatedGamePath = null;
|
||||
_actionMenu.Sensitive = false;
|
||||
_firmwareInstallFile.Sensitive = true;
|
||||
_firmwareInstallDirectory.Sensitive = true;
|
||||
|
@ -1758,7 +1713,7 @@ namespace Ryujinx.Ui
|
|||
_emulationContext.Processes.ActiveApplication.ProgramId,
|
||||
_emulationContext.Processes.ActiveApplication.ApplicationControlProperties
|
||||
.Title[(int)_emulationContext.System.State.DesiredTitleLanguage].NameString.ToString(),
|
||||
_currentApplicationData.Path);
|
||||
_currentEmulatedGamePath);
|
||||
|
||||
window.Destroyed += CheatWindow_Destroyed;
|
||||
window.Show();
|
||||
|
|
|
@ -16,7 +16,6 @@ using Ryujinx.Common.Logging;
|
|||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using Ryujinx.Ui.Common.Helper;
|
||||
|
@ -24,6 +23,7 @@ using Ryujinx.Ui.Windows;
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
@ -36,13 +36,17 @@ namespace Ryujinx.Ui.Widgets
|
|||
private readonly VirtualFileSystem _virtualFileSystem;
|
||||
private readonly AccountManager _accountManager;
|
||||
private readonly HorizonClient _horizonClient;
|
||||
private readonly BlitStruct<ApplicationControlProperty> _controlData;
|
||||
|
||||
private readonly ApplicationData _title;
|
||||
private readonly string _titleFilePath;
|
||||
private readonly string _titleName;
|
||||
private readonly string _titleIdText;
|
||||
private readonly ulong _titleId;
|
||||
|
||||
private MessageDialog _dialog;
|
||||
private bool _cancel;
|
||||
|
||||
public GameTableContextMenu(MainWindow parent, VirtualFileSystem virtualFileSystem, AccountManager accountManager, HorizonClient horizonClient, ApplicationData applicationData)
|
||||
public GameTableContextMenu(MainWindow parent, VirtualFileSystem virtualFileSystem, AccountManager accountManager, HorizonClient horizonClient, string titleFilePath, string titleName, string titleId, BlitStruct<ApplicationControlProperty> controlData)
|
||||
{
|
||||
_parent = parent;
|
||||
|
||||
|
@ -51,13 +55,23 @@ namespace Ryujinx.Ui.Widgets
|
|||
_virtualFileSystem = virtualFileSystem;
|
||||
_accountManager = accountManager;
|
||||
_horizonClient = horizonClient;
|
||||
_title = applicationData;
|
||||
_titleFilePath = titleFilePath;
|
||||
_titleName = titleName;
|
||||
_titleIdText = titleId;
|
||||
_controlData = controlData;
|
||||
|
||||
_openSaveUserDirMenuItem.Sensitive = !Utilities.IsZeros(_title.ControlHolder.ByteSpan) && _title.ControlHolder.Value.UserAccountSaveDataSize > 0;
|
||||
_openSaveDeviceDirMenuItem.Sensitive = !Utilities.IsZeros(_title.ControlHolder.ByteSpan) && _title.ControlHolder.Value.DeviceSaveDataSize > 0;
|
||||
_openSaveBcatDirMenuItem.Sensitive = !Utilities.IsZeros(_title.ControlHolder.ByteSpan) && _title.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
|
||||
if (!ulong.TryParse(_titleIdText, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out _titleId))
|
||||
{
|
||||
GtkDialog.CreateErrorDialog("The selected game did not have a valid Title Id");
|
||||
|
||||
string fileExt = System.IO.Path.GetExtension(_title.Path).ToLower();
|
||||
return;
|
||||
}
|
||||
|
||||
_openSaveUserDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.UserAccountSaveDataSize > 0;
|
||||
_openSaveDeviceDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.DeviceSaveDataSize > 0;
|
||||
_openSaveBcatDirMenuItem.Sensitive = !Utilities.IsZeros(controlData.ByteSpan) && controlData.Value.BcatDeliveryCacheStorageSize > 0;
|
||||
|
||||
string fileExt = System.IO.Path.GetExtension(_titleFilePath).ToLower();
|
||||
bool hasNca = fileExt == ".nca" || fileExt == ".nsp" || fileExt == ".pfs0" || fileExt == ".xci";
|
||||
|
||||
_extractRomFsMenuItem.Sensitive = hasNca;
|
||||
|
@ -123,7 +137,7 @@ namespace Ryujinx.Ui.Widgets
|
|||
|
||||
private void OpenSaveDir(in SaveDataFilter saveDataFilter)
|
||||
{
|
||||
if (!TryFindSaveData(_title.Name, _title.Id, _title.ControlHolder, in saveDataFilter, out ulong saveDataId))
|
||||
if (!TryFindSaveData(_titleName, _titleId, _controlData, in saveDataFilter, out ulong saveDataId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -176,7 +190,7 @@ namespace Ryujinx.Ui.Widgets
|
|||
{
|
||||
Title = "Ryujinx - NCA Section Extractor",
|
||||
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"),
|
||||
SecondaryText = $"Extracting {ncaSectionType} section from {System.IO.Path.GetFileName(_title.Path)}...",
|
||||
SecondaryText = $"Extracting {ncaSectionType} section from {System.IO.Path.GetFileName(_titleFilePath)}...",
|
||||
WindowPosition = WindowPosition.Center,
|
||||
};
|
||||
|
||||
|
@ -188,18 +202,18 @@ namespace Ryujinx.Ui.Widgets
|
|||
}
|
||||
});
|
||||
|
||||
using FileStream file = new(_title.Path, FileMode.Open, FileAccess.Read);
|
||||
using FileStream file = new(_titleFilePath, FileMode.Open, FileAccess.Read);
|
||||
|
||||
Nca mainNca = null;
|
||||
Nca patchNca = null;
|
||||
|
||||
if ((System.IO.Path.GetExtension(_title.Path).ToLower() == ".nsp") ||
|
||||
(System.IO.Path.GetExtension(_title.Path).ToLower() == ".pfs0") ||
|
||||
(System.IO.Path.GetExtension(_title.Path).ToLower() == ".xci"))
|
||||
if ((System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".nsp") ||
|
||||
(System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".pfs0") ||
|
||||
(System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".xci"))
|
||||
{
|
||||
IFileSystem pfs;
|
||||
|
||||
if (System.IO.Path.GetExtension(_title.Path).ToLower() == ".xci")
|
||||
if (System.IO.Path.GetExtension(_titleFilePath) == ".xci")
|
||||
{
|
||||
Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage());
|
||||
|
||||
|
@ -235,7 +249,7 @@ namespace Ryujinx.Ui.Widgets
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (System.IO.Path.GetExtension(_title.Path).ToLower() == ".nca")
|
||||
else if (System.IO.Path.GetExtension(_titleFilePath).ToLower() == ".nca")
|
||||
{
|
||||
mainNca = new Nca(_virtualFileSystem.KeySet, file.AsStorage());
|
||||
}
|
||||
|
@ -252,11 +266,7 @@ namespace Ryujinx.Ui.Widgets
|
|||
return;
|
||||
}
|
||||
|
||||
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
|
||||
? IntegrityCheckLevel.ErrorOnInvalid
|
||||
: IntegrityCheckLevel.None;
|
||||
|
||||
(Nca updatePatchNca, _) = mainNca.GetUpdateData(_virtualFileSystem, checkLevel, programIndex, out _);
|
||||
(Nca updatePatchNca, _) = ApplicationLibrary.GetGameUpdateData(_virtualFileSystem, mainNca.Header.TitleId.ToString("x16"), programIndex, out _);
|
||||
|
||||
if (updatePatchNca != null)
|
||||
{
|
||||
|
@ -450,44 +460,44 @@ namespace Ryujinx.Ui.Widgets
|
|||
private void OpenSaveUserDir_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
var userId = new LibHac.Fs.UserId((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low);
|
||||
var saveDataFilter = SaveDataFilter.Make(_title.Id, saveType: default, userId, saveDataId: default, index: default);
|
||||
var saveDataFilter = SaveDataFilter.Make(_titleId, saveType: default, userId, saveDataId: default, index: default);
|
||||
|
||||
OpenSaveDir(in saveDataFilter);
|
||||
}
|
||||
|
||||
private void OpenSaveDeviceDir_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
var saveDataFilter = SaveDataFilter.Make(_title.Id, SaveDataType.Device, userId: default, saveDataId: default, index: default);
|
||||
var saveDataFilter = SaveDataFilter.Make(_titleId, SaveDataType.Device, userId: default, saveDataId: default, index: default);
|
||||
|
||||
OpenSaveDir(in saveDataFilter);
|
||||
}
|
||||
|
||||
private void OpenSaveBcatDir_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
var saveDataFilter = SaveDataFilter.Make(_title.Id, SaveDataType.Bcat, userId: default, saveDataId: default, index: default);
|
||||
var saveDataFilter = SaveDataFilter.Make(_titleId, SaveDataType.Bcat, userId: default, saveDataId: default, index: default);
|
||||
|
||||
OpenSaveDir(in saveDataFilter);
|
||||
}
|
||||
|
||||
private void ManageTitleUpdates_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
new TitleUpdateWindow(_parent, _virtualFileSystem, _title).Show();
|
||||
new TitleUpdateWindow(_parent, _virtualFileSystem, _titleIdText, _titleName).Show();
|
||||
}
|
||||
|
||||
private void ManageDlc_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
new DlcWindow(_virtualFileSystem, _title.IdString, _title).Show();
|
||||
new DlcWindow(_virtualFileSystem, _titleIdText, _titleName).Show();
|
||||
}
|
||||
|
||||
private void ManageCheats_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
new CheatWindow(_virtualFileSystem, _title.Id, _title.Name, _title.Path).Show();
|
||||
new CheatWindow(_virtualFileSystem, _titleId, _titleName, _titleFilePath).Show();
|
||||
}
|
||||
|
||||
private void OpenTitleModDir_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
string modsBasePath = ModLoader.GetModsBasePath();
|
||||
string titleModsPath = ModLoader.GetTitleDir(modsBasePath, _title.IdString);
|
||||
string titleModsPath = ModLoader.GetTitleDir(modsBasePath, _titleIdText);
|
||||
|
||||
OpenHelper.OpenFolder(titleModsPath);
|
||||
}
|
||||
|
@ -495,7 +505,7 @@ namespace Ryujinx.Ui.Widgets
|
|||
private void OpenTitleSdModDir_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
string sdModsBasePath = ModLoader.GetSdModsBasePath();
|
||||
string titleModsPath = ModLoader.GetTitleDir(sdModsBasePath, _title.IdString);
|
||||
string titleModsPath = ModLoader.GetTitleDir(sdModsBasePath, _titleIdText);
|
||||
|
||||
OpenHelper.OpenFolder(titleModsPath);
|
||||
}
|
||||
|
@ -517,7 +527,7 @@ namespace Ryujinx.Ui.Widgets
|
|||
|
||||
private void OpenPtcDir_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
string ptcDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, _title.IdString, "cache", "cpu");
|
||||
string ptcDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu");
|
||||
|
||||
string mainPath = System.IO.Path.Combine(ptcDir, "0");
|
||||
string backupPath = System.IO.Path.Combine(ptcDir, "1");
|
||||
|
@ -534,7 +544,7 @@ namespace Ryujinx.Ui.Widgets
|
|||
|
||||
private void OpenShaderCacheDir_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
string shaderCacheDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, _title.IdString, "cache", "shader");
|
||||
string shaderCacheDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "shader");
|
||||
|
||||
if (!Directory.Exists(shaderCacheDir))
|
||||
{
|
||||
|
@ -546,10 +556,10 @@ namespace Ryujinx.Ui.Widgets
|
|||
|
||||
private void PurgePtcCache_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
DirectoryInfo mainDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _title.IdString, "cache", "cpu", "0"));
|
||||
DirectoryInfo backupDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _title.IdString, "cache", "cpu", "1"));
|
||||
DirectoryInfo mainDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu", "0"));
|
||||
DirectoryInfo backupDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu", "1"));
|
||||
|
||||
MessageDialog warningDialog = GtkDialog.CreateConfirmationDialog("Warning", $"You are about to queue a PPTC rebuild on the next boot of:\n\n<b>{_title.Name}</b>\n\nAre you sure you want to proceed?");
|
||||
MessageDialog warningDialog = GtkDialog.CreateConfirmationDialog("Warning", $"You are about to queue a PPTC rebuild on the next boot of:\n\n<b>{_titleName}</b>\n\nAre you sure you want to proceed?");
|
||||
|
||||
List<FileInfo> cacheFiles = new();
|
||||
|
||||
|
@ -583,9 +593,9 @@ namespace Ryujinx.Ui.Widgets
|
|||
|
||||
private void PurgeShaderCache_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
DirectoryInfo shaderCacheDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _title.IdString, "cache", "shader"));
|
||||
DirectoryInfo shaderCacheDir = new(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "shader"));
|
||||
|
||||
using MessageDialog warningDialog = GtkDialog.CreateConfirmationDialog("Warning", $"You are about to delete the shader cache for :\n\n<b>{_title.Name}</b>\n\nAre you sure you want to proceed?");
|
||||
using MessageDialog warningDialog = GtkDialog.CreateConfirmationDialog("Warning", $"You are about to delete the shader cache for :\n\n<b>{_titleName}</b>\n\nAre you sure you want to proceed?");
|
||||
|
||||
List<DirectoryInfo> oldCacheDirectories = new();
|
||||
List<FileInfo> newCacheFiles = new();
|
||||
|
@ -627,11 +637,8 @@ namespace Ryujinx.Ui.Widgets
|
|||
|
||||
private void CreateShortcut_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
|
||||
? IntegrityCheckLevel.ErrorOnInvalid
|
||||
: IntegrityCheckLevel.None;
|
||||
byte[] appIcon = new ApplicationLibrary(_virtualFileSystem, checkLevel).GetApplicationIcon(_title.Path, ConfigurationState.Instance.System.Language, _title.Id);
|
||||
ShortcutHelper.CreateAppShortcut(_title.Path, _title.Name, _title.IdString, appIcon);
|
||||
byte[] appIcon = new ApplicationLibrary(_virtualFileSystem).GetApplicationIcon(_titleFilePath, ConfigurationState.Instance.System.Language);
|
||||
ShortcutHelper.CreateAppShortcut(_titleFilePath, _titleName, _titleIdText, appIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
using Gtk;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
@ -29,13 +27,8 @@ namespace Ryujinx.Ui.Windows
|
|||
private CheatWindow(Builder builder, VirtualFileSystem virtualFileSystem, ulong titleId, string titleName, string titlePath) : base(builder.GetRawOwnedObject("_cheatWindow"))
|
||||
{
|
||||
builder.Autoconnect(this);
|
||||
|
||||
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
|
||||
? IntegrityCheckLevel.ErrorOnInvalid
|
||||
: IntegrityCheckLevel.None;
|
||||
|
||||
_baseTitleInfoLabel.Text = $"Cheats Available for {titleName} [{titleId:X16}]";
|
||||
_buildIdTextView.Buffer.Text = $"BuildId: {ApplicationData.GetBuildId(virtualFileSystem, checkLevel, titlePath)}";
|
||||
_buildIdTextView.Buffer.Text = $"BuildId: {ApplicationData.GetApplicationBuildId(virtualFileSystem, titlePath)}";
|
||||
|
||||
string modsBasePath = ModLoader.GetModsBasePath();
|
||||
string titleModsPath = ModLoader.GetTitleDir(modsBasePath, titleId.ToString("X16"));
|
||||
|
|
|
@ -9,12 +9,9 @@ using LibHac.Tools.FsSystem.NcaUtils;
|
|||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using Ryujinx.Ui.Widgets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using GUI = Gtk.Builder.ObjectAttribute;
|
||||
|
||||
|
@ -23,7 +20,7 @@ namespace Ryujinx.Ui.Windows
|
|||
public class DlcWindow : Window
|
||||
{
|
||||
private readonly VirtualFileSystem _virtualFileSystem;
|
||||
private readonly string _applicationId;
|
||||
private readonly string _titleId;
|
||||
private readonly string _dlcJsonPath;
|
||||
private readonly List<DownloadableContentContainer> _dlcContainerList;
|
||||
|
||||
|
@ -35,16 +32,16 @@ namespace Ryujinx.Ui.Windows
|
|||
[GUI] TreeSelection _dlcTreeSelection;
|
||||
#pragma warning restore CS0649, IDE0044
|
||||
|
||||
public DlcWindow(VirtualFileSystem virtualFileSystem, string titleId, ApplicationData title) : this(new Builder("Ryujinx.Ui.Windows.DlcWindow.glade"), virtualFileSystem, titleId, title) { }
|
||||
public DlcWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName) : this(new Builder("Ryujinx.Ui.Windows.DlcWindow.glade"), virtualFileSystem, titleId, titleName) { }
|
||||
|
||||
private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string applicationId, ApplicationData title) : base(builder.GetRawOwnedObject("_dlcWindow"))
|
||||
private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetRawOwnedObject("_dlcWindow"))
|
||||
{
|
||||
builder.Autoconnect(this);
|
||||
|
||||
_applicationId = applicationId;
|
||||
_titleId = titleId;
|
||||
_virtualFileSystem = virtualFileSystem;
|
||||
_dlcJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _applicationId, "dlc.json");
|
||||
_baseTitleInfoLabel.Text = $"DLC Available for {title.Name} [{applicationId.ToUpper()}]";
|
||||
_dlcJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "dlc.json");
|
||||
_baseTitleInfoLabel.Text = $"DLC Available for {titleName} [{titleId.ToUpper()}]";
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -75,12 +72,9 @@ namespace Ryujinx.Ui.Windows
|
|||
};
|
||||
|
||||
_dlcTreeView.AppendColumn("Enabled", enableToggle, "active", 0);
|
||||
_dlcTreeView.AppendColumn("ApplicationId", new CellRendererText(), "text", 1);
|
||||
_dlcTreeView.AppendColumn("TitleId", new CellRendererText(), "text", 1);
|
||||
_dlcTreeView.AppendColumn("Path", new CellRendererText(), "text", 2);
|
||||
|
||||
// NOTE: Try to load downloadable contents from PFS first.
|
||||
AddDlc(title.Path, true);
|
||||
|
||||
foreach (DownloadableContentContainer dlcContainer in _dlcContainerList)
|
||||
{
|
||||
if (File.Exists(dlcContainer.ContainerPath))
|
||||
|
@ -95,10 +89,7 @@ namespace Ryujinx.Ui.Windows
|
|||
using FileStream containerFile = File.OpenRead(dlcContainer.ContainerPath);
|
||||
|
||||
PartitionFileSystem pfs = new();
|
||||
if (pfs.Initialize(containerFile.AsStorage()).IsFailure())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
pfs.Initialize(containerFile.AsStorage()).ThrowIfFailure();
|
||||
|
||||
_virtualFileSystem.ImportTickets(pfs);
|
||||
|
||||
|
@ -137,57 +128,6 @@ namespace Ryujinx.Ui.Windows
|
|||
return null;
|
||||
}
|
||||
|
||||
private void AddDlc(string path, bool ignoreNotFound = false)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using FileStream containerFile = File.OpenRead(path);
|
||||
|
||||
PartitionFileSystem pfs = new();
|
||||
pfs.Initialize(containerFile.AsStorage()).ThrowIfFailure();
|
||||
|
||||
bool containsDlc = false;
|
||||
|
||||
_virtualFileSystem.ImportTickets(pfs);
|
||||
|
||||
TreeIter? parentIter = null;
|
||||
|
||||
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
||||
{
|
||||
using var ncaFile = new UniqueRef<IFile>();
|
||||
|
||||
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), path);
|
||||
|
||||
if (nca == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nca.Header.ContentType == NcaContentType.PublicData)
|
||||
{
|
||||
if (nca.GetProgramIdBase() != (ulong.Parse(_applicationId, NumberStyles.HexNumber) & ~0x1FFFUL))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
parentIter ??= ((TreeStore)_dlcTreeView.Model).AppendValues(true, "", path);
|
||||
|
||||
((TreeStore)_dlcTreeView.Model).AppendValues(parentIter.Value, true, nca.Header.TitleId.ToString("X16"), fileEntry.FullPath);
|
||||
containsDlc = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!containsDlc && !ignoreNotFound)
|
||||
{
|
||||
GtkDialog.CreateErrorDialog("The specified file does not contain DLC for the selected title!");
|
||||
}
|
||||
}
|
||||
|
||||
private void AddButton_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
FileChooserNative fileChooser = new("Select DLC files", this, FileChooserAction.Open, "Add", "Cancel")
|
||||
|
@ -207,7 +147,52 @@ namespace Ryujinx.Ui.Windows
|
|||
{
|
||||
foreach (string containerPath in fileChooser.Filenames)
|
||||
{
|
||||
AddDlc(containerPath);
|
||||
if (!File.Exists(containerPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using FileStream containerFile = File.OpenRead(containerPath);
|
||||
|
||||
PartitionFileSystem pfs = new();
|
||||
pfs.Initialize(containerFile.AsStorage()).ThrowIfFailure();
|
||||
bool containsDlc = false;
|
||||
|
||||
_virtualFileSystem.ImportTickets(pfs);
|
||||
|
||||
TreeIter? parentIter = null;
|
||||
|
||||
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
||||
{
|
||||
using var ncaFile = new UniqueRef<IFile>();
|
||||
|
||||
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), containerPath);
|
||||
|
||||
if (nca == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nca.Header.ContentType == NcaContentType.PublicData)
|
||||
{
|
||||
if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000).ToString("x16") != _titleId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
parentIter ??= ((TreeStore)_dlcTreeView.Model).AppendValues(true, "", containerPath);
|
||||
|
||||
((TreeStore)_dlcTreeView.Model).AppendValues(parentIter.Value, true, nca.Header.TitleId.ToString("X16"), fileEntry.FullPath);
|
||||
containsDlc = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!containsDlc)
|
||||
{
|
||||
GtkDialog.CreateErrorDialog("The specified file does not contain DLC for the selected title!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,15 +4,12 @@ using LibHac.Fs;
|
|||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Ns;
|
||||
using LibHac.Tools.Fs;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using Ryujinx.Ui.Widgets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -27,7 +24,7 @@ namespace Ryujinx.Ui.Windows
|
|||
{
|
||||
private readonly MainWindow _parent;
|
||||
private readonly VirtualFileSystem _virtualFileSystem;
|
||||
private readonly ApplicationData _title;
|
||||
private readonly string _titleId;
|
||||
private readonly string _updateJsonPath;
|
||||
|
||||
private TitleUpdateMetadata _titleUpdateWindowData;
|
||||
|
@ -41,17 +38,17 @@ namespace Ryujinx.Ui.Windows
|
|||
[GUI] RadioButton _noUpdateRadioButton;
|
||||
#pragma warning restore CS0649, IDE0044
|
||||
|
||||
public TitleUpdateWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, ApplicationData applicationData) : this(new Builder("Ryujinx.Ui.Windows.TitleUpdateWindow.glade"), parent, virtualFileSystem, applicationData) { }
|
||||
public TitleUpdateWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : this(new Builder("Ryujinx.Ui.Windows.TitleUpdateWindow.glade"), parent, virtualFileSystem, titleId, titleName) { }
|
||||
|
||||
private TitleUpdateWindow(Builder builder, MainWindow parent, VirtualFileSystem virtualFileSystem, ApplicationData applicationData) : base(builder.GetRawOwnedObject("_titleUpdateWindow"))
|
||||
private TitleUpdateWindow(Builder builder, MainWindow parent, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetRawOwnedObject("_titleUpdateWindow"))
|
||||
{
|
||||
_parent = parent;
|
||||
|
||||
builder.Autoconnect(this);
|
||||
|
||||
_title = applicationData;
|
||||
_titleId = titleId;
|
||||
_virtualFileSystem = virtualFileSystem;
|
||||
_updateJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, applicationData.IdString, "updates.json");
|
||||
_updateJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "updates.json");
|
||||
_radioButtonToPathDictionary = new Dictionary<RadioButton, string>();
|
||||
|
||||
try
|
||||
|
@ -67,10 +64,7 @@ namespace Ryujinx.Ui.Windows
|
|||
};
|
||||
}
|
||||
|
||||
_baseTitleInfoLabel.Text = $"Updates Available for {applicationData.Name} [{applicationData.IdString}]";
|
||||
|
||||
// Try to get updates from PFS first
|
||||
AddUpdate(_title.Path, true);
|
||||
_baseTitleInfoLabel.Text = $"Updates Available for {titleName} [{titleId.ToUpper()}]";
|
||||
|
||||
foreach (string path in _titleUpdateWindowData.Paths)
|
||||
{
|
||||
|
@ -90,41 +84,18 @@ namespace Ryujinx.Ui.Windows
|
|||
}
|
||||
}
|
||||
|
||||
private void AddUpdate(string path, bool ignoreNotFound = false)
|
||||
private void AddUpdate(string path)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
|
||||
? IntegrityCheckLevel.ErrorOnInvalid
|
||||
: IntegrityCheckLevel.None;
|
||||
|
||||
using FileStream file = new(path, FileMode.Open, FileAccess.Read);
|
||||
|
||||
IFileSystem pfs;
|
||||
PartitionFileSystem nsp = new();
|
||||
nsp.Initialize(file.AsStorage()).ThrowIfFailure();
|
||||
|
||||
try
|
||||
{
|
||||
if (System.IO.Path.GetExtension(path).ToLower() == ".xci")
|
||||
{
|
||||
pfs = new Xci(_virtualFileSystem.KeySet, file.AsStorage()).OpenPartition(XciPartitionType.Secure);
|
||||
}
|
||||
else
|
||||
{
|
||||
var pfsTemp = new PartitionFileSystem();
|
||||
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
|
||||
pfs = pfsTemp;
|
||||
}
|
||||
|
||||
Dictionary<ulong, ContentCollection> updates = pfs.GetUpdateData(_virtualFileSystem, checkLevel);
|
||||
|
||||
Nca patchNca = null;
|
||||
Nca controlNca = null;
|
||||
|
||||
if (updates.TryGetValue(_title.Id, out ContentCollection update))
|
||||
{
|
||||
patchNca = update.GetNcaByType(_virtualFileSystem.KeySet, LibHac.Ncm.ContentType.Program);
|
||||
controlNca = update.GetNcaByType(_virtualFileSystem.KeySet, LibHac.Ncm.ContentType.Control);
|
||||
}
|
||||
(Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(_virtualFileSystem, nsp, _titleId, 0);
|
||||
|
||||
if (controlNca != null && patchNca != null)
|
||||
{
|
||||
|
@ -135,14 +106,7 @@ namespace Ryujinx.Ui.Windows
|
|||
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
|
||||
|
||||
string radioLabel = $"Version {controlData.DisplayVersionString.ToString()} - {path}";
|
||||
|
||||
if (System.IO.Path.GetExtension(path).ToLower() == ".xci")
|
||||
{
|
||||
radioLabel = "Bundled: " + radioLabel;
|
||||
}
|
||||
|
||||
RadioButton radioButton = new(radioLabel);
|
||||
RadioButton radioButton = new($"Version {controlData.DisplayVersionString.ToString()} - {path}");
|
||||
radioButton.JoinGroup(_noUpdateRadioButton);
|
||||
|
||||
_availableUpdatesBox.Add(radioButton);
|
||||
|
@ -153,10 +117,7 @@ namespace Ryujinx.Ui.Windows
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!ignoreNotFound)
|
||||
{
|
||||
GtkDialog.CreateErrorDialog("The specified file does not contain an update for the selected title!");
|
||||
}
|
||||
GtkDialog.CreateErrorDialog("The specified file does not contain an update for the selected title!");
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue