using FishNet.CodeAnalysis.Annotations; using FishNet.Component.ColliderRollback; using FishNet.Connection; using FishNet.Managing; using FishNet.Managing.Client; using FishNet.Managing.Observing; using FishNet.Managing.Predicting; using FishNet.Managing.Scened; using FishNet.Managing.Server; using FishNet.Managing.Timing; using FishNet.Managing.Transporting; using FishNet.Serializing.Helping; using System; using UnityEngine; namespace FishNet.Object { public partial class NetworkObject : MonoBehaviour { #region Public. #region Obsoletes [Obsolete("Use IsClientOnlyInitialized. Note the difference between IsClientOnlyInitialized and IsClientOnlyStarted.")] public bool IsClientOnly => IsClientOnlyInitialized; [Obsolete("Use IsServerOnlyInitialized. Note the difference between IsServerOnlyInitialized and IsServerOnlyStarted.")] public bool IsServerOnly => IsServerOnlyInitialized; [Obsolete("Use IsHostInitialized. Note the difference between IsHostInitialized and IsHostStarted.")] public bool IsHost => IsHostInitialized; [Obsolete("Use IsClientInitialized. Note the difference between IsClientInitialized and IsClientStarted.")] public bool IsClient => IsClientInitialized; [Obsolete("Use IsServerInitialized. Note the difference between IsServerInitialized and IsServerStarted.")] public bool IsServer => IsServerInitialized; #endregion /// /// True if predicted spawning is allowed for this object. /// internal bool AllowPredictedSpawning => (PredictedSpawn == null) ? false : PredictedSpawn.GetAllowSpawning(); /// /// True if predicted spawning is allowed for this object. /// internal bool AllowPredictedDespawning => (PredictedSpawn == null) ? false : PredictedSpawn.GetAllowDespawning(); /// /// True if this object has been initialized on the client side. /// This is set true right before client start callbacks and after stop callbacks. /// public bool IsClientInitialized { get; private set; } /// /// True if the client is started and authenticated. This will return true on clientHost even if the object has not initialized yet for the client. /// To check if this object has been initialized for the client use IsClientInitialized. /// public bool IsClientStarted => (NetworkManager == null) ? false : NetworkManager.IsClientStarted; /// /// True if this object has been initialized only on the server side. /// This is set true right before server start callbacks and after stop callbacks. /// public bool IsClientOnlyInitialized => (!IsServerInitialized && IsClientInitialized); /// /// True if only the client is started and authenticated. /// public bool IsClientOnlyStarted => (IsClientStarted && !IsServerStarted); /// /// True if this object has been initialized on the server side. /// This is set true right before server start callbacks and after stop callbacks. /// public bool IsServerInitialized { get; private set; } /// /// True if the server is active. This will return true on clientHost even if the object is being deinitialized on the server. /// To check if this object has been initialized for the server use IsServerInitialized. /// public bool IsServerStarted => (NetworkManager == null) ? false : NetworkManager.IsServerStarted; /// /// True if this object has been initialized only on the server side. /// This is set true right before server start callbacks and after stop callbacks. /// public bool IsServerOnlyInitialized => (IsServerInitialized && !IsClientInitialized); /// /// True if only the server is started. /// public bool IsServerOnlyStarted => (IsServerStarted && !IsClientStarted); /// /// True if client and server are started. /// public bool IsHostStarted => (IsClientStarted && IsServerStarted); /// /// True if this object has been initialized on the server and client side. /// public bool IsHostInitialized => (IsClientInitialized && IsServerInitialized); /// /// True if client nor server are started. /// public bool IsOffline => (!IsClientStarted && !IsServerStarted); #if !PREDICTION_1 /// /// True if a reconcile is occuring on the PredictionManager. Note the difference between this and IsBehaviourReconciling. /// public bool IsManagerReconciling => PredictionManager.IsReconciling; #endif /// /// True if the local client is the owner of this object. /// This will only return true if IsClientInitialized is also true. You may check ownership status regardless of client initialized state by using Owner.IsLocalClient. /// [PreventUsageInside("global::FishNet.Object.NetworkBehaviour", "OnStartServer", "")] [PreventUsageInside("global::FishNet.Object.NetworkBehaviour", "OnStartNetwork", " Use base.Owner.IsLocalClient instead.")] [PreventUsageInside("global::FishNet.Object.NetworkBehaviour", "Awake", "")] [PreventUsageInside("global::FishNet.Object.NetworkBehaviour", "Start", "")] public bool IsOwner { get { /* ClientInitialized becomes true when this * NetworkObject has been initialized on the client side. * * This value is used to prevent IsOwner from returning true * when running as host; primarily in Update or Tick callbacks * where IsOwner would be true as host but OnStartClient has * not called yet. * * EG: server will set owner when it spawns the object. * If IsOwner is checked before the object spawns on the * client-host then it would also return true, since the * Owner reference would be the same as what was set by server. * * This is however bad when the client hasn't initialized the object * yet because it gives a false sense of execution order. * As a result, Update or Ticks may return IsOwner as true well before OnStartClient * is called. Many users rightfully create code with the assumption the client has been * initialized by the time IsOwner is true. * * This is a double edged sword though because now IsOwner would return true * within OnStartNetwork for clients only, but not for host given the client * side won't be initialized yet as host. As a work around CodeAnalysis will * inform users to instead use base.Owner.IsLocalClient within OnStartNetwork. */ if (!IsClientInitialized) return false; return Owner.IsLocalClient; } } /// /// True if IsOwner, or if IsServerInitialized with no Owner. /// [PreventUsageInside("global::FishNet.Object.NetworkBehaviour", "OnStartServer", "")] [PreventUsageInside("global::FishNet.Object.NetworkBehaviour", "OnStartNetwork", " Use (base.Owner.IsLocalClient || (base.IsServerInitialized && !Owner.Isvalid) instead.")] [PreventUsageInside("global::FishNet.Object.NetworkBehaviour", "Awake", "")] [PreventUsageInside("global::FishNet.Object.NetworkBehaviour", "Start", "")] public bool IsOwnerOrServer => (IsOwner || (IsServerInitialized && !Owner.IsValid)); /// /// /// private NetworkConnection _owner; /// /// Owner of this object. /// public NetworkConnection Owner { get { //Ensures a null Owner is never returned. if (_owner == null) return FishNet.Managing.NetworkManager.EmptyConnection; return _owner; } private set { _owner = value; } } /// /// ClientId for this NetworkObject owner. /// public int OwnerId => (!Owner.IsValid) ? -1 : Owner.ClientId; /// /// True if the object is initialized for the network. /// public bool IsSpawned => (!IsDeinitializing && ObjectId != NetworkObject.UNSET_OBJECTID_VALUE); /// /// The local connection of the client calling this method. /// public NetworkConnection LocalConnection => (NetworkManager == null) ? new NetworkConnection() : NetworkManager.ClientManager.Connection; /// /// NetworkManager for this object. /// public NetworkManager NetworkManager { get; private set; } /// /// ServerManager for this object. /// public ServerManager ServerManager { get; private set; } /// /// ClientManager for this object. /// public ClientManager ClientManager { get; private set; } /// /// ObserverManager for this object. /// public ObserverManager ObserverManager { get; private set; } /// /// TransportManager for this object. /// public TransportManager TransportManager { get; private set; } /// /// TimeManager for this object. /// public TimeManager TimeManager { get; private set; } /// /// SceneManager for this object. /// public SceneManager SceneManager { get; private set; } /// /// PredictionManager for this object. /// public PredictionManager PredictionManager { get; private set; } /// /// RollbackManager for this object. /// public RollbackManager RollbackManager { get; private set; } #endregion /// /// Returns a NetworkBehaviour on this NetworkObject. /// /// ComponentIndex of the NetworkBehaviour. /// True to error if not found. /// public NetworkBehaviour GetNetworkBehaviour(byte componentIndex, bool error) { if (componentIndex >= NetworkBehaviours.Length) { if (error) { string message = $"ComponentIndex of {componentIndex} is out of bounds on {gameObject.name} [id {ObjectId}]. This may occur if you have modified your gameObject/prefab without saving it, or the scene."; NetworkManager.LogError(message); } } return NetworkBehaviours[componentIndex]; } /// /// Despawns a GameObject. Only call from the server. /// /// GameObject to despawn. /// What happens to the object after being despawned. public void Despawn(GameObject go, DespawnType? despawnType = null) { NetworkManager?.ServerManager.Despawn(go, despawnType); } /// /// Despawns a NetworkObject. Only call from the server. /// /// NetworkObject to despawn. /// What happens to the object after being despawned. public void Despawn(NetworkObject nob, DespawnType? despawnType = null) { NetworkManager?.ServerManager.Despawn(nob, despawnType); } /// /// Despawns this NetworkObject. Only call from the server. /// /// What happens to the object after being despawned. public void Despawn(DespawnType? despawnType = null) { NetworkObject nob = this; NetworkManager?.ServerManager.Despawn(nob, despawnType); } /// /// Spawns an object over the network. Only call from the server. /// public void Spawn(GameObject go, NetworkConnection ownerConnection = null, UnityEngine.SceneManagement.Scene scene = default) { NetworkManager?.ServerManager.Spawn(go, ownerConnection, scene); } /// /// Spawns an object over the network. Only call from the server. /// public void Spawn(NetworkObject nob, NetworkConnection ownerConnection = null, UnityEngine.SceneManagement.Scene scene = default) { NetworkManager?.ServerManager.Spawn(nob, ownerConnection, scene); } /// /// Takes ownership of this object and child network objects, allowing immediate control. /// /// Connection to give ownership to. public void SetLocalOwnership(NetworkConnection caller) { NetworkConnection prevOwner = Owner; SetOwner(caller); int count; count = NetworkBehaviours.Length; for (int i = 0; i < count; i++) NetworkBehaviours[i].OnOwnershipClient_Internal(prevOwner); count = NestedRootNetworkBehaviours.Count; for (int i = 0; i < count; i++) NestedRootNetworkBehaviours[i].SetLocalOwnership(caller); } #region Registered components /// /// Invokes an action when a specified component becomes registered. Action will invoke immediately if already registered. /// /// Component type. /// Action to invoke. public void RegisterInvokeOnInstance(Action handler) where T : UnityEngine.Component => NetworkManager.RegisterInvokeOnInstance(handler); /// /// Removes an action to be invoked when a specified component becomes registered. /// /// Component type. /// Action to invoke. public void UnregisterInvokeOnInstance(Action handler) where T : UnityEngine.Component => NetworkManager.UnregisterInvokeOnInstance(handler); /// /// Returns if an instance exists for type. /// /// /// public bool HasInstance() where T : UnityEngine.Component => NetworkManager.HasInstance(); /// /// Returns class of type if found within CodegenBase classes. /// /// /// public T GetInstance() where T : UnityEngine.Component => NetworkManager.GetInstance(); /// /// Registers a new component to this NetworkManager. /// /// Type to register. /// Reference of the component being registered. /// True to replace existing references. public void RegisterInstance(T component, bool replace = true) where T : UnityEngine.Component => NetworkManager.RegisterInstance(component, replace); /// /// Tries to registers a new component to this NetworkManager. /// This will not register the instance if another already exists. /// /// Type to register. /// Reference of the component being registered. /// True if was able to register, false if an instance is already registered. public bool TryRegisterInstance(T component) where T : UnityEngine.Component => NetworkManager.TryRegisterInstance(component); /// /// Returns class of type from registered instances. /// /// Outputted component. /// Type to get. /// True if was able to get instance. public bool TryGetInstance(out T component) where T : UnityEngine.Component => NetworkManager.TryGetInstance(out component); /// /// Unregisters a component from this NetworkManager. /// /// Type to unregister. public void UnregisterInstance() where T : UnityEngine.Component => NetworkManager.UnregisterInstance(); #endregion } }