mirror of
https://github.com/sp-tarkov/modules.git
synced 2025-02-12 15:10:44 -05:00
Transpiler changes to quest loading method to fix quests failing when they shouldn't
This commit is contained in:
parent
f7c3b7917e
commit
9a3e1de1ba
@ -0,0 +1,75 @@
|
||||
using HarmonyLib;
|
||||
using SPT.Reflection.Patching;
|
||||
using SPT.Reflection.Utils;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace SPT.SinglePlayer.Patches.Progression
|
||||
{
|
||||
/// <summary>
|
||||
/// Transpiler used to resolve BSG checking quest conditions prior to quest condition handlers being connected.
|
||||
///
|
||||
/// In Tarkov 0.15.5, BSG refactored quest initialization, and added a call to `CheckForStatusChange` during the
|
||||
/// init process. This happened prior to the quest condition handlers being setup, so quests would end up failing
|
||||
/// even if you didn't meet the fail criteria in some cases. The most obvious case is the "Getting Acquainted" quest
|
||||
/// failing on raid start/relog after accepting it
|
||||
///
|
||||
/// Their fix (And the below fix) is to remove the call to `CheckForStatusChange` from the quest loading code
|
||||
///
|
||||
/// This patch is only necessary for SPT targetting client version 0.15.5, the bug is fixed in 0.16
|
||||
/// </summary>
|
||||
internal class QuestLoadStatusChangePatch : ModulePatch
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
var methodName = "SetQuestStatusData";
|
||||
var flags = BindingFlags.Public | BindingFlags.Instance;
|
||||
|
||||
var desiredType = PatchConstants.EftTypes.SingleCustom(x => x.GetMethod(methodName, flags) != null);
|
||||
var desiredMethod = AccessTools.FirstMethod(desiredType, IsTargetMethod);
|
||||
|
||||
Logger.LogDebug($"{this.GetType().Name} Type: {desiredType?.Name}");
|
||||
Logger.LogDebug($"{this.GetType().Name} Method: {desiredMethod?.Name}");
|
||||
|
||||
return desiredMethod;
|
||||
}
|
||||
|
||||
private bool IsTargetMethod(MethodInfo method)
|
||||
{
|
||||
ParameterInfo[] parameters = method.GetParameters();
|
||||
|
||||
return method.Name.StartsWith("method_")
|
||||
&& method.ReturnType == typeof(void)
|
||||
&& parameters.Length == 1
|
||||
&& parameters[0].ParameterType == typeof(RawQuestClass);
|
||||
}
|
||||
|
||||
[PatchTranspiler]
|
||||
public static IEnumerable<CodeInstruction> Transpile(IEnumerable<CodeInstruction> instructions)
|
||||
{
|
||||
var codeList = new List<CodeInstruction>(instructions);
|
||||
for (var i = 0; i < codeList.Count; i++)
|
||||
{
|
||||
// We're looking for a `Callvirt` opcode, so skip anything else
|
||||
if (codeList[i].opcode != OpCodes.Callvirt) continue;
|
||||
|
||||
// We want to find a call to `CheckForStatusChange`, so skip anything else
|
||||
var stringOperand = codeList[i].operand.ToString();
|
||||
if (stringOperand == null || !stringOperand.Contains("CheckForStatusChange")) continue;
|
||||
|
||||
// We've found our call, NOP it out. We need to NOP out the current code, and previous 3 to fully remove it
|
||||
Logger.LogDebug($"QuestLoadStatusChangePatch Code: |{codeList[i]?.opcode}| |{codeList[i].operand}|");
|
||||
codeList[i].opcode = OpCodes.Nop;
|
||||
codeList[i - 1].opcode = OpCodes.Nop;
|
||||
codeList[i - 2].opcode = OpCodes.Nop;
|
||||
codeList[i - 3].opcode = OpCodes.Nop;
|
||||
|
||||
// There should only be one, so we can break out early
|
||||
break;
|
||||
}
|
||||
|
||||
return codeList;
|
||||
}
|
||||
}
|
||||
}
|
@ -66,6 +66,9 @@ namespace SPT.SinglePlayer
|
||||
new FirearmControllerShowIncompatibleNotificationClass().Enable();
|
||||
new FixKeyAlreadyExistsErrorOnAchievementPatch().Enable();
|
||||
|
||||
// 3.10.x specific, should be removed for 4.0.x
|
||||
new QuestLoadStatusChangePatch().Enable();
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user