using System.Collections; using NitroxClient.GameLogic.Bases; using NitroxClient.GameLogic.InitialSync.Abstract; using NitroxClient.MonoBehaviours; using NitroxClient.MonoBehaviours.Cyclops; using NitroxModel.MultiplayerSession; using NitroxModel.Packets; using UnityEngine; namespace NitroxClient.GameLogic.InitialSync; /// /// Makes sure players can be spawned in entities in the global root (such as vehicles/escape pod). /// /// /// This allows for:
/// - vehicles to use equipment /// - other players to be set as drivers of some vehicle ///
public sealed class GlobalRootInitialSyncProcessor : InitialSyncProcessor { private readonly Entities entities; private readonly Vehicles vehicles; private readonly PlayerManager playerManager; private readonly BulletManager bulletManager; public GlobalRootInitialSyncProcessor(Entities entities, Vehicles vehicles, PlayerManager playerManager, BulletManager bulletManager) { this.entities = entities; this.vehicles = vehicles; this.playerManager = playerManager; this.bulletManager = bulletManager; // As we migrate systems over to entities, we want to ensure the required components are in place to spawn these entities. // For example, migrating inventories to the entity system requires players are spawned in the world before we try to add // inventory items to them. Eventually, all of the below processors will become entities on their own AddDependency(); AddDependency(); AddDependency(); AddStep(WorldSettledForBuildings); AddStep(SpawnEntities); AddStep(RestoreDrivers); } public IEnumerator WorldSettledForBuildings(InitialPlayerSync packet) { yield return new WaitUntil(LargeWorldStreamer.main.IsWorldSettled); // Make sure all building-related prefabs are fully loaded (happen to bug when launching multiple clients locally) yield return Base.InitializeAsync(); yield return BaseGhost.InitializeAsync(); yield return BaseDeconstructable.InitializeAsync(); yield return VirtualCyclops.InitializeConstructablesCache(); yield return bulletManager.Initialize(); BuildingHandler.Main.InitializeOperations(packet.BuildOperationIds); } public IEnumerator SpawnEntities(InitialPlayerSync packet) { Log.Info($"Received initial sync packet with {packet.GlobalRootEntities.Count} global root entities"); yield return entities.SpawnBatchAsync(packet.GlobalRootEntities); } public void RestoreDrivers(InitialPlayerSync packet) { // At this step, vehicles have been spawned already (by SpawnEntities) foreach (PlayerContext playerContext in packet.OtherPlayers) { if (playerContext.DrivingVehicle != null) { Log.Info($"Restoring driver state of {playerContext.PlayerName} in {playerContext.DrivingVehicle}"); vehicles.SetOnPilotMode(playerContext.DrivingVehicle, playerContext.PlayerId, true); if (playerManager.TryFind(playerContext.PlayerId, out RemotePlayer remotePlayer)) { // As remote players are still driving, they aren't updating their IsUnderwater state so AnimationSender.Update // isn't going to send a packet. Therefore we need to set this by hand remotePlayer.UpdateAnimationAndCollider(AnimChangeType.UNDERWATER, AnimChangeState.OFF); } } } } }