605 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			605 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using FishNet.Connection;
 | |
| using FishNet.Managing.Logging;
 | |
| using FishNet.Managing.Object;
 | |
| using FishNet.Object;
 | |
| using FishNet.Object.Helping;
 | |
| using FishNet.Serializing;
 | |
| using FishNet.Utility.Extension;
 | |
| using FishNet.Utility.Performance;
 | |
| using System;
 | |
| using System.Collections.Generic;
 | |
| using UnityEngine;
 | |
| using UnityEngine.Scripting;
 | |
| 
 | |
| namespace FishNet.Managing.Client
 | |
| {
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Information about cached network objects.
 | |
|     /// </summary>
 | |
|     internal class ClientObjectCache
 | |
|     {
 | |
|         #region Types.
 | |
|         public enum CacheSearchType
 | |
|         {
 | |
|             Any = 0,
 | |
|             Spawning = 1,
 | |
|             Despawning = 2
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         #region Internal.
 | |
|         /// <summary>
 | |
|         /// Objets which are being spawned during iteration.
 | |
|         /// </summary>
 | |
|         internal Dictionary<int, NetworkObject> SpawningObjects = new Dictionary<int, NetworkObject>();
 | |
|         #endregion
 | |
| 
 | |
|         #region Private.
 | |
|         /// <summary>
 | |
|         /// Cached objects buffer. Contains spawns and despawns.
 | |
|         /// </summary>
 | |
|         private ListCache<CachedNetworkObject> _cachedObjects = new ListCache<CachedNetworkObject>();
 | |
|         /// <summary>
 | |
|         /// NetworkObjects which have been spawned already during the current iteration.
 | |
|         /// </summary>
 | |
|         private HashSet<NetworkObject> _iteratedSpawns = new HashSet<NetworkObject>();
 | |
|         /// <summary>
 | |
|         /// Despawns which are occurring the same tick as their spawn.
 | |
|         /// </summary>
 | |
|         private HashSet<int> _conflictingDespawns = new HashSet<int>();
 | |
|         /// <summary>
 | |
|         /// ClientObjects reference.
 | |
|         /// </summary>
 | |
|         private ClientObjects _clientObjects;
 | |
|         /// <summary>
 | |
|         /// NetworkManager for this cache.
 | |
|         /// </summary>
 | |
|         private NetworkManager _networkManager;
 | |
|         /// <summary>
 | |
|         /// True if logged the warning about despawning on the same tick as the spawn.
 | |
|         /// This exist to prevent excessive spam of the warning.
 | |
|         /// </summary>
 | |
|         private bool _loggedSameTickWarning;
 | |
|         /// <summary>
 | |
|         /// True if initializeOrder was not default for any spawned objects.
 | |
|         /// </summary>
 | |
|         private bool _initializeOrderChanged;
 | |
|         #endregion
 | |
| 
 | |
|         public ClientObjectCache(ClientObjects cobs, NetworkManager networkManager)
 | |
|         {
 | |
|             _clientObjects = cobs;
 | |
|             _networkManager = networkManager;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Returns a NetworkObject found in spawned cache using objectId.
 | |
|         /// </summary>
 | |
|         /// <param name="objectId"></param>
 | |
|         /// <returns></returns>
 | |
|         public NetworkObject GetInCached(int objectId, CacheSearchType searchType)
 | |
|         {
 | |
|             int count = _cachedObjects.Written;
 | |
|             List<CachedNetworkObject> collection = _cachedObjects.Collection;
 | |
|             for (int i = 0; i < count; i++)
 | |
|             {
 | |
|                 CachedNetworkObject cnob = collection[i];
 | |
|                 if (cnob.ObjectId == objectId)
 | |
|                 {
 | |
|                     //Any condition always returns.
 | |
|                     if (searchType == CacheSearchType.Any)
 | |
|                         return cnob.NetworkObject;
 | |
| 
 | |
|                     bool spawning = (searchType == CacheSearchType.Spawning);
 | |
|                     bool spawnAction = (cnob.Action == CachedNetworkObject.ActionType.Spawn);
 | |
|                     if (spawning == spawnAction)
 | |
|                         return cnob.NetworkObject;
 | |
|                     else
 | |
|                         return null;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             //Fall through.
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Initializes for a spawned NetworkObject.
 | |
|         /// </summary>
 | |
|         /// <param name="nob"></param>
 | |
|         /// <param name="syncValues"></param>
 | |
|         /// <param name="manager"></param>
 | |
|         public void AddSpawn(NetworkManager manager, ushort collectionId, int objectId, sbyte initializeOrder, int ownerId, SpawnType ost, byte componentIndex, int rootObjectId, int? parentObjectId, byte? parentComponentIndex
 | |
|             , int? prefabId, Vector3? localPosition, Quaternion? localRotation, Vector3? localScale, ulong sceneId, ArraySegment<byte> rpcLinks, ArraySegment<byte> syncValues)
 | |
|         {
 | |
|             //Set if initialization order has changed.
 | |
|             _initializeOrderChanged |= (initializeOrder != 0);
 | |
| 
 | |
|             CachedNetworkObject cnob = null;
 | |
|             //If order has not changed then add normally.
 | |
|             if (!_initializeOrderChanged)
 | |
|             {
 | |
|                 cnob = _cachedObjects.AddReference();
 | |
|             }
 | |
|             //Otherwise see if values need to be sorted.
 | |
|             else
 | |
|             {
 | |
|                 /* Spawns will be ordered at the end of their nearest order.
 | |
|                  * If spawns arrived with Id order of 5, 7, 2 then the result
 | |
|                  * would be as shown below...
 | |
|                  * Id 5 / order -5
 | |
|                  * Id 7 / order -5
 | |
|                  * Id 2 / order 0
 | |
|                  * Not as if the values were inserted first such as...
 | |
|                  * Id 7 / order -5
 | |
|                  * Id 5 / order -5
 | |
|                  * Id 2 / order 0 
 | |
|                  * This is to prevent the likeliness of child nobs being out of order
 | |
|                  * as well to preserve user spawn order if they spawned multiple
 | |
|                  * objects the same which, with the same order. */
 | |
| 
 | |
|                 int written = _cachedObjects.Written;
 | |
|                 for (int i = 0; i < written; i++)
 | |
|                 {
 | |
|                     CachedNetworkObject item = _cachedObjects.Collection[i];
 | |
|                     /* If item order is larger then that means
 | |
|                      * initializeOrder has reached the last entry
 | |
|                      * of its value. Insert just before item index. */
 | |
|                     if (initializeOrder < item.InitializeOrder)
 | |
|                     {
 | |
|                         cnob = _cachedObjects.InsertReference(i);
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 //If here and cnob is null then it was not inserted; add to end.
 | |
|                 if (cnob == null)
 | |
|                     cnob = _cachedObjects.AddReference();
 | |
|             }
 | |
| 
 | |
|             cnob.InitializeSpawn(manager, collectionId, objectId, initializeOrder, ownerId, ost, componentIndex, rootObjectId, parentObjectId, parentComponentIndex
 | |
|                 , prefabId, localPosition, localRotation, localScale, sceneId, rpcLinks, syncValues);
 | |
|         }
 | |
| 
 | |
|         public void AddDespawn(int objectId, DespawnType despawnType)
 | |
|         {
 | |
|             CachedNetworkObject cnob = _cachedObjects.AddReference();
 | |
|             cnob.InitializeDespawn(objectId, despawnType);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Iterates any written objects.
 | |
|         /// </summary>
 | |
|         public void Iterate()
 | |
|         {
 | |
|             int written = _cachedObjects.Written;
 | |
|             if (written == 0)
 | |
|                 return;
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 //Indexes which have already been processed.
 | |
|                 HashSet<int> processedIndexes = new HashSet<int>();
 | |
|                 List<CachedNetworkObject> collection = _cachedObjects.Collection;
 | |
|                 _conflictingDespawns.Clear();
 | |
|                 /* The next iteration will set rpclinks,
 | |
|                  * synctypes, and so on. */
 | |
|                 for (int i = 0; i < written; i++)
 | |
|                 {
 | |
|                     /* An index may already be processed if it was pushed ahead.
 | |
|                      * This can occur if a nested object spawn exists but the root
 | |
|                      * object has not spawned yet. In this situation the root spawn is
 | |
|                      * found and performed first. */
 | |
|                     if (processedIndexes.Contains(i))
 | |
|                         continue;
 | |
|                     CachedNetworkObject cnob = collection[i];
 | |
|                     bool spawn = (cnob.Action == CachedNetworkObject.ActionType.Spawn);
 | |
| 
 | |
|                     /* See if nested, and if so check if root is already spawned.
 | |
|                      * If parent is not spawned then find it and process the parent first. */
 | |
|                     if (spawn)
 | |
|                     {
 | |
|                         /* When an object is nested or has a parent it is
 | |
|                          * dependent upon either the root of nested, or the parent,
 | |
|                          * being spawned to setup properly.
 | |
|                          * 
 | |
|                          * When either of these are true check spawned objects first
 | |
|                          * to see if the objects exist. If not check if they are appearing
 | |
|                          * later in the cache. Root or parent objects can appear later
 | |
|                          * in the cache depending on the order of which observers are rebuilt.
 | |
|                          * While it is possible to have the server ensure spawns always send
 | |
|                          * root/parents first, that's a giant can of worms that's not worth getting into.
 | |
|                          * Not only are there many scenarios to cover, but it also puts more work
 | |
|                          * on the server. It's more effective to have the client handle the sorting. */
 | |
| 
 | |
|                         //Nested.
 | |
|                         if (cnob.IsNested || cnob.HasParent)
 | |
|                         {
 | |
|                             bool nested = cnob.IsNested;
 | |
|                             //It's not possible to be nested and have a parent. Set the Id to look for based on if nested or parented.
 | |
|                             int targetObjectId = (nested) ? cnob.RootObjectId : cnob.ParentObjectId.Value;
 | |
|                             NetworkObject nob = GetSpawnedObject(targetObjectId);
 | |
|                             //If not spawned yet.
 | |
|                             if (nob == null)
 | |
|                             {
 | |
|                                 bool found = false;
 | |
|                                 string errMsg;
 | |
|                                 for (int z = (i + 1); z < written; z++)
 | |
|                                 {
 | |
|                                     CachedNetworkObject zCnob = collection[z];
 | |
|                                     if (zCnob.ObjectId == targetObjectId)
 | |
|                                     {
 | |
|                                         found = true;
 | |
|                                         if (cnob.Action != CachedNetworkObject.ActionType.Spawn)
 | |
|                                         {
 | |
|                                             errMsg = (nested)
 | |
|                                                 ? $"ObjectId {targetObjectId} was found for a nested spawn, but ActionType is not spawn. ComponentIndex {cnob.ComponentIndex} will not be spawned."
 | |
|                                                 : $"ObjectId {targetObjectId} was found for a parented spawn, but ActionType is not spawn. ObjectId {cnob.ObjectId} will not be spawned.";
 | |
|                                             _networkManager.LogError(errMsg);
 | |
|                                             break;
 | |
|                                         }
 | |
|                                         else
 | |
|                                         {
 | |
|                                             ProcessObject(zCnob, true, z);
 | |
|                                             break;
 | |
|                                         }
 | |
|                                     }
 | |
|                                 }
 | |
| 
 | |
|                                 //Root nob could not be found.
 | |
|                                 if (!found)
 | |
|                                 {
 | |
|                                     errMsg = (nested)
 | |
|                                         ? $"ObjectId {targetObjectId} could not be found for a nested spawn. ComponentIndex {cnob.ComponentIndex} will not be spawned."
 | |
|                                         : $"ObjectId {targetObjectId} was found for a parented spawn. ObjectId {cnob.ObjectId} will not be spawned.";
 | |
|                                     _networkManager.LogError(errMsg);
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     ProcessObject(cnob, spawn, i);
 | |
|                 }
 | |
| 
 | |
|                 void ProcessObject(CachedNetworkObject cnob, bool spawn, int index)
 | |
|                 {
 | |
|                     processedIndexes.Add(index);
 | |
| 
 | |
|                     if (spawn)
 | |
|                     {
 | |
|                         if (cnob.IsSceneObject)
 | |
|                             cnob.NetworkObject = _clientObjects.GetSceneNetworkObject(cnob.SceneId);
 | |
|                         else if (cnob.IsNested)
 | |
|                             cnob.NetworkObject = _clientObjects.GetNestedNetworkObject(cnob);
 | |
|                         else
 | |
|                             cnob.NetworkObject = _clientObjects.GetInstantiatedNetworkObject(cnob);
 | |
| 
 | |
|                         /* Apply transform changes but only if not host.
 | |
|                          * These would have already been applied server side. */
 | |
|                         if (!_networkManager.IsHost && cnob.NetworkObject != null)
 | |
|                         {
 | |
|                             Transform t = cnob.NetworkObject.transform;
 | |
|                             _clientObjects.GetTransformProperties(cnob.LocalPosition, cnob.LocalRotation, cnob.LocalScale, t, out Vector3 pos, out Quaternion rot, out Vector3 scale);
 | |
|                             t.SetLocalPositionRotationAndScale(pos, rot, scale);
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         cnob.NetworkObject = _clientObjects.GetSpawnedNetworkObject(cnob);
 | |
|                         /* Do not log unless not nested. Nested nobs sometimes
 | |
|                          * could be destroyed if parent was first. */
 | |
|                         if (!_networkManager.IsHost && cnob.NetworkObject == null && !cnob.IsNested)
 | |
|                             _networkManager.Log($"NetworkObject for ObjectId of {cnob.ObjectId} was found null. Unable to despawn object. This may occur if a nested NetworkObject had it's parent object unexpectedly destroyed. This incident is often safe to ignore.");
 | |
|                     }
 | |
|                     NetworkObject nob = cnob.NetworkObject;
 | |
|                     //No need to error here, the other Gets above would have.
 | |
|                     if (nob == null)
 | |
|                         return;
 | |
| 
 | |
|                     if (spawn)
 | |
|                     {
 | |
|                         //If not also server then object also has to be preinitialized.
 | |
|                         if (!_networkManager.IsServer)
 | |
|                         {
 | |
|                             int ownerId = cnob.OwnerId;
 | |
|                             //If local client is owner then use localconnection reference.
 | |
|                             NetworkConnection localConnection = _networkManager.ClientManager.Connection;
 | |
|                             NetworkConnection owner;
 | |
|                             //If owner is self.
 | |
|                             if (ownerId == localConnection.ClientId)
 | |
|                             {
 | |
|                                 owner = localConnection;
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 /* If owner cannot be found then share owners
 | |
|                                  * is disabled */
 | |
|                                 if (!_networkManager.ClientManager.Clients.TryGetValueIL2CPP(ownerId, out owner))
 | |
|                                     owner = NetworkManager.EmptyConnection;
 | |
|                             }
 | |
|                             nob.Preinitialize_Internal(_networkManager, cnob.ObjectId, owner, false);
 | |
|                         }
 | |
| 
 | |
|                         _clientObjects.AddToSpawned(cnob.NetworkObject, false);
 | |
|                         SpawningObjects.Add(cnob.ObjectId, cnob.NetworkObject);
 | |
| 
 | |
|                         IterateSpawn(cnob);
 | |
|                         _iteratedSpawns.Add(cnob.NetworkObject);
 | |
| 
 | |
|                         /* Enable networkObject here if client only.
 | |
|                         * This is to ensure Awake fires in the same order
 | |
|                         * as InitializeOrder settings. There is no need
 | |
|                         * to perform this action if server because server
 | |
|                         * would have already spawned in order. */
 | |
|                         if (!_networkManager.IsServer && cnob.NetworkObject != null)
 | |
|                             cnob.NetworkObject.gameObject.SetActive(true);
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         /* If spawned already this iteration then the nob
 | |
|                          * must be initialized so that the start/stop cycles
 | |
|                          * complete normally. Otherwise, the despawn callbacks will
 | |
|                          * fire immediately while the start callbacks will run after all
 | |
|                          * spawns have been iterated.
 | |
|                          * The downside to this is that synctypes
 | |
|                          * for spawns later in this iteration will not be initialized
 | |
|                          * yet, and if the nob being spawned/despawned references
 | |
|                          * those synctypes the values will be default.
 | |
|                          * 
 | |
|                          * The alternative is to delay the despawning until after
 | |
|                          * all spawns are iterated, but that will break the order
 | |
|                          * reliability. This is unfortunately a lose/lose situation so
 | |
|                          * the best we can do is let the user know the risk. */
 | |
|                         if (_iteratedSpawns.Contains(cnob.NetworkObject))
 | |
|                         {
 | |
|                             if (!_loggedSameTickWarning)
 | |
|                             {
 | |
|                                 _loggedSameTickWarning = true;
 | |
|                                 _networkManager.LogWarning($"NetworkObject {cnob.NetworkObject.name} is being despawned on the same tick it's spawned." +
 | |
|                                                $" When this occurs SyncTypes will not be set on other objects during the time of this despawn." +
 | |
|                                                $" In result, if NetworkObject {cnob.NetworkObject.name} is referencing a SyncType of another object being spawned this tick, the returned values will be default.");
 | |
|                             }
 | |
| 
 | |
|                             _conflictingDespawns.Add(cnob.ObjectId);
 | |
|                             cnob.NetworkObject.gameObject.SetActive(true);
 | |
|                             cnob.NetworkObject.Initialize(false, true);
 | |
|                         }
 | |
|                         //Now being initialized, despawn the object.
 | |
|                         IterateDespawn(cnob);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 /* Activate the objects after all data
 | |
|                  * has been synchronized. This will apply synctypes. */
 | |
|                 for (int i = 0; i < written; i++)
 | |
|                 {
 | |
|                     CachedNetworkObject cnob = collection[i];
 | |
|                     if (cnob.Action == CachedNetworkObject.ActionType.Spawn && cnob.NetworkObject != null)
 | |
|                     {
 | |
|                         /* Apply syncTypes. It's very important to do this after all
 | |
|                          * spawns have been processed and added to the manager.Objects collection.
 | |
|                          * Otherwise, the synctype may reference an object spawning the same tick
 | |
|                          * and the result would be null due to said object not being in spawned.
 | |
|                          * 
 | |
|                          * At this time the NetworkObject is not initialized so by calling
 | |
|                          * OnSyncType the changes are cached to invoke callbacks after initialization,
 | |
|                          * not during the time of this action. */
 | |
|                         foreach (NetworkBehaviour nb in cnob.NetworkObject.NetworkBehaviours)
 | |
|                         {
 | |
|                             PooledReader reader = cnob.SyncValuesReader;
 | |
|                             //SyncVars.
 | |
|                             int length = reader.ReadInt32();
 | |
|                             nb.OnSyncType(reader, length, false);
 | |
|                             //SyncObjects
 | |
|                             length = reader.ReadInt32();
 | |
|                             nb.OnSyncType(reader, length, true);
 | |
|                         }
 | |
| 
 | |
|                         /* Only continue with the initialization if it wasn't initialized
 | |
|                          * early to prevent a despawn conflict. */
 | |
|                         bool canInitialize = (!_conflictingDespawns.Contains(cnob.ObjectId) || !_iteratedSpawns.Contains(cnob.NetworkObject));
 | |
|                         if (canInitialize)
 | |
|                             cnob.NetworkObject.Initialize(false, false);
 | |
|                     }
 | |
|                 }
 | |
|                 //Invoke synctype callbacks.
 | |
|                 for (int i = 0; i < written; i++)
 | |
|                 {
 | |
|                     CachedNetworkObject cnob = collection[i];
 | |
|                     if (cnob.Action == CachedNetworkObject.ActionType.Spawn && cnob.NetworkObject != null)
 | |
|                         cnob.NetworkObject.InvokeSyncTypeCallbacks(false);
 | |
|                 }
 | |
|             }
 | |
|             finally
 | |
|             {
 | |
|                 //Once all have been iterated reset.
 | |
|                 Reset();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Initializes an object on clients and spawns the NetworkObject.
 | |
|         /// </summary>
 | |
|         /// <param name="cnob"></param>
 | |
|         private void IterateSpawn(CachedNetworkObject cnob)
 | |
|         {
 | |
|             /* All nob spawns have been added to spawned before
 | |
|             * they are processed. This ensures they will be found if
 | |
|             * anything is referencing them before/after initialization. */
 | |
|             /* However, they have to be added again here should an ItereteDespawn
 | |
|              * had removed them. This can occur if an object is set to be spawned,
 | |
|              * thus added to spawned before iterations, then a despawn runs which
 | |
|              * removes it from spawn. */
 | |
|             _clientObjects.AddToSpawned(cnob.NetworkObject, false);
 | |
|             _clientObjects.ApplyRpcLinks(cnob.NetworkObject, cnob.RpcLinkReader);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Deinitializes an object on clients and despawns the NetworkObject.
 | |
|         /// </summary>
 | |
|         /// <param name="cnob"></param>
 | |
|         private void IterateDespawn(CachedNetworkObject cnob)
 | |
|         {
 | |
|             _clientObjects.Despawn(cnob.NetworkObject, cnob.DespawnType, false);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Returns a NetworkObject found in spawn cache, or Spawned.
 | |
|         /// </summary>
 | |
|         /// <param name="objectId"></param>
 | |
|         internal NetworkObject GetSpawnedObject(int objectId)
 | |
|         {
 | |
|             NetworkObject result;
 | |
|             //If not found in Spawning then check Spawned.
 | |
|             if (!SpawningObjects.TryGetValue(objectId, out result))
 | |
|             {
 | |
|                 Dictionary<int, NetworkObject> spawned = (_networkManager.IsHost) ?
 | |
|                     _networkManager.ServerManager.Objects.Spawned
 | |
|                     : _networkManager.ClientManager.Objects.Spawned;
 | |
|                 spawned.TryGetValue(objectId, out result);
 | |
|             }
 | |
| 
 | |
|             return result;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Resets cache.
 | |
|         /// </summary>
 | |
|         public void Reset()
 | |
|         {
 | |
|             _initializeOrderChanged = false;
 | |
|             _cachedObjects.Reset();
 | |
|             _iteratedSpawns.Clear();
 | |
|             SpawningObjects.Clear();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// A cached network object which exist in world but has not been Initialized yet.
 | |
|     /// </summary>
 | |
|     [Preserve]
 | |
|     internal class CachedNetworkObject
 | |
|     {
 | |
|         #region Types.
 | |
|         public enum ActionType
 | |
|         {
 | |
|             Unset = 0,
 | |
|             Spawn = 1,
 | |
|             Despawn = 2,
 | |
|         }
 | |
|         #endregion
 | |
| 
 | |
|         /// <summary>
 | |
|         /// True if cached object is nested.
 | |
|         /// </summary>
 | |
|         public bool IsNested => (ComponentIndex > 0);
 | |
|         /// <summary>
 | |
|         /// True if a scene object.
 | |
|         /// </summary>
 | |
|         public bool IsSceneObject => (SceneId > 0);
 | |
|         /// <summary>
 | |
|         /// True if this object has a parent.
 | |
|         /// </summary>
 | |
|         public bool HasParent => (ParentObjectId != null);
 | |
|         /// <summary>
 | |
|         /// True if the parent object is a NetworkBehaviour.
 | |
|         /// </summary>
 | |
|         public bool ParentIsNetworkBehaviour => (HasParent && (ParentComponentIndex != null));
 | |
| 
 | |
|         public ushort CollectionId;
 | |
|         public int ObjectId;
 | |
|         public sbyte InitializeOrder;
 | |
|         public int OwnerId;
 | |
|         public SpawnType SpawnType;
 | |
|         public DespawnType DespawnType;
 | |
|         public byte ComponentIndex;
 | |
|         public int RootObjectId;
 | |
|         public int? ParentObjectId;
 | |
|         public byte? ParentComponentIndex;
 | |
|         public int? PrefabId;
 | |
|         public Vector3? LocalPosition;
 | |
|         public Quaternion? LocalRotation;
 | |
|         public Vector3? LocalScale;
 | |
|         public ulong SceneId;
 | |
|         public ArraySegment<byte> RpcLinks;
 | |
|         public ArraySegment<byte> SyncValues;
 | |
| 
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// True if spawning.
 | |
|         /// </summary>
 | |
|         public ActionType Action { get; private set; }
 | |
|         /// <summary>
 | |
|         /// Cached NetworkObject.
 | |
|         /// </summary>
 | |
| #pragma warning disable 0649
 | |
|         public NetworkObject NetworkObject;
 | |
|         /// <summary>
 | |
|         /// Reader containing rpc links for the network object.
 | |
|         /// </summary>
 | |
|         public PooledReader RpcLinkReader { get; private set; }
 | |
|         /// <summary>
 | |
|         /// Reader containing sync values for the network object.
 | |
|         /// </summary>
 | |
|         public PooledReader SyncValuesReader { get; private set; }
 | |
| #pragma warning restore 0649
 | |
| 
 | |
|         public void InitializeSpawn(NetworkManager manager, ushort collectionId, int objectId, sbyte initializeOrder, int ownerId, SpawnType objectSpawnType, byte componentIndex, int rootObjectId, int? parentObjectId, byte? parentComponentIndex
 | |
|     , int? prefabId, Vector3? localPosition, Quaternion? localRotation, Vector3? localScale, ulong sceneId, ArraySegment<byte> rpcLinks, ArraySegment<byte> syncValues)
 | |
|         {
 | |
|             ResetValues();
 | |
|             Action = ActionType.Spawn;
 | |
|             CollectionId = collectionId;
 | |
|             ObjectId = objectId;
 | |
|             InitializeOrder = initializeOrder;
 | |
|             OwnerId = ownerId;
 | |
|             SpawnType = objectSpawnType;
 | |
|             ComponentIndex = componentIndex;
 | |
|             RootObjectId = rootObjectId;
 | |
|             ParentObjectId = parentObjectId;
 | |
|             ParentComponentIndex = parentComponentIndex;
 | |
|             PrefabId = prefabId;
 | |
|             LocalPosition = localPosition;
 | |
|             LocalRotation = localRotation;
 | |
|             LocalScale = localScale;
 | |
|             SceneId = sceneId;
 | |
|             RpcLinks = rpcLinks;
 | |
|             SyncValues = syncValues;
 | |
| 
 | |
|             RpcLinkReader = ReaderPool.GetReader(rpcLinks, manager);
 | |
|             SyncValuesReader = ReaderPool.GetReader(syncValues, manager);
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Initializes for a despawned NetworkObject.
 | |
|         /// </summary>
 | |
|         /// <param name="nob"></param>
 | |
|         public void InitializeDespawn(int objectId, DespawnType despawnType)
 | |
|         {
 | |
|             ResetValues();
 | |
|             Action = ActionType.Despawn;
 | |
|             DespawnType = despawnType;
 | |
|             ObjectId = objectId;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Resets values which could malform identify the cached object.
 | |
|         /// </summary>
 | |
|         private void ResetValues()
 | |
|         {
 | |
|             NetworkObject = null;
 | |
|         }
 | |
| 
 | |
|         ~CachedNetworkObject()
 | |
|         {
 | |
|             if (RpcLinkReader != null)
 | |
|                 RpcLinkReader.Dispose();
 | |
|             if (SyncValuesReader != null)
 | |
|                 SyncValuesReader.Dispose();
 | |
|         }
 | |
|     }
 | |
| 
 | |
| } |