Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ac21abbb9d | ||
|
a3dd04deef | ||
|
3705c20668 |
@@ -1,10 +1,14 @@
|
||||
using System.Reflection;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
// DO NOT EDIT, filled by CI
|
||||
public static class ReleaseInformations
|
||||
{
|
||||
private const string FlatHubChannelOwner = "flathub";
|
||||
|
||||
public static string BuildVersion = "%%RYUJINX_BUILD_VERSION%%";
|
||||
public static string BuildGitHash = "%%RYUJINX_BUILD_GIT_HASH%%";
|
||||
public static string ReleaseChannelName = "%%RYUJINX_TARGET_RELEASE_CHANNEL_NAME%%";
|
||||
@@ -19,6 +23,11 @@ namespace Ryujinx.Common
|
||||
!ReleaseChannelRepo.StartsWith("%%");
|
||||
}
|
||||
|
||||
public static bool IsFlatHubBuild()
|
||||
{
|
||||
return IsValid() && ReleaseChannelOwner.Equals(FlatHubChannelOwner);
|
||||
}
|
||||
|
||||
public static string GetVersion()
|
||||
{
|
||||
if (IsValid())
|
||||
@@ -30,5 +39,15 @@ namespace Ryujinx.Common
|
||||
return Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetBaseApplicationDirectory()
|
||||
{
|
||||
if (IsFlatHubBuild())
|
||||
{
|
||||
return AppDataManager.BaseDirPath;
|
||||
}
|
||||
|
||||
return AppDomain.CurrentDomain.BaseDirectory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -481,14 +481,14 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
if (result.IsSuccess() && bytesRead == controlData.ByteSpan.Length)
|
||||
{
|
||||
titleName = controlData.Value.Titles[(int)device.System.State.DesiredTitleLanguage].Name.ToString();
|
||||
titleName = controlData.Value.Title[(int)device.System.State.DesiredTitleLanguage].NameString.ToString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(titleName))
|
||||
{
|
||||
titleName = controlData.Value.Titles.ToArray().FirstOrDefault(x => x.Name[0] != 0).Name.ToString();
|
||||
titleName = controlData.Value.Title.ItemsRo.ToArray().FirstOrDefault(x => x.Name[0] != 0).NameString.ToString();
|
||||
}
|
||||
|
||||
displayVersion = controlData.Value.DisplayVersion.ToString();
|
||||
displayVersion = controlData.Value.DisplayVersionString.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -615,20 +615,20 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
ref ApplicationControlProperty nacp = ref ControlData.Value;
|
||||
|
||||
programInfo.Name = nacp.Titles[(int)_device.System.State.DesiredTitleLanguage].Name.ToString();
|
||||
programInfo.Name = nacp.Title[(int)_device.System.State.DesiredTitleLanguage].NameString.ToString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(programInfo.Name))
|
||||
{
|
||||
programInfo.Name = nacp.Titles.ToArray().FirstOrDefault(x => x.Name[0] != 0).Name.ToString();
|
||||
programInfo.Name = nacp.Title.ItemsRo.ToArray().FirstOrDefault(x => x.Name[0] != 0).NameString.ToString();
|
||||
}
|
||||
|
||||
if (nacp.PresenceGroupId != 0)
|
||||
{
|
||||
programInfo.ProgramId = nacp.PresenceGroupId;
|
||||
}
|
||||
else if (nacp.SaveDataOwnerId.Value != 0)
|
||||
else if (nacp.SaveDataOwnerId != 0)
|
||||
{
|
||||
programInfo.ProgramId = nacp.SaveDataOwnerId.Value;
|
||||
programInfo.ProgramId = nacp.SaveDataOwnerId;
|
||||
}
|
||||
else if (nacp.AddOnContentBaseId != 0)
|
||||
{
|
||||
@@ -776,14 +776,14 @@ namespace Ryujinx.HLE.HOS
|
||||
// The set sizes don't actually matter as long as they're non-zero because we use directory savedata.
|
||||
control.UserAccountSaveDataSize = 0x4000;
|
||||
control.UserAccountSaveDataJournalSize = 0x4000;
|
||||
control.SaveDataOwnerId = applicationId;
|
||||
control.SaveDataOwnerId = applicationId.Value;
|
||||
|
||||
Logger.Warning?.Print(LogClass.Application,
|
||||
"No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games.");
|
||||
}
|
||||
|
||||
HorizonClient hos = _device.System.LibHacHorizonManager.RyujinxClient;
|
||||
Result resultCode = hos.Fs.EnsureApplicationCacheStorage(out _, out _, applicationId, ref control);
|
||||
Result resultCode = hos.Fs.EnsureApplicationCacheStorage(out _, out _, applicationId, in control);
|
||||
|
||||
if (resultCode.IsFailure())
|
||||
{
|
||||
@@ -792,7 +792,7 @@ namespace Ryujinx.HLE.HOS
|
||||
return resultCode;
|
||||
}
|
||||
|
||||
resultCode = EnsureApplicationSaveData(hos.Fs, out _, applicationId, ref control, ref user);
|
||||
resultCode = hos.Fs.EnsureApplicationSaveData(out _, applicationId, in control, in user);
|
||||
|
||||
if (resultCode.IsFailure())
|
||||
{
|
||||
|
@@ -466,7 +466,7 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
AudioRendererManager.Dispose();
|
||||
|
||||
LibHacHorizonManager.AmClient.Fs.UnregisterProgram(LibHacHorizonManager.ApplicationClient.Os.GetCurrentProcessId().Value);
|
||||
LibHacHorizonManager.PmClient.Fs.UnregisterProgram(LibHacHorizonManager.ApplicationClient.Os.GetCurrentProcessId().Value).ThrowIfFailure();
|
||||
|
||||
KernelContext.Dispose();
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ namespace Ryujinx.HLE.HOS
|
||||
public HorizonClient BcatClient { get; private set; }
|
||||
public HorizonClient FsClient { get; private set; }
|
||||
public HorizonClient NsClient { get; private set; }
|
||||
public HorizonClient PmClient { get; private set; }
|
||||
public HorizonClient SdbClient { get; private set; }
|
||||
|
||||
private SharedRef<LibHacIReader> _arpIReader;
|
||||
@@ -65,6 +66,7 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
public void InitializeSystemClients()
|
||||
{
|
||||
PmClient = Server.CreatePrivilegedHorizonClient();
|
||||
AccountClient = Server.CreateHorizonClient(new ProgramLocation(SystemProgramId.Account, StorageId.BuiltInSystem), AccountFsPermissions);
|
||||
AmClient = Server.CreateHorizonClient(new ProgramLocation(SystemProgramId.Am, StorageId.BuiltInSystem), AmFsPermissions);
|
||||
NsClient = Server.CreateHorizonClient(new ProgramLocation(SystemProgramId.Ns, StorageId.BuiltInSystem), NsFsPermissions);
|
||||
|
@@ -695,7 +695,7 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
var buildIds = programs.Select(p => p switch
|
||||
{
|
||||
NsoExecutable nso => BitConverter.ToString(nso.BuildId.Bytes.ToArray()).Replace("-", "").TrimEnd('0'),
|
||||
NsoExecutable nso => BitConverter.ToString(nso.BuildId.ItemsRo.ToArray()).Replace("-", "").TrimEnd('0'),
|
||||
NroExecutable nro => BitConverter.ToString(nro.Header.BuildId).Replace("-", "").TrimEnd('0'),
|
||||
_ => string.Empty
|
||||
}).ToList();
|
||||
|
@@ -160,7 +160,7 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
var buildIds = executables.Select(e => (e switch
|
||||
{
|
||||
NsoExecutable nso => BitConverter.ToString(nso.BuildId.Bytes.ToArray()),
|
||||
NsoExecutable nso => BitConverter.ToString(nso.BuildId.ItemsRo.ToArray()),
|
||||
NroExecutable nro => BitConverter.ToString(nro.Header.BuildId),
|
||||
_ => ""
|
||||
}).Replace("-", "").ToUpper());
|
||||
|
@@ -3,6 +3,7 @@ using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Shim;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@@ -25,7 +26,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||
|
||||
public UserProfile LastOpenedUser { get; private set; }
|
||||
|
||||
public AccountManager(HorizonClient horizonClient)
|
||||
public AccountManager(HorizonClient horizonClient, string initialProfileName = null)
|
||||
{
|
||||
_horizonClient = horizonClient;
|
||||
|
||||
@@ -43,7 +44,14 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||
}
|
||||
else
|
||||
{
|
||||
OpenUser(_accountSaveDataManager.LastOpened);
|
||||
UserId commandLineUserProfileOverride = default;
|
||||
if (!string.IsNullOrEmpty(initialProfileName))
|
||||
{
|
||||
commandLineUserProfileOverride = _profiles.Values.FirstOrDefault(x => x.Name == initialProfileName)?.UserId ?? default;
|
||||
if (commandLineUserProfileOverride.IsNull)
|
||||
Logger.Warning?.Print(LogClass.Application, $"The command line specified profile named '{initialProfileName}' was not found");
|
||||
}
|
||||
OpenUser(commandLineUserProfileOverride.IsNull ? _accountSaveDataManager.LastOpened : commandLineUserProfileOverride);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,8 +176,8 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||
|
||||
private void DeleteSaveData(UserId userId)
|
||||
{
|
||||
SaveDataFilter saveDataFilter = new SaveDataFilter();
|
||||
saveDataFilter.SetUserId(new LibHac.Fs.UserId((ulong)userId.High, (ulong)userId.Low));
|
||||
var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: default,
|
||||
new LibHac.Fs.UserId((ulong)userId.High, (ulong)userId.Low), saveDataId: default, index: default);
|
||||
|
||||
using var saveDataIterator = new UniqueRef<SaveDataIterator>();
|
||||
|
||||
|
@@ -169,7 +169,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||
// TODO: Account actually calls nn::arp::detail::IReader::GetApplicationControlProperty() with the current Pid and store the result (NACP file) internally.
|
||||
// But since we use LibHac and we load one Application at a time, it's not necessary.
|
||||
|
||||
context.ResponseData.Write(context.Device.Application.ControlData.Value.UserAccountSwitchLock);
|
||||
context.ResponseData.Write((byte)context.Device.Application.ControlData.Value.UserAccountSwitchLock);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
|
||||
|
||||
|
@@ -131,7 +131,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||
}
|
||||
|
||||
HorizonClient hos = context.Device.System.LibHacHorizonManager.AmClient;
|
||||
Result result = EnsureApplicationSaveData(hos.Fs, out long requiredSize, applicationId, ref control, ref userId);
|
||||
Result result = hos.Fs.EnsureApplicationSaveData(out long requiredSize, applicationId, in control, in userId);
|
||||
|
||||
context.ResponseData.Write(requiredSize);
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||
// TODO: When above calls are implemented, switch to using ns:am
|
||||
|
||||
long desiredLanguageCode = context.Device.System.State.DesiredLanguageCode;
|
||||
int supportedLanguages = (int)context.Device.Application.ControlData.Value.SupportedLanguages;
|
||||
int supportedLanguages = (int)context.Device.Application.ControlData.Value.SupportedLanguageFlag;
|
||||
int firstSupported = BitOperations.TrailingZeroCount(supportedLanguages);
|
||||
|
||||
if (firstSupported > (int)SystemState.TitleLanguage.BrazilianPortuguese)
|
||||
@@ -190,7 +190,6 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||
// GetDisplayVersion() -> nn::oe::DisplayVersion
|
||||
public ResultCode GetDisplayVersion(ServiceCtx context)
|
||||
{
|
||||
// This should work as DisplayVersion U8Span always gives a 0x10 size byte array.
|
||||
// If an NACP isn't found, the buffer will be all '\0' which seems to be the correct implementation.
|
||||
context.ResponseData.Write(context.Device.Application.ControlData.Value.DisplayVersion);
|
||||
|
||||
@@ -252,7 +251,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||
BlitStruct<ApplicationControlProperty> controlHolder = context.Device.Application.ControlData;
|
||||
|
||||
Result result = _horizon.Fs.CreateApplicationCacheStorage(out long requiredSize,
|
||||
out CacheStorageTargetMedia storageTarget, applicationId, ref controlHolder.Value, index, saveSize,
|
||||
out CacheStorageTargetMedia storageTarget, applicationId, in controlHolder.Value, index, saveSize,
|
||||
journalSize);
|
||||
|
||||
if (result.IsFailure()) return (ResultCode)result.Value;
|
||||
|
@@ -16,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Arp
|
||||
{
|
||||
launchProperty = new LibHac.Arp.ApplicationLaunchProperty
|
||||
{
|
||||
BaseStorageId = StorageId.BuiltInUser,
|
||||
StorageId = StorageId.BuiltInUser,
|
||||
ApplicationId = ApplicationId
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Ryujinx.HLE.HOS.Services.Arp
|
||||
{
|
||||
launchProperty = new LibHac.Arp.ApplicationLaunchProperty
|
||||
{
|
||||
BaseStorageId = StorageId.BuiltInUser,
|
||||
StorageId = StorageId.BuiltInUser,
|
||||
ApplicationId = applicationId
|
||||
};
|
||||
|
||||
|
@@ -132,22 +132,10 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
||||
}
|
||||
}
|
||||
|
||||
public static Result ReadFsPath(out FsPath path, ServiceCtx context, int index = 0)
|
||||
{
|
||||
ulong position = context.Request.PtrBuff[index].Position;
|
||||
ulong size = context.Request.PtrBuff[index].Size;
|
||||
|
||||
byte[] pathBytes = new byte[size];
|
||||
|
||||
context.Memory.Read(position, pathBytes);
|
||||
|
||||
return FsPath.FromSpan(out path, pathBytes);
|
||||
}
|
||||
|
||||
public static ref readonly FspPath GetFspPath(ServiceCtx context, int index = 0)
|
||||
{
|
||||
ulong position = (ulong)context.Request.PtrBuff[index].Position;
|
||||
ulong size = (ulong)context.Request.PtrBuff[index].Size;
|
||||
ulong position = context.Request.PtrBuff[index].Position;
|
||||
ulong size = context.Request.PtrBuff[index].Size;
|
||||
|
||||
ReadOnlySpan<byte> buffer = context.Memory.GetSpan(position, (int)size);
|
||||
ReadOnlySpan<FspPath> fspBuffer = MemoryMarshal.Cast<byte, FspPath>(buffer);
|
||||
@@ -157,8 +145,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
||||
|
||||
public static ref readonly LibHac.FsSrv.Sf.Path GetSfPath(ServiceCtx context, int index = 0)
|
||||
{
|
||||
ulong position = (ulong)context.Request.PtrBuff[index].Position;
|
||||
ulong size = (ulong)context.Request.PtrBuff[index].Size;
|
||||
ulong position = context.Request.PtrBuff[index].Position;
|
||||
ulong size = context.Request.PtrBuff[index].Size;
|
||||
|
||||
ReadOnlySpan<byte> buffer = context.Memory.GetSpan(position, (int)size);
|
||||
ReadOnlySpan<LibHac.FsSrv.Sf.Path> pathBuffer = MemoryMarshal.Cast<byte, LibHac.FsSrv.Sf.Path>(buffer);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
using LibHac;
|
||||
using LibHac.Common;
|
||||
using LibHac.FsSrv;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Fs
|
||||
{
|
||||
|
@@ -1,8 +1,9 @@
|
||||
using LibHac.Ns;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Services.Arp;
|
||||
using System;
|
||||
|
||||
using static LibHac.Ns.ApplicationControlProperty;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory
|
||||
{
|
||||
class IParentalControlService : IpcService
|
||||
@@ -52,8 +53,8 @@ namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory
|
||||
_titleId = titleId;
|
||||
|
||||
// TODO: Call nn::arp::GetApplicationControlProperty here when implemented, if it return ResultCode.Success we assign fields.
|
||||
_ratingAge = Array.ConvertAll(context.Device.Application.ControlData.Value.RatingAge.ToArray(), Convert.ToInt32);
|
||||
_parentalControlFlag = context.Device.Application.ControlData.Value.ParentalControl;
|
||||
_ratingAge = Array.ConvertAll(context.Device.Application.ControlData.Value.RatingAge.ItemsRo.ToArray(), Convert.ToInt32);
|
||||
_parentalControlFlag = context.Device.Application.ControlData.Value.ParentalControlFlag;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,7 +225,7 @@ namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory
|
||||
private ResultCode IsStereoVisionPermittedImpl()
|
||||
{
|
||||
/*
|
||||
// TODO: Application Exemptions are readed from file "appExemptions.dat" in the service savedata.
|
||||
// TODO: Application Exemptions are read from file "appExemptions.dat" in the service savedata.
|
||||
// Since we don't support the pctl savedata for now, this can be implemented later.
|
||||
|
||||
if (appExemption)
|
||||
|
@@ -15,6 +15,8 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
||||
|
||||
internal static ResultCode GetPlayStatistics(ServiceCtx context, bool byUserId = false)
|
||||
{
|
||||
ref readonly var controlProperty = ref context.Device.Application.ControlData.Value;
|
||||
|
||||
ulong inputPosition = context.Request.SendBuff[0].Position;
|
||||
ulong inputSize = context.Request.SendBuff[0].Size;
|
||||
|
||||
@@ -31,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
||||
}
|
||||
}
|
||||
|
||||
PlayLogQueryCapability queryCapability = (PlayLogQueryCapability)context.Device.Application.ControlData.Value.PlayLogQueryCapability;
|
||||
PlayLogQueryCapability queryCapability = (PlayLogQueryCapability)controlProperty.PlayLogQueryCapability;
|
||||
|
||||
List<ulong> titleIds = new List<ulong>();
|
||||
|
||||
@@ -45,7 +47,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
||||
// Check if input title ids are in the whitelist.
|
||||
foreach (ulong titleId in titleIds)
|
||||
{
|
||||
if (!context.Device.Application.ControlData.Value.PlayLogQueryableApplicationId.Contains(titleId))
|
||||
if (!controlProperty.PlayLogQueryableApplicationId.ItemsRo.Contains(titleId))
|
||||
{
|
||||
return (ResultCode)Am.ResultCode.ObjectInvalid;
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
using LibHac.Common;
|
||||
using LibHac.Common.FixedArrays;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Loader;
|
||||
using LibHac.Tools.FsSystem;
|
||||
@@ -26,8 +26,8 @@ namespace Ryujinx.HLE.Loaders.Executables
|
||||
public uint DataSize { get; }
|
||||
public uint BssSize { get; }
|
||||
|
||||
public string Name;
|
||||
public Buffer32 BuildId;
|
||||
public string Name;
|
||||
public Array32<byte> BuildId;
|
||||
|
||||
public NsoExecutable(IStorage inStorage, string name = null)
|
||||
{
|
||||
|
@@ -19,7 +19,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Concentus" Version="1.1.7" />
|
||||
<PackageReference Include="LibHac" Version="0.15.0" />
|
||||
<PackageReference Include="LibHac" Version="0.16.0" />
|
||||
<PackageReference Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||
|
@@ -310,7 +310,7 @@ namespace Ryujinx.Headless.SDL2
|
||||
{
|
||||
controllerConfig.RangeLeft = 1.0f;
|
||||
controllerConfig.RangeRight = 1.0f;
|
||||
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} stick range reset. Save the profile now to update your configuration");
|
||||
}
|
||||
}
|
||||
@@ -396,7 +396,7 @@ namespace Ryujinx.Headless.SDL2
|
||||
if ((bool)option.EnableFileLog)
|
||||
{
|
||||
Logger.AddTarget(new AsyncLogTargetWrapper(
|
||||
new FileLogTarget(AppDomain.CurrentDomain.BaseDirectory, "file"),
|
||||
new FileLogTarget(ReleaseInformations.GetBaseApplicationDirectory(), "file"),
|
||||
1000,
|
||||
AsyncLogTargetOverflowAction.Block
|
||||
));
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@@ -81,7 +82,7 @@ namespace Ryujinx.SDL2.Common
|
||||
|
||||
SDL_EventState(SDL_EventType.SDL_CONTROLLERSENSORUPDATE, SDL_DISABLE);
|
||||
|
||||
string gamepadDbPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SDL_GameControllerDB.txt");
|
||||
string gamepadDbPath = Path.Combine(ReleaseInformations.GetBaseApplicationDirectory(), "SDL_GameControllerDB.txt");
|
||||
|
||||
if (File.Exists(gamepadDbPath))
|
||||
{
|
||||
|
@@ -80,7 +80,7 @@ namespace Ryujinx.Configuration
|
||||
if (e.NewValue)
|
||||
{
|
||||
Logger.AddTarget(new AsyncLogTargetWrapper(
|
||||
new FileLogTarget(AppDomain.CurrentDomain.BaseDirectory, "file"),
|
||||
new FileLogTarget(ReleaseInformations.GetBaseApplicationDirectory(), "file"),
|
||||
1000,
|
||||
AsyncLogTargetOverflowAction.Block
|
||||
));
|
||||
|
@@ -311,7 +311,7 @@ namespace Ryujinx.Modules
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, e.Message);
|
||||
Logger.Warning?.Print(LogClass.Application, $"Multi-Threaded update failed, falling back to single-threaded updater.");
|
||||
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
|
||||
|
||||
DoUpdateWithSingleThread(updateDialog, downloadUrl, updateFile);
|
||||
|
||||
@@ -327,8 +327,8 @@ namespace Ryujinx.Modules
|
||||
catch (WebException ex)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, ex.Message);
|
||||
Logger.Warning?.Print(LogClass.Application, $"Multi-Threaded update failed, falling back to single-threaded updater.");
|
||||
|
||||
Logger.Warning?.Print(LogClass.Application, "Multi-Threaded update failed, falling back to single-threaded updater.");
|
||||
|
||||
for (int j = 0; j < webClients.Count; j++)
|
||||
{
|
||||
webClients[j].CancelAsync();
|
||||
@@ -567,7 +567,14 @@ namespace Ryujinx.Modules
|
||||
#else
|
||||
if (showWarnings)
|
||||
{
|
||||
GtkDialog.CreateWarningDialog("Updater Disabled!", "Please download Ryujinx at https://ryujinx.org/ if you are looking for a supported version.");
|
||||
if (ReleaseInformations.IsFlatHubBuild())
|
||||
{
|
||||
GtkDialog.CreateWarningDialog("Updater Disabled!", "Please update Ryujinx via FlatHub.");
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkDialog.CreateWarningDialog("Updater Disabled!", "Please download Ryujinx at https://ryujinx.org/ if you are looking for a supported version.");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@@ -27,6 +27,8 @@ namespace Ryujinx
|
||||
|
||||
public static string ConfigurationPath { get; set; }
|
||||
|
||||
public static string CommandLineProfile { get; set; }
|
||||
|
||||
[DllImport("libX11")]
|
||||
private extern static int XInitThreads();
|
||||
|
||||
@@ -52,6 +54,17 @@ namespace Ryujinx
|
||||
|
||||
baseDirPathArg = args[++i];
|
||||
}
|
||||
else if (arg == "-p" || arg == "--profile")
|
||||
{
|
||||
if (i + 1 >= args.Length)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
CommandLineProfile = args[++i];
|
||||
}
|
||||
else if (arg == "-f" || arg == "--fullscreen")
|
||||
{
|
||||
startFullscreenArg = true;
|
||||
|
@@ -558,10 +558,10 @@ namespace Ryujinx.Ui.App
|
||||
{
|
||||
_ = Enum.TryParse(_desiredTitleLanguage.ToString(), out TitleLanguage desiredTitleLanguage);
|
||||
|
||||
if (controlData.Titles.Length > (int)desiredTitleLanguage)
|
||||
if (controlData.Title.ItemsRo.Length > (int)desiredTitleLanguage)
|
||||
{
|
||||
titleName = controlData.Titles[(int)desiredTitleLanguage].Name.ToString();
|
||||
publisher = controlData.Titles[(int)desiredTitleLanguage].Publisher.ToString();
|
||||
titleName = controlData.Title[(int)desiredTitleLanguage].NameString.ToString();
|
||||
publisher = controlData.Title[(int)desiredTitleLanguage].PublisherString.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -571,11 +571,11 @@ namespace Ryujinx.Ui.App
|
||||
|
||||
if (string.IsNullOrWhiteSpace(titleName))
|
||||
{
|
||||
foreach (ApplicationControlTitle controlTitle in controlData.Titles)
|
||||
foreach (ref readonly var controlTitle in controlData.Title.ItemsRo)
|
||||
{
|
||||
if (!((U8Span)controlTitle.Name).IsEmpty())
|
||||
if (!controlTitle.NameString.IsEmpty())
|
||||
{
|
||||
titleName = controlTitle.Name.ToString();
|
||||
titleName = controlTitle.NameString.ToString();
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -584,11 +584,11 @@ namespace Ryujinx.Ui.App
|
||||
|
||||
if (string.IsNullOrWhiteSpace(publisher))
|
||||
{
|
||||
foreach (ApplicationControlTitle controlTitle in controlData.Titles)
|
||||
foreach (ref readonly var controlTitle in controlData.Title.ItemsRo)
|
||||
{
|
||||
if (!((U8Span)controlTitle.Publisher).IsEmpty())
|
||||
if (!controlTitle.PublisherString.IsEmpty())
|
||||
{
|
||||
publisher = controlTitle.Publisher.ToString();
|
||||
publisher = controlTitle.PublisherString.ToString();
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -599,7 +599,7 @@ namespace Ryujinx.Ui.App
|
||||
{
|
||||
titleId = controlData.PresenceGroupId.ToString("x16");
|
||||
}
|
||||
else if (controlData.SaveDataOwnerId.Value != 0)
|
||||
else if (controlData.SaveDataOwnerId != 0)
|
||||
{
|
||||
titleId = controlData.SaveDataOwnerId.ToString();
|
||||
}
|
||||
@@ -612,7 +612,7 @@ namespace Ryujinx.Ui.App
|
||||
titleId = "0000000000000000";
|
||||
}
|
||||
|
||||
version = controlData.DisplayVersion.ToString();
|
||||
version = controlData.DisplayVersionString.ToString();
|
||||
}
|
||||
|
||||
private bool IsUpdateApplied(string titleId, out IFileSystem updatedControlFs)
|
||||
|
@@ -178,7 +178,7 @@ namespace Ryujinx.Ui
|
||||
VirtualFileSystem.FixExtraData(_libHacHorizonManager.RyujinxClient);
|
||||
|
||||
_contentManager = new ContentManager(_virtualFileSystem);
|
||||
_accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient);
|
||||
_accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient, Program.CommandLineProfile);
|
||||
_userChannelPersistence = new UserChannelPersistence();
|
||||
|
||||
// Instantiate GUI objects.
|
||||
@@ -1291,7 +1291,7 @@ namespace Ryujinx.Ui
|
||||
|
||||
private void OpenLogsFolder_Pressed(object sender, EventArgs args)
|
||||
{
|
||||
string logPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs");
|
||||
string logPath = System.IO.Path.Combine(ReleaseInformations.GetBaseApplicationDirectory(), "Logs");
|
||||
|
||||
new DirectoryInfo(logPath).Create();
|
||||
|
||||
|
@@ -6,7 +6,6 @@ using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.Fs.Shim;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Ncm;
|
||||
using LibHac.Ns;
|
||||
using LibHac.Tools.Fs;
|
||||
using LibHac.Tools.FsSystem;
|
||||
@@ -26,8 +25,6 @@ using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
||||
using static LibHac.Fs.ApplicationSaveDataManagement;
|
||||
|
||||
namespace Ryujinx.Ui.Widgets
|
||||
{
|
||||
public partial class GameTableContextMenu : Menu
|
||||
@@ -81,7 +78,7 @@ namespace Ryujinx.Ui.Widgets
|
||||
PopupAtPointer(null);
|
||||
}
|
||||
|
||||
private bool TryFindSaveData(string titleName, ulong titleId, BlitStruct<ApplicationControlProperty> controlHolder, SaveDataFilter filter, out ulong saveDataId)
|
||||
private bool TryFindSaveData(string titleName, ulong titleId, BlitStruct<ApplicationControlProperty> controlHolder, in SaveDataFilter filter, out ulong saveDataId)
|
||||
{
|
||||
saveDataId = default;
|
||||
|
||||
@@ -121,7 +118,7 @@ namespace Ryujinx.Ui.Widgets
|
||||
|
||||
Uid user = new Uid((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low);
|
||||
|
||||
result = EnsureApplicationSaveData(_horizonClient.Fs, out _, new LibHac.Ncm.ApplicationId(titleId), ref control, ref user);
|
||||
result = _horizonClient.Fs.EnsureApplicationSaveData(out _, new LibHac.Ncm.ApplicationId(titleId), in control, in user);
|
||||
|
||||
if (result.IsFailure())
|
||||
{
|
||||
@@ -146,11 +143,9 @@ namespace Ryujinx.Ui.Widgets
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OpenSaveDir(SaveDataFilter saveDataFilter)
|
||||
private void OpenSaveDir(in SaveDataFilter saveDataFilter)
|
||||
{
|
||||
saveDataFilter.SetProgramId(new ProgramId(_titleId));
|
||||
|
||||
if (!TryFindSaveData(_titleName, _titleId, _controlData, saveDataFilter, out ulong saveDataId))
|
||||
if (!TryFindSaveData(_titleName, _titleId, _controlData, in saveDataFilter, out ulong saveDataId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -439,26 +434,24 @@ namespace Ryujinx.Ui.Widgets
|
||||
//
|
||||
private void OpenSaveUserDir_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
SaveDataFilter saveDataFilter = new SaveDataFilter();
|
||||
saveDataFilter.SetUserId(new LibHac.Fs.UserId((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low));
|
||||
var userId = new LibHac.Fs.UserId((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low);
|
||||
var saveDataFilter = SaveDataFilter.Make(_titleId, saveType: default, userId, saveDataId: default, index: default);
|
||||
|
||||
OpenSaveDir(saveDataFilter);
|
||||
OpenSaveDir(in saveDataFilter);
|
||||
}
|
||||
|
||||
private void OpenSaveDeviceDir_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
SaveDataFilter saveDataFilter = new SaveDataFilter();
|
||||
saveDataFilter.SetSaveDataType(SaveDataType.Device);
|
||||
var saveDataFilter = SaveDataFilter.Make(_titleId, SaveDataType.Device, userId: default, saveDataId: default, index: default);
|
||||
|
||||
OpenSaveDir(saveDataFilter);
|
||||
OpenSaveDir(in saveDataFilter);
|
||||
}
|
||||
|
||||
private void OpenSaveBcatDir_Clicked(object sender, EventArgs args)
|
||||
{
|
||||
SaveDataFilter saveDataFilter = new SaveDataFilter();
|
||||
saveDataFilter.SetSaveDataType(SaveDataType.Bcat);
|
||||
var saveDataFilter = SaveDataFilter.Make(_titleId, SaveDataType.Bcat, userId: default, saveDataId: default, index: default);
|
||||
|
||||
OpenSaveDir(saveDataFilter);
|
||||
OpenSaveDir(in saveDataFilter);
|
||||
}
|
||||
|
||||
private void ManageTitleUpdates_Clicked(object sender, EventArgs args)
|
||||
|
@@ -105,7 +105,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();
|
||||
|
||||
RadioButton radioButton = new RadioButton($"Version {controlData.DisplayVersion.ToString()} - {path}");
|
||||
RadioButton radioButton = new RadioButton($"Version {controlData.DisplayVersionString.ToString()} - {path}");
|
||||
radioButton.JoinGroup(_noUpdateRadioButton);
|
||||
|
||||
_availableUpdatesBox.Add(radioButton);
|
||||
|
1
distribution/linux/ryujinx-logo.svg
Normal file
1
distribution/linux/ryujinx-logo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 255.76 255.76"><defs><style>.cls-1{fill:#02c5e5;}.cls-2{fill:#ff5f55;}.cls-3{fill:none;}</style></defs><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><g id="Ebene_2-2" data-name="Ebene 2"><g id="Ebene_1-2-2" data-name="Ebene 1-2"><path class="cls-1" d="M80.63,0V220.39H44.37c-14,0-35.74-20.74-35.74-39.13V40.13C8.63,19.19,31.36,0,49.06,0Z"/><path class="cls-2" d="M175.13,35.37V255.76h36.26c14,0,35.74-20.74,35.74-39.13V75.5c0-20.94-22.73-40.13-40.43-40.13Z"/><polygon class="cls-1" points="124.34 137.96 122.58 145.57 90.64 145.57 92.89 137.96 124.34 137.96"/><polygon class="cls-2" points="160.29 137.96 157.84 145.57 122.58 145.57 124.34 137.96 160.29 137.96"/><polygon class="cls-1" points="130.39 111.86 128.62 119.47 95.14 119.47 97.39 111.86 130.39 111.86"/><polygon class="cls-2" points="164.79 111.86 162.34 119.47 128.62 119.47 130.39 111.86 164.79 111.86"/><polygon class="cls-1" points="104.24 167.99 122.83 87.77 129.78 87.77 111.19 167.99 104.24 167.99"/><polygon class="cls-2" points="128.18 167.99 146.77 87.77 153.89 87.77 135.3 167.99 128.18 167.99"/></g><rect class="cls-3" width="255.76" height="255.76"/></g></g></g></svg>
|
After Width: | Height: | Size: 1.2 KiB |
23
distribution/linux/ryujinx-mime.xml
Normal file
23
distribution/linux/ryujinx-mime.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
|
||||
<mime-type type="application/x-nx-nca">
|
||||
<comment>Nintendo Content Archive</comment>
|
||||
<glob pattern="*.nca"/>
|
||||
</mime-type>
|
||||
<mime-type type="application/x-nx-nro">
|
||||
<comment>Nintendo Relocatable Object</comment>
|
||||
<glob pattern="*.nro"/>
|
||||
</mime-type>
|
||||
<mime-type type="application/x-nx-nso">
|
||||
<comment>Nintendo Shared Object</comment>
|
||||
<glob pattern="*.nso"/>
|
||||
</mime-type>
|
||||
<mime-type type="application/x-nx-nsp">
|
||||
<comment>Nintendo Submission Package</comment>
|
||||
<glob pattern="*.nsp"/>
|
||||
</mime-type>
|
||||
<mime-type type="application/x-nx-xci">
|
||||
<comment>Nintendo Switch Cartridge</comment>
|
||||
<glob pattern="*.xci"/>
|
||||
</mime-type>
|
||||
</mime-info>
|
14
distribution/linux/ryujinx.desktop
Normal file
14
distribution/linux/ryujinx.desktop
Normal file
@@ -0,0 +1,14 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Name=Ryujinx
|
||||
Comment=A Nintendo Switch Emulator
|
||||
Type=Application
|
||||
GenericName=Nintendo Switch Emulator
|
||||
Icon=ryujinx
|
||||
Terminal=false
|
||||
Exec=Ryujinx %f
|
||||
Categories=Game;Emulator;GTK;
|
||||
MimeType=application/x-nx-nca;application/x-nx-nro;application/x-nx-nso;application/x-nx-nsp;application/x-nx-xci;
|
||||
Keywords=Switch;Nintendo;Emulator;
|
||||
StartupWMClass=Ryujinx
|
||||
PrefersNonDefaultGPU=true
|
Reference in New Issue
Block a user