using FishNet.Connection; using FishNet.Managing.Logging; using FishNet.Managing.Transporting; using FishNet.Object; using FishNet.Transporting; using FishNet.Transporting.Multipass; using System; using System.Runtime.CompilerServices; using UnityEngine; namespace FishNet.Managing.Server { public sealed partial class ServerManager : MonoBehaviour { /// /// Returns true if only one server is started. /// /// internal bool OneServerStarted() { int startedCount = 0; TransportManager tm = NetworkManager.TransportManager; //If using multipass check all transports. if (tm.Transport is Multipass mp) { foreach (Transport t in mp.Transports) { //Another transport is started, no need to load start scenes again. if (t.GetConnectionState(true) == LocalConnectionState.Started) startedCount++; } } //Not using multipass. else { if (tm.Transport.GetConnectionState(true) == LocalConnectionState.Started) startedCount = 1; } return (startedCount == 1); } /// /// Returns true if any server socket is in the started state. /// /// When set the transport on this index will be ignored. This value is only used with Multipass. /// internal bool AnyServerStarted(int? excludedIndex = null) { TransportManager tm = NetworkManager.TransportManager; //If using multipass check all transports. if (tm.Transport is Multipass mp) { //Get transport which had state changed. Transport excludedTransport = (excludedIndex == null) ? null : mp.GetTransport(excludedIndex.Value); foreach (Transport t in mp.Transports) { /* Skip t if is the transport that had it's state changed. * We are looking for other transports already in started. */ if (t == excludedTransport) continue; //Another transport is started, no need to load start scenes again. if (t.GetConnectionState(true) == LocalConnectionState.Started) return true; } } //Not using multipass. else { return (tm.Transport.GetConnectionState(true) == LocalConnectionState.Started); } //Fall through, none started. return false; } /// /// Spawns an object over the network. Can only be called on the server. /// /// GameObject instance to spawn. /// Connection to give ownership to. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Spawn(GameObject go, NetworkConnection ownerConnection = null) { if (!CanSpawnOrDespawn(true)) return; if (go == null) { if (NetworkManager.CanLog(LoggingType.Warning)) Debug.LogWarning($"GameObject cannot be spawned because it is null."); return; } NetworkObject nob = go.GetComponent(); Spawn(nob, ownerConnection); } /// /// Spawns an object over the network. Can only be called on the server. /// /// MetworkObject instance to spawn. /// Connection to give ownership to. public void Spawn(NetworkObject nob, NetworkConnection ownerConnection = null) { if (!CanSpawnOrDespawn(true)) return; if (nob == null) { if (NetworkManager.CanLog(LoggingType.Warning)) Debug.LogWarning($"NetworkObject cannot be spawned because it is null."); return; } Objects.Spawn(nob, ownerConnection); } /// /// Spawns an object over the network. Can only be called on the server. /// /// MetworkObject instance to spawn. /// Connection to give ownership to. /// True to synchronize the parent object in the spawn message. The parent must have a NetworkObject or NetworkBehaviour component for this to work. [Obsolete("SynchronizeParent is now automatic, and no longer optional. Use Spawn(NetworkObject, NetworkConnection) instead.")] //Remove 2023/01/01. public void Spawn(NetworkObject nob, NetworkConnection ownerConnection, bool synchronizeParent) { if (!CanSpawnOrDespawn(true)) return; if (nob == null) { if (NetworkManager.CanLog(LoggingType.Warning)) Debug.LogWarning($"NetworkObject cannot be spawned because it is null."); return; } Objects.Spawn(nob, ownerConnection); } /// /// Returns if Spawn can be called. /// /// True to warn if not able to execute spawn or despawn. /// private bool CanSpawnOrDespawn(bool warn) { bool canLog = (warn && NetworkManager.CanLog(LoggingType.Warning)); if (!Started) { if (canLog) Debug.Log($"The server must be active to spawn or despawn networked objects."); return false; } return true; } /// /// Despawns an object over the network. Can only be called on the server. /// /// GameObject instance to despawn. /// Overrides the default DisableOnDespawn value for this single despawn. Scene objects will never be destroyed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Despawn(GameObject go, bool? disableOnDespawnOverride = null) { if (!CanSpawnOrDespawn(true)) return; if (go == null) { if (NetworkManager.CanLog(LoggingType.Warning)) Debug.LogWarning($"GameObject cannot be despawned because it is null."); return; } NetworkObject nob = go.GetComponent(); Despawn(nob, disableOnDespawnOverride); } /// /// Despawns an object over the network. Can only be called on the server. /// /// NetworkObject instance to despawn. /// Overrides the default DisableOnDespawn value for this single despawn. Scene objects will never be destroyed. public void Despawn(NetworkObject networkObject, bool? disableOnDespawnOverride = null) { if (!CanSpawnOrDespawn(true)) return; if (networkObject == null) { if (NetworkManager.CanLog(LoggingType.Warning)) Debug.LogWarning($"NetworkObject cannot be despawned because it is null."); return; } bool disableOnDespawn = (disableOnDespawnOverride == null) ? networkObject.DisableOnDespawn : disableOnDespawnOverride.Value; Objects.Despawn(networkObject, disableOnDespawn, true); } } }