SceneInterestManagement.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using UnityEngine.SceneManagement;
  4. namespace Mirror
  5. {
  6. [AddComponentMenu("Network/ Interest Management/ Scene/Scene Interest Management")]
  7. public class SceneInterestManagement : InterestManagement
  8. {
  9. // Use Scene instead of string scene.name because when additively
  10. // loading multiples of a subscene the name won't be unique
  11. readonly Dictionary<Scene, HashSet<NetworkIdentity>> sceneObjects =
  12. new Dictionary<Scene, HashSet<NetworkIdentity>>();
  13. readonly Dictionary<NetworkIdentity, Scene> lastObjectScene =
  14. new Dictionary<NetworkIdentity, Scene>();
  15. HashSet<Scene> dirtyScenes = new HashSet<Scene>();
  16. [ServerCallback]
  17. public override void OnSpawned(NetworkIdentity identity)
  18. {
  19. Scene currentScene = identity.gameObject.scene;
  20. lastObjectScene[identity] = currentScene;
  21. // Debug.Log($"SceneInterestManagement.OnSpawned({identity.name}) currentScene: {currentScene}");
  22. if (!sceneObjects.TryGetValue(currentScene, out HashSet<NetworkIdentity> objects))
  23. {
  24. objects = new HashSet<NetworkIdentity>();
  25. sceneObjects.Add(currentScene, objects);
  26. }
  27. objects.Add(identity);
  28. }
  29. [ServerCallback]
  30. public override void OnDestroyed(NetworkIdentity identity)
  31. {
  32. // Don't RebuildSceneObservers here - that will happen in Update.
  33. // Multiple objects could be destroyed in same frame and we don't
  34. // want to rebuild for each one...let Update do it once.
  35. // We must add the current scene to dirtyScenes for Update to rebuild it.
  36. if (lastObjectScene.TryGetValue(identity, out Scene currentScene))
  37. {
  38. lastObjectScene.Remove(identity);
  39. if (sceneObjects.TryGetValue(currentScene, out HashSet<NetworkIdentity> objects) && objects.Remove(identity))
  40. dirtyScenes.Add(currentScene);
  41. }
  42. }
  43. // internal so we can update from tests
  44. [ServerCallback]
  45. internal void Update()
  46. {
  47. // for each spawned:
  48. // if scene changed:
  49. // add previous to dirty
  50. // add new to dirty
  51. foreach (NetworkIdentity identity in NetworkServer.spawned.Values)
  52. {
  53. if (!lastObjectScene.TryGetValue(identity, out Scene currentScene))
  54. continue;
  55. Scene newScene = identity.gameObject.scene;
  56. if (newScene == currentScene)
  57. continue;
  58. // Mark new/old scenes as dirty so they get rebuilt
  59. dirtyScenes.Add(currentScene);
  60. dirtyScenes.Add(newScene);
  61. // This object is in a new scene so observers in the prior scene
  62. // and the new scene need to rebuild their respective observers lists.
  63. // Remove this object from the hashset of the scene it just left
  64. sceneObjects[currentScene].Remove(identity);
  65. // Set this to the new scene this object just entered
  66. lastObjectScene[identity] = newScene;
  67. // Make sure this new scene is in the dictionary
  68. if (!sceneObjects.ContainsKey(newScene))
  69. sceneObjects.Add(newScene, new HashSet<NetworkIdentity>());
  70. // Add this object to the hashset of the new scene
  71. sceneObjects[newScene].Add(identity);
  72. }
  73. // rebuild all dirty scenes
  74. foreach (Scene dirtyScene in dirtyScenes)
  75. RebuildSceneObservers(dirtyScene);
  76. dirtyScenes.Clear();
  77. }
  78. void RebuildSceneObservers(Scene scene)
  79. {
  80. foreach (NetworkIdentity netIdentity in sceneObjects[scene])
  81. if (netIdentity != null)
  82. NetworkServer.RebuildObservers(netIdentity, false);
  83. }
  84. public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver)
  85. {
  86. return identity.gameObject.scene == newObserver.identity.gameObject.scene;
  87. }
  88. public override void OnRebuildObservers(NetworkIdentity identity, HashSet<NetworkConnectionToClient> newObservers)
  89. {
  90. if (!sceneObjects.TryGetValue(identity.gameObject.scene, out HashSet<NetworkIdentity> objects))
  91. return;
  92. // Add everything in the hashset for this object's current scene
  93. foreach (NetworkIdentity networkIdentity in objects)
  94. if (networkIdentity != null && networkIdentity.connectionToClient != null)
  95. newObservers.Add(networkIdentity.connectionToClient);
  96. }
  97. }
  98. }