0
0
mirror of https://github.com/sp-tarkov/modules.git synced 2025-02-13 06:30:43 -05:00

BTR code refactors and turret aim improvements (!67)

Todo:

* Make BTR spawn at random time during raid instead of at the start
* Find out why some players receive error relating to `BTRBotAttachPatch` resulting BTR failing to initialise

Co-authored-by: Nympfonic <arys.steam@gmail.com>
Reviewed-on: SPT-AKI/Modules#67
Co-authored-by: Arys <arys@noreply.dev.sp-tarkov.com>
Co-committed-by: Arys <arys@noreply.dev.sp-tarkov.com>
This commit is contained in:
Arys 2024-01-25 08:52:33 +00:00 committed by chomp
parent 72dec65d8e
commit 89f0db250d
14 changed files with 229 additions and 184 deletions

View File

@ -54,8 +54,8 @@ namespace Aki.Custom
new BTRActivateTraderDialogPatch().Enable(); new BTRActivateTraderDialogPatch().Enable();
new BTRInteractionPatch().Enable(); new BTRInteractionPatch().Enable();
new BTRExtractPassengersPatch().Enable(); new BTRExtractPassengersPatch().Enable();
new BTRBotAttachPatch().Enable();
new BTRBotInitPatch().Enable(); new BTRBotInitPatch().Enable();
new BTRBotAttachPatch().Enable();
new BTRReceiveDamageInfoPatch().Enable(); new BTRReceiveDamageInfoPatch().Enable();
new BTRTurretCanShootPatch().Enable(); new BTRTurretCanShootPatch().Enable();
new BTRTurretDefaultAimingPositionPatch().Enable(); new BTRTurretDefaultAimingPositionPatch().Enable();

View File

