mirror of
https://github.com/sp-tarkov/modules.git
synced 2025-02-13 03:10:45 -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:
parent
72dec65d8e
commit
89f0db250d
@ -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();
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InitBTR();
|
gameWorld.BtrController = btrController = Singleton<BTRControllerClass>.Instance;
|
||||||
|
|
||||||
|
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,44 +289,42 @@ 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)
|
||||||
{
|
{
|
||||||
var player = gameWorld.MainPlayer;
|
try
|
||||||
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
|
var player = gameWorld.MainPlayer;
|
||||||
|| lastInteractedBtrSide != null && btrSides[i] == lastInteractedBtrSide)
|
|
||||||
{
|
|
||||||
switch (i)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
btrServerSide.LeftSideState = state;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
btrServerSide.RightSideState = state;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastInteractedBtrSide = player.BtrInteractionSide;
|
BTRSide btrSide = player.BtrInteractionSide != null ? player.BtrInteractionSide : lastInteractedBtrSide;
|
||||||
|
byte sideId = btrClientSide.GetSideId(btrSide);
|
||||||
|
switch (sideId)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
btrServerSide.LeftSideState = state;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
btrServerSide.RightSideState = state;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 (currentTarget != null)
|
||||||
if (enemies.Any())
|
|
||||||
{
|
{
|
||||||
currentTarget = enemies.First().Key;
|
|
||||||
if (!currentTarget.HealthController.IsAlive)
|
|
||||||
{
|
|
||||||
enemies.Remove(currentTarget);
|
|
||||||
currentTarget = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsAimingAtTarget()
|
private void SetAim()
|
||||||
{
|
{
|
||||||
bool turretInDefaultRotation = btrTurretServer.targetTransform == btrTurretDefaultTargetTransform
|
if (currentTarget.IsVisible)
|
||||||
&& btrTurretServer.targetPosition == btrTurretServer.defaultAimingPosition;
|
|
||||||
|
|
||||||
if (currentTarget != null)
|
|
||||||
{
|
{
|
||||||
Transform currentTargetTransform = currentTarget.Transform.Original;
|
Vector3 targetPos = currentTarget.CurrPosition;
|
||||||
EnemyInfo currentTargetInfo = btrBotShooter.EnemiesController.EnemyInfos[currentTarget];
|
Transform targetTransform = currentTarget.Person.Transform.Original;
|
||||||
|
if (btrTurretServer.CheckPositionInAimingZone(targetPos) && btrTurretServer.targetTransform != targetTransform)
|
||||||
if (currentTargetInfo.IsVisible)
|
|
||||||
{
|
{
|
||||||
Vector3 currentTargetPosition = currentTargetTransform.position;
|
btrTurretServer.EnableAimingObject(targetTransform);
|
||||||
if (btrTurretServer.CheckPositionInAimingZone(currentTargetPosition))
|
|
||||||
{
|
|
||||||
if (btrTurretServer.targetTransform == currentTargetTransform && btrBotShooter.BotBtrData.CanShoot())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (btrTurretServer.targetTransform != currentTargetTransform)
|
|
||||||
{
|
|
||||||
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)
|
else
|
||||||
|
{
|
||||||
|
Vector3 targetLastPos = currentTarget.EnemyLastPositionReal;
|
||||||
|
if (btrTurretServer.CheckPositionInAimingZone(targetLastPos)
|
||||||
|
&& Time.time - currentTarget.PersonalLastSeenTime < 3f
|
||||||
|
&& btrTurretServer.targetPosition != targetLastPos)
|
||||||
{
|
{
|
||||||
btrTurretServer.EnableAimingPosition(currentTargetInfo.EnemyLastPosition);
|
btrTurretServer.EnableAimingPosition(targetLastPos);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (currentTargetInfo.TimeLastSeen >= 3f && !turretInDefaultRotation)
|
else if (Time.time - currentTarget.PersonalLastSeenTime >= 3f && !isTurretInDefaultRotation)
|
||||||
{
|
{
|
||||||
currentTarget = null;
|
|
||||||
btrTurretServer.DisableAiming();
|
btrTurretServer.DisableAiming();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!turretInDefaultRotation)
|
}
|
||||||
|
|
||||||
|
private bool CanShoot()
|
||||||
|
{
|
||||||
|
if (currentTarget.IsVisible && btrBotShooter.BotBtrData.CanShoot())
|
||||||
{
|
{
|
||||||
btrTurretServer.DisableAiming();
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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);
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>())
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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]
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user