0
0
mirror of https://github.com/sp-tarkov/modules.git synced 2025-02-13 02:10:45 -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 StaticLootDumper().Enable();
new BTRPathLoadPatch().Enable();
new BTRActivateTraderDialogPatch().Enable();
new BTRInteractionPatch().Enable();
new BTRExtractPassengersPatch().Enable();
new BTRBotAttachPatch().Enable();
new BTRBotInitPatch().Enable();
new BTRIsDoorsClosedPath().Enable();
new BTRPatch().Enable();
new BTRPatch().Enable();
}
catch (Exception ex)
{

View File

@ -1,7 +1,10 @@
using Comfort.Common;
using Aki.Reflection.Utils;
using Comfort.Common;
using EFT;
using EFT.Vehicle;
using HarmonyLib;
using System;
using System.Linq;
using UnityEngine;
using BTRController = GClass2911;
using BTRDataPacket = GStruct378;
@ -12,12 +15,18 @@ namespace Aki.Debugging.BTR
public class BTRManager : MonoBehaviour
{
private GameWorld gameWorld;
private BotsController botsController;
private BotBTRService btrBotService;
private BTRController btrController;
private BTRVehicle serverSideBtr;
private BTRView clientSideBtr;
private BTRVehicle btrServerSide;
private BTRView btrClientSide;
private BTRDataPacket btrDataPacket = default;
private bool btrBotShooterInitialized = false;
private EPlayerBtrState previousPlayerBtrState;
private BTRSide previousInteractedBtrSide;
private BTRSide lastInteractedBtrSide;
public BTRSide LastInteractedBtrSide => lastInteractedBtrSide;
private void Start()
@ -41,27 +50,10 @@ namespace Aki.Debugging.BTR
gameWorld.BtrController = btrController = Singleton<BTRController>.Instance;
}
var btrControllerType = btrController.GetType();
AccessTools.Method(btrControllerType, "method_3").Invoke(btrController, null); // spawns server-side BTR game object
Singleton<IBotGame>.Instance.BotsController.BotSpawner.SpawnBotBTR(); // spawns the scav bot which controls the BTR's turret
botsController = Singleton<IBotGame>.Instance.BotsController;
btrBotService = botsController.BotTradersServices.BTRServices;
serverSideBtr = btrController.BtrVehicle;
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;
InitBTR();
}
catch
{
@ -74,6 +66,15 @@ namespace Aki.Debugging.BTR
private void Update()
{
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)
@ -104,30 +105,55 @@ namespace Aki.Debugging.BTR
{
if (interactPacket.SlotId == 0)
{
if (playerGoIn) serverSideBtr.LeftSlot0State = 1;
else if (playerGoOut) serverSideBtr.LeftSlot0State = 0;
if (playerGoIn) btrServerSide.LeftSlot0State = 1;
else if (playerGoOut) btrServerSide.LeftSlot0State = 0;
}
else if (interactPacket.SlotId == 1)
{
if (playerGoIn) serverSideBtr.LeftSlot1State = 1;
else if (playerGoOut) serverSideBtr.LeftSlot1State = 0;
if (playerGoIn) btrServerSide.LeftSlot1State = 1;
else if (playerGoOut) btrServerSide.LeftSlot1State = 0;
}
}
else if (interactPacket.SideId == 1)
{
if (interactPacket.SlotId == 0)
{
if (playerGoIn) serverSideBtr.RightSlot0State = 1;
else if (playerGoOut) serverSideBtr.RightSlot0State = 0;
if (playerGoIn) btrServerSide.RightSlot0State = 1;
else if (playerGoOut) btrServerSide.RightSlot0State = 0;
}
else if (interactPacket.SlotId == 1)
{
if (playerGoIn) serverSideBtr.RightSlot1State = 1;
else if (playerGoOut) serverSideBtr.RightSlot1State = 0;
if (playerGoIn) btrServerSide.RightSlot1State = 1;
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)
{
var player = gameWorld.MainPlayer;
@ -136,15 +162,14 @@ namespace Aki.Debugging.BTR
for (int i = 0; i < btrSides.Length; i++)
{
if (player.BtrInteractionSide != null && btrSides[i] == player.BtrInteractionSide
|| previousInteractedBtrSide != null && btrSides[i] == previousInteractedBtrSide)
|| lastInteractedBtrSide != null && btrSides[i] == lastInteractedBtrSide)
{
if (i == 0) serverSideBtr.LeftSideState = state;
else if (i == 1) serverSideBtr.RightSideState = state;
if (i == 0) btrServerSide.LeftSideState = state;
else if (i == 1) btrServerSide.RightSideState = state;
if ((previousInteractedBtrSide != player.BtrInteractionSide && player.BtrInteractionSide != null)
|| previousInteractedBtrSide == null)
if (lastInteractedBtrSide != player.BtrInteractionSide)
{
previousInteractedBtrSide = player.BtrInteractionSide;
lastInteractedBtrSide = player.BtrInteractionSide;
}
}
}
@ -152,25 +177,25 @@ namespace Aki.Debugging.BTR
private BTRDataPacket UpdateDataPacket()
{
btrDataPacket.position = serverSideBtr.transform.position;
btrDataPacket.rotation = serverSideBtr.transform.rotation;
if (serverSideBtr.BTRTurret?.gunsBlockRoot != null)
btrDataPacket.position = btrServerSide.transform.position;
btrDataPacket.rotation = btrServerSide.transform.rotation;
if (btrServerSide.BTRTurret?.gunsBlockRoot != null)
{
btrDataPacket.turretRotation = serverSideBtr.BTRTurret.transform.rotation;
btrDataPacket.gunsBlockRotation = serverSideBtr.BTRTurret.gunsBlockRoot.rotation;
btrDataPacket.turretRotation = btrServerSide.BTRTurret.transform.rotation;
btrDataPacket.gunsBlockRotation = btrServerSide.BTRTurret.gunsBlockRoot.rotation;
}
btrDataPacket.State = (byte)serverSideBtr.BtrState;
btrDataPacket.RouteState = (byte)serverSideBtr.VehicleRouteState;
btrDataPacket.LeftSideState = serverSideBtr.LeftSideState;
btrDataPacket.LeftSlot0State = serverSideBtr.LeftSlot0State;
btrDataPacket.LeftSlot1State = serverSideBtr.LeftSlot1State;
btrDataPacket.RightSideState = serverSideBtr.RightSideState;
btrDataPacket.RightSlot0State = serverSideBtr.RightSlot0State;
btrDataPacket.RightSlot1State = serverSideBtr.RightSlot1State;
btrDataPacket.currentSpeed = serverSideBtr.currentSpeed;
btrDataPacket.timeToEndPause = serverSideBtr.timeToEndPause;
btrDataPacket.moveDirection = (byte)serverSideBtr.VehicleMoveDirection;
btrDataPacket.MoveSpeed = serverSideBtr.moveSpeed;
btrDataPacket.State = (byte)btrServerSide.BtrState;
btrDataPacket.RouteState = (byte)btrServerSide.VehicleRouteState;
btrDataPacket.LeftSideState = btrServerSide.LeftSideState;
btrDataPacket.LeftSlot0State = btrServerSide.LeftSlot0State;
btrDataPacket.LeftSlot1State = btrServerSide.LeftSlot1State;
btrDataPacket.RightSideState = btrServerSide.RightSideState;
btrDataPacket.RightSlot0State = btrServerSide.RightSlot0State;
btrDataPacket.RightSlot1State = btrServerSide.RightSlot1State;
btrDataPacket.currentSpeed = btrServerSide.currentSpeed;
btrDataPacket.timeToEndPause = btrServerSide.timeToEndPause;
btrDataPacket.moveDirection = (byte)btrServerSide.VehicleMoveDirection;
btrDataPacket.MoveSpeed = btrServerSide.moveSpeed;
if (btrController.BotShooterBtr != null)
{
btrDataPacket.BtrBotId = btrController.BotShooterBtr.Id;
@ -181,30 +206,49 @@ namespace Aki.Debugging.BTR
private void DisableServerSideRenderers()
{
var meshRenderers = serverSideBtr.transform.GetComponentsInChildren<MeshRenderer>();
var meshRenderers = btrServerSide.transform.GetComponentsInChildren<MeshRenderer>();
foreach (var renderer in meshRenderers)
{
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()
{
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();
}
if (gameWorld != null)
if (gameWorld?.MainPlayer != null)
{
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 player = (Player)__instance;
var btrManager = gameWorld.GetComponent<BTRManager>();
try
{
@ -34,9 +35,7 @@ namespace Aki.Debugging.BTR.Patches
throw new NullReferenceException("BtrView not found");
}
var btrManager = gameWorld.GetComponent<BTRManager>();
btrManager.OnPlayerInteractDoor(interactionBtrPacket);
btrView.Interaction(player, interactionBtrPacket);
}
}

View File

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