@ -3,6 +3,7 @@ using Aki.SinglePlayer.Utils.TraderServices;
using Comfort.Common; using Comfort.Common;
using EFT; using EFT;
using EFT.InventoryLogic; using EFT.InventoryLogic;
using EFT.UI;
using EFT.Vehicle; using EFT.Vehicle;
using HarmonyLib; using HarmonyLib;
using System; using System;
@ -28,20 +29,25 @@ namespace Aki.Custom.BTR
private BotOwner btrBotShooter; private BotOwner btrBotShooter;
private BTRDataPacket btrDataPacket = default; private BTRDataPacket btrDataPacket = default;
private bool btrBotShooterInitialized = false; private bool btrBotShooterInitialized = false;
private float coverFireTime = 90f;
private EPlayerBtrState previousPlayerBtrState; private float coverFireTime = 90f;
private Coroutine _coverFireTimerCoroutine;
private BTRSide lastInteractedBtrSide; private BTRSide lastInteractedBtrSide;
public BTRSide LastInteractedBtrSide => lastInteractedBtrSide; public BTRSide LastInteractedBtrSide => lastInteractedBtrSide;
private Coroutine _coverFireTimerCoroutine;
private BTRTurretServer btrTurretServer;
private Transform btrTurretDefaultTargetTransform;
private Coroutine _shootingTargetCoroutine; private Coroutine _shootingTargetCoroutine;
private IPlayer currentTarget = null; private BTRTurretServer btrTurretServer;
private bool isTurretInDefaultRotation;
private EnemyInfo currentTarget = null;
private bool isShooting = false; private bool isShooting = false;
private float machineGunAimDelay = 0.4f;
private Vector2 machineGunBurstCount;
private Vector2 machineGunRecoveryTime;
private BulletClass btrMachineGunAmmo; private BulletClass btrMachineGunAmmo;
private Item btrMachineGunWeapon; private Item btrMachineGunWeapon;
private Player.FirearmController firearmController;
private WeaponSoundPlayer weaponSoundPlayer;
private MethodInfo _updateTaxiPriceMethod; private MethodInfo _updateTaxiPriceMethod;
@ -56,65 +62,29 @@ namespace Aki.Custom.BTR
try try
{ {
gameWorld = Singleton<GameWorld>.Instance; gameWorld = Singleton<GameWorld>.Instance;
if (gameWorld == null) if (gameWorld == null)
{ {
Destroy(this); Destroy(this);
return; return;
} }
if (gameWorld.BtrController == null) if (gameWorld.BtrController == null && !Singleton<BTRControllerClass>.Instantiated)
{
if (!Singleton<BTRControllerClass>.Instantiated)
{ {
Singleton<BTRControllerClass>.Create(new BTRControllerClass()); Singleton<BTRControllerClass>.Create(new BTRControllerClass());
} }
gameWorld.BtrController = btrController = Singleton<BTRControllerClass>.Instance; gameWorld.BtrController = btrController = Singleton<BTRControllerClass>.Instance;
}
InitBTR(); InitBtr();
} }
catch catch
{ {
Debug.LogError("[AKI-BTR]: Unable to spawn BTR"); ConsoleScreen.LogError("[AKI-BTR] Unable to spawn BTR. Check logs.");
DestroyGameObjects(); DestroyGameObjects();
throw; throw;
} }
} }
// Find `BTRControllerClass.method_9(PathDestination currentDestinationPoint, bool lastRoutePoint)`
private bool IsUpdateTaxiPriceMethod(MethodInfo method)
{
return (method.GetParameters().Length == 2 && method.GetParameters()[0].ParameterType == typeof(PathDestination));
}
private void Update()
{
btrController.SyncBTRVehicleFromServer(UpdateDataPacket());
if (btrController.BotShooterBtr == null) return;
// BotShooterBtr doesn't get assigned to BtrController immediately so we check this in Update
if (!btrBotShooterInitialized)
{
btrBotShooter = btrController.BotShooterBtr;
btrBotService.Reset(); // Player will be added to Neutrals list and removed from Enemies list
TraderServicesManager.Instance.OnTraderServicePurchased += BTRTraderServicePurchased;
btrBotShooterInitialized = true;
}
if (HasTarget() && IsAimingAtTarget() && !isShooting)
{
_shootingTargetCoroutine = StaticManager.BeginCoroutine(ShootTarget());
}
if (_coverFireTimerCoroutine != null && ShouldCancelCoverFireSupport())
{
CancelCoverFireSupport();
}
}
public void OnPlayerInteractDoor(PlayerInteractPacket interactPacket) public void OnPlayerInteractDoor(PlayerInteractPacket interactPacket)
{ {
btrServerSide.LeftSlot0State = 0; btrServerSide.LeftSlot0State = 0;
@ -148,11 +118,44 @@ namespace Aki.Custom.BTR
} }
} }
private void InitBTR() // Find `BTRControllerClass.method_9(PathDestination currentDestinationPoint, bool lastRoutePoint)`
private bool IsUpdateTaxiPriceMethod(MethodInfo method)
{ {
// Fetch config from the server return (method.GetParameters().Length == 2 && method.GetParameters()[0].ParameterType == typeof(PathDestination));
var serverConfig = BTRUtil.GetConfigFromServer(); }
private void Update()
{
btrController.SyncBTRVehicleFromServer(UpdateDataPacket());
if (btrController.BotShooterBtr == null) return;
// BotShooterBtr doesn't get assigned to BtrController immediately so we check this in Update
if (!btrBotShooterInitialized)
{
InitBtrBotService();
btrBotShooterInitialized = true;
}
UpdateTarget();
if (HasTarget())
{
SetAim();
if (!isShooting && CanShoot())
{
StartShooting();
}
}
else if (!isTurretInDefaultRotation)
{
btrTurretServer.DisableAiming();
}
}
private void InitBtr()
{
// Initial setup // Initial setup
botEventHandler = Singleton<BotEventHandler>.Instance; botEventHandler = Singleton<BotEventHandler>.Instance;
var botsController = Singleton<IBotGame>.Instance.BotsController; var botsController = Singleton<IBotGame>.Instance.BotsController;
@ -162,14 +165,11 @@ namespace Aki.Custom.BTR
// Initial BTR configuration // Initial BTR configuration
btrServerSide = btrController.BtrVehicle; btrServerSide = btrController.BtrVehicle;
btrClientSide = btrController.BtrView;
btrServerSide.transform.Find("KillBox").gameObject.AddComponent<BTRRoadKillTrigger>(); btrServerSide.transform.Find("KillBox").gameObject.AddComponent<BTRRoadKillTrigger>();
// Update values from server side config // Get config from server and initialise respective settings
btrServerSide.moveSpeed = serverConfig.MoveSpeed; ConfigureSettingsFromServer();
btrServerSide.pauseDurationRange.x = serverConfig.PointWaitTime.Min;
btrServerSide.pauseDurationRange.y = serverConfig.PointWaitTime.Max;
btrServerSide.readyToDeparture = serverConfig.TaxiWaitTime;
coverFireTime = serverConfig.CoverFireTime;
var btrMapConfig = btrController.MapPathsConfiguration; var btrMapConfig = btrController.MapPathsConfiguration;
btrServerSide.CurrentPathConfig = btrMapConfig.PathsConfiguration.pathsConfigurations.RandomElement(); btrServerSide.CurrentPathConfig = btrMapConfig.PathsConfiguration.pathsConfigurations.RandomElement();
@ -185,13 +185,14 @@ namespace Aki.Custom.BTR
// Sync initial position and rotation // Sync initial position and rotation
UpdateDataPacket(); UpdateDataPacket();
btrClientSide = btrController.BtrView;
btrClientSide.transform.position = btrDataPacket.position; btrClientSide.transform.position = btrDataPacket.position;
btrClientSide.transform.rotation = btrDataPacket.rotation; btrClientSide.transform.rotation = btrDataPacket.rotation;
// Initialise turret variables // Initialise turret variables
btrTurretServer = btrServerSide.BTRTurret; btrTurretServer = btrServerSide.BTRTurret;
btrTurretDefaultTargetTransform = (Transform)AccessTools.Field(btrTurretServer.GetType(), "defaultTargetTransform").GetValue(btrTurretServer); var btrTurretDefaultTargetTransform = (Transform)AccessTools.Field(btrTurretServer.GetType(), "defaultTargetTransform").GetValue(btrTurretServer);
isTurretInDefaultRotation = btrTurretServer.targetTransform == btrTurretDefaultTargetTransform
&& btrTurretServer.targetPosition == btrTurretServer.defaultAimingPosition;
btrMachineGunAmmo = (BulletClass)BTRUtil.CreateItem(BTRUtil.BTRMachineGunAmmoTplId); btrMachineGunAmmo = (BulletClass)BTRUtil.CreateItem(BTRUtil.BTRMachineGunAmmoTplId);
btrMachineGunWeapon = BTRUtil.CreateItem(BTRUtil.BTRMachineGunWeaponTplId); btrMachineGunWeapon = BTRUtil.CreateItem(BTRUtil.BTRMachineGunWeaponTplId);
@ -199,6 +200,31 @@ namespace Aki.Custom.BTR
TraderServicesManager.Instance.GetTraderServicesDataFromServer(BTRUtil.BTRTraderId); TraderServicesManager.Instance.GetTraderServicesDataFromServer(BTRUtil.BTRTraderId);
} }
private void ConfigureSettingsFromServer()
{
var serverConfig = BTRUtil.GetConfigFromServer();
btrServerSide.moveSpeed = serverConfig.MoveSpeed;
btrServerSide.pauseDurationRange.x = serverConfig.PointWaitTime.Min;
btrServerSide.pauseDurationRange.y = serverConfig.PointWaitTime.Max;
btrServerSide.readyToDeparture = serverConfig.TaxiWaitTime;
coverFireTime = serverConfig.CoverFireTime;
machineGunAimDelay = serverConfig.MachineGunAimDelay;
machineGunBurstCount = new Vector2(serverConfig.MachineGunBurstCount.Min, serverConfig.MachineGunBurstCount.Max);
machineGunRecoveryTime = new Vector2(serverConfig.MachineGunRecoveryTime.Min, serverConfig.MachineGunRecoveryTime.Max);
}
private void InitBtrBotService()
{
btrBotShooter = btrController.BotShooterBtr;
firearmController = btrBotShooter.GetComponent<Player.FirearmController>();
var weaponPrefab = (WeaponPrefab)AccessTools.Field(firearmController.GetType(), "weaponPrefab_0").GetValue(firearmController);
weaponSoundPlayer = weaponPrefab.GetComponent<WeaponSoundPlayer>();
btrBotService.Reset(); // Player will be added to Neutrals list and removed from Enemies list
TraderServicesManager.Instance.OnTraderServicePurchased += BtrTraderServicePurchased;
}
/** /**
* BTR has arrived at a destination, re-calculate taxi prices and remove purchased taxi service * BTR has arrived at a destination, re-calculate taxi prices and remove purchased taxi service
*/ */
@ -226,7 +252,7 @@ namespace Aki.Custom.BTR
return false; return false;
} }
private void BTRTraderServicePurchased(ETraderServiceType serviceType, string subserviceId) private void BtrTraderServicePurchased(ETraderServiceType serviceType, string subserviceId)
{ {
if (!IsBtrService(serviceType)) if (!IsBtrService(serviceType))
{ {
@ -255,23 +281,6 @@ namespace Aki.Custom.BTR
_coverFireTimerCoroutine = StaticManager.BeginCoroutine(CoverFireTimer(time)); _coverFireTimerCoroutine = StaticManager.BeginCoroutine(CoverFireTimer(time));
} }
private bool ShouldCancelCoverFireSupport()
{
var friendlyPlayersByBtrSupport = (List<Player>)AccessTools.Field(btrBotService.GetType(), "_friendlyPlayersByBtrSupport").GetValue(btrBotService);
if (!friendlyPlayersByBtrSupport.Any())
{
return true;
}
return false;
}
private void CancelCoverFireSupport()
{
StaticManager.KillCoroutine(ref _coverFireTimerCoroutine);
botEventHandler.StopTraderServiceBtrSupport();
}
private IEnumerator CoverFireTimer(float time) private IEnumerator CoverFireTimer(float time)
{ {
yield return new WaitForSecondsRealtime(time); yield return new WaitForSecondsRealtime(time);
@ -280,33 +289,27 @@ namespace Aki.Custom.BTR
private void HandleBtrDoorState(EPlayerBtrState playerBtrState) private void HandleBtrDoorState(EPlayerBtrState playerBtrState)
{ {
if (previousPlayerBtrState == EPlayerBtrState.Approach && playerBtrState == EPlayerBtrState.GoIn if (playerBtrState == EPlayerBtrState.GoIn || playerBtrState == EPlayerBtrState.GoOut)
|| previousPlayerBtrState == EPlayerBtrState.Inside && playerBtrState == EPlayerBtrState.GoOut)
{ {
// Open Door // Open Door
UpdateBTRSideDoorState(1); UpdateBTRSideDoorState(1);
} }
else if (previousPlayerBtrState == EPlayerBtrState.GoIn && playerBtrState == EPlayerBtrState.Inside else if (playerBtrState == EPlayerBtrState.Inside || playerBtrState == EPlayerBtrState.Outside)
|| previousPlayerBtrState == EPlayerBtrState.GoOut && playerBtrState == EPlayerBtrState.Outside)
{ {
// Close Door // Close Door
UpdateBTRSideDoorState(0); UpdateBTRSideDoorState(0);
} }
previousPlayerBtrState = playerBtrState;
} }
private void UpdateBTRSideDoorState(byte state) private void UpdateBTRSideDoorState(byte state)
{
try
{ {
var player = gameWorld.MainPlayer; var player = gameWorld.MainPlayer;
var btrSides = (BTRSide[])AccessTools.Field(typeof(BTRView), "_btrSides").GetValue(btrController.BtrView);
for (int i = 0; i < btrSides.Length; i++) BTRSide btrSide = player.BtrInteractionSide != null ? player.BtrInteractionSide : lastInteractedBtrSide;
{ byte sideId = btrClientSide.GetSideId(btrSide);
if (player.BtrInteractionSide != null && btrSides[i] == player.BtrInteractionSide switch (sideId)
|| lastInteractedBtrSide != null && btrSides[i] == lastInteractedBtrSide)
{
switch (i)
{ {
case 0: case 0:
btrServerSide.LeftSideState = state; btrServerSide.LeftSideState = state;
@ -318,6 +321,10 @@ namespace Aki.Custom.BTR
lastInteractedBtrSide = player.BtrInteractionSide; lastInteractedBtrSide = player.BtrInteractionSide;
} }
catch
{
ConsoleScreen.LogError("[AKI-BTR] lastInteractedBtrSide is null when it shouldn't be. Check logs.");
throw;
} }
} }
@ -325,7 +332,7 @@ namespace Aki.Custom.BTR
{ {
btrDataPacket.position = btrServerSide.transform.position; btrDataPacket.position = btrServerSide.transform.position;
btrDataPacket.rotation = btrServerSide.transform.rotation; btrDataPacket.rotation = btrServerSide.transform.rotation;
if (btrTurretServer?.gunsBlockRoot != null) if (btrTurretServer != null && btrTurretServer.gunsBlockRoot != null)
{ {
btrDataPacket.turretRotation = btrTurretServer.transform.rotation; btrDataPacket.turretRotation = btrTurretServer.transform.rotation;
btrDataPacket.gunsBlockRotation = btrTurretServer.gunsBlockRoot.rotation; btrDataPacket.gunsBlockRotation = btrTurretServer.gunsBlockRoot.rotation;
@ -342,7 +349,7 @@ namespace Aki.Custom.BTR
btrDataPacket.timeToEndPause = btrServerSide.timeToEndPause; btrDataPacket.timeToEndPause = btrServerSide.timeToEndPause;
btrDataPacket.moveDirection = (byte)btrServerSide.VehicleMoveDirection; btrDataPacket.moveDirection = (byte)btrServerSide.VehicleMoveDirection;
btrDataPacket.MoveSpeed = btrServerSide.moveSpeed; btrDataPacket.MoveSpeed = btrServerSide.moveSpeed;
if (btrController.BotShooterBtr != null) if (btrController != null && btrController.BotShooterBtr != null)
{ {
btrDataPacket.BtrBotId = btrController.BotShooterBtr.Id; btrDataPacket.BtrBotId = btrController.BotShooterBtr.Id;
} }
@ -359,92 +366,95 @@ namespace Aki.Custom.BTR
} }
} }
private void UpdateTarget()
{
currentTarget = btrBotShooter.Memory.GoalEnemy;
}
private bool HasTarget() private bool HasTarget()
{ {
var enemies = btrBotShooter.BotsGroup.Enemies;
if (enemies.Any())
{
currentTarget = enemies.First().Key;
if (!currentTarget.HealthController.IsAlive)
{
enemies.Remove(currentTarget);
currentTarget = null;
return false;
}
return true;
}
return false;
}
private bool IsAimingAtTarget()
{
bool turretInDefaultRotation = btrTurretServer.targetTransform == btrTurretDefaultTargetTransform
&& btrTurretServer.targetPosition == btrTurretServer.defaultAimingPosition;
if (currentTarget != null) if (currentTarget != null)
{ {
Transform currentTargetTransform = currentTarget.Transform.Original; return true;
EnemyInfo currentTargetInfo = btrBotShooter.EnemiesController.EnemyInfos[currentTarget]; }
if (currentTargetInfo.IsVisible) return false;
}
private void SetAim()
{ {
Vector3 currentTargetPosition = currentTargetTransform.position; if (currentTarget.IsVisible)
if (btrTurretServer.CheckPositionInAimingZone(currentTargetPosition))
{ {
if (btrTurretServer.targetTransform == currentTargetTransform && btrBotShooter.BotBtrData.CanShoot()) Vector3 targetPos = currentTarget.CurrPosition;
Transform targetTransform = currentTarget.Person.Transform.Original;
if (btrTurretServer.CheckPositionInAimingZone(targetPos) && btrTurretServer.targetTransform != targetTransform)
{
btrTurretServer.EnableAimingObject(targetTransform);
}
}
else
{
Vector3 targetLastPos = currentTarget.EnemyLastPositionReal;
if (btrTurretServer.CheckPositionInAimingZone(targetLastPos)
&& Time.time - currentTarget.PersonalLastSeenTime < 3f
&& btrTurretServer.targetPosition != targetLastPos)
{
btrTurretServer.EnableAimingPosition(targetLastPos);
}
else if (Time.time - currentTarget.PersonalLastSeenTime >= 3f && !isTurretInDefaultRotation)
{
btrTurretServer.DisableAiming();
}
}
}
private bool CanShoot()
{
if (currentTarget.IsVisible && btrBotShooter.BotBtrData.CanShoot())
{ {
return true; return true;
} }
if (btrTurretServer.targetTransform != currentTargetTransform) return false;
{
btrTurretServer.EnableAimingObject(currentTargetTransform);
}
}
}
// Turret will hold the angle where target was last seen for 3 seconds before resetting its rotation
else if (btrTurretServer.targetPosition != currentTargetInfo.EnemyLastPosition && btrTurretServer.targetTransform != null)
{
btrTurretServer.EnableAimingPosition(currentTargetInfo.EnemyLastPosition);
}
else if (currentTargetInfo.TimeLastSeen >= 3f && !turretInDefaultRotation)
{
currentTarget = null;
btrTurretServer.DisableAiming();
}
}
else if (!turretInDefaultRotation)
{
btrTurretServer.DisableAiming();
} }
return false; private void StartShooting()
{
_shootingTargetCoroutine = StaticManager.BeginCoroutine(ShootMachineGun());
} }
/// <summary> /// <summary>
/// Custom method to make the BTR coaxial machine gun shoot. /// Custom method to make the BTR coaxial machine gun shoot.
/// </summary> /// </summary>
private IEnumerator ShootTarget() private IEnumerator ShootMachineGun()
{ {
isShooting = true; isShooting = true;
Transform machineGunMuzzle = btrTurretServer.machineGunLaunchPoint; yield return new WaitForSecondsRealtime(machineGunAimDelay);
Player.FirearmController firearmController = btrBotShooter.GetComponent<Player.FirearmController>(); if (!currentTarget.IsVisible || !btrBotShooter.BotBtrData.CanShoot())
WeaponPrefab weaponPrefab = (WeaponPrefab)AccessTools.Field(firearmController.GetType(), "weaponPrefab_0").GetValue(firearmController); {
WeaponSoundPlayer weaponSoundPlayer = weaponPrefab.GetComponent<WeaponSoundPlayer>(); isShooting = false;
yield break;
}
int burstCount = Random.Range(5, 8); Transform machineGunMuzzle = btrTurretServer.machineGunLaunchPoint;
var ballisticCalculator = gameWorld.SharedBallisticsCalculator;
int burstMin = Mathf.FloorToInt(machineGunBurstCount.x);
int burstMax = Mathf.FloorToInt(machineGunBurstCount.y);
int burstCount = Random.Range(burstMin, burstMax + 1);
while (burstCount > 0) while (burstCount > 0)
{ {
gameWorld.SharedBallisticsCalculator.Shoot(btrMachineGunAmmo, machineGunMuzzle.position, machineGunMuzzle.forward, btrBotShooter.ProfileId, btrMachineGunWeapon, 1f, 0); Vector3 targetHeadPos = currentTarget.Person.PlayerBones.Head.position;
firearmController.method_54(weaponSoundPlayer, btrMachineGunAmmo, machineGunMuzzle.position, machineGunMuzzle.forward, false); Vector3 aimDirection = Vector3.Normalize(targetHeadPos - machineGunMuzzle.position);
ballisticCalculator.Shoot(btrMachineGunAmmo, machineGunMuzzle.position, aimDirection, btrBotShooter.ProfileId, btrMachineGunWeapon, 1f, 0);
firearmController.method_54(weaponSoundPlayer, btrMachineGunAmmo, machineGunMuzzle.position, aimDirection, false);
burstCount--; burstCount--;
yield return new WaitForSecondsRealtime(0.092308f); // 650 RPM yield return new WaitForSecondsRealtime(0.092308f); // 650 RPM
} }
float waitTime = Random.Range(0.8f, 1.7f); // 0.8 - 1.7 second pause between bursts float waitTime = Random.Range(machineGunRecoveryTime.x, machineGunRecoveryTime.y);
yield return new WaitForSecondsRealtime(waitTime); yield return new WaitForSecondsRealtime(waitTime);
isShooting = false; isShooting = false;
@ -471,14 +481,14 @@ namespace Aki.Custom.BTR
btrController.Dispose(); btrController.Dispose();
} }
if (gameWorld?.MainPlayer != null) if (gameWorld.MainPlayer != null)
{ {
gameWorld.MainPlayer.OnBtrStateChanged -= HandleBtrDoorState; gameWorld.MainPlayer.OnBtrStateChanged -= HandleBtrDoorState;
} }
if (TraderServicesManager.Instance != null) if (TraderServicesManager.Instance != null)
{ {
TraderServicesManager.Instance.OnTraderServicePurchased -= BTRTraderServicePurchased; TraderServicesManager.Instance.OnTraderServicePurchased -= BtrTraderServicePurchased;
} }
StaticManager.KillCoroutine(ref _shootingTargetCoroutine); StaticManager.KillCoroutine(ref _shootingTargetCoroutine);

View File

@ -1,9 +1,9 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Serialization; using Newtonsoft.Json.Serialization;
namespace Aki.Debugging.BTR.Models namespace Aki.Custom.BTR.Models
{ {
public class BtrConfigModel public class BTRConfigModel
{ {
[JsonProperty("moveSpeed")] [JsonProperty("moveSpeed")]
public float MoveSpeed { get; set; } public float MoveSpeed { get; set; }
@ -16,6 +16,15 @@ namespace Aki.Debugging.BTR.Models
[JsonProperty("taxiWaitTime")] [JsonProperty("taxiWaitTime")]
public float TaxiWaitTime { get; set; } public float TaxiWaitTime { get; set; }
[JsonProperty("machineGunAimDelay")]
public float MachineGunAimDelay { get; set; }
[JsonProperty("machineGunBurstCount")]
public BtrMinMaxValue MachineGunBurstCount { get; set; }
[JsonProperty("machineGunRecoveryTime")]
public BtrMinMaxValue MachineGunRecoveryTime { get; set; }
} }
public class BtrMinMaxValue public class BtrMinMaxValue

View File

@ -6,7 +6,6 @@ using EFT.Vehicle;
using HarmonyLib; using HarmonyLib;
using System; using System;
using System.Reflection; using System.Reflection;
using static EFT.UI.TraderDialogScreen;
using BTRDialog = EFT.UI.TraderDialogScreen.GClass3132; using BTRDialog = EFT.UI.TraderDialogScreen.GClass3132;
namespace Aki.Custom.BTR.Patches namespace Aki.Custom.BTR.Patches

View File

@ -27,27 +27,36 @@ namespace Aki.Custom.BTR.Patches
private static bool PatchPrefix(BTRTurretView __instance, int btrBotId) private static bool PatchPrefix(BTRTurretView __instance, int btrBotId)
{ {
var gameWorld = Singleton<GameWorld>.Instance; var gameWorld = Singleton<GameWorld>.Instance;
if (gameWorld == null)
var __instanceTupleField = (ValueTuple<ObservedPlayerView, bool>)AccessTools.Field(__instance.GetType(), "valueTuple_0")
.GetValue(__instance);
if (!__instanceTupleField.Item2)
{
var __instanceMethod = AccessTools.Method(__instance.GetType(), "method_1");
__instanceMethod.Invoke(__instance, new object[] { btrBotId });
}
if (!__instanceTupleField.Item2)
{ {
Logger.LogError("[AKI-BTR] BTRBotAttachPatch - GameWorld is null");
return false; return false;
} }
var btrBot = gameWorld.BtrController.BotShooterBtr?.GetPlayer; var btrTurretViewTupleField = (ValueTuple<ObservedPlayerView, bool>)AccessTools.Field(__instance.GetType(), "valueTuple_0").GetValue(__instance);
if (btrBot == null) if (!btrTurretViewTupleField.Item2)
{ {
__instance.method_1(btrBotId);
return false; return false;
} }
var btrController = gameWorld.BtrController;
if (btrController == null)
{
Logger.LogError("[AKI-BTR] BTRBotAttachPatch - BtrController is null");
return false;
}
var btrBotShooter = btrController.BotShooterBtr;
if (btrBotShooter == null)
{
Logger.LogError("[AKI-BTR] BTRBotAttachPatch - BtrBotShooter is null");
return false;
}
try try
{ {
var btrBot = btrBotShooter.GetPlayer;
var botRootTransform = __instance.BotRoot; var botRootTransform = __instance.BotRoot;
btrBot.Transform.position = botRootTransform.position; btrBot.Transform.position = botRootTransform.position;
@ -62,7 +71,7 @@ namespace Aki.Custom.BTR.Patches
} }
catch catch
{ {
ConsoleScreen.LogError("[AKI-BTR]: Could not finish BtrBot initialization. Check logs."); ConsoleScreen.LogError("[AKI-BTR] Could not finish BtrBot initialization. Check logs.");
throw; throw;
} }
} }

View File

@ -22,7 +22,7 @@ namespace Aki.Custom.BTR.Patches
{ {
protected override MethodBase GetTargetMethod() protected override MethodBase GetTargetMethod()
{ {
return AccessTools.Method(typeof(BTRTurretView), "method_1"); return AccessTools.Method(typeof(BTRTurretView), nameof(BTRTurretView.method_1));
} }
[PatchPostfix] [PatchPostfix]
@ -31,6 +31,7 @@ namespace Aki.Custom.BTR.Patches
var gameWorld = Singleton<GameWorld>.Instance; var gameWorld = Singleton<GameWorld>.Instance;
if (gameWorld == null) if (gameWorld == null)
{ {
Logger.LogError("[AKI-BTR] BTRBotInitPatch - GameWorld is null");
return; return;
} }
@ -55,7 +56,7 @@ namespace Aki.Custom.BTR.Patches
foreach (var text in currentWeaponPrefab.RemoveChildrenOf) foreach (var text in currentWeaponPrefab.RemoveChildrenOf)
{ {
var transform = currentWeaponPrefab.transform.FindTransform(text); var transform = currentWeaponPrefab.transform.FindTransform(text);
transform?.gameObject.SetActive(false); transform.gameObject.SetActive(false);
} }
} }
foreach (var renderer in currentWeaponPrefab.GetComponentsInChildren<Renderer>()) foreach (var renderer in currentWeaponPrefab.GetComponentsInChildren<Renderer>())

View File

@ -30,10 +30,15 @@ namespace Aki.Custom.BTR.Patches
public static void PatchPrefix() public static void PatchPrefix()
{ {
GameWorld gameWorld = Singleton<GameWorld>.Instance; GameWorld gameWorld = Singleton<GameWorld>.Instance;
var player = gameWorld?.MainPlayer; if (gameWorld == null)
if (gameWorld == null || player == null)
{ {
Logger.LogError("[AKI-BTR] End Raid - GameWorld or Player is null"); Logger.LogError("[AKI-BTR] BTREndRaidItemDeliveryPatch - GameWorld is null");
return;
}
var player = gameWorld.MainPlayer;
if (player == null)
{
Logger.LogError("[AKI-BTR] BTREndRaidItemDeliveryPatch - Player is null");
return; return;
} }
@ -45,7 +50,7 @@ namespace Aki.Custom.BTR.Patches
if (!gameWorld.BtrController.HasNonEmptyTransferContainer(player.Profile.Id)) if (!gameWorld.BtrController.HasNonEmptyTransferContainer(player.Profile.Id))
{ {
Logger.LogDebug("[AKI-BTR] End Raid - No items in transfer container"); Logger.LogDebug("[AKI-BTR] BTREndRaidItemDeliveryPatch - No items in transfer container");
return; return;
} }

View File

@ -24,6 +24,7 @@ namespace Aki.Custom.BTR.Patches
var btrSide = btrManager.LastInteractedBtrSide; var btrSide = btrManager.LastInteractedBtrSide;
if (btrSide == null) if (btrSide == null)
{ {
Logger.LogError($"[AKI-BTR] BTRExtractPassengersPatch - btrSide is null");
return; return;
} }
@ -35,11 +36,12 @@ namespace Aki.Custom.BTR.Patches
BTRView btrView = gameWorld.BtrController.BtrView; BTRView btrView = gameWorld.BtrController.BtrView;
if (btrView == null) if (btrView == null)
{ {
Logger.LogError($"[AKI-BTR] BTRExtractPassengersPatch - btrView is null");
return; return;
} }
btrManager.OnPlayerInteractDoor(interactionBtrPacket);
btrView.Interaction(player, interactionBtrPacket); btrView.Interaction(player, interactionBtrPacket);
btrManager.OnPlayerInteractDoor(interactionBtrPacket);
} }
} }
} }

View File

@ -47,11 +47,12 @@ namespace Aki.Custom.BTR.Patches
BTRView btrView = gameWorld.BtrController.BtrView; BTRView btrView = gameWorld.BtrController.BtrView;
if (btrView == null) if (btrView == null)
{ {
Logger.LogError("[AKI-BTR] BTRInteractionPatch - btrView is null");
return; return;
} }
btrManager.OnPlayerInteractDoor(interactionBtrPacket);
btrView.Interaction(__instance, interactionBtrPacket); btrView.Interaction(__instance, interactionBtrPacket);
btrManager.OnPlayerInteractDoor(interactionBtrPacket);
} }
} }
} }

