mirror of
https://github.com/sp-tarkov/modules.git
synced 2025-02-13 09:50:43 -05:00
Fix multiple NREs thrown in bot code (!84)
1) The called bot's enemy position is being passed to TryCall, instead of the calling bot's enemy position. This is both incorrect and can lead to an NRE if the called bot has no enemy. Fix by passing in the calling bot's enemy position 2) In the TryCall method, the caller's enemy is added to the called bot, however the code doesn't verify that it was added before accessing it in the `EnemyInfos` array. This can throw a missing key exception if the bot failed to add to the enemies list. Fix by making sure the enemy is added to the enemy list before executing TryCall 3) When a BotOwner is disposed, the CalledData is never properly cleaned up, resulting in a bot's OnEnemyAdd being triggered after the bot has been killed, this can throw an NRE. Fix by calling CalledData.SetOff before BotOwner.Dispose Co-authored-by: DrakiaXYZ <565558+TheDgtl@users.noreply.github.com> Reviewed-on: SPT-AKI/Modules#84 Co-authored-by: DrakiaXYZ <drakiaxyz@noreply.dev.sp-tarkov.com> Co-committed-by: DrakiaXYZ <drakiaxyz@noreply.dev.sp-tarkov.com>
This commit is contained in:
parent
28e945a7dd
commit
e1caef80dc
@ -32,6 +32,9 @@ namespace Aki.Custom
|
||||
// new SessionIdPatch().Enable();
|
||||
new VersionLabelPatch().Enable();
|
||||
new IsEnemyPatch().Enable();
|
||||
new BotCalledDataTryCallPatch().Enable();
|
||||
new BotCallForHelpCallBotPatch().Enable();
|
||||
new BotOwnerDisposePatch().Enable();
|
||||
new LocationLootCacheBustingPatch().Enable();
|
||||
//new AddSelfAsEnemyPatch().Enable();
|
||||
new CheckAndAddEnemyPatch().Enable();
|
||||
|
54
project/Aki.Custom/Patches/BotCallForHelpCallBotPatch.cs
Normal file
54
project/Aki.Custom/Patches/BotCallForHelpCallBotPatch.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using Aki.Reflection.Patching;
|
||||
using EFT;
|
||||
using HarmonyLib;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Aki.Custom.Patches
|
||||
{
|
||||
/**
|
||||
* BSG passes the wrong target location into the TryCall method for BotCallForHelp, it's passing in
|
||||
* the bots current target instead of the target of the bot calling for help
|
||||
*
|
||||
* This results in both an NRE, and the called bots target location being wrong
|
||||
*/
|
||||
internal class BotCallForHelpCallBotPatch : ModulePatch
|
||||
{
|
||||
private static FieldInfo _originalPanicTypeField;
|
||||
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
_originalPanicTypeField = AccessTools.Field(typeof(BotCallForHelp), "_originalPanicType");
|
||||
|
||||
return AccessTools.FirstMethod(typeof(BotCallForHelp), IsTargetMethod);
|
||||
}
|
||||
|
||||
protected bool IsTargetMethod(MethodBase method)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
return (parameters.Length == 1
|
||||
&& parameters[0].Name == "calledBot");
|
||||
}
|
||||
|
||||
[PatchPrefix]
|
||||
private static bool PatchPrefix(ref bool __result, BotCallForHelp __instance, BotOwner calledBot, BotOwner ___botOwner_0)
|
||||
{
|
||||
if (__instance.method_2(calledBot) && ___botOwner_0.Memory.GoalEnemy != null)
|
||||
{
|
||||
_originalPanicTypeField.SetValue(calledBot.CallForHelp, calledBot.DangerPointsData.PanicType);
|
||||
calledBot.DangerPointsData.PanicType = PanicType.none;
|
||||
calledBot.Brain.BaseBrain.CalcActionNextFrame();
|
||||
// Note: This differs from BSG's implementation in that we pass in botOwner_0's enemy pos instead of calledBot's enemy pos
|
||||
calledBot.CalledData.TryCall(new Vector3?(___botOwner_0.Memory.GoalEnemy.Person.Position), ___botOwner_0, true);
|
||||
__result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
__result = false;
|
||||
}
|
||||
|
||||
// Skip original
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
49
project/Aki.Custom/Patches/BotCalledDataTryCallPatch.cs
Normal file
49
project/Aki.Custom/Patches/BotCalledDataTryCallPatch.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using Aki.Reflection.Patching;
|
||||
using EFT;
|
||||
using HarmonyLib;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Aki.Custom.Patches
|
||||
{
|
||||
/**
|
||||
* It's possible for `AddEnemy` to return false, in that case, further code in TryCall will fail,
|
||||
* so we do the first bit of `TryCall` ourselves, and skip the original function if AddEnemy fails
|
||||
*/
|
||||
internal class BotCalledDataTryCallPatch : ModulePatch
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return AccessTools.Method(typeof(BotCalledData), nameof(BotCalledData.TryCall));
|
||||
}
|
||||
|
||||
[PatchPrefix]
|
||||
private static bool PatchPrefix(ref bool __result, BotOwner caller, BotOwner ___botOwner_0, BotOwner ____caller)
|
||||
{
|
||||
if (___botOwner_0.EnemiesController.IsEnemy(caller.AIData.Player) || ____caller != null)
|
||||
{
|
||||
__result = false;
|
||||
|
||||
// Skip original
|
||||
return false;
|
||||
}
|
||||
|
||||
if (caller.Memory.GoalEnemy != null)
|
||||
{
|
||||
IPlayer person = caller.Memory.GoalEnemy.Person;
|
||||
if (!___botOwner_0.BotsGroup.Enemies.ContainsKey(person))
|
||||
{
|
||||
if (!___botOwner_0.BotsGroup.AddEnemy(person, EBotEnemyCause.callBot))
|
||||
{
|
||||
__result = false;
|
||||
|
||||
// Skip original
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allow original
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
28
project/Aki.Custom/Patches/BotOwnerDisposePatch.cs
Normal file
28
project/Aki.Custom/Patches/BotOwnerDisposePatch.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using Aki.Reflection.Patching;
|
||||
using EFT;
|
||||
using HarmonyLib;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Aki.Custom.Patches
|
||||
{
|
||||
/**
|
||||
* BotOwner doesn't call SetOff on the CalledData object when a bot is disposed, this can result
|
||||
* in bots that are no longer alive having their `OnEnemyAdd` method called
|
||||
*/
|
||||
internal class BotOwnerDisposePatch : ModulePatch
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return AccessTools.Method(typeof(BotOwner), nameof(BotOwner.Dispose));
|
||||
}
|
||||
|
||||
[PatchPrefix]
|
||||
private static void PatchPrefix(BotOwner __instance)
|
||||
{
|
||||
if (__instance.CalledData != null)
|
||||
{
|
||||
__instance.CalledData.SetOff();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user