Compare commits
3 Commits
Canary-1.2
...
9cfec4dde3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9cfec4dde3 | ||
|
|
0bf3191262 | ||
|
|
7ab8ebca21 |
@@ -20,4 +20,42 @@ if command -v gamemoderun > /dev/null 2>&1; then
|
||||
COMMAND="$COMMAND gamemoderun"
|
||||
fi
|
||||
|
||||
exec $COMMAND "$SCRIPT_DIR/$RYUJINX_BIN" "$@"
|
||||
# Check if user already has a manual Avalonia scaling override or session type is x11.
|
||||
if [[ -n "${AVALONIA_GLOBAL_SCALE_FACTOR-}" || "$(echo "$XDG_SESSION_TYPE")" == "x11" ]]; then
|
||||
echo "Scaling: Performed by environment, skipping." >&2
|
||||
else
|
||||
# Query monitor config directly (GNOME), default display only.
|
||||
if [[ "$(echo "$XDG_CURRENT_DESKTOP")" == "GNOME" && -f ~/.config/monitors.xml ]] then
|
||||
echo -n 'Scaling: Monitor config located, querying scale...' >&2
|
||||
SCALING="$(grep '<scale' ~/.config/monitors.xml -m 1 | cut -f2 -d">"|cut -f1 -d"<")"
|
||||
SCALING="${SCALING##* }"
|
||||
echo "found! Factor: ${SCALING}" >&2
|
||||
|
||||
# Fallback to X DPI query for others.
|
||||
# Plasma handles this fine, GNOME will always round up e.g. 1.25 -> 2.00.
|
||||
elif command -v xrdb >/dev/null; then
|
||||
echo -n 'Scaling: Attempting to get scaling from X DPI value...' >&2
|
||||
dpi="$(xrdb -get Xft.dpi)"
|
||||
if [[ -n "${dpi}" ]]; then
|
||||
SCALING=$(echo "scale=2; ${dpi}/96" | bc)
|
||||
fi
|
||||
echo "found! Factor: ${SCALING}"
|
||||
|
||||
# Query kscreen-doctor for Plasma as a fallback.
|
||||
elif [[ "$(echo "$XDG_CURRENT_DESKTOP")" == "KDE" ]] && command -v kscreen-doctor >/dev/null; then
|
||||
echo -n 'Scaling: Attempting to get Plasma desktop scaling factor...' >&2
|
||||
SCALING="$(kscreen-doctor --outputs | grep "Scale" -m 1)"
|
||||
SCALING="${SCALING##* }"
|
||||
SCALING=$(echo $SCALING | sed 's/\x1B\[[0-9;]*m//g') # Trim ANSI chars from ksd output.
|
||||
echo "found! Factor: ${SCALING}"
|
||||
fi
|
||||
|
||||
if [[ -z "${SCALING-}" || "${SCALING-}" == "0" ]]; then
|
||||
echo 'Unset invalid scaling value' >&2
|
||||
SCALING="1"
|
||||
fi
|
||||
|
||||
COMMAND="$COMMAND AVALONIA_GLOBAL_SCALE_FACTOR=$SCALING"
|
||||
fi
|
||||
|
||||
exec $COMMAND "$SCRIPT_DIR/$RYUJINX_BIN" "$@"
|
||||
@@ -34,10 +34,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
{
|
||||
if (errorCode != LinuxError.SUCCESS)
|
||||
{
|
||||
if (errorCode != LinuxError.EWOULDBLOCK)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Operation failed with error {errorCode}.");
|
||||
}
|
||||
result = -1;
|
||||
}
|
||||
|
||||
@@ -70,8 +66,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
BsdSocketType type = (BsdSocketType)context.RequestData.ReadInt32();
|
||||
ProtocolType protocol = (ProtocolType)context.RequestData.ReadInt32();
|
||||
|
||||
Logger.Info?.PrintMsg(LogClass.ServiceBsd, $"Creating socket with domain={domain}, type={type}, protocol={protocol}");
|
||||
|
||||
BsdSocketCreationFlags creationFlags = (BsdSocketCreationFlags)((int)type >> (int)BsdSocketCreationFlags.FlagsShift);
|
||||
type &= BsdSocketType.TypeMask;
|
||||
|
||||
@@ -101,21 +95,12 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
}
|
||||
}
|
||||
|
||||
LinuxError errno = LinuxError.SUCCESS;
|
||||
ISocket newBsdSocket;
|
||||
ISocket newBsdSocket = new ManagedSocket(netDomain, (SocketType)type, protocol, context.Device.Configuration.MultiplayerLanInterfaceId)
|
||||
{
|
||||
Blocking = !creationFlags.HasFlag(BsdSocketCreationFlags.NonBlocking),
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
newBsdSocket = new ManagedSocket(netDomain, (SocketType)type, protocol, context.Device.Configuration.MultiplayerLanInterfaceId)
|
||||
{
|
||||
Blocking = !creationFlags.HasFlag(BsdSocketCreationFlags.NonBlocking),
|
||||
};
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
LinuxError errNo = WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
return WriteBsdResult(context, 0, errNo);
|
||||
}
|
||||
LinuxError errno = LinuxError.SUCCESS;
|
||||
|
||||
int newSockFd = _context.RegisterFileDescriptor(newBsdSocket);
|
||||
|
||||
@@ -126,7 +111,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
|
||||
if (exempt)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.ServiceBsd, "Disconnecting exempt socket.");
|
||||
newBsdSocket.Disconnect();
|
||||
}
|
||||
|
||||
@@ -813,11 +797,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
{
|
||||
errno = socket.Listen(backlog);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warning?.PrintMsg(LogClass.ServiceBsd, $"Invalid socket fd '{socketFd}'.");
|
||||
}
|
||||
|
||||
|
||||
return WriteBsdResult(context, 0, errno);
|
||||
}
|
||||
|
||||
|
||||
@@ -92,30 +92,18 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
{
|
||||
newSocket = new ManagedSocket(Socket.Accept());
|
||||
|
||||
IPEndPoint remoteEndPoint = newSocket.RemoteEndPoint;
|
||||
bool isPrivateIp = remoteEndPoint.Address.ToString().StartsWith("192.168.");
|
||||
Logger.Info?.PrintMsg(LogClass.ServiceBsd,
|
||||
isPrivateIp
|
||||
? $"Accepted connection from {ProtocolType}/{remoteEndPoint.Address}:{remoteEndPoint.Port}"
|
||||
: $"Accepted connection from {ProtocolType}/***:{remoteEndPoint.Port}");
|
||||
|
||||
return LinuxError.SUCCESS;
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
newSocket = null;
|
||||
|
||||
if (exception.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Socket Exception: {exception}");
|
||||
}
|
||||
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
}
|
||||
}
|
||||
|
||||
public LinuxError Bind(IPEndPoint localEndPoint)
|
||||
{
|
||||
Logger.Info?.PrintMsg(LogClass.ServiceBsd, $"Socket binding to: {ProtocolType}/{localEndPoint.Port}");
|
||||
try
|
||||
{
|
||||
Socket.Bind(localEndPoint);
|
||||
@@ -124,10 +112,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
if (exception.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Socket Exception: {exception}");
|
||||
}
|
||||
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
}
|
||||
}
|
||||
@@ -139,15 +123,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
|
||||
public LinuxError Connect(IPEndPoint remoteEndPoint)
|
||||
{
|
||||
bool isLDNPrivateIP = remoteEndPoint.Address.ToString().StartsWith("192.168.");
|
||||
if (isLDNPrivateIP)
|
||||
{
|
||||
Logger.Info?.PrintMsg(LogClass.ServiceBsd, $"Connecting to: {ProtocolType}/{remoteEndPoint.Address}:{remoteEndPoint.Port}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info?.PrintMsg(LogClass.ServiceBsd, $"Connecting to: {ProtocolType}/***:{remoteEndPoint.Port}");
|
||||
}
|
||||
try
|
||||
{
|
||||
Socket.Connect(remoteEndPoint);
|
||||
@@ -162,10 +137,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exception.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Socket Exception: {exception}");
|
||||
}
|
||||
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
}
|
||||
}
|
||||
@@ -173,13 +144,11 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
Logger.Info?.Print(LogClass.ServiceBsd, "Socket disconnecting");
|
||||
Socket.Disconnect(true);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Logger.Info?.Print(LogClass.ServiceBsd, "Socket closed");
|
||||
Socket.Close();
|
||||
Socket.Dispose();
|
||||
}
|
||||
@@ -190,16 +159,10 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
{
|
||||
Socket.Listen(backlog);
|
||||
|
||||
Logger.Info?.PrintMsg(LogClass.ServiceBsd, $"Socket listening: {ProtocolType}/{(Socket.LocalEndPoint as IPEndPoint).Port}");
|
||||
|
||||
return LinuxError.SUCCESS;
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
if (exception.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Socket Exception: {exception}");
|
||||
}
|
||||
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
}
|
||||
}
|
||||
@@ -219,15 +182,11 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
if (exception.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Socket Exception: {exception}");
|
||||
}
|
||||
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _hasEmittedBlockingWarning;
|
||||
bool hasEmittedBlockingWarning = false;
|
||||
|
||||
public LinuxError Receive(out int receiveSize, Span<byte> buffer, BsdSocketFlags flags)
|
||||
{
|
||||
@@ -243,10 +202,10 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
shouldBlockAfterOperation = true;
|
||||
}
|
||||
|
||||
if (Blocking && !_hasEmittedBlockingWarning)
|
||||
if (Blocking && !hasEmittedBlockingWarning)
|
||||
{
|
||||
Logger.Warning?.PrintMsg(LogClass.ServiceBsd, "Blocking socket operations are not yet working properly. Expect network errors.");
|
||||
_hasEmittedBlockingWarning = true;
|
||||
hasEmittedBlockingWarning = true;
|
||||
}
|
||||
|
||||
receiveSize = Socket.Receive(buffer, ConvertBsdSocketFlags(flags));
|
||||
@@ -255,10 +214,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
if (exception.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Socket Exception: {exception}");
|
||||
}
|
||||
receiveSize = -1;
|
||||
|
||||
result = WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
@@ -290,10 +245,10 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
shouldBlockAfterOperation = true;
|
||||
}
|
||||
|
||||
if (Blocking && !_hasEmittedBlockingWarning)
|
||||
if (Blocking && !hasEmittedBlockingWarning)
|
||||
{
|
||||
Logger.Warning?.PrintMsg(LogClass.ServiceBsd, "Blocking socket operations are not yet working properly. Expect network errors.");
|
||||
_hasEmittedBlockingWarning = true;
|
||||
hasEmittedBlockingWarning = true;
|
||||
}
|
||||
|
||||
if (!Socket.IsBound)
|
||||
@@ -310,10 +265,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
if (exception.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Socket Exception: {exception}");
|
||||
}
|
||||
receiveSize = -1;
|
||||
|
||||
result = WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
@@ -337,10 +288,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
if (exception.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Socket Exception: {exception}");
|
||||
}
|
||||
sendSize = -1;
|
||||
|
||||
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
@@ -357,10 +304,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
if (exception.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Socket Exception: {exception}");
|
||||
}
|
||||
sendSize = -1;
|
||||
|
||||
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
@@ -398,10 +341,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
if (exception.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Socket Exception: {exception}");
|
||||
}
|
||||
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
}
|
||||
}
|
||||
@@ -448,10 +387,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
if (exception.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Socket Exception: {exception}");
|
||||
}
|
||||
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
}
|
||||
}
|
||||
@@ -584,10 +519,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
if (exception.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Socket Exception: {exception}");
|
||||
}
|
||||
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
}
|
||||
}
|
||||
@@ -626,10 +557,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
|
||||
}
|
||||
catch (SocketException exception)
|
||||
{
|
||||
if (exception.SocketErrorCode != SocketError.WouldBlock)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceBsd, $"Socket Exception: {exception}");
|
||||
}
|
||||
return WinSockHelper.ConvertError((WsaError)exception.ErrorCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnRyu.Proxy;
|
||||
using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -66,18 +64,10 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Proxy
|
||||
{
|
||||
if (_proxy.Supported(domain, type, protocol))
|
||||
{
|
||||
Logger.Info?.PrintMsg(LogClass.ServiceBsd, $"Socket is using LDN proxy");
|
||||
return new LdnProxySocket(domain, type, protocol, _proxy);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Warning?.PrintMsg(LogClass.ServiceBsd, $"LDN proxy does not support socket {domain}, {type}, {protocol}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Info?.PrintMsg(LogClass.ServiceBsd, $"Opening socket using host networking stack");
|
||||
}
|
||||
|
||||
return new DefaultSocket(domain, type, protocol, lanInterfaceId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,31 +447,6 @@
|
||||
"zh_TW": "開啟 Ryujinx 資料夾"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarFileOpenScreenshotsFolder",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "Open Screenshots Folder",
|
||||
"es_ES": "",
|
||||
"fr_FR": "",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarFileOpenLogsFolder",
|
||||
"Translations": {
|
||||
@@ -17222,31 +17197,6 @@
|
||||
"zh_TW": "開啟 Ryujinx 檔案系統資料夾"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "OpenScreenshotFolderTooltip",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "Open Ryujinx screenshots folder",
|
||||
"es_ES": "",
|
||||
"fr_FR": "",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "OpenRyujinxLogsTooltip",
|
||||
"Translations": {
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
private static readonly string _description =
|
||||
ReleaseInformation.IsValid
|
||||
? $"{VersionString} {ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelSourceRepo}"
|
||||
? $"{VersionString} {ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelSourceRepo}@{ReleaseInformation.BuildGitHash}"
|
||||
: "dev build";
|
||||
|
||||
private const string ApplicationId = "1293250299716173864";
|
||||
@@ -56,7 +56,6 @@ namespace Ryujinx.Ava
|
||||
ConfigurationState.Instance.EnableDiscordIntegration.Event += Update;
|
||||
TitleIDs.CurrentApplication.Event += (_, e) => Use(e.NewValue);
|
||||
HorizonStatic.PlayReport += HandlePlayReport;
|
||||
PlayReports.Initialize();
|
||||
}
|
||||
|
||||
private static void Update(object sender, ReactiveEventArgs<bool> evnt)
|
||||
|
||||
@@ -119,23 +119,17 @@
|
||||
TextWrapping="Wrap" >
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Spacing="5" ToolTip.Tip="{Binding DynamicRichPresenceDescription}">
|
||||
<ui:SymbolIcon
|
||||
Foreground="ForestGreen"
|
||||
Symbol="Checkmark"
|
||||
IsVisible="{Binding AppData.HasDynamicRichPresenceSupport}"/>
|
||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||
<ui:SymbolIcon Foreground="ForestGreen" Symbol="Checkmark" IsVisible="{Binding AppData.HasDynamicRichPresenceSupport}"/>
|
||||
<TextBlock
|
||||
Foreground="ForestGreen"
|
||||
HorizontalAlignment="Stretch"
|
||||
IsVisible="{Binding AppData.HasDynamicRichPresenceSupport}"
|
||||
Text="{ext:Locale GameInfoRpcDynamic}"
|
||||
TextAlignment="Start"
|
||||
TextWrapping="Wrap">
|
||||
TextWrapping="Wrap" >
|
||||
</TextBlock>
|
||||
<ui:SymbolIcon
|
||||
Foreground="Red"
|
||||
Symbol="Cancel"
|
||||
IsVisible="{Binding !AppData.HasDynamicRichPresenceSupport}"/>
|
||||
<ui:SymbolIcon Foreground="Red" Symbol="Cancel" IsVisible="{Binding !AppData.HasDynamicRichPresenceSupport}"/>
|
||||
<TextBlock
|
||||
Foreground="Red"
|
||||
HorizontalAlignment="Stretch"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Gommon;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Utilities.AppLibrary;
|
||||
using Ryujinx.Ava.Utilities.PlayReport;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
@@ -11,11 +10,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
public ApplicationDataViewModel(ApplicationData appData) => AppData = appData;
|
||||
|
||||
public string DynamicRichPresenceDescription =>
|
||||
AppData.HasDynamicRichPresenceSupport
|
||||
? AppData.RichPresenceSpec.Value.Description
|
||||
: GameSpec.DefaultDescription;
|
||||
|
||||
public string FormattedVersion => LocaleManager.Instance[LocaleKeys.GameListHeaderVersion].Format(AppData.Version);
|
||||
public string FormattedDeveloper => LocaleManager.Instance[LocaleKeys.GameListHeaderDeveloper].Format(AppData.Developer);
|
||||
public string FormattedFileExtension => LocaleManager.Instance[LocaleKeys.GameListHeaderFileExtension].Format(AppData.FileExtension);
|
||||
|
||||
@@ -1347,25 +1347,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
OpenHelper.OpenFolder(AppDataManager.BaseDirPath);
|
||||
}
|
||||
|
||||
public void OpenScreenshotsFolder()
|
||||
{
|
||||
string screenshotsDir = Path.Combine(AppDataManager.BaseDirPath, "screenshots");
|
||||
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(screenshotsDir))
|
||||
Directory.CreateDirectory(screenshotsDir);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"Failed to create directory at path {screenshotsDir}. Error : {ex.GetType().Name}", "Screenshot");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
OpenHelper.OpenFolder(screenshotsDir);
|
||||
}
|
||||
|
||||
public void OpenLogsFolder()
|
||||
{
|
||||
string logPath = AppDataManager.GetOrCreateLogsDir();
|
||||
|
||||
@@ -66,10 +66,6 @@
|
||||
Command="{Binding OpenRyujinxFolder}"
|
||||
Header="{ext:Locale MenuBarFileOpenEmuFolder}"
|
||||
ToolTip.Tip="{ext:Locale OpenRyujinxFolderTooltip}" />
|
||||
<MenuItem
|
||||
Command="{Binding OpenScreenshotsFolder}"
|
||||
Header="{ext:Locale MenuBarFileOpenScreenshotsFolder}"
|
||||
ToolTip.Tip="{ext:Locale OpenScreenshotFolderTooltip}"/>
|
||||
<MenuItem
|
||||
Command="{Binding OpenLogsFolder}"
|
||||
Header="{ext:Locale MenuBarFileOpenLogsFolder}"
|
||||
|
||||
@@ -10,7 +10,6 @@ using LibHac.Tools.FsSystem;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Utilities.Compat;
|
||||
using Ryujinx.Ava.Utilities.PlayReport;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||
@@ -36,14 +35,9 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
||||
{
|
||||
_id = value;
|
||||
|
||||
Compatibility = CompatibilityCsv.Find(value);
|
||||
RichPresenceSpec = PlayReports.Analyzer.TryGetSpec(IdString, out GameSpec gameSpec)
|
||||
? gameSpec
|
||||
: default(Optional<GameSpec>);
|
||||
Compatibility = CompatibilityCsv.Find(Id);
|
||||
}
|
||||
}
|
||||
public Optional<GameSpec> RichPresenceSpec { get; set; }
|
||||
|
||||
public string Developer { get; set; } = "Unknown";
|
||||
public string Version { get; set; } = "0";
|
||||
public int PlayerCount { get; set; }
|
||||
@@ -52,7 +46,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
||||
public bool HasLdnGames => PlayerCount != 0 && GameCount != 0;
|
||||
|
||||
public bool HasRichPresenceAsset => DiscordIntegrationModule.HasAssetImage(IdString);
|
||||
public bool HasDynamicRichPresenceSupport => RichPresenceSpec.HasValue;
|
||||
public bool HasDynamicRichPresenceSupport => DiscordIntegrationModule.HasAnalyzer(IdString);
|
||||
|
||||
public TimeSpan TimePlayed { get; set; }
|
||||
public DateTime? LastPlayed { get; set; }
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Gommon;
|
||||
using Ryujinx.Ava.Utilities.AppLibrary;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
@@ -20,11 +19,6 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||
|
||||
public IReadOnlyList<GameSpec> Specs => new ReadOnlyCollection<GameSpec>(_specs);
|
||||
|
||||
public GameSpec GetSpec(string titleId) => _specs.First(x => x.TitleIds.ContainsIgnoreCase(titleId));
|
||||
|
||||
public bool TryGetSpec(string titleId, out GameSpec gameSpec)
|
||||
=> (gameSpec = _specs.FirstOrDefault(x => x.TitleIds.ContainsIgnoreCase(titleId))) != null;
|
||||
|
||||
/// <summary>
|
||||
/// Add an analysis spec matching a specific game by title ID, with the provided spec configuration.
|
||||
/// </summary>
|
||||
@@ -33,12 +27,10 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||
/// <returns>The current <see cref="Analyzer"/>, for chaining convenience.</returns>
|
||||
public Analyzer AddSpec(string titleId, Func<GameSpec, GameSpec> transform)
|
||||
{
|
||||
if (ulong.TryParse(titleId, NumberStyles.HexNumber, null, out _))
|
||||
return AddSpec(transform(GameSpec.Create(titleId)));
|
||||
Guard.Ensure(ulong.TryParse(titleId, NumberStyles.HexNumber, null, out _),
|
||||
$"Cannot use a non-hexadecimal string as the Title ID for a {nameof(GameSpec)}.");
|
||||
|
||||
Logger.Notice.PrintMsg(LogClass.Application,
|
||||
$"Tried to add a {nameof(GameSpec)} with a non-hexadecimal title ID value. Input: '{titleId}'");
|
||||
return this;
|
||||
return AddSpec(transform(GameSpec.Create(titleId)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -49,12 +41,10 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||
/// <returns>The current <see cref="Analyzer"/>, for chaining convenience.</returns>
|
||||
public Analyzer AddSpec(string titleId, Action<GameSpec> transform)
|
||||
{
|
||||
if (ulong.TryParse(titleId, NumberStyles.HexNumber, null, out _))
|
||||
return AddSpec(GameSpec.Create(titleId).Apply(transform));
|
||||
Guard.Ensure(ulong.TryParse(titleId, NumberStyles.HexNumber, null, out _),
|
||||
$"Cannot use a non-hexadecimal string as the Title ID for a {nameof(GameSpec)}.");
|
||||
|
||||
Logger.Notice.PrintMsg(LogClass.Application,
|
||||
$"Tried to add a {nameof(GameSpec)} with a non-hexadecimal title ID value. Input: '{titleId}'");
|
||||
return this;
|
||||
return AddSpec(GameSpec.Create(titleId).Apply(transform));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -67,19 +57,10 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||
Func<GameSpec, GameSpec> transform)
|
||||
{
|
||||
string[] tids = titleIds.ToArray();
|
||||
if (tids.All(x => ulong.TryParse(x, NumberStyles.HexNumber, null, out _) && !string.IsNullOrEmpty(x)))
|
||||
return AddSpec(transform(GameSpec.Create(tids)));
|
||||
Guard.Ensure(tids.All(x => ulong.TryParse(x, NumberStyles.HexNumber, null, out _)),
|
||||
$"Cannot use a non-hexadecimal string as the Title ID for a {nameof(GameSpec)}.");
|
||||
|
||||
Logger.Notice.PrintMsg(LogClass.Application,
|
||||
$"Tried to add a {nameof(GameSpec)} with a non-hexadecimal title ID value. Input: '{
|
||||
tids.FormatCollection(
|
||||
x => x,
|
||||
separator: ", ",
|
||||
prefix: "[",
|
||||
suffix: "]"
|
||||
)
|
||||
}'");
|
||||
return this;
|
||||
return AddSpec(transform(GameSpec.Create(tids)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -91,21 +72,12 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||
public Analyzer AddSpec(IEnumerable<string> titleIds, Action<GameSpec> transform)
|
||||
{
|
||||
string[] tids = titleIds.ToArray();
|
||||
if (tids.All(x => ulong.TryParse(x, NumberStyles.HexNumber, null, out _) && !string.IsNullOrEmpty(x)))
|
||||
return AddSpec(GameSpec.Create(tids).Apply(transform));
|
||||
Guard.Ensure(tids.All(x => ulong.TryParse(x, NumberStyles.HexNumber, null, out _)),
|
||||
$"Cannot use a non-hexadecimal string as the Title ID for a {nameof(GameSpec)}.");
|
||||
|
||||
Logger.Notice.PrintMsg(LogClass.Application,
|
||||
$"Tried to add a {nameof(GameSpec)} with a non-hexadecimal title ID value. Input: '{
|
||||
tids.FormatCollection(
|
||||
x => x,
|
||||
separator: ", ",
|
||||
prefix: "[",
|
||||
suffix: "]"
|
||||
)
|
||||
}'");
|
||||
return this;
|
||||
return AddSpec(GameSpec.Create(tids).Apply(transform));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Add an analysis spec matching a specific game by title ID, with the provided pre-configured spec.
|
||||
/// </summary>
|
||||
@@ -133,13 +105,13 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||
{
|
||||
if (!playReport.ReportData.IsDictionary)
|
||||
return FormattedValue.Unhandled;
|
||||
|
||||
if (!TryGetSpec(runningGameId, out GameSpec spec))
|
||||
|
||||
if (!_specs.TryGetFirst(s => runningGameId.EqualsAnyIgnoreCase(s.TitleIds), out GameSpec spec))
|
||||
return FormattedValue.Unhandled;
|
||||
|
||||
foreach (FormatterSpecBase formatSpec in spec.ValueFormatters.OrderBy(x => x.Priority))
|
||||
{
|
||||
if (!formatSpec.TryFormat(appMeta, playReport, out FormattedValue value))
|
||||
if (!formatSpec.Format(appMeta, playReport, out FormattedValue value))
|
||||
continue;
|
||||
|
||||
return value;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Gommon;
|
||||
using Humanizer;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
@@ -19,9 +18,6 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||
< -201d => "Exploring the Depths",
|
||||
_ => "Roaming Hyrule"
|
||||
};
|
||||
|
||||
private static FormattedValue SkywardSwordHD_Rupees(SingleValue value)
|
||||
=> "rupee".ToQuantity(value.Matched.IntValue);
|
||||
|
||||
private static FormattedValue SuperMarioOdyssey_AssistMode(SingleValue value)
|
||||
=> value.Matched.BoxedValue is 1 ? "Playing in Assist Mode" : "Playing in Regular Mode";
|
||||
|
||||
@@ -1,22 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.Utilities.PlayReport
|
||||
namespace Ryujinx.Ava.Utilities.PlayReport
|
||||
{
|
||||
public static partial class PlayReports
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
// init lazy value
|
||||
_ = Analyzer;
|
||||
}
|
||||
|
||||
public static Analyzer Analyzer => _analyzerLazy.Value;
|
||||
|
||||
private static readonly Lazy<Analyzer> _analyzerLazy = new(() => new Analyzer()
|
||||
public static Analyzer Analyzer { get; } = new Analyzer()
|
||||
.AddSpec(
|
||||
"01007ef00011e000",
|
||||
spec => spec
|
||||
.WithDescription("based on being in Master Mode.")
|
||||
.AddValueFormatter("IsHardMode", BreathOfTheWild_MasterMode)
|
||||
// reset to normal status when switching between normal & master mode in title screen
|
||||
.AddValueFormatter("AoCVer", FormattedValue.SingleAlwaysResets)
|
||||
@@ -24,49 +13,34 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||
.AddSpec(
|
||||
"0100f2c0115b6000",
|
||||
spec => spec
|
||||
.WithDescription("based on where you are in Hyrule (Depths, Surface, Sky).")
|
||||
.AddValueFormatter("PlayerPosY", TearsOfTheKingdom_CurrentField))
|
||||
.AddSpec(
|
||||
"01002da013484000",
|
||||
spec => spec
|
||||
.WithDescription("based on how many Rupees you have.")
|
||||
.AddValueFormatter("rupees", SkywardSwordHD_Rupees))
|
||||
.AddSpec(
|
||||
"0100000000010000",
|
||||
spec => spec
|
||||
.WithDescription("based on if you're playing with Assist Mode.")
|
||||
.AddValueFormatter("is_kids_mode", SuperMarioOdyssey_AssistMode)
|
||||
spec =>
|
||||
spec.AddValueFormatter("is_kids_mode", SuperMarioOdyssey_AssistMode)
|
||||
)
|
||||
.AddSpec(
|
||||
"010075000ecbe000",
|
||||
spec => spec
|
||||
.WithDescription("based on if you're playing with Assist Mode.")
|
||||
.AddValueFormatter("is_kids_mode", SuperMarioOdysseyChina_AssistMode)
|
||||
spec =>
|
||||
spec.AddValueFormatter("is_kids_mode", SuperMarioOdysseyChina_AssistMode)
|
||||
)
|
||||
.AddSpec(
|
||||
"010028600ebda000",
|
||||
spec => spec
|
||||
.WithDescription("based on being in either Super Mario 3D World or Bowser's Fury.")
|
||||
.AddValueFormatter("mode", SuperMario3DWorldOrBowsersFury)
|
||||
spec => spec.AddValueFormatter("mode", SuperMario3DWorldOrBowsersFury)
|
||||
)
|
||||
.AddSpec( // Global & China IDs
|
||||
["0100152000022000", "010075100e8ec000"],
|
||||
spec => spec
|
||||
.WithDescription(
|
||||
"based on what modes you're selecting in the menu & whether or not you're in a race.")
|
||||
.AddValueFormatter("To", MarioKart8Deluxe_Mode)
|
||||
spec => spec.AddValueFormatter("To", MarioKart8Deluxe_Mode)
|
||||
)
|
||||
.AddSpec(
|
||||
["0100a3d008c5c000", "01008f6008c5e000"],
|
||||
spec => spec
|
||||
.WithDescription("based on what area of Paldea you're exploring.")
|
||||
.AddValueFormatter("area_no", PokemonSVArea)
|
||||
.AddValueFormatter("team_circle", PokemonSVUnionCircle)
|
||||
)
|
||||
.AddSpec(
|
||||
"01006a800016e000",
|
||||
spec => spec
|
||||
.WithDescription("based on what mode you're playing, who won, and what characters were present.")
|
||||
.AddSparseMultiValueFormatter(
|
||||
[
|
||||
// Metadata to figure out what PlayReport we have.
|
||||
@@ -84,15 +58,10 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||
)
|
||||
.AddSpec(
|
||||
[
|
||||
"0100c9a00ece6000", "01008d300c50c000", "0100d870045b6000",
|
||||
"010012f017576000", "0100c62011050000", "0100b3c014bda000"
|
||||
],
|
||||
spec => spec
|
||||
.WithDescription(
|
||||
"based on what game you first launch.\n\nNSO emulators do not print any Play Report information past the first game launch so it's all we got.")
|
||||
.AddValueFormatter("launch_title_id", NsoEmulator_LaunchedGame)
|
||||
)
|
||||
);
|
||||
"0100c9a00ece6000", "01008d300c50c000", "0100d870045b6000",
|
||||
"010012f017576000", "0100c62011050000", "0100b3c014bda000"],
|
||||
spec => spec.AddValueFormatter("launch_title_id", NsoEmulator_LaunchedGame)
|
||||
);
|
||||
|
||||
private static string Playing(string game) => $"Playing {game}";
|
||||
}
|
||||
|
||||
@@ -23,20 +23,6 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||
|
||||
public required string[] TitleIds { get; init; }
|
||||
|
||||
public const string DefaultDescription = "Formats the details on your Discord presence based on logged data from the game.";
|
||||
|
||||
private string _valueDescription;
|
||||
|
||||
public string Description => _valueDescription ?? DefaultDescription;
|
||||
|
||||
public GameSpec WithDescription(string description)
|
||||
{
|
||||
_valueDescription = description != null
|
||||
? $"Formats the details on your Discord presence {description}"
|
||||
: null;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<FormatterSpecBase> ValueFormatters { get; } = [];
|
||||
|
||||
|
||||
@@ -211,7 +197,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
||||
public string[] ReportKeys { get; init; }
|
||||
public Delegate Formatter { get; init; }
|
||||
|
||||
public bool TryFormat(ApplicationMetadata appMeta, Horizon.Prepo.Types.PlayReport playReport,
|
||||
public bool Format(ApplicationMetadata appMeta, Horizon.Prepo.Types.PlayReport playReport,
|
||||
out FormattedValue formattedValue)
|
||||
{
|
||||
formattedValue = default;
|
||||
|
||||
Reference in New Issue
Block a user