View File

@ -16,9 +16,17 @@ namespace Aki.Custom.BTR.Patches
[PatchPrefix] [PatchPrefix]
private static bool PatchPrefix(ref bool __result) private static bool PatchPrefix(ref bool __result)
{ {
var serverSideBTR = Singleton<GameWorld>.Instance?.BtrController.BtrVehicle; var gameWorld = Singleton<GameWorld>.Instance;
if (gameWorld == null)
{
Logger.LogError("[AKI-BTR] BTRIsDoorsClosedPatch - GameWorld is null");
return true;
}
var serverSideBTR = gameWorld.BtrController.BtrVehicle;
if (serverSideBTR == null) if (serverSideBTR == null)
{ {
Logger.LogError("[AKI-BTR] BTRIsDoorsClosedPatch - serverSideBTR is null");
return true; return true;
} }

View File

@ -40,7 +40,7 @@ namespace Aki.Custom.BTR.Patches
} }
catch (System.Exception) catch (System.Exception)
{ {
ConsoleScreen.LogError("[AKI-BTR]: Exception thrown, check logs."); ConsoleScreen.LogError("[AKI-BTR] Exception thrown, check logs.");
throw; throw;
} }
} }

View File

@ -16,7 +16,7 @@ namespace Aki.Custom.BTR.Patches
{ {
_statusProperty = AccessTools.Property(typeof(AbstractGame), nameof(AbstractGame.Status)); _statusProperty = AccessTools.Property(typeof(AbstractGame), nameof(AbstractGame.Status));
return AccessTools.Method(typeof(BTRControllerClass), "method_1"); return AccessTools.Method(typeof(BTRControllerClass), nameof(BTRControllerClass.method_1));
} }
[PatchPrefix] [PatchPrefix]

View File

@ -24,6 +24,7 @@ namespace Aki.Custom.BTR.Patches
var botEventHandler = Singleton<BotEventHandler>.Instance; var botEventHandler = Singleton<BotEventHandler>.Instance;
if (botEventHandler == null) if (botEventHandler == null)
{ {
Logger.LogError($"[AKI-BTR] BTRReceiveDamageInfoPatch - BotEventHandler is null");
return; return;
} }

View File

@ -1,5 +1,5 @@
using Aki.Common.Http; using Aki.Common.Http;
using Aki.Debugging.BTR.Models; using Aki.Custom.BTR.Models;
using Comfort.Common; using Comfort.Common;
using EFT; using EFT;
using EFT.InventoryLogic; using EFT.InventoryLogic;
@ -23,10 +23,10 @@ namespace Aki.Custom.BTR.Utils
return Singleton<ItemFactory>.Instance.CreateItem(id, tplId, null); return Singleton<ItemFactory>.Instance.CreateItem(id, tplId, null);
} }
public static BtrConfigModel GetConfigFromServer() public static BTRConfigModel GetConfigFromServer()
{ {
string json = RequestHandler.GetJson("/singleplayer/btr/config"); string json = RequestHandler.GetJson("/singleplayer/btr/config");
return JsonConvert.DeserializeObject<BtrConfigModel>(json); return JsonConvert.DeserializeObject<BTRConfigModel>(json);
} }
} }
} }