SceneInterestManagement.cs 4.2 KB

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