Advertisement
Guest User

Untitled

a guest
May 12th, 2023
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.97 KB | None | 0 0
  1. using FishNet.Connection;
  2. using FishNet.Managing.Logging;
  3. using FishNet.Managing.Object;
  4. using FishNet.Object;
  5. using FishNet.Object.Helping;
  6. using FishNet.Serializing;
  7. using FishNet.Utility.Extension;
  8. using FishNet.Utility.Performance;
  9. using System;
  10. using System.Collections.Generic;
  11. using UnityEngine;
  12. using UnityEngine.Scripting;
  13.  
  14. namespace FishNet.Managing.Client
  15. {
  16.  
  17. /// <summary>
  18. /// Information about cached network objects.
  19. /// </summary>
  20. internal class ClientObjectCache
  21. {
  22. #region Types.
  23. public enum CacheSearchType
  24. {
  25. Any = 0,
  26. Spawning = 1,
  27. Despawning = 2
  28. }
  29. #endregion
  30.  
  31. #region Internal.
  32. /// <summary>
  33. /// Objets which are being spawned during iteration.
  34. /// </summary>
  35. internal Dictionary<int, NetworkObject> SpawningObjects = new Dictionary<int, NetworkObject>();
  36. #endregion
  37.  
  38. #region Private.
  39. /// <summary>
  40. /// Cached objects buffer. Contains spawns and despawns.
  41. /// </summary>
  42. private ListCache<CachedNetworkObject> _cachedObjects = new ListCache<CachedNetworkObject>();
  43. /// <summary>
  44. /// NetworkObjects which have been spawned already during the current iteration.
  45. /// </summary>
  46. private HashSet<NetworkObject> _iteratedSpawns = new HashSet<NetworkObject>();
  47. /// <summary>
  48. /// Despawns which are occurring the same tick as their spawn.
  49. /// </summary>
  50. private HashSet<int> _conflictingDespawns = new HashSet<int>();
  51. /// <summary>
  52. /// ClientObjects reference.
  53. /// </summary>
  54. private ClientObjects _clientObjects;
  55. /// <summary>
  56. /// NetworkManager for this cache.
  57. /// </summary>
  58. private NetworkManager _networkManager;
  59. /// <summary>
  60. /// True if logged the warning about despawning on the same tick as the spawn.
  61. /// This exist to prevent excessive spam of the warning.
  62. /// </summary>
  63. private bool _loggedSameTickWarning;
  64. #endregion
  65.  
  66. public ClientObjectCache(ClientObjects cobs, NetworkManager networkManager)
  67. {
  68. _clientObjects = cobs;
  69. _networkManager = networkManager;
  70. }
  71.  
  72. /// <summary>
  73. /// Returns a NetworkObject found in spawned cache using objectId.
  74. /// </summary>
  75. /// <param name="objectId"></param>
  76. /// <returns></returns>
  77. public NetworkObject GetInCached(int objectId, CacheSearchType searchType)
  78. {
  79. int count = _cachedObjects.Written;
  80. List<CachedNetworkObject> collection = _cachedObjects.Collection;
  81. for (int i = 0; i < count; i++)
  82. {
  83. CachedNetworkObject cnob = collection[i];
  84. if (cnob.ObjectId == objectId)
  85. {
  86. //Any condition always returns.
  87. if (searchType == CacheSearchType.Any)
  88. return cnob.NetworkObject;
  89.  
  90. bool spawning = (searchType == CacheSearchType.Spawning);
  91. bool spawnAction = (cnob.Action == CachedNetworkObject.ActionType.Spawn);
  92. if (spawning == spawnAction)
  93. return cnob.NetworkObject;
  94. else
  95. return null;
  96. }
  97. }
  98.  
  99. //Fall through.
  100. return null;
  101. }
  102.  
  103. /// <summary>
  104. /// </summary>
  105. /// <param name="nob"></param>
  106. /// <param name="syncValues"></param>
  107. /// <param name="manager"></param>
  108. public void AddSpawn(NetworkManager manager, int objectId, int ownerId, SpawnType ost, byte componentIndex, int rootObjectId
  109. , short? prefabId, Vector3? localPosition, Quaternion? localRotation, Vector3? localScale, ulong sceneId, ArraySegment<byte> rpcLinks, ArraySegment<byte> syncValues)
  110. {
  111. CachedNetworkObject cnob = _cachedObjects.AddReference();
  112. clientObjects.AddToSpawned(cnob.NetworkObject, false);
  113. cnob.InitializeSpawn(manager, objectId, ownerId, ost, componentIndex, rootObjectId, parentObjectId, parentComponentIndex
  114. , prefabId, localPosition, localRotation, localScale);
  115. }
  116.  
  117. public void AddDespawn(int objectId, DespawnType despawnType)
  118. {
  119. CachedNetworkObject cnob = _cachedObjects.AddReference();
  120. cnob.InitializeDespawn(objectId, despawnType);
  121. }
  122.  
  123. /// <summary>
  124. /// Iterates any written objects.
  125. /// </summary>
  126. public void Iterate()
  127. {
  128. int written = _cachedObjects.Written;
  129. if (written == 0)
  130. return;
  131.  
  132. try
  133. {
  134. //Indexes which have already been processed.
  135. HashSet<int> processedIndexes = new HashSet<int>();
  136. List<CachedNetworkObject> collection = _cachedObjects.Collection;
  137. _conflictingDespawns.Clear();
  138. /* The next iteration will set rpclinks,
  139. * synctypes, and so on. */
  140. for (int i = 0; i < written; i++)
  141. {
  142. /* An index may already be processed if it was pushed ahead.
  143. * This can occur if a nested object spawn exists but the root
  144. * object has not spawned yet. In this situation the root spawn is
  145. * found and performed first. */
  146. if (processedIndexes.Contains(i))
  147. continue;
  148. CachedNetworkObject cnob = collection[i];
  149. bool spawn = (cnob.Action == CachedNetworkObject.ActionType.Spawn);
  150.  
  151. /* See if nested, and if so check if root is already spawned.
  152. * If parent is not spawned then find it and process the parent first. */
  153. if (spawn)
  154. {
  155. /* When an object is nested or has a parent it is
  156. * dependent upon either the root of nested, or the parent,
  157. * being spawned to setup properly.
  158. *
  159. * When either of these are true check spawned objects first
  160. * to see if the objects exist. If not check if they are appearing
  161. * later in the cache. Root or parent objects can appear later
  162. * in the cache depending on the order of which observers are rebuilt.
  163. * While it is possible to have the server ensure spawns always send
  164. * root/parents first, that's a giant can of worms that's not worth getting into.
  165. * Not only are there many scenarios to cover, but it also puts more work
  166. * on the server. It's more effective to have the client handle the sorting. */
  167.  
  168. //Nested.
  169. if (cnob.IsNested || cnob.HasParent)
  170. {
  171. bool nested = cnob.IsNested;
  172. //It's not possible to be nested and have a parent. Set the Id to look for based on if nested or parented.
  173. int targetObjectId = (nested) ? cnob.RootObjectId : cnob.ParentObjectId.Value;
  174. NetworkObject nob = GetSpawnedObject(targetObjectId);
  175. //If not spawned yet.
  176. if (nob == null)
  177. {
  178. bool found = false;
  179. string errMsg;
  180. for (int z = (i + 1); z < written; z++)
  181. {
  182. CachedNetworkObject zCnob = collection[z];
  183. if (zCnob.ObjectId == targetObjectId)
  184. {
  185. found = true;
  186. if (cnob.Action != CachedNetworkObject.ActionType.Spawn)
  187. {
  188. errMsg = (nested)
  189. ? $"ObjectId {targetObjectId} was found for a nested spawn, but ActionType is not spawn. ComponentIndex {cnob.ComponentIndex} will not be spawned."
  190. : $"ObjectId {targetObjectId} was found for a parented spawn, but ActionType is not spawn. ObjectId {cnob.ObjectId} will not be spawned.";
  191. _networkManager.LogError(errMsg);
  192. break;
  193. }
  194. else
  195. {
  196. ProcessObject(zCnob, true, z);
  197. break;
  198. }
  199. }
  200. }
  201.  
  202. //Root nob could not be found.
  203. if (!found)
  204. {
  205. errMsg = (nested)
  206. ? $"ObjectId {targetObjectId} could not be found for a nested spawn. ComponentIndex {cnob.ComponentIndex} will not be spawned."
  207. : $"ObjectId {targetObjectId} was found for a parented spawn. ObjectId {cnob.ObjectId} will not be spawned.";
  208. _networkManager.LogError(errMsg);
  209. }
  210. }
  211. }
  212. }
  213.  
  214. ProcessObject(cnob, spawn, i);
  215. }
  216.  
  217. void ProcessObject(CachedNetworkObject cnob, bool spawn, int index)
  218. {
  219. processedIndexes.Add(index);
  220.  
  221. if (spawn)
  222. {
  223. if (cnob.IsSceneObject)
  224. cnob.NetworkObject = _clientObjects.GetSceneNetworkObject(cnob);
  225. else if (cnob.IsNested)
  226. cnob.NetworkObject = _clientObjects.GetNestedNetworkObject(cnob);
  227. else
  228. cnob.NetworkObject = _clientObjects.GetInstantiatedNetworkObject(cnob);
  229. }
  230. else
  231. {
  232. cnob.NetworkObject = _clientObjects.GetSpawnedNetworkObject(cnob);
  233. /* Do not log unless not nested. Nested nobs sometimes
  234. * could be destroyed if parent was first. */
  235. if (!_networkManager.IsHost && cnob.NetworkObject == null && !cnob.IsNested)
  236. _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.");
  237. }
  238. NetworkObject nob = cnob.NetworkObject;
  239. //No need to error here, the other Gets above would have.
  240. if (nob == null)
  241. return;
  242.  
  243. if (spawn)
  244. {
  245. //If not also server then object also has to be preinitialized.
  246. if (!_networkManager.IsServer)
  247. {
  248. int ownerId = cnob.OwnerId;
  249. //If local client is owner then use localconnection reference.
  250. NetworkConnection localConnection = _networkManager.ClientManager.Connection;
  251. NetworkConnection owner;
  252. //If owner is self.
  253. if (ownerId == localConnection.ClientId)
  254. {
  255. owner = localConnection;
  256. }
  257. else
  258. {
  259. /* If owner cannot be found then share owners
  260. * is disabled */
  261. if (!_networkManager.ClientManager.Clients.TryGetValueIL2CPP(ownerId, out owner))
  262. owner = NetworkManager.EmptyConnection;
  263. }
  264. nob.PreinitializeInternal(_networkManager, cnob.ObjectId, owner, false);
  265. }
  266.  
  267. _clientObjects.AddToSpawned(cnob.NetworkObject, false);
  268. SpawningObjects.Add(cnob.ObjectId, cnob.NetworkObject);
  269.  
  270. IterateSpawn(cnob);
  271. _iteratedSpawns.Add(cnob.NetworkObject);
  272. }
  273. else
  274. {
  275. /* If spawned already this iteration then the nob
  276. * must be initialized so that the start/stop cycles
  277. * complete normally. Otherwise, the despawn callbacks will
  278. * fire immediately while the start callbacks will run after all
  279. * spawns have been iterated.
  280. * The downside to this is that synctypes
  281. * for spawns later in this iteration will not be initialized
  282. * yet, and if the nob being spawned/despawned references
  283. * those synctypes the values will be default.
  284. *
  285. * The alternative is to delay the despawning until after
  286. * all spawns are iterated, but that will break the order
  287. * reliability. This is unfortunately a lose/lose situation so
  288. * the best we can do is let the user know the risk. */
  289. if (_iteratedSpawns.Contains(cnob.NetworkObject))
  290. {
  291. if (!_loggedSameTickWarning)
  292. {
  293. _loggedSameTickWarning = true;
  294. _networkManager.LogWarning($"NetworkObject {cnob.NetworkObject.name} is being despawned on the same tick it's spawned." +
  295. $" When this occurs SyncTypes will not be set on other objects during the time of this despawn." +
  296. $" In result, if NetworkObject {cnob.NetworkObject.name} is referencing a SyncType of another object being spawned this tick, the returned values will be default.");
  297. }
  298.  
  299. _conflictingDespawns.Add(cnob.ObjectId);
  300. cnob.NetworkObject.gameObject.SetActive(true);
  301. cnob.NetworkObject.Initialize(false);
  302. }
  303. //Now being initialized, despawn the object.
  304. IterateDespawn(cnob);
  305. }
  306. }
  307.  
  308. /* Lastly activate the objects after all data
  309. * has been synchronized. This will execute callbacks,
  310. * and any synctype hooks after the callbacks. */
  311. for (int i = 0; i < written; i++)
  312. {
  313. CachedNetworkObject cnob = collection[i];
  314. if (cnob.Action == CachedNetworkObject.ActionType.Spawn)
  315. {
  316. /* Apply syncTypes. It's very important to do this after all
  317. * spawns have been processed and added to the manager.Objects collection.
  318. * Otherwise, the synctype may reference an object spawning the same tick
  319. * and the result would be null due to said object not being in spawned. */
  320. if (cnob.NetworkObject = collection[i]) {
  321. foreach (NetworkBehaviour nb in cnob.NetworkObject.NetworkBehaviours) {
  322. {
  323. PooledReader reader = cnob.SyncValuesReader;
  324. //SyncVars.
  325. int length = reader.ReadInt32();
  326. nb.OnSyncType(reader, length, false);
  327. //SyncObjects
  328. length = reader.ReadInt32();
  329. nb.OnSyncType(reader, length, true);
  330.  
  331. }
  332. }
  333. } else {
  334. Debug.LogError("NetworkObject is null for CachedNetworkObject " + cnob.ObjectId);
  335. }
  336.  
  337. /* Only continue with the initialization if it wasn't initialized
  338. * early to prevent a despawn conflict. */
  339. bool canInitialize = (!_conflictingDespawns.Contains(cnob.ObjectId) || !_iteratedSpawns.Contains(cnob.NetworkObject));
  340. if (canInitialize)
  341. {
  342. cnob.NetworkObject.gameObject.SetActive(true);
  343. cnob.NetworkObject.Initialize(false);
  344. }
  345. }
  346. }
  347. }
  348. finally
  349. {
  350. //Once all have been iterated reset.
  351. Reset();
  352. }
  353. }
  354.  
  355. /// <summary>
  356. /// Initializes an object on clients and spawns the NetworkObject.
  357. /// </summary>
  358. /// <param name="cnob"></param>
  359. private void IterateSpawn(CachedNetworkObject cnob)
  360. {
  361. /* All nob spawns have been added to spawned before
  362. * they are processed. This ensures they will be found if
  363. * anything is referencing them before/after initialization. */
  364. /* However, they have to be added again here should an ItereteDespawn
  365. * had removed them. This can occur if an object is set to be spawned,
  366. * thus added to spawned before iterations, then a despawn runs which
  367. * removes it from spawn. */
  368. _clientObjects.AddToSpawned(cnob.NetworkObject, false);
  369.  
  370. List<ushort> rpcLinkIndexes = new List<ushort>();
  371. //Apply rpcLinks.
  372. foreach (NetworkBehaviour nb in cnob.NetworkObject.NetworkBehaviours)
  373. {
  374. PooledReader reader = cnob.RpcLinkReader;
  375. int length = reader.ReadInt32();
  376.  
  377. int readerStart = reader.Position;
  378. while (reader.Position - readerStart < length)
  379. {
  380. //Index of RpcLink.
  381. ushort linkIndex = reader.ReadUInt16();
  382. RpcLink link = new RpcLink(
  383. cnob.NetworkObject.ObjectId, nb.ComponentIndex,
  384. //RpcHash.
  385. reader.ReadUInt16(),
  386. //ObserverRpc.
  387. (RpcType)reader.ReadByte());
  388. //Add to links.
  389. _clientObjects.SetRpcLink(linkIndex, link);
  390.  
  391. rpcLinkIndexes.Add(linkIndex);
  392. }
  393. }
  394. cnob.NetworkObject.SetRpcLinkIndexes(rpcLinkIndexes);
  395. }
  396.  
  397. /// <summary>
  398. /// Deinitializes an object on clients and despawns the NetworkObject.
  399. /// </summary>
  400. /// <param name="cnob"></param>
  401. private void IterateDespawn(CachedNetworkObject cnob)
  402. {
  403. _clientObjects.Despawn(cnob.NetworkObject, cnob.DespawnType, false);
  404. }
  405.  
  406. /// <summary>
  407. /// Returns a NetworkObject found in spawn cache, or Spawned.
  408. /// </summary>
  409. /// <param name="objectId"></param>
  410. internal NetworkObject GetSpawnedObject(int objectId)
  411. {
  412. NetworkObject result;
  413. //If not found in Spawning then check Spawned.
  414. if (!SpawningObjects.TryGetValue(objectId, out result))
  415. {
  416. Dictionary<int, NetworkObject> spawned = (_networkManager.IsHost) ?
  417. _networkManager.ServerManager.Objects.Spawned
  418. : _networkManager.ClientManager.Objects.Spawned;
  419. spawned.TryGetValue(objectId, out result);
  420. }
  421.  
  422. return result;
  423. }
  424.  
  425.  
  426. /// <summary>
  427. /// Resets cache.
  428. /// </summary>
  429. public void Reset()
  430. {
  431. _cachedObjects.Reset();
  432. _iteratedSpawns.Clear();
  433. SpawningObjects.Clear();
  434. }
  435. }
  436.  
  437. /// <summary>
  438. /// A cached network object which exist in world but has not been Initialized yet.
  439. /// </summary>
  440. [Preserve]
  441. internal class CachedNetworkObject
  442. {
  443. #region Types.
  444. public enum ActionType
  445. {
  446. Unset = 0,
  447. Spawn = 1,
  448. Despawn = 2,
  449. }
  450. #endregion
  451.  
  452. /// <summary>
  453. /// True if cached object is nested.
  454. /// </summary>
  455. public bool IsNested => (ComponentIndex > 0);
  456. /// <summary>
  457. /// True if a scene object.
  458. /// </summary>
  459. public bool IsSceneObject => (SceneId > 0);
  460. /// <summary>
  461. /// True if this object has a parent.
  462. /// </summary>
  463. public bool HasParent => (ParentObjectId != null);
  464. /// <summary>
  465. /// True if the parent object is a NetworkBehaviour.
  466. /// </summary>
  467. public bool ParentIsNetworkBehaviour => (HasParent && (ParentComponentIndex != null));
  468.  
  469. public int ObjectId;
  470. public int OwnerId;
  471. public SpawnType SpawnType;
  472. public DespawnType DespawnType;
  473. public byte ComponentIndex;
  474. public int RootObjectId;
  475. public int? ParentObjectId;
  476. public byte? ParentComponentIndex;
  477. public short? PrefabId;
  478. public Vector3? LocalPosition;
  479. public Quaternion? LocalRotation;
  480. public Vector3? LocalScale;
  481. public ulong SceneId;
  482. public ArraySegment<byte> RpcLinks;
  483. public ArraySegment<byte> SyncValues;
  484.  
  485.  
  486.  
  487. /// <summary>
  488. /// True if spawning.
  489. /// </summary>
  490. public ActionType Action { get; private set; }
  491. /// <summary>
  492. /// Cached NetworkObject.
  493. /// </summary>
  494. #pragma warning disable 0649
  495. public NetworkObject NetworkObject;
  496. /// <summary>
  497. /// Reader containing rpc links for the network object.
  498. /// </summary>
  499. public PooledReader RpcLinkReader { get; private set; }
  500. /// <summary>
  501. /// Reader containing sync values for the network object.
  502. /// </summary>
  503. public PooledReader SyncValuesReader { get; private set; }
  504. #pragma warning restore 0649
  505.  
  506. public void InitializeSpawn(NetworkManager manager, int objectId, int ownerId, SpawnType objectSpawnType, byte componentIndex, int rootObjectId, int? parentObjectId, byte? parentComponentIndex
  507. , short? prefabId, Vector3? localPosition, Quaternion? localRotation, Vector3? localScale, ulong sceneId, ArraySegment<byte> rpcLinks, ArraySegment<byte> syncValues)
  508. {
  509. ResetValues();
  510. Action = ActionType.Spawn;
  511. ObjectId = objectId;
  512. OwnerId = ownerId;
  513. SpawnType = objectSpawnType;
  514. ComponentIndex = componentIndex;
  515. RootObjectId = rootObjectId;
  516. ParentObjectId = parentObjectId;
  517. ParentComponentIndex = parentComponentIndex;
  518. PrefabId = prefabId;
  519. LocalPosition = localPosition;
  520. LocalRotation = localRotation;
  521. LocalScale = localScale;
  522. SceneId = sceneId;
  523. RpcLinks = rpcLinks;
  524. SyncValues = syncValues;
  525.  
  526. RpcLinkReader = ReaderPool.GetReader(rpcLinks, manager);
  527. SyncValuesReader = ReaderPool.GetReader(syncValues, manager);
  528. }
  529.  
  530. /// <summary>
  531. /// Initializes for a despawned NetworkObject.
  532. /// </summary>
  533. /// <param name="nob"></param>
  534. public void InitializeDespawn(int objectId, DespawnType despawnType)
  535. {
  536. ResetValues();
  537. Action = ActionType.Despawn;
  538. DespawnType = despawnType;
  539. ObjectId = objectId;
  540. }
  541.  
  542. /// <summary>
  543. /// Resets values which could malform identify the cached object.
  544. /// </summary>
  545. private void ResetValues()
  546. {
  547. NetworkObject = null;
  548. }
  549.  
  550. ~CachedNetworkObject()
  551. {
  552. if (RpcLinkReader != null)
  553. RpcLinkReader.Dispose();
  554. if (SyncValuesReader != null)
  555. SyncValuesReader.Dispose();
  556. }
  557. }
  558.  
  559. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement