diff --git a/Source/Coop/Components/ActionPacketHandlerComponent.cs b/Source/Coop/Components/ActionPacketHandlerComponent.cs index 1eb7cc95..a14fe1bb 100644 --- a/Source/Coop/Components/ActionPacketHandlerComponent.cs +++ b/Source/Coop/Components/ActionPacketHandlerComponent.cs @@ -3,6 +3,7 @@ using BepInEx.Logging; using Comfort.Common; using EFT; +using EFT.MovingPlatforms; using EFT.UI.BattleTimer; using StayInTarkov.AkiSupport.Airdrops.Models; using StayInTarkov.Coop.Matchmaker; @@ -220,6 +221,10 @@ bool ProcessWorldPacket(ref Dictionary packet) ReplicateTimeAndWeather(packet); result = true; break; + case "ArmoredTrainTime": + ReplicateArmoredTrainTime(packet); + result = true; + break; case "LootableContainer_Interact": LootableContainer_Interact_Patch.Replicated(packet); result = true; @@ -462,5 +467,38 @@ static bool VectorIsSameQuadrant(Vector2 v1, Vector2 v2, out int flag) } } } + + void ReplicateArmoredTrainTime(Dictionary packet) + { + CoopGameComponent coopGameComponent = CoopGameComponent.GetCoopGameComponent(); + if (coopGameComponent == null) + return; + + if (MatchmakerAcceptPatches.IsClient) + { + DateTime utcTime = new(long.Parse(packet["utcTime"].ToString())); + + if (coopGameComponent.LocalGameInstance is CoopGame coopGame) + { + Timer1 gameTimer = coopGame.GameTimer; + + // Process only after raid began. + if (gameTimer.StartDateTime.HasValue && gameTimer.SessionTime.HasValue) + { + // Looking for Armored Train, if there is nothing, then we are not on the Reserve or Lighthouse. + Locomotive locomotive = FindObjectOfType(); + if (locomotive != null) + { + // The time won't change, if we already have replicated the time, don't override it again. + FieldInfo departField = ReflectionHelpers.GetFieldFromType(typeof(MovingPlatform), "_depart"); + if (utcTime == (DateTime)departField.GetValue(locomotive)) + return; + + locomotive.Init(utcTime); + } + } + } + } + } } } diff --git a/Source/Coop/CoopGame.cs b/Source/Coop/CoopGame.cs index 089bf2cb..bc766373 100644 --- a/Source/Coop/CoopGame.cs +++ b/Source/Coop/CoopGame.cs @@ -6,6 +6,7 @@ using EFT.Game.Spawning; using EFT.InputSystem; using EFT.Interactive; +using EFT.MovingPlatforms; using EFT.UI; using EFT.Weather; using JsonType; @@ -19,6 +20,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Threading.Tasks; using UnityEngine; @@ -200,6 +202,7 @@ public void CreateCoopGameComponent() StartCoroutine(HostPinger()); StartCoroutine(GameTimerSync()); StartCoroutine(TimeAndWeatherSync()); + StartCoroutine(ArmoredTrainTimeSync()); } StartCoroutine(ClientLoadingPinger()); @@ -289,7 +292,7 @@ private IEnumerator GameTimerSync() } } - public IEnumerator TimeAndWeatherSync() + private IEnumerator TimeAndWeatherSync() { var waitSeconds = new WaitForSeconds(15f); @@ -335,6 +338,39 @@ public IEnumerator TimeAndWeatherSync() } } + private IEnumerator ArmoredTrainTimeSync() + { + var waitSeconds = new WaitForSeconds(30f); + + while (true) + { + yield return waitSeconds; + + if (!CoopGameComponent.TryGetCoopGameComponent(out var coopGameComponent)) + yield break; + + // Make sure packet is only sent after the raid begins. + if (GameTimer.StartDateTime.HasValue && GameTimer.SessionTime.HasValue) + { + // Looking for Armored Train, if there is nothing, then we are not on the Reserve or Lighthouse. + Locomotive locomotive = FindObjectOfType(); + if (locomotive == null) + yield break; + + // Utc time where the train will start moving. + FieldInfo departField = ReflectionHelpers.GetFieldFromType(typeof(MovingPlatform), "_depart"); + + Dictionary dict = new() + { + { "serverId", coopGameComponent.ServerId }, + { "m", "ArmoredTrainTime" }, + { "utcTime", ((DateTime)departField.GetValue(locomotive)).Ticks }, + }; + AkiBackendCommunication.Instance.SendDataToPool(dict.ToJson()); + } + } + } + public Dictionary Bots { get; } = new (); private async Task CreatePhysicalBot(Profile profile, Vector3 position)