diff --git a/Multiplayer/Components/MainMenu/ServerBrowser/ServerBrowserElement.cs b/Multiplayer/Components/MainMenu/ServerBrowser/ServerBrowserElement.cs index 18476b38..5110137e 100644 --- a/Multiplayer/Components/MainMenu/ServerBrowser/ServerBrowserElement.cs +++ b/Multiplayer/Components/MainMenu/ServerBrowser/ServerBrowserElement.cs @@ -76,7 +76,7 @@ protected override void Awake() goIconLAN = this.FindChildByName("LAN Icon"); } else - { + { goIconLAN = Instantiate(goIconPassword, goIconPassword.transform.parent); goIconLAN.name = "LAN Icon"; Vector3 LANpos = goIconLAN.transform.localPosition; @@ -113,7 +113,7 @@ public void UpdateView() serverName.text = data.Name; playerCount.text = $"{data.CurrentPlayers} / {data.MaxPlayers}"; - ping.text = $"{(data.Ping < 0 ? "?" : data.Ping)} ms"; + ping.text = $"{(data.Ping < 0 ? "?" : data.Ping.ToString())} ms"; // Hide the icon if the server does not have a password goIconPassword.SetActive(data.HasPassword); diff --git a/Multiplayer/Networking/Managers/Client/NetworkClient.cs b/Multiplayer/Networking/Managers/Client/NetworkClient.cs index f2f22879..4eceeffc 100644 --- a/Multiplayer/Networking/Managers/Client/NetworkClient.cs +++ b/Multiplayer/Networking/Managers/Client/NetworkClient.cs @@ -1293,6 +1293,11 @@ public void SendTrainSyncRequest(ushort netId) }, DeliveryMethod.ReliableUnordered); } + public void SendTrainCarSpawnRequest(TrainCar trainCar) + { + SendPacketToServer(ServerboundTrainCarSpawnRequest.FromTrainCar(trainCar), DeliveryMethod.ReliableOrdered); + } + public void SendTrainDeleteRequest(ushort netId) { SendPacketToServer(new ServerboundTrainDeleteRequestPacket diff --git a/Multiplayer/Networking/Managers/NetworkManager.cs b/Multiplayer/Networking/Managers/NetworkManager.cs index 68d06194..3bf9e5ab 100644 --- a/Multiplayer/Networking/Managers/NetworkManager.cs +++ b/Multiplayer/Networking/Managers/NetworkManager.cs @@ -29,7 +29,7 @@ public abstract class NetworkManager protected NetworkManager(Settings settings) { netPacketProcessor = new NetPacketProcessor(); - //transport = new LiteNetLibTransport(); + // transport = new LiteNetLibTransport(); transport = new SteamWorksTransport(); transport.OnConnectionRequest += OnConnectionRequest; diff --git a/Multiplayer/Networking/Managers/Server/NetworkServer.cs b/Multiplayer/Networking/Managers/Server/NetworkServer.cs index a71b1def..07e322fe 100644 --- a/Multiplayer/Networking/Managers/Server/NetworkServer.cs +++ b/Multiplayer/Networking/Managers/Server/NetworkServer.cs @@ -31,6 +31,7 @@ using Multiplayer.Networking.Packets.Serverbound.Train; using Multiplayer.Networking.Packets.Unconnected; using System.Text; +using Multiplayer.Components; using Multiplayer.Networking.Data.Train; using Multiplayer.Networking.TransportLayers; using Multiplayer.Networking.Packets.Serverbound.Jobs; @@ -131,6 +132,7 @@ protected override void Subscribe() netPacketProcessor.SubscribeReusable(OnServerboundPlayerPositionPacket); netPacketProcessor.SubscribeReusable(OnServerboundTrainSyncRequestPacket); + netPacketProcessor.SubscribeReusable(OnServerboundTrainCarSpawnRequest); netPacketProcessor.SubscribeReusable(OnServerboundTrainDeleteRequestPacket); netPacketProcessor.SubscribeReusable(OnServerboundTrainRerailRequestPacket); netPacketProcessor.SubscribeReusable(OnServerboundLicensePurchaseRequestPacket); @@ -208,7 +210,7 @@ public override void OnPeerConnected(ITransportPeer peer) public override void OnPeerDisconnected(ITransportPeer peer, DisconnectReason disconnectReason) { byte id = (byte)peer.Id; - Log($"Player {(serverPlayers.TryGetValue(id, out ServerPlayer player) ? player : id)} disconnected: {disconnectReason}"); + Log($"Player {(serverPlayers.TryGetValue(id, out ServerPlayer player) ? player.Id : id)} disconnected: {disconnectReason}"); if (WorldStreamingInit.isLoaded) SaveGameManager.Instance.UpdateInternalData(); @@ -1025,6 +1027,20 @@ private void OnServerboundTrainSyncRequestPacket(ServerboundTrainSyncRequestPack networkedTrainCar.Server_DirtyAllState(); } + private void OnServerboundTrainCarSpawnRequest(ServerboundTrainCarSpawnRequest packet) + { + if (!TrainComponentLookup.Instance.LiveryFromId(packet.LiveryID, out TrainCarLivery livery)) + { + NetworkLifecycle.Instance.Client.LogDebug(() => $"Tried spawning car but couldn't find TrainCarLivery with ID {packet.LiveryID}"); + return; + } + + Multiplayer.Log($"Client spawned {livery.name} car"); + TrainCar trainCar = CarSpawner.Instance.SpawnCar(livery.prefab, RailTrack.GetClosest(packet.Position).track, packet.Position, packet.Forward, true); + NetworkedTrainCar networkedTrainCar = NetworkedCarSpawner.SpawnCar(TrainsetSpawnPart.FromTrainSet([trainCar])[0]); + NetworkLifecycle.Instance.Server.SendSpawnTrainCar(networkedTrainCar); + } + private void OnServerboundTrainDeleteRequestPacket(ServerboundTrainDeleteRequestPacket packet, ITransportPeer peer) { if (!TryGetServerPlayer(peer, out ServerPlayer player)) @@ -1176,7 +1192,7 @@ private void OnServerboundWarehouseMachineControllerRequestPacket(ServerboundWar if(!NetworkedWarehouseMachineController.Get(packet.NetId, out var targetWarehouse)) { LogWarning($"ServerboundWarehouseMachineControllerRequestPacket() WarehouseMachineController not found. NetId: {packet.NetId}"); - return; + return; } //Todo: add check for player distance from machine diff --git a/Multiplayer/Networking/Packets/Serverbound/Train/ServerboundTrainCarSpawnRequest.cs b/Multiplayer/Networking/Packets/Serverbound/Train/ServerboundTrainCarSpawnRequest.cs new file mode 100644 index 00000000..fbeccfcd --- /dev/null +++ b/Multiplayer/Networking/Packets/Serverbound/Train/ServerboundTrainCarSpawnRequest.cs @@ -0,0 +1,23 @@ +using DV.ThingTypes; +using UnityEngine; + +namespace Multiplayer.Networking.Packets.Serverbound.Train; + +public class ServerboundTrainCarSpawnRequest +{ + public Vector3 Position { get; set; } + public Vector3 Forward { get; set; } + public bool Derailed { get; set; } + public string LiveryID { get; set; } + + public static ServerboundTrainCarSpawnRequest FromTrainCar(TrainCar trainCar) + { + return new ServerboundTrainCarSpawnRequest + { + Position = trainCar.transform.position, + Forward = trainCar.transform.forward, + Derailed = trainCar.derailed, + LiveryID = trainCar.carLivery.id, + }; + } +} diff --git a/Multiplayer/Patches/CommsRadio/CommsRadioCarSpawnerPatch.cs b/Multiplayer/Patches/CommsRadio/CommsRadioCarSpawnerPatch.cs deleted file mode 100644 index 092e5874..00000000 --- a/Multiplayer/Patches/CommsRadio/CommsRadioCarSpawnerPatch.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Collections; -using DV; -using DV.InventorySystem; -using HarmonyLib; -using Multiplayer.Components.Networking; -using Multiplayer.Components.Networking.Train; -using Multiplayer.Utils; -using UnityEngine; - -namespace Multiplayer.Patches.CommsRadio; - - -[HarmonyPatch(typeof(CommsRadioCarSpawner))] -public static class CommsRadioCarSpawnerPatch -{ - [HarmonyPrefix] - [HarmonyPatch(nameof(CommsRadioCarSpawner.OnUse))] - private static bool OnUse_Prefix(CommsRadioCarSpawner __instance) - { - if (__instance.state != CommsRadioCarSpawner.State.PickDestination) - return true; - if (NetworkLifecycle.Instance.IsHost()) - return true; - - //temporarily disable client spawning - CommsRadioController.PlayAudioFromRadio(__instance.cancelSound, __instance.transform); - __instance.ClearFlags(); - return false; - - } -} - - //private static IEnumerator PlaySoundsLater(CommsRadioCarDeleter __instance, Vector3 trainPosition, bool playMoneyRemovedSound = true) - //{ - // yield return new WaitForSecondsRealtime((NetworkLifecycle.Instance.Client.Ping * 3f)/1000); - // if (playMoneyRemovedSound && __instance.moneyRemovedSound != null) - // __instance.moneyRemovedSound.Play2D(); - // // The TrainCar may already be deleted when we're done waiting, so we play the sound manually. - // __instance.removeCarSound.Play(trainPosition, minDistance: CommsRadioController.CAR_AUDIO_SOURCE_MIN_DISTANCE, parent: WorldMover.Instance.originShiftParent); - // CommsRadioController.PlayAudioFromRadio(__instance.confirmSound, __instance.transform); - //} - - diff --git a/Multiplayer/Patches/Train/CarSpawnerPatch.cs b/Multiplayer/Patches/Train/CarSpawnerPatch.cs index 7aaad68f..e68fc0dd 100644 --- a/Multiplayer/Patches/Train/CarSpawnerPatch.cs +++ b/Multiplayer/Patches/Train/CarSpawnerPatch.cs @@ -3,6 +3,8 @@ using Multiplayer.Components.Networking.Train; using Multiplayer.Utils; using System.Collections.Generic; +using DV.ThingTypes; +using UnityEngine; namespace Multiplayer.Patches.Train; @@ -24,59 +26,88 @@ private static void PrepareTrainCarForDeleting(TrainCar trainCar) NetworkLifecycle.Instance.Server?.SendDestroyTrainCar(networkedTrainCar); } - //Called from - [HarmonyPatch(nameof(CarSpawner.SpawnCars))] - [HarmonyPostfix] - private static void SpawnCars(List __result) - { - if (UnloadWatcher.isUnloading) - return; - - if (!NetworkLifecycle.Instance.IsHost()) - return; - - if (__result == null || __result.Count == 0) - return; - - //Coupling is delayed by AutoCouple(), so a true trainset for the entire consist doesn't exist yet - Multiplayer.LogDebug(() => $"SpawnCars() {__result?.Count} cars spawned, sending to players"); - NetworkLifecycle.Instance.Server.SendSpawnTrainset(__result, true, true); - - } - - [HarmonyPatch(nameof(CarSpawner.SpawnCarFromRemote))] + [HarmonyPatch(nameof(CarSpawner.SpawnCar))] [HarmonyPostfix] - private static void SpawnCarFromRemote(TrainCar __result) + private static void SpawnCar(TrainCar __result) { if (UnloadWatcher.isUnloading) return; if (!NetworkLifecycle.Instance.IsHost()) + { + NetworkLifecycle.Instance.Client.SendTrainCarSpawnRequest(__result); + CarSpawner.Instance.DeleteCar(__result); return; + } if (__result == null) return; - Multiplayer.LogDebug(() => $"SpawnCarFromRemote() {__result?.carLivery?.name} spawned, sending to players"); + //Coupling is delayed by AutoCouple(), so a true trainset for the entire consist doesn't exist yet + Multiplayer.LogDebug(() => $"SpawnCar() {__result?.carLivery?.name} car spawned, sending to players"); NetworkLifecycle.Instance.Server.SendSpawnTrainset([__result], true, true); - } - [HarmonyPatch(nameof(CarSpawner.SpawnCarOnClosestTrack))] + [HarmonyPatch(nameof(CarSpawner.SpawnCars))] [HarmonyPostfix] - private static void SpawnCarOnClosestTrack(TrainCar __result) + private static void SpawnCars(List __result) { if (UnloadWatcher.isUnloading) return; if (!NetworkLifecycle.Instance.IsHost()) - return; + { + // todo: Create a SendTrainSetSpawnRequest packet and use that in these situations. + foreach (TrainCar trainCar in __result) + { + NetworkLifecycle.Instance.Client.SendTrainCarSpawnRequest(trainCar); + CarSpawner.Instance.DeleteCar(trainCar); + } - if (__result == null) return; + } - Multiplayer.LogDebug(() => $"SpawnCarOnClosestTrack() {__result?.carLivery?.name} spawned, sending to players"); - NetworkLifecycle.Instance.Server.SendSpawnTrainset([__result], true, true); + if (__result == null || __result.Count == 0) + return; + //Coupling is delayed by AutoCouple(), so a true trainset for the entire consist doesn't exist yet + Multiplayer.LogDebug(() => $"SpawnCars() {__result?.Count} cars spawned, sending to players"); + NetworkLifecycle.Instance.Server.SendSpawnTrainset(__result, true, true); } + + // [HarmonyPatch(nameof(CarSpawner.SpawnCarFromRemote))] + // [HarmonyPostfix] + // private static void SpawnCarFromRemote(TrainCar __result) + // { + // if (UnloadWatcher.isUnloading) + // return; + // + // if (!NetworkLifecycle.Instance.IsHost()) + // return; + // + // if (__result == null) + // return; + // + // Multiplayer.LogDebug(() => $"SpawnCarFromRemote() {__result?.carLivery?.name} spawned, sending to players"); + // NetworkLifecycle.Instance.Server.SendSpawnTrainset([__result], true, true); + // + // } + // + // [HarmonyPatch(nameof(CarSpawner.SpawnCarOnClosestTrack))] + // [HarmonyPostfix] + // private static void SpawnCarOnClosestTrack(TrainCar __result) + // { + // if (UnloadWatcher.isUnloading) + // return; + // + // if (!NetworkLifecycle.Instance.IsHost()) + // return; + // + // if (__result == null) + // return; + // + // Multiplayer.LogDebug(() => $"SpawnCarOnClosestTrack() {__result?.carLivery?.name} spawned, sending to players"); + // NetworkLifecycle.Instance.Server.SendSpawnTrainset([__result], true, true); + // + // } }