using FishNet.CodeGenerating;
using FishNet.Documenting;
using FishNet.Managing.Transporting;
using FishNet.Serializing.Helping;
using FishNet.Utility;
using System.Runtime.CompilerServices;
using FishNet.Managing;
using UnityEngine;
[assembly: InternalsVisibleTo(UtilityConstants.CODEGEN_ASSEMBLY_NAME)]
namespace FishNet.Object
{
///
/// Scripts which inherit from NetworkBehaviour can be used to gain insight of, and perform actions on the network.
///
[ExcludeSerialization]
public abstract partial class NetworkBehaviour : MonoBehaviour
{
#region Public.
///
/// True if this NetworkBehaviour is initialized for the network.
///
public bool IsSpawned => _networkObjectCache.IsSpawned;
///
///
///
[SerializeField, HideInInspector]
private byte _componentIndexCache = NetworkBehaviour.UNSET_NETWORKBEHAVIOUR_ID;
///
/// ComponentIndex for this NetworkBehaviour.
///
public byte ComponentIndex
{
get => _componentIndexCache;
private set => _componentIndexCache = value;
}
#if UNITY_EDITOR
///
/// NetworkObject automatically added or discovered during edit time.
///
[SerializeField, HideInInspector]
private NetworkObject _addedNetworkObject;
#endif
///
/// Cache of the TransportManager.
///
private TransportManager _transportManagerCache;
///
///
///
[SerializeField, HideInInspector]
private NetworkObject _networkObjectCache;
///
/// NetworkObject this behaviour is for.
///
public NetworkObject NetworkObject => _networkObjectCache;
#endregion
#region Private.
///
/// True if initialized at some point asServer.
///
private bool _initializedOnceServer;
#pragma warning disable CS0414
///
/// True if initialized at some point not asServer.
///
private bool _initializedOnceClient;
#pragma warning restore CS0414
#endregion
#region Consts.
///
/// Maximum number of allowed added NetworkBehaviours.
///
public const byte MAXIMUM_NETWORKBEHAVIOURS = (UNSET_NETWORKBEHAVIOUR_ID - 1);
///
/// Id for when a NetworkBehaviour is not valid.
///
public const byte UNSET_NETWORKBEHAVIOUR_ID = byte.MaxValue;
#endregion
///
/// Outputs data about this NetworkBehaviour to string.
///
///
public override string ToString()
{
return $"Name [{gameObject.name}] ComponentId [{ComponentIndex}] NetworkObject Name [{_networkObjectCache.name}] NetworkObject Id [{_networkObjectCache.ObjectId}]";
}
[MakePublic]
internal virtual void NetworkInitialize___Early() { }
[MakePublic]
internal virtual void NetworkInitialize___Late() { }
///
/// Preinitializes this script for the network.
///
internal void InitializeEarly(NetworkObject nob, bool asServer)
{
_transportManagerCache = nob.TransportManager;
SyncTypes_Preinitialize(asServer);
if (asServer)
{
InitializeRpcLinks();
_initializedOnceServer = true;
}
else
{
if (!_initializedOnceClient && nob.EnablePrediction && _usesPrediction)
nob.RegisterPredictionBehaviourOnce(this);
_initializedOnceClient = true;
}
}
internal void Deinitialize(bool asServer)
{
ResetState_SyncTypes(asServer);
}
///
/// Called by the NetworkObject when this object is destroyed.
///
internal void NetworkBehaviour_OnDestroy()
{
SyncTypes_OnDestroy();
}
///
/// Serializes information for network components.
///
internal void SerializeComponents(NetworkObject nob, byte componentIndex)
{
_networkObjectCache = nob;
ComponentIndex = componentIndex;
}
///
/// Manually initializes network content for the NetworkBehaviour if the object it's on is disabled.
///
internal void InitializeIfDisabled()
{
if (gameObject.activeInHierarchy)
return;
NetworkInitializeIfDisabled();
}
///
/// Long name is to prevent users from potentially creating their own method named the same.
///
[MakePublic]
[APIExclude]
internal virtual void NetworkInitializeIfDisabled() { }
#region Editor.
protected virtual void Reset()
{
#if UNITY_EDITOR
if (Application.isPlaying)
return;
TryAddNetworkObject();
#endif
}
protected virtual void OnValidate()
{
#if UNITY_EDITOR
if (Application.isPlaying)
return;
TryAddNetworkObject();
#endif
}
///
/// Resets this NetworkBehaviour so that it may be added to an object pool.
///
public virtual void ResetState(bool asServer)
{
ResetState_SyncTypes(asServer);
ResetState_Prediction(asServer);
ClearReplicateCache();
ClearBuffedRpcs();
}
///
/// Tries to add the NetworkObject component.
///
private NetworkObject TryAddNetworkObject()
{
#if UNITY_EDITOR
if (Application.isPlaying)
return _addedNetworkObject;
if (_addedNetworkObject != null)
{
AlertToDuplicateNetworkObjects(_addedNetworkObject.transform);
return _addedNetworkObject;
}
/* Manually iterate up the chain because GetComponentInParent doesn't
* work when modifying prefabs in the inspector. Unity, you're starting
* to suck a lot right now. */
NetworkObject result = null;
Transform climb = transform;
while (climb != null)
{
if (climb.TryGetComponent(out result))
break;
else
climb = climb.parent;
}
if (result != null)
{
_addedNetworkObject = result;
}
//Not found, add a new nob.
else
{
_addedNetworkObject = transform.root.gameObject.AddComponent();
NetworkManagerExtensions.Log($"Script {GetType().Name} on object {gameObject.name} added a NetworkObject component to {transform.root.name}.");
}
AlertToDuplicateNetworkObjects(_addedNetworkObject.transform);
return _addedNetworkObject;
//Removes duplicate network objects from t.
void AlertToDuplicateNetworkObjects(Transform t)
{
NetworkObject[] nobs = t.GetComponents();
//This shouldn't be possible but does occur sometimes; maybe a unity bug?
if (nobs.Length > 1)
{
//Update added to first entryt.
_addedNetworkObject = nobs[0];
string useMenu = " You may also use the Fish-Networking menu to automatically remove duplicate NetworkObjects.";
string sceneName = t.gameObject.scene.name;
if (string.IsNullOrEmpty(sceneName))
Debug.LogError($"Prefab {t.name} has multiple NetworkObject components. Please remove the extra component(s) to prevent errors.{useMenu}");
else
Debug.LogError($"Object {t.name} in scene {sceneName} has multiple NetworkObject components. Please remove the extra component(s) to prevent errors.{useMenu}");
}
}
#else
return null;
#endif
}
#endregion
}
}