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

Player can now talk to BTR driver (!52)

Todo:

* BTR trader services requires implementation server-side
  * Send items to player stash (2x4)
  * Provide covering fire
  * Taxi to a specific location on Streets
* Fix turret aiming at player from raid start
* Make turret shoot at enemies (including player)

Co-authored-by: Nympfonic <arys.steam@gmail.com>
Reviewed-on: SPT-AKI/Modules#52
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-05 08:58:15 +00:00 committed by chomp
parent 5fcc904a89
commit 37432541c3
6 changed files with 206 additions and 77 deletions

View File

@ -19,11 +19,13 @@ namespace Aki.Debugging
// new CoordinatesPatch().Enable(); // new CoordinatesPatch().Enable();
// new StaticLootDumper().Enable(); // new StaticLootDumper().Enable();
new BTRPathLoadPatch().Enable(); new BTRPathLoadPatch().Enable();
new BTRActivateTraderDialogPatch().Enable();
new BTRInteractionPatch().Enable(); new BTRInteractionPatch().Enable();
new BTRExtractPassengersPatch().Enable();
new BTRBotAttachPatch().Enable(); new BTRBotAttachPatch().Enable();
new BTRBotInitPatch().Enable(); new BTRBotInitPatch().Enable();
new BTRIsDoorsClosedPath().Enable(); new BTRIsDoorsClosedPath().Enable();
new BTRPatch().Enable(); new BTRPatch().Enable();
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -1,7 +1,10 @@
using Comfort.Common; using Aki.Reflection.Utils;
using Comfort.Common;
using EFT; using EFT;
using EFT.Vehicle; using EFT.Vehicle;
using HarmonyLib; using HarmonyLib;
using System;
using System.Linq;
using UnityEngine; using UnityEngine;
using BTRController = GClass2911; using BTRController = GClass2911;
using BTRDataPacket = GStruct378; using BTRDataPacket = GStruct378;
@ -12,12 +15,18 @@ namespace Aki.Debugging.BTR
public class BTRManager : MonoBehaviour public class BTRManager : MonoBehaviour
{ {
private GameWorld gameWorld; private GameWorld gameWorld;
private BotsController botsController;
private BotBTRService btrBotService;
private BTRController btrController; private BTRController btrController;
private BTRVehicle serverSideBtr; private BTRVehicle btrServerSide;
private BTRView clientSideBtr; private BTRView btrClientSide;
private BTRDataPacket btrDataPacket = default; private BTRDataPacket btrDataPacket = default;
private bool btrBotShooterInitialized = false;
private EPlayerBtrState previousPlayerBtrState; private EPlayerBtrState previousPlayerBtrState;
private BTRSide previousInteractedBtrSide; private BTRSide lastInteractedBtrSide;
public BTRSide LastInteractedBtrSide => lastInteractedBtrSide;
private void Start() private void Start()
@ -41,27 +50,10 @@ namespace Aki.Debugging.BTR
gameWorld.BtrController = btrController = Singleton<BTRController>.Instance; gameWorld.BtrController = btrController = Singleton<BTRController>.Instance;
} }
var btrControllerType = btrController.GetType(); botsController = Singleton<IBotGame>.Instance.BotsController;
AccessTools.Method(btrControllerType, "method_3").Invoke(btrController, null); // spawns server-side BTR game object btrBotService = botsController.BotTradersServices.BTRServices;
Singleton<IBotGame>.Instance.BotsController.BotSpawner.SpawnBotBTR(); // spawns the scav bot which controls the BTR's turret
serverSideBtr = btrController.BtrVehicle; InitBTR();
serverSideBtr.moveSpeed = 20f;
var btrMapConfig = btrController.MapPathsConfiguration;
serverSideBtr.CurrentPathConfig = btrMapConfig.PathsConfiguration.pathsConfigurations.RandomElement();
serverSideBtr.Initialization(btrMapConfig);
AccessTools.Method(btrControllerType, "method_14").Invoke(btrController, null); // creates and assigns the BTR a fake stash
clientSideBtr = btrController.BtrView;
UpdateDataPacket();
clientSideBtr.transform.position = btrDataPacket.position;
clientSideBtr.transform.rotation = btrDataPacket.rotation;
DisableServerSideRenderers();
previousPlayerBtrState = gameWorld.MainPlayer.BtrState;
gameWorld.MainPlayer.OnBtrStateChanged += HandleBtrDoorState;
} }
catch catch
{ {
@ -74,6 +66,15 @@ namespace Aki.Debugging.BTR
private void Update() private void Update()
{ {
btrController.SyncBTRVehicleFromServer(UpdateDataPacket()); btrController.SyncBTRVehicleFromServer(UpdateDataPacket());
// BotShooterBtr doesn't get assigned to BtrController immediately so we nullcheck this in Update
if (btrController.BotShooterBtr != null && !btrBotShooterInitialized)
{
btrBotService.Reset(); // Player will be added to Neutrals list and removed from Enemies list
btrBotShooterInitialized = true;
}
AimAtEnemy();
} }
public void HandleBtrDoorState(EPlayerBtrState playerBtrState) public void HandleBtrDoorState(EPlayerBtrState playerBtrState)
@ -104,30 +105,55 @@ namespace Aki.Debugging.BTR
{ {
if (interactPacket.SlotId == 0) if (interactPacket.SlotId == 0)
{ {
if (playerGoIn) serverSideBtr.LeftSlot0State = 1; if (playerGoIn) btrServerSide.LeftSlot0State = 1;
else if (playerGoOut) serverSideBtr.LeftSlot0State = 0; else if (playerGoOut) btrServerSide.LeftSlot0State = 0;
} }
else if (interactPacket.SlotId == 1) else if (interactPacket.SlotId == 1)
{ {
if (playerGoIn) serverSideBtr.LeftSlot1State = 1; if (playerGoIn) btrServerSide.LeftSlot1State = 1;
else if (playerGoOut) serverSideBtr.LeftSlot1State = 0; else if (playerGoOut) btrServerSide.LeftSlot1State = 0;
} }
} }
else if (interactPacket.SideId == 1) else if (interactPacket.SideId == 1)
{ {
if (interactPacket.SlotId == 0) if (interactPacket.SlotId == 0)
{ {
if (playerGoIn) serverSideBtr.RightSlot0State = 1; if (playerGoIn) btrServerSide.RightSlot0State = 1;
else if (playerGoOut) serverSideBtr.RightSlot0State = 0; else if (playerGoOut) btrServerSide.RightSlot0State = 0;
} }
else if (interactPacket.SlotId == 1) else if (interactPacket.SlotId == 1)
{ {
if (playerGoIn) serverSideBtr.RightSlot1State = 1; if (playerGoIn) btrServerSide.RightSlot1State = 1;
else if (playerGoOut) serverSideBtr.RightSlot1State = 0; else if (playerGoOut) btrServerSide.RightSlot1State = 0;
} }
} }
} }
private void InitBTR()
{
var btrControllerType = btrController.GetType();
AccessTools.Method(btrControllerType, "method_3").Invoke(btrController, null); // spawns server-side BTR game object
botsController.BotSpawner.SpawnBotBTR(); // spawns the scav bot which controls the BTR's turret
btrServerSide = btrController.BtrVehicle;
btrServerSide.moveSpeed = 20f;
var btrMapConfig = btrController.MapPathsConfiguration;
btrServerSide.CurrentPathConfig = btrMapConfig.PathsConfiguration.pathsConfigurations.RandomElement();
btrServerSide.Initialization(btrMapConfig);
AccessTools.Method(btrControllerType, "method_14").Invoke(btrController, null); // creates and assigns the BTR a fake stash
DisableServerSideRenderers();
gameWorld.MainPlayer.OnBtrStateChanged += HandleBtrDoorState;
btrServerSide.MoveEnable();
UpdateDataPacket();
btrClientSide = btrController.BtrView;
btrClientSide.transform.position = btrDataPacket.position;
btrClientSide.transform.rotation = btrDataPacket.rotation;
}
private void UpdateBTRSideDoorState(byte state) private void UpdateBTRSideDoorState(byte state)
{ {
var player = gameWorld.MainPlayer; var player = gameWorld.MainPlayer;
@ -136,15 +162,14 @@ namespace Aki.Debugging.BTR
for (int i = 0; i < btrSides.Length; i++) for (int i = 0; i < btrSides.Length; i++)
{ {
if (player.BtrInteractionSide != null && btrSides[i] == player.BtrInteractionSide if (player.BtrInteractionSide != null && btrSides[i] == player.BtrInteractionSide
|| previousInteractedBtrSide != null && btrSides[i] == previousInteractedBtrSide) || lastInteractedBtrSide != null && btrSides[i] == lastInteractedBtrSide)
{ {
if (i == 0) serverSideBtr.LeftSideState = state; if (i == 0) btrServerSide.LeftSideState = state;
else if (i == 1) serverSideBtr.RightSideState = state; else if (i == 1) btrServerSide.RightSideState = state;
if ((previousInteractedBtrSide != player.BtrInteractionSide && player.BtrInteractionSide != null) if (lastInteractedBtrSide != player.BtrInteractionSide)
|| previousInteractedBtrSide == null)
{ {
previousInteractedBtrSide = player.BtrInteractionSide; lastInteractedBtrSide = player.BtrInteractionSide;
} }
} }
} }
@ -152,25 +177,25 @@ namespace Aki.Debugging.BTR
private BTRDataPacket UpdateDataPacket() private BTRDataPacket UpdateDataPacket()
{ {
btrDataPacket.position = serverSideBtr.transform.position; btrDataPacket.position = btrServerSide.transform.position;
btrDataPacket.rotation = serverSideBtr.transform.rotation; btrDataPacket.rotation = btrServerSide.transform.rotation;
if (serverSideBtr.BTRTurret?.gunsBlockRoot != null) if (btrServerSide.BTRTurret?.gunsBlockRoot != null)
{ {
btrDataPacket.turretRotation = serverSideBtr.BTRTurret.transform.rotation; btrDataPacket.turretRotation = btrServerSide.BTRTurret.transform.rotation;
btrDataPacket.gunsBlockRotation = serverSideBtr.BTRTurret.gunsBlockRoot.rotation; btrDataPacket.gunsBlockRotation = btrServerSide.BTRTurret.gunsBlockRoot.rotation;
} }
btrDataPacket.State = (byte)serverSideBtr.BtrState; btrDataPacket.State = (byte)btrServerSide.BtrState;
btrDataPacket.RouteState = (byte)serverSideBtr.VehicleRouteState; btrDataPacket.RouteState = (byte)btrServerSide.VehicleRouteState;
btrDataPacket.LeftSideState = serverSideBtr.LeftSideState; btrDataPacket.LeftSideState = btrServerSide.LeftSideState;
btrDataPacket.LeftSlot0State = serverSideBtr.LeftSlot0State; btrDataPacket.LeftSlot0State = btrServerSide.LeftSlot0State;
btrDataPacket.LeftSlot1State = serverSideBtr.LeftSlot1State; btrDataPacket.LeftSlot1State = btrServerSide.LeftSlot1State;
btrDataPacket.RightSideState = serverSideBtr.RightSideState; btrDataPacket.RightSideState = btrServerSide.RightSideState;
btrDataPacket.RightSlot0State = serverSideBtr.RightSlot0State; btrDataPacket.RightSlot0State = btrServerSide.RightSlot0State;
btrDataPacket.RightSlot1State = serverSideBtr.RightSlot1State; btrDataPacket.RightSlot1State = btrServerSide.RightSlot1State;
btrDataPacket.currentSpeed = serverSideBtr.currentSpeed; btrDataPacket.currentSpeed = btrServerSide.currentSpeed;
btrDataPacket.timeToEndPause = serverSideBtr.timeToEndPause; btrDataPacket.timeToEndPause = btrServerSide.timeToEndPause;
btrDataPacket.moveDirection = (byte)serverSideBtr.VehicleMoveDirection; btrDataPacket.moveDirection = (byte)btrServerSide.VehicleMoveDirection;
btrDataPacket.MoveSpeed = serverSideBtr.moveSpeed; btrDataPacket.MoveSpeed = btrServerSide.moveSpeed;
if (btrController.BotShooterBtr != null) if (btrController.BotShooterBtr != null)
{ {
btrDataPacket.BtrBotId = btrController.BotShooterBtr.Id; btrDataPacket.BtrBotId = btrController.BotShooterBtr.Id;
@ -181,30 +206,49 @@ namespace Aki.Debugging.BTR
private void DisableServerSideRenderers() private void DisableServerSideRenderers()
{ {
var meshRenderers = serverSideBtr.transform.GetComponentsInChildren<MeshRenderer>(); var meshRenderers = btrServerSide.transform.GetComponentsInChildren<MeshRenderer>();
foreach (var renderer in meshRenderers) foreach (var renderer in meshRenderers)
{ {
renderer.enabled = false; renderer.enabled = false;
} }
} }
private void AimAtEnemy()
{
if (btrController.BotShooterBtr == null)
{
return;
}
var btrTurret = btrServerSide.BTRTurret;
var enemies = btrController.BotShooterBtr.BotsGroup.Enemies;
if (enemies.Any())
{
btrTurret.EnableAimingObject(enemies.First().Key.Transform.Original);
}
else
{
btrTurret.DisableAiming();
}
}
private void DestroyGameObjects() private void DestroyGameObjects()
{ {
if (btrController != null) if (btrController != null)
{ {
if (serverSideBtr != null) if (btrServerSide != null)
{ {
Destroy(serverSideBtr.gameObject); Destroy(btrServerSide.gameObject);
} }
if (clientSideBtr != null) if (btrClientSide != null)
{ {
Destroy(clientSideBtr.gameObject); Destroy(btrClientSide.gameObject);
} }
btrController.Dispose(); btrController.Dispose();
} }
if (gameWorld != null) if (gameWorld?.MainPlayer != null)
{ {
gameWorld.MainPlayer.OnBtrStateChanged -= HandleBtrDoorState; gameWorld.MainPlayer.OnBtrStateChanged -= HandleBtrDoorState;
} }

View File

@ -0,0 +1,38 @@
using Aki.Reflection.Patching;
using Aki.Reflection.Utils;
using Comfort.Common;
using EFT;
using EFT.UI.Screens;
using HarmonyLib;
using System.Linq;
using System.Reflection;
using static EFT.UI.TraderDialogScreen;
namespace Aki.Debugging.BTR.Patches
{
public class BTRActivateTraderDialogPatch : ModulePatch
{
protected override MethodBase GetTargetMethod()
{
var targetType = typeof(GClass1854).GetNestedTypes(PatchConstants.PrivateFlags).Where(x => x.Name == "Class1469").First();
return AccessTools.Method(targetType, "method_2");
}
[PatchPrefix]
public static bool PatchPrefix()
{
var gameWorld = Singleton<GameWorld>.Instance;
var player = gameWorld.MainPlayer;
var questController = (GClass3201)AccessTools.Field(player.GetType(), "_questController").GetValue(player);
var inventoryController = (InventoryControllerClass)AccessTools.Field(player.GetType(), "_inventoryController").GetValue(player);
GClass3130 btrDialog = new GClass3130(player.Profile, Profile.TraderInfo.BTR_TRADER_ID, questController, inventoryController, null);
btrDialog.OnClose += player.UpdateInteractionCast;
btrDialog.ShowScreen(EScreenState.Queued);
//GClass1952.ShowDialogScreen(Profile.ETraderServiceSource.Btr, true);
return false;
}
}
}

View File

@ -0,0 +1,55 @@
using Aki.Reflection.Patching;
using Comfort.Common;
using EFT;
using EFT.Vehicle;
using HarmonyLib;
using System;
using System.Reflection;
namespace Aki.Debugging.BTR.Patches
{
public class BTRExtractPassengersPatch : ModulePatch
{
protected override MethodBase GetTargetMethod()
{
return AccessTools.Method(typeof(VehicleBase), "ExtractPassengers");
}
[PatchPrefix]
public static void PatchPrefix()
{
var gameWorld = Singleton<GameWorld>.Instance;
var player = gameWorld.MainPlayer;
var btrManager = gameWorld.GetComponent<BTRManager>();
try
{
var btrSide = btrManager.LastInteractedBtrSide;
if (btrSide == null)
{
return;
}
if (btrSide.TryGetCachedPlace(out byte b))
{
var interactionBtrPacket = btrSide.GetInteractWithBtrPacket(b, EInteractionType.GoOut);
if (interactionBtrPacket.HasInteraction)
{
BTRView btrView = gameWorld.BtrController.BtrView;
if (btrView == null)
{
throw new NullReferenceException("BtrView not found");
}
btrManager.OnPlayerInteractDoor(interactionBtrPacket);
btrView.Interaction(player, interactionBtrPacket);
}
}
}
catch (Exception ex19)
{
UnityEngine.Debug.LogException(ex19);
}
}
}
}

View File

@ -20,6 +20,7 @@ namespace Aki.Debugging.BTR.Patches
{ {
var gameWorld = Singleton<GameWorld>.Instance; var gameWorld = Singleton<GameWorld>.Instance;
var player = (Player)__instance; var player = (Player)__instance;
var btrManager = gameWorld.GetComponent<BTRManager>();
try try
{ {
@ -33,10 +34,8 @@ namespace Aki.Debugging.BTR.Patches
{ {
throw new NullReferenceException("BtrView not found"); throw new NullReferenceException("BtrView not found");
} }
var btrManager = gameWorld.GetComponent<BTRManager>();
btrManager.OnPlayerInteractDoor(interactionBtrPacket); btrManager.OnPlayerInteractDoor(interactionBtrPacket);
btrView.Interaction(player, interactionBtrPacket); btrView.Interaction(player, interactionBtrPacket);
} }
} }

View File

@ -17,22 +17,13 @@ namespace Aki.Debugging.BTR.Patches
[PatchPrefix] [PatchPrefix]
public static bool PatchPrefix(ref bool __result) public static bool PatchPrefix(ref bool __result)
{ {
var btrView = Singleton<GameWorld>.Instance?.BtrController?.BtrView; var serverSideBTR = Singleton<GameWorld>.Instance?.BtrController.BtrVehicle;
if (btrView == null) if (serverSideBTR == null)
{ {
return true; return true;
} }
var btrSides = (BTRSide[])AccessTools.Field(typeof(BTRView), "_btrSides").GetValue(btrView); if (serverSideBTR.LeftSideState == 0 && serverSideBTR.RightSideState == 0)
int doorsClosed = 0;
foreach (var side in btrSides)
{
if (side.State == BTRSide.EState.Free)
{
doorsClosed++;
}
}
if (doorsClosed == btrSides.Length)
{ {
__result = true; __result = true;
return false; return false;