Merge branch 'TMNT_SR_FIX' into 'master'

Fix Crash TMNT Shredder's Revenges

See merge request [ryubing/ryujinx!117](https://git.ryujinx.app/ryubing/ryujinx/-/merge_requests/117)
This commit is contained in:
Goodfeat
2025-09-06 17:16:51 -05:00
7 changed files with 56 additions and 2 deletions

View File

@ -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)

View File

@ -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;
@ -47,6 +49,10 @@ namespace Ryujinx.HLE.HOS.Services.Nv
{ "/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();
private IVirtualMemoryManager _clientMemory;
@ -248,6 +254,20 @@ namespace Ryujinx.HLE.HOS.Services.Nv
int fd = context.RequestData.ReadInt32();
NvIoctl ioctlCommand = context.RequestData.ReadStruct<NvIoctl>();
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<byte> arguments);
if (errorCode == NvResult.Success)

View File

@ -166,6 +166,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);
}

View File

@ -754,6 +754,8 @@ namespace Ryujinx.Ava.Systems.Configuration
public ReactiveObject<bool> Xc2MenuSoftlockFix { get; private set; }
public ReactiveObject<bool> TmntSrCutsceneCrashFix { get; private set; }
public ReactiveObject<bool> DisableNifmIsAnyInternetRequestAccepted { get; private set; }
public HacksSection()
@ -763,6 +765,8 @@ namespace Ryujinx.Ava.Systems.Configuration
Xc2MenuSoftlockFix.Event += HackChanged;
DisableNifmIsAnyInternetRequestAccepted = new ReactiveObject<bool>();
DisableNifmIsAnyInternetRequestAccepted.Event += HackChanged;
TmntSrCutsceneCrashFix = new ReactiveObject<bool>();
TmntSrCutsceneCrashFix.Event += HackChanged;
}
private void HackChanged(object sender, ReactiveEventArgs<bool> 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)

View File

@ -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");
});
}
}

View File

@ -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);

View File

@ -55,6 +55,20 @@
VerticalAlignment="Center"
Text="Disable IsAnyInternetRequestAccepted" />
</StackPanel>
<Separator/>
<StackPanel
Margin="0,10,0,0"
Orientation="Horizontal"
HorizontalAlignment="Center"
ToolTip.Tip="{Binding DirtyHacks.TmntSrCutsceneCrashFixTooltip}">
<CheckBox
Margin="0"
IsChecked="{Binding DirtyHacks.TmntSrCutsceneCrashFix}"/>
<TextBlock
VerticalAlignment="Center"
Text="TMNT Shredder's Revenge Fix" />
</StackPanel>
<Separator/>
</StackPanel>
</Border>
</ScrollViewer>