diff --git a/src/Ryujinx.Common/Configuration/DirtyHack.cs b/src/Ryujinx.Common/Configuration/DirtyHack.cs index ae3416a27..94d53558a 100644 --- a/src/Ryujinx.Common/Configuration/DirtyHack.cs +++ b/src/Ryujinx.Common/Configuration/DirtyHack.cs @@ -10,7 +10,8 @@ namespace Ryujinx.Common.Configuration { Xc2MenuSoftlockFix = 1, // ShaderTranslationDelay = 2 - NifmServiceDisableIsAnyInternetRequestAccepted = 3 + NifmServiceDisableIsAnyInternetRequestAccepted = 3, + TmntSrCutsceneCrashFix = 4 } public readonly struct EnabledDirtyHack(DirtyHack hack, int value) diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs b/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs index 89ef76616..84ca2eb22 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/INvDrvServices.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Cpu; using Ryujinx.HLE.Exceptions; @@ -12,6 +13,7 @@ using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostDbgGpu; using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostProfGpu; using Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap; using Ryujinx.HLE.HOS.Services.Nv.Types; +using Ryujinx.HLE.HOS.Tamper.Operations; using Ryujinx.Memory; using System; using System.Collections.Generic; @@ -46,6 +48,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv { "/dev/nvhost-dbg-gpu", typeof(NvHostDbgGpuDeviceFile) }, { "/dev/nvhost-prof-gpu", typeof(NvHostProfGpuDeviceFile) }, }; + + + private const string TmntSrTitleId = "0100fe701475a000"; + private static bool IsTmntSr => TitleIDs.CurrentApplication.Value.OrDefault() is TmntSrTitleId; public static IdDictionary DeviceFileIdRegistry = new(); @@ -248,6 +254,20 @@ namespace Ryujinx.HLE.HOS.Services.Nv int fd = context.RequestData.ReadInt32(); NvIoctl ioctlCommand = context.RequestData.ReadStruct(); + if (context.Device.DirtyHacks.IsEnabled(DirtyHack.TmntSrCutsceneCrashFix) && IsTmntSr) + { + // This fixes an emulator crash before the cutscene for + // TMNT Shredder's Revenge. + // + // NOTE: Delay of 50ms is a stable value. Trying to reduce latency will crash when going to intro cutscene + + if ((ioctlCommand.Type == NvIoctl.NvGpuAsMagic && (ioctlCommand.Number == 0x05 || ioctlCommand.Number == 0x06))) + { + System.Threading.Thread.Sleep(50); + Logger.Debug?.Print(LogClass.ServiceNv, $"Type_{ioctlCommand.Type}, Command_{ioctlCommand.Number} Delay!"); + } + } + errorCode = GetIoctlArgument(context, ioctlCommand, out Span arguments); if (errorCode == NvResult.Success) diff --git a/src/Ryujinx/Systems/Configuration/ConfigurationState.Migration.cs b/src/Ryujinx/Systems/Configuration/ConfigurationState.Migration.cs index a91a74711..414512bed 100644 --- a/src/Ryujinx/Systems/Configuration/ConfigurationState.Migration.cs +++ b/src/Ryujinx/Systems/Configuration/ConfigurationState.Migration.cs @@ -167,6 +167,7 @@ namespace Ryujinx.Ava.Systems.Configuration DirtyHacks hacks = new(cff.DirtyHacks ?? []); Hacks.Xc2MenuSoftlockFix.Value = hacks.IsEnabled(DirtyHack.Xc2MenuSoftlockFix); + Hacks.TmntSrCutsceneCrashFix.Value = hacks.IsEnabled(DirtyHack.TmntSrCutsceneCrashFix); } diff --git a/src/Ryujinx/Systems/Configuration/ConfigurationState.Model.cs b/src/Ryujinx/Systems/Configuration/ConfigurationState.Model.cs index 405400b81..d1b630e69 100644 --- a/src/Ryujinx/Systems/Configuration/ConfigurationState.Model.cs +++ b/src/Ryujinx/Systems/Configuration/ConfigurationState.Model.cs @@ -754,6 +754,8 @@ namespace Ryujinx.Ava.Systems.Configuration public ReactiveObject Xc2MenuSoftlockFix { get; private set; } + public ReactiveObject TmntSrCutsceneCrashFix { get; private set; } + public ReactiveObject DisableNifmIsAnyInternetRequestAccepted { get; private set; } public HacksSection() @@ -763,6 +765,8 @@ namespace Ryujinx.Ava.Systems.Configuration Xc2MenuSoftlockFix.Event += HackChanged; DisableNifmIsAnyInternetRequestAccepted = new ReactiveObject(); DisableNifmIsAnyInternetRequestAccepted.Event += HackChanged; + TmntSrCutsceneCrashFix = new ReactiveObject(); + TmntSrCutsceneCrashFix.Event += HackChanged; } private void HackChanged(object sender, ReactiveEventArgs rxe) @@ -796,6 +800,9 @@ namespace Ryujinx.Ava.Systems.Configuration if (DisableNifmIsAnyInternetRequestAccepted) Apply(DirtyHack.NifmServiceDisableIsAnyInternetRequestAccepted); + if (TmntSrCutsceneCrashFix) + Apply(DirtyHack.TmntSrCutsceneCrashFix); + return enabledHacks.ToArray(); void Apply(DirtyHack hack, int value = 0) diff --git a/src/Ryujinx/UI/ViewModels/SettingsHacksViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsHacksViewModel.cs index 230887e34..6087449c8 100644 --- a/src/Ryujinx/UI/ViewModels/SettingsHacksViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/SettingsHacksViewModel.cs @@ -17,7 +17,7 @@ namespace Ryujinx.Ava.UI.ViewModels [ObservableProperty] private bool _xc2MenuSoftlockFix = ConfigurationState.Instance.Hacks.Xc2MenuSoftlockFix; [ObservableProperty] private bool _nifmDisableIsAnyInternetRequestAccepted = ConfigurationState.Instance.Hacks.DisableNifmIsAnyInternetRequestAccepted; - + [ObservableProperty] private bool _tmntSrCutsceneCrashFix = ConfigurationState.Instance.Hacks.TmntSrCutsceneCrashFix; public static string Xc2MenuFixTooltip { get; } = Lambda.String(sb => { sb.AppendLine( @@ -39,5 +39,15 @@ namespace Ryujinx.Ava.UI.ViewModels sb.Append("Lets DOOM 2016 go in game."); }); + + public static string TmntSrCutsceneCrashFixTooltip { get; } = Lambda.String(sb => + { + sb.AppendLine( + "This hack adds a 50ms delay to NvGpuAsMagic NvIoctl calls. This prevents the game from crashing when the cutscene starts.") + .AppendLine(); + + sb.Append( + "This simply just gives the game some time to properly interact with guest memory"); + }); } } diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs index acf7517d8..b2795f938 100644 --- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs @@ -856,6 +856,7 @@ namespace Ryujinx.Ava.UI.ViewModels config.Hacks.Xc2MenuSoftlockFix.Value = DirtyHacks.Xc2MenuSoftlockFix; config.Hacks.DisableNifmIsAnyInternetRequestAccepted.Value = DirtyHacks.NifmDisableIsAnyInternetRequestAccepted; + config.Hacks.TmntSrCutsceneCrashFix.Value = DirtyHacks.TmntSrCutsceneCrashFix; config.ToFileFormat().SaveConfig(Program.ConfigurationPath); diff --git a/src/Ryujinx/UI/Views/Settings/SettingsHacksView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsHacksView.axaml index 229f9e866..0c123b73a 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsHacksView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsHacksView.axaml @@ -55,6 +55,20 @@ VerticalAlignment="Center" Text="Disable IsAnyInternetRequestAccepted" /> + + + + + +