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 System; using UnityEngine; namespace FishNet.Object { public sealed partial class NetworkObject : MonoBehaviour { #region Public. /// <summary> /// True if predicted spawning is allowed for this object. /// </summary> internal bool AllowPredictedSpawning => (PredictedSpawn == null) ? false : PredictedSpawn.GetAllowSpawning(); /// <summary> /// True if predicted spawning is allowed for this object. /// </summary> internal bool AllowPredictedDespawning => (PredictedSpawn == null) ? false : PredictedSpawn.GetAllowDespawning(); /// <summary> /// True to allow clients to predicted set syncTypes prior to spawning the item. Set values will be applied on the server and sent to other clients. /// </summary> internal bool AllowPredictedSyncTypes => (PredictedSpawn == null) ? false : PredictedSpawn.GetAllowSyncTypes(); /// <summary> /// True if this object has been initialized on the client side. /// This is set true right before client callbacks. /// </summary> public bool ClientInitialized { get; private set; } /// <summary> /// /// </summary> private bool _isClient; /// <summary> /// True if the client is active and authenticated. /// </summary> public bool IsClient { /* This needs to use a special check when * player is acting as host. Clients won't * set IsClient until they receive the spawn message * but the user may expect this true after client * gains observation but before client gets spawn. */ get { if (IsServer) return (NetworkManager == null) ? false : NetworkManager.IsClient; else return _isClient; } private set => _isClient = value; } /// <summary> /// True if only the client is active and authenticated. /// </summary> public bool IsClientOnly => (IsClient && !IsServer); /// <summary> /// True if server is active. /// </summary> public bool IsServer { get; private set; } /// <summary> /// True if only the server is active. /// </summary> public bool IsServerOnly => (IsServer && !IsClient); /// <summary> /// True if client and server are active. /// </summary> public bool IsHost => (IsClient && IsServer); /// <summary> /// True if client nor server are active. /// </summary> public bool IsOffline => (!IsClient && !IsServer); /// <summary> /// True if the local client is the owner of this object. /// </summary> 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 (!ClientInitialized) return false; return Owner.IsLocalClient; } } /// <summary> /// /// </summary> private NetworkConnection _owner; /// <summary> /// Owner of this object. /// </summary> 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; } } /// <summary> /// ClientId for this NetworkObject owner. /// </summary> public int OwnerId => (!Owner.IsValid) ? -1 : Owner.ClientId; /// <summary> /// True if the object is initialized for the network. /// </summary> public bool IsSpawned => (!IsDeinitializing && ObjectId != NetworkObject.UNSET_OBJECTID_VALUE); /// <summary> /// The local connection of the client calling this method. /// </summary> public NetworkConnection LocalConnection => (NetworkManager == null) ? new NetworkConnection() : NetworkManager.ClientManager.Connection; /// <summary> /// NetworkManager for this object. /// </summary> public NetworkManager NetworkManager { get; private set; } /// <summary> /// ServerManager for this object. /// </summary> public ServerManager ServerManager { get; private set; } /// <summary> /// ClientManager for this object. /// </summary> public ClientManager ClientManager { get; private set; } /// <summary> /// ObserverManager for this object. /// </summary> public ObserverManager ObserverManager { get; private set; } /// <summary> /// TransportManager for this object. /// </summary> public TransportManager TransportManager { get; private set; } /// <summary> /// TimeManager for this object. /// </summary> public TimeManager TimeManager { get; private set; } /// <summary> /// SceneManager for this object. /// </summary> public SceneManager SceneManager { get; private set; } /// <summary> /// PredictionManager for this object. /// </summary> public PredictionManager PredictionManager {get;private set;} /// <summary> /// RollbackManager for this object. /// </summary> public RollbackManager RollbackManager { get; private set; } #endregion /// <summary> /// Returns a NetworkBehaviour on this NetworkObject. /// </summary> /// <param name="componentIndex">ComponentIndex of the NetworkBehaviour.</param> /// <param name="error">True to error if not found.</param> /// <returns></returns> 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."; if (NetworkManager == null) NetworkManager.StaticLogError(message); else NetworkManager.LogError(message); } } return NetworkBehaviours[componentIndex]; } /// <summary> /// Despawns a GameObject. Only call from the server. /// </summary> /// <param name="go">GameObject to despawn.</param> /// <param name="despawnType">What happens to the object after being despawned.</param> public void Despawn(GameObject go, DespawnType? despawnType = null) { NetworkManager?.ServerManager.Despawn(go, despawnType); } /// <summary> /// Despawns a NetworkObject. Only call from the server. /// </summary> /// <param name="nob">NetworkObject to despawn.</param> /// <param name="despawnType">What happens to the object after being despawned.</param> public void Despawn(NetworkObject nob, DespawnType? despawnType = null) { NetworkManager?.ServerManager.Despawn(nob, despawnType); } /// <summary> /// Despawns this NetworkObject. Only call from the server. /// </summary> /// <param name="despawnType">What happens to the object after being despawned.</param> public void Despawn(DespawnType? despawnType = null) { NetworkObject nob = this; NetworkManager?.ServerManager.Despawn(nob, despawnType); } /// <summary> /// Spawns an object over the network. Only call from the server. /// </summary> public void Spawn(GameObject go, NetworkConnection ownerConnection = null) { NetworkManager?.ServerManager.Spawn(go, ownerConnection); } /// <summary> /// Spawns an object over the network. Only call from the server. /// </summary> public void Spawn(NetworkObject nob, NetworkConnection ownerConnection = null) { NetworkManager?.ServerManager.Spawn(nob, ownerConnection); } /// <summary> /// Takes ownership of this object and child network objects, allowing immediate control. /// </summary> /// <param name="caller">Connection to give ownership to.</param> 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(prevOwner); count = ChildNetworkObjects.Count; for (int i = 0; i < count; i++) ChildNetworkObjects[i].SetLocalOwnership(caller); } #region Registered components /// <summary> /// Invokes an action when a specified component becomes registered. Action will invoke immediately if already registered. /// </summary> /// <typeparam name="T">Component type.</typeparam> /// <param name="handler">Action to invoke.</param> public void RegisterInvokeOnInstance<T>(Action<UnityEngine.Component> handler) where T : UnityEngine.Component => NetworkManager.RegisterInvokeOnInstance<T>(handler); /// <summary> /// Removes an action to be invoked when a specified component becomes registered. /// </summary> /// <typeparam name="T">Component type.</typeparam> /// <param name="handler">Action to invoke.</param> public void UnregisterInvokeOnInstance<T>(Action<UnityEngine.Component> handler) where T : UnityEngine.Component => NetworkManager.UnregisterInvokeOnInstance<T>(handler); /// <summary> /// Returns if an instance exists for type. /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public bool HasInstance<T>() where T : UnityEngine.Component => NetworkManager.HasInstance<T>(); /// <summary> /// Returns class of type if found within CodegenBase classes. /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public T GetInstance<T>() where T : UnityEngine.Component => NetworkManager.GetInstance<T>(); /// <summary> /// Registers a new component to this NetworkManager. /// </summary> /// <typeparam name="T">Type to register.</typeparam> /// <param name="component">Reference of the component being registered.</param> /// <param name="replace">True to replace existing references.</param> public void RegisterInstance<T>(T component, bool replace = true) where T : UnityEngine.Component => NetworkManager.RegisterInstance<T>(component, replace); /// <summary> /// Unregisters a component from this NetworkManager. /// </summary> /// <typeparam name="T">Type to unregister.</typeparam> public void UnregisterInstance<T>() where T : UnityEngine.Component => NetworkManager.UnregisterInstance<T>(); #endregion } }