NetworkIdentity

This commit is contained in:
Chris Langsenkamp 2019-07-29 04:24:22 -04:00
parent 01d144bc62
commit f4ab3e853c

View File

@ -14,6 +14,32 @@
namespace Mirror
{
/// <summary>
/// The NetworkIdentity identifies objects across the network, between server and clients. Its primary data is a NetworkInstanceId which is allocated by the server and then set on clients. This is used in network communications to be able to lookup game objects on different machines.
/// <para>The NetworkIdentity is used to synchronize information in the object with the network. Only the server should create instances of objects which have NetworkIdentity as otherwise they will not be properly connected to the system.</para>
/// <para>For complex objects with a hierarchy of subcomponents, the NetworkIdentity must be on the root of the hierarchy. It is not supported to have multiple NetworkIdentity components on subcomponents of a hierarchy.</para>
/// <para>NetworkBehaviour scripts require a NetworkIdentity on the game object to be able to function.</para>
/// <para>The NetworkIdentity manages the dirty state of the NetworkBehaviours of the object. When it discovers that NetworkBehaviours are dirty, it causes an update packet to be created and sent to clients.</para>
/// <para>The flow for serialization updates managed by the NetworkIdentity is:</para>
/// <para>* Each NetworkBehaviour has a dirty mask. This mask is available inside OnSerialize as syncVarDirtyBits</para>
/// <para>* Each SyncVar in a NetworkBehaviour script is assigned a bit in the dirty mask.</para>
/// <para>* Changing the value of SyncVars causes the bit for that SyncVar to be set in the dirty mask</para>
/// <para>* Alternatively, calling SetDirtyBit() writes directly to the dirty mask</para>
/// <para>* NetworkIdentity objects are checked on the server as part of it&apos;s update loop</para>
/// <para>* If any NetworkBehaviours on a NetworkIdentity are dirty, then an UpdateVars packet is created for that object</para>
/// <para>* The UpdateVars packet is populated by calling OnSerialize on each NetworkBehaviour on the object</para>
/// <para>* NetworkBehaviours that are NOT dirty write a zero to the packet for their dirty bits</para>
/// <para>* NetworkBehaviours that are dirty write their dirty mask, then the values for the SyncVars that have changed</para>
/// <para>* If OnSerialize returns true for a NetworkBehaviour, the dirty mask is reset for that NetworkBehaviour, so it will not send again until its value changes.</para>
/// <para>* The UpdateVars packet is sent to ready clients that are observing the object</para>
/// <para>On the client:</para>
/// <para>* an UpdateVars packet is received for an object</para>
/// <para>* The OnDeserialize function is called for each NetworkBehaviour script on the object</para>
/// <para>* Each NetworkBehaviour script on the object reads a dirty mask.</para>
/// <para>* If the dirty mask for a NetworkBehaviour is zero, the OnDeserialize functions returns without reading any more</para>
/// <para>* If the dirty mask is non-zero value, then the OnDeserialize function reads the values for the SyncVars that correspond to the dirty bits that are set</para>
/// <para>* If there are SyncVar hook functions, those are invoked with the value read from the stream.</para>
/// </summary>
[ExecuteInEditMode]
[DisallowMultipleComponent]
[AddComponentMenu("Network/NetworkIdentity")]
@ -28,47 +54,104 @@ public sealed class NetworkIdentity : MonoBehaviour
// check MarkForReset for more information.
bool m_Reset;
// properties
/// <summary>
/// Returns true if running as a client and this object was spawned by a server.
/// </summary>
public bool isClient { get; internal set; }
// dont return true if server stopped.
/// <summary>
/// Returns true if NetworkServer.active and server is not stopped.
/// </summary>
public bool isServer
{
get => m_IsServer && NetworkServer.active && netId != 0;
internal set => m_IsServer = value;
}
/// <summary>
/// This returns true if this object is the one that represents the player on the local machine.
/// <para>This is set when the server has spawned an object for this particular client.</para>
/// </summary>
public bool isLocalPlayer { get; private set; }
/// <summary>
/// This returns true if this object is the authoritative version of the object in the distributed network application.
/// <para>This value is determined at runtime, as opposed to localPlayerAuthority which is set on the prefab. For most objects, authority is held by the server / host. For objects with localPlayerAuthority set, authority is held by the client of that player.</para>
/// <para>For objects that had their authority set by AssignClientAuthority on the server, this will be true on the client that owns the object. NOT on other clients.</para>
/// </summary>
public bool hasAuthority { get; private set; }
// <connectionId, NetworkConnection>
// null until OnStartServer was called. this is necessary for SendTo...
// to work properly in server-only mode.
/// <summary>
/// The set of network connections (players) that can see this object.
/// <para>null until OnStartServer was called. this is necessary for SendTo* to work properly in server-only mode.</para>
/// </summary>
public Dictionary<int, NetworkConnection> observers;
/// <summary>
/// Unique identifier for this particular object instance, used for tracking objects between networked clients and the server.
/// <para>This is a unique identifier for this particular GameObject instance. Use it to track GameObjects between networked clients and the server.</para>
/// </summary>
public uint netId { get; internal set; }
/// <summary>
/// A unique identifier for NetworkIdentity objects within a scene.
/// <para>This is used for spawning scene objects on clients.</para>
/// </summary>
public ulong sceneId => m_SceneId;
/// <summary>
/// Flag to make this object only exist when the game is running as a server (or host).
/// </summary>
[FormerlySerializedAs("m_ServerOnly")]
public bool serverOnly;
/// <summary>
/// localPlayerAuthority means that the client of the "owning" player has authority over their own player object.
/// <para>Authority for this object will be on the player's client. So hasAuthority will be true on that client - and false on the server and on other clients.</para>
/// </summary>
[FormerlySerializedAs("m_LocalPlayerAuthority")]
public bool localPlayerAuthority;
/// <summary>
/// The client that has authority for this object. This will be null if no client has authority.
/// <para>This is set for player objects with localPlayerAuthority, and for objects set with AssignClientAuthority, and spawned with SpawnWithClientAuthority.</para>
/// </summary>
public NetworkConnection clientAuthorityOwner { get; internal set; }
/// <summary>
/// The NetworkConnection associated with this NetworkIdentity. This is only valid for player objects on a local client.
/// </summary>
public NetworkConnection connectionToServer { get; internal set; }
/// <summary>
/// The NetworkConnection associated with this <see cref="NetworkIdentity">NetworkIdentity.</see> This is only valid for player objects on the server.
/// <para>Use it to return details such as the connection&apos;s identity, IP address and ready status.</para>
/// </summary>
public NetworkConnection connectionToClient { get; internal set; }
// all spawned NetworkIdentities by netId. needed on server and client.
/// <summary>
/// All spawned NetworkIdentities by netId. Available on server and client.
/// </summary>
public static readonly Dictionary<uint, NetworkIdentity> spawned = new Dictionary<uint, NetworkIdentity>();
public NetworkBehaviour[] NetworkBehaviours => networkBehavioursCache = networkBehavioursCache ?? GetComponents<NetworkBehaviour>();
// the AssetId trick:
// - ideally we would have a serialized 'Guid m_AssetId' but Unity can't
// serialize it because Guid's internal bytes are private
// - UNET used 'NetworkHash128' originally, with byte0, ..., byte16
// which works, but it just unnecessary extra code
// - using just the Guid string would work, but it's 32 chars long and
// would then be sent over the network as 64 instead of 16 bytes
// -> the solution is to serialize the string internally here and then
// use the real 'Guid' type for everything else via .assetId
[SerializeField] string m_AssetId;
/// <summary>
/// Unique identifier used to find the source assets when server spawns the on clients.
/// <para>
/// the AssetId trick:
/// - ideally we would have a serialized 'Guid m_AssetId' but Unity can't
/// serialize it because Guid's internal bytes are private
/// - UNET used 'NetworkHash128' originally, with byte0, ..., byte16
/// which works, but it just unnecessary extra code
/// - using just the Guid string would work, but it's 32 chars long and
/// would then be sent over the network as 64 instead of 16 bytes
/// -> the solution is to serialize the string internally here and then
/// use the real 'Guid' type for everything else via .assetId
/// </para>
/// </summary>
public Guid assetId
{
get
@ -131,9 +214,25 @@ internal void ForceAuthority(bool authority)
static uint nextNetworkId = 1;
internal static uint GetNextNetworkId() => nextNetworkId++;
/// <summary>
/// Resets nextNetworkId = 1
/// </summary>
public static void ResetNextNetworkId() => nextNetworkId = 1;
/// <summary>
/// The delegate type for the clientAuthorityCallback.
/// </summary>
/// <param name="conn">The network connection that is gaining or losing authority.</param>
/// <param name="identity">The object whose client authority status is being changed.</param>
/// <param name="authorityState">The new state of client authority of the object for the connection.</param>
public delegate void ClientAuthorityCallback(NetworkConnection conn, NetworkIdentity identity, bool authorityState);
/// <summary>
/// A callback that can be populated to be notified when the client-authority state of objects changes.
/// <para>Whenever an object is spawned using SpawnWithClientAuthority, or the client authority status of an object is changed with AssignClientAuthority or RemoveClientAuthority, then this callback will be invoked.</para>
/// <para>This callback is used by the NetworkMigrationManager to distribute client authority state to peers for host migration. If the NetworkMigrationManager is not being used, this callback does not need to be populated.</para>
/// </summary>
public static ClientAuthorityCallback clientAuthorityCallback;
// used when the player object for a connection changes
@ -806,6 +905,10 @@ internal void AddObserver(NetworkConnection conn)
static readonly HashSet<NetworkConnection> newObservers = new HashSet<NetworkConnection>();
/// <summary>
/// This causes the set of players that can see this object to be rebuild. The OnRebuildObservers callback function will be invoked on each NetworkBehaviour.
/// </summary>
/// <param name="initialize">True if this is the first time.</param>
public void RebuildObservers(bool initialize)
{
if (observers == null)
@ -905,6 +1008,12 @@ public void RebuildObservers(bool initialize)
}
}
/// <summary>
/// Removes ownership for an object for a client by its conneciton.
/// <para>This applies to objects that had authority set by AssignClientAuthority, or NetworkServer.SpawnWithClientAuthority. Authority cannot be removed for player objects.</para>
/// </summary>
/// <param name="conn">The connection of the client to remove authority for.</param>
/// <returns>True if authority is removed.</returns>
public bool RemoveClientAuthority(NetworkConnection conn)
{
if (!isServer)
@ -949,6 +1058,13 @@ public bool RemoveClientAuthority(NetworkConnection conn)
return true;
}
/// <summary>
/// This assigns control of an object to a client via the client's <see cref="NetworkConnection">NetworkConnection.</see>
/// <para>This causes hasAuthority to be set on the client that owns the object, and NetworkBehaviour.OnStartAuthority will be called on that client. This object then will be in the NetworkConnection.clientOwnedObjects list for the connection.</para>
/// <para>Authority can be removed with RemoveClientAuthority. Only one client can own an object at any time. Only NetworkIdentities with localPlayerAuthority set can have client authority assigned. This does not need to be called for player objects, as their authority is setup automatically.</para>
/// </summary>
/// <param name="conn"> The connection of the client to assign authority to.</param>
/// <returns>True if authority was assigned.</returns>
public bool AssignClientAuthority(NetworkConnection conn)
{
if (!isServer)