mirror of
https://github.com/sp-tarkov/modules.git
synced 2025-02-13 09:50:43 -05:00
Player can now enter and exit the BTR (!51)
Todo: * BTR Driver services * Send to items to player stash (2x4) * Provide covering fire * Taxi to a specific location on Streets * BTR turns hostile if you shoot it * BTR automatically follows a set path from raid start, stopping at locations for 90 seconds each stop Co-authored-by: Nympfonic <arys.steam@gmail.com> Reviewed-on: SPT-AKI/Modules#51 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:
parent
e4f91a58e4
commit
33e6c151af
@ -18,8 +18,11 @@ namespace Aki.Debugging
|
|||||||
new EndRaidDebug().Enable();
|
new EndRaidDebug().Enable();
|
||||||
// new CoordinatesPatch().Enable();
|
// new CoordinatesPatch().Enable();
|
||||||
// new StaticLootDumper().Enable();
|
// new StaticLootDumper().Enable();
|
||||||
|
new BTRPathLoadPatch().Enable();
|
||||||
|
new BTRInteractionPatch().Enable();
|
||||||
new BTRBotAttachPatch().Enable();
|
new BTRBotAttachPatch().Enable();
|
||||||
new BTRBotInitPatch().Enable();
|
new BTRBotInitPatch().Enable();
|
||||||
|
new BTRIsDoorsClosedPath().Enable();
|
||||||
new BTRPatch().Enable();
|
new BTRPatch().Enable();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -5,22 +5,26 @@ using HarmonyLib;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using BTRController = GClass2911;
|
using BTRController = GClass2911;
|
||||||
using BTRDataPacket = GStruct378;
|
using BTRDataPacket = GStruct378;
|
||||||
|
using PlayerInteractPacket = GStruct167;
|
||||||
|
|
||||||
namespace Aki.Debugging.BTR
|
namespace Aki.Debugging.BTR
|
||||||
{
|
{
|
||||||
public class BTRManager : MonoBehaviour
|
public class BTRManager : MonoBehaviour
|
||||||
{
|
{
|
||||||
|
private GameWorld gameWorld;
|
||||||
private BTRController btrController;
|
private BTRController btrController;
|
||||||
private BTRVehicle serverSideBtr;
|
private BTRVehicle serverSideBtr;
|
||||||
private BTRView clientSideBtr;
|
private BTRView clientSideBtr;
|
||||||
private BTRDataPacket btrDataPacket = default;
|
private BTRDataPacket btrDataPacket = default;
|
||||||
|
private EPlayerBtrState previousPlayerBtrState;
|
||||||
|
private BTRSide previousInteractedBtrSide;
|
||||||
|
|
||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var gameWorld = Singleton<GameWorld>.Instance;
|
gameWorld = Singleton<GameWorld>.Instance;
|
||||||
|
|
||||||
if (gameWorld == null)
|
if (gameWorld == null)
|
||||||
{
|
{
|
||||||
@ -55,6 +59,9 @@ namespace Aki.Debugging.BTR
|
|||||||
clientSideBtr.transform.rotation = btrDataPacket.rotation;
|
clientSideBtr.transform.rotation = btrDataPacket.rotation;
|
||||||
|
|
||||||
DisableServerSideRenderers();
|
DisableServerSideRenderers();
|
||||||
|
|
||||||
|
previousPlayerBtrState = gameWorld.MainPlayer.BtrState;
|
||||||
|
gameWorld.MainPlayer.OnBtrStateChanged += HandleBtrDoorState;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -69,6 +76,80 @@ namespace Aki.Debugging.BTR
|
|||||||
btrController.SyncBTRVehicleFromServer(UpdateDataPacket());
|
btrController.SyncBTRVehicleFromServer(UpdateDataPacket());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void HandleBtrDoorState(EPlayerBtrState playerBtrState)
|
||||||
|
{
|
||||||
|
if (previousPlayerBtrState == EPlayerBtrState.Approach && playerBtrState == EPlayerBtrState.GoIn
|
||||||
|
|| previousPlayerBtrState == EPlayerBtrState.Inside && playerBtrState == EPlayerBtrState.GoOut)
|
||||||
|
{
|
||||||
|
// Open Door
|
||||||
|
UpdateBTRSideDoorState(1);
|
||||||
|
}
|
||||||
|
else if (previousPlayerBtrState == EPlayerBtrState.GoIn && playerBtrState == EPlayerBtrState.Inside
|
||||||
|
|| previousPlayerBtrState == EPlayerBtrState.GoOut && playerBtrState == EPlayerBtrState.Outside)
|
||||||
|
{
|
||||||
|
// Close Door
|
||||||
|
UpdateBTRSideDoorState(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
previousPlayerBtrState = playerBtrState;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Please tell me there's a better way than this xd
|
||||||
|
public void OnPlayerInteractDoor(PlayerInteractPacket interactPacket)
|
||||||
|
{
|
||||||
|
var playerGoIn = interactPacket.InteractionType == EInteractionType.GoIn;
|
||||||
|
var playerGoOut = interactPacket.InteractionType == EInteractionType.GoOut;
|
||||||
|
|
||||||
|
if (interactPacket.SideId == 0)
|
||||||
|
{
|
||||||
|
if (interactPacket.SlotId == 0)
|
||||||
|
{
|
||||||
|
if (playerGoIn) serverSideBtr.LeftSlot0State = 1;
|
||||||
|
else if (playerGoOut) serverSideBtr.LeftSlot0State = 0;
|
||||||
|
}
|
||||||
|
else if (interactPacket.SlotId == 1)
|
||||||
|
{
|
||||||
|
if (playerGoIn) serverSideBtr.LeftSlot1State = 1;
|
||||||
|
else if (playerGoOut) serverSideBtr.LeftSlot1State = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (interactPacket.SideId == 1)
|
||||||
|
{
|
||||||
|
if (interactPacket.SlotId == 0)
|
||||||
|
{
|
||||||
|
if (playerGoIn) serverSideBtr.RightSlot0State = 1;
|
||||||
|
else if (playerGoOut) serverSideBtr.RightSlot0State = 0;
|
||||||
|
}
|
||||||
|
else if (interactPacket.SlotId == 1)
|
||||||
|
{
|
||||||
|
if (playerGoIn) serverSideBtr.RightSlot1State = 1;
|
||||||
|
else if (playerGoOut) serverSideBtr.RightSlot1State = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateBTRSideDoorState(byte state)
|
||||||
|
{
|
||||||
|
var player = gameWorld.MainPlayer;
|
||||||
|
var btrSides = (BTRSide[])AccessTools.Field(typeof(BTRView), "_btrSides").GetValue(btrController.BtrView);
|
||||||
|
|
||||||
|
for (int i = 0; i < btrSides.Length; i++)
|
||||||
|
{
|
||||||
|
if (player.BtrInteractionSide != null && btrSides[i] == player.BtrInteractionSide
|
||||||
|
|| previousInteractedBtrSide != null && btrSides[i] == previousInteractedBtrSide)
|
||||||
|
{
|
||||||
|
if (i == 0) serverSideBtr.LeftSideState = state;
|
||||||
|
else if (i == 1) serverSideBtr.RightSideState = state;
|
||||||
|
|
||||||
|
if ((previousInteractedBtrSide != player.BtrInteractionSide && player.BtrInteractionSide != null)
|
||||||
|
|| previousInteractedBtrSide == null)
|
||||||
|
{
|
||||||
|
previousInteractedBtrSide = player.BtrInteractionSide;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private BTRDataPacket UpdateDataPacket()
|
private BTRDataPacket UpdateDataPacket()
|
||||||
{
|
{
|
||||||
btrDataPacket.position = serverSideBtr.transform.position;
|
btrDataPacket.position = serverSideBtr.transform.position;
|
||||||
@ -122,6 +203,11 @@ namespace Aki.Debugging.BTR
|
|||||||
|
|
||||||
btrController.Dispose();
|
btrController.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gameWorld != null)
|
||||||
|
{
|
||||||
|
gameWorld.MainPlayer.OnBtrStateChanged -= HandleBtrDoorState;
|
||||||
|
}
|
||||||
Destroy(this);
|
Destroy(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,11 +59,12 @@ namespace Aki.Debugging.BTR.Patches
|
|||||||
currentWeaponPrefab.transform.position = botRootTransform.position;
|
currentWeaponPrefab.transform.position = botRootTransform.position;
|
||||||
|
|
||||||
btrBot.PlayerBones.Weapon_Root_Anim.SetPositionAndRotation(botRootTransform.position, botRootTransform.rotation);
|
btrBot.PlayerBones.Weapon_Root_Anim.SetPositionAndRotation(botRootTransform.position, botRootTransform.rotation);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@ namespace Aki.Debugging.BTR.Patches
|
|||||||
// Context:
|
// Context:
|
||||||
// ClientGameWorld in LiveEFT will register the server-side BTR Bot as type ObservedPlayerView and is stored in GameWorld's allObservedPlayersByID dictionary.
|
// ClientGameWorld in LiveEFT will register the server-side BTR Bot as type ObservedPlayerView and is stored in GameWorld's allObservedPlayersByID dictionary.
|
||||||
// In SPT, allObservedPlayersByID is empty which results in the game never finishing the initialization of the BTR Bot which includes disabling its gun, voice and mesh renderers.
|
// In SPT, allObservedPlayersByID is empty which results in the game never finishing the initialization of the BTR Bot which includes disabling its gun, voice and mesh renderers.
|
||||||
// Perhaps some research should be done into getting the dictionary populated as ObservedPlayerView seems to be utilised by several aspects of the BTR's functionality.
|
|
||||||
// For now, we do dirty patches to work around the lack of ObservedPlayerView, using Player instead.
|
// For now, we do dirty patches to work around the lack of ObservedPlayerView, using Player instead.
|
||||||
public class BTRBotInitPatch : ModulePatch
|
public class BTRBotInitPatch : ModulePatch
|
||||||
{
|
{
|
||||||
|
49
project/Aki.Debugging/BTR/Patches/BTRInteractionPatch.cs
Normal file
49
project/Aki.Debugging/BTR/Patches/BTRInteractionPatch.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using Aki.Reflection.Patching;
|
||||||
|
using Comfort.Common;
|
||||||
|
using EFT;
|
||||||
|
using EFT.Vehicle;
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Aki.Debugging.BTR.Patches
|
||||||
|
{
|
||||||
|
public class BTRInteractionPatch : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
|
||||||
|
return typeof(Player).GetMethod("BtrInteraction", bindingFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
public static void PatchPostfix(object __instance, BTRSide btr, byte placeId, EInteractionType interaction)
|
||||||
|
{
|
||||||
|
var gameWorld = Singleton<GameWorld>.Instance;
|
||||||
|
var player = (Player)__instance;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var interactionBtrPacket = btr.GetInteractWithBtrPacket(placeId, interaction);
|
||||||
|
player.UpdateInteractionCast();
|
||||||
|
|
||||||
|
if (interactionBtrPacket.HasInteraction)
|
||||||
|
{
|
||||||
|
BTRView btrView = gameWorld.BtrController.BtrView;
|
||||||
|
if (btrView == null)
|
||||||
|
{
|
||||||
|
throw new NullReferenceException("BtrView not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
var btrManager = gameWorld.GetComponent<BTRManager>();
|
||||||
|
btrManager.OnPlayerInteractDoor(interactionBtrPacket);
|
||||||
|
|
||||||
|
btrView.Interaction(player, interactionBtrPacket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex19)
|
||||||
|
{
|
||||||
|
UnityEngine.Debug.LogException(ex19);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
project/Aki.Debugging/BTR/Patches/BTRIsDoorsClosedPatch.cs
Normal file
44
project/Aki.Debugging/BTR/Patches/BTRIsDoorsClosedPatch.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using Aki.Reflection.Patching;
|
||||||
|
using Comfort.Common;
|
||||||
|
using EFT;
|
||||||
|
using EFT.Vehicle;
|
||||||
|
using HarmonyLib;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Aki.Debugging.BTR.Patches
|
||||||
|
{
|
||||||
|
public class BTRIsDoorsClosedPath : ModulePatch
|
||||||
|
{
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
return AccessTools.Method(typeof(VehicleBase), "IsDoorsClosed");
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static bool PatchPrefix(ref bool __result)
|
||||||
|
{
|
||||||
|
var btrView = Singleton<GameWorld>.Instance?.BtrController?.BtrView;
|
||||||
|
if (btrView == 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)
|
||||||
|
{
|
||||||
|
__result = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,9 @@ using EFT.UI;
|
|||||||
|
|
||||||
namespace Aki.Debugging.BTR.Patches
|
namespace Aki.Debugging.BTR.Patches
|
||||||
{
|
{
|
||||||
// Adds a BTRManager component to the GameWorld game object when raid starts.
|
/// <summary>
|
||||||
|
/// Adds a BTRManager component to the GameWorld game object when raid starts.
|
||||||
|
/// </summary>
|
||||||
public class BTRPatch : ModulePatch
|
public class BTRPatch : ModulePatch
|
||||||
{
|
{
|
||||||
protected override MethodBase GetTargetMethod()
|
protected override MethodBase GetTargetMethod()
|
||||||
@ -36,7 +38,7 @@ namespace Aki.Debugging.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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
35
project/Aki.Debugging/BTR/Patches/BTRPathLoadPatch.cs
Normal file
35
project/Aki.Debugging/BTR/Patches/BTRPathLoadPatch.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using Aki.Reflection.Patching;
|
||||||
|
using Comfort.Common;
|
||||||
|
using EFT;
|
||||||
|
using HarmonyLib;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Aki.Debugging.BTR.Patches
|
||||||
|
{
|
||||||
|
// The BTRManager MapPathsConfiguration loading depends on the game state being set to Starting
|
||||||
|
// so set it to Starting while the method is running, then reset it afterwards
|
||||||
|
public class BTRPathLoadPatch : ModulePatch
|
||||||
|
{
|
||||||
|
private static PropertyInfo _statusProperty;
|
||||||
|
private static GameStatus originalStatus;
|
||||||
|
protected override MethodBase GetTargetMethod()
|
||||||
|
{
|
||||||
|
_statusProperty = AccessTools.Property(typeof(AbstractGame), "Status");
|
||||||
|
|
||||||
|
return AccessTools.Method(typeof(GClass2911), "method_1");
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPrefix]
|
||||||
|
public static void PatchPrefix()
|
||||||
|
{
|
||||||
|
originalStatus = Singleton<AbstractGame>.Instance.Status;
|
||||||
|
_statusProperty.SetValue(Singleton<AbstractGame>.Instance, GameStatus.Starting);
|
||||||
|
}
|
||||||
|
|
||||||
|
[PatchPostfix]
|
||||||
|
public static void PatchPostfix()
|
||||||
|
{
|
||||||
|
_statusProperty.SetValue(Singleton<AbstractGame>.Instance, originalStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user