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.
///
/// 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 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.
///
internal bool AllowPredictedSyncTypes => (PredictedSpawn == null) ? false : PredictedSpawn.GetAllowSyncTypes();
///
/// True if this object has been initialized on the client side.
/// This is set true right before client callbacks.
///
public bool ClientInitialized { get; private set; }
///
///
///
private bool _isClient;
///
/// True if the client is active and authenticated.
///
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;
}
///
/// True if only the client is active and authenticated.
///
public bool IsClientOnly => (IsClient && !IsServer);
///
/// True if server is active.
///
public bool IsServer { get; private set; }
///
/// True if only the server is active.
///
public bool IsServerOnly => (IsServer && !IsClient);
///
/// True if client and server are active.
///
public bool IsHost => (IsClient && IsServer);
///
/// True if client nor server are active.
///
public bool IsOffline => (!IsClient && !IsServer);
///
/// True if the local client is the owner of this object.
///
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;
}
}
///
///
///
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.";
if (NetworkManager == null)
NetworkManager.StaticLogError(message);
else
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)
{
NetworkManager?.ServerManager.Spawn(go, ownerConnection);
}
///
/// Spawns an object over the network. Only call from the server.
///
public void Spawn(NetworkObject nob, NetworkConnection ownerConnection = null)
{
NetworkManager?.ServerManager.Spawn(nob, ownerConnection);
}
///
/// 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(prevOwner);
count = ChildNetworkObjects.Count;
for (int i = 0; i < count; i++)
ChildNetworkObjects[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);
///
/// Unregisters a component from this NetworkManager.
///
/// Type to unregister.
public void UnregisterInstance() where T : UnityEngine.Component => NetworkManager.UnregisterInstance();
#endregion
}
}