1
0

NetworkScenePostProcess.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using UnityEditor;
  4. using UnityEditor.Callbacks;
  5. using UnityEngine;
  6. namespace Mirror
  7. {
  8. public class NetworkScenePostProcess : MonoBehaviour
  9. {
  10. [PostProcessScene]
  11. public static void OnPostProcessScene()
  12. {
  13. // find all NetworkIdentities in all scenes
  14. // => can't limit it to GetActiveScene() because that wouldn't work
  15. // for additive scene loads (the additively loaded scene is never
  16. // the active scene)
  17. // => ignore DontDestroyOnLoad scene! this avoids weird situations
  18. // like in NetworkZones when we destroy the local player and
  19. // load another scene afterwards, yet the local player is still
  20. // in the FindObjectsOfType result with scene=DontDestroyOnLoad
  21. // for some reason
  22. // => OfTypeAll so disabled objects are included too
  23. // => Unity 2019 returns prefabs here too, so filter them out.
  24. IEnumerable<NetworkIdentity> identities = Resources.FindObjectsOfTypeAll<NetworkIdentity>()
  25. .Where(identity => identity.gameObject.hideFlags != HideFlags.NotEditable &&
  26. identity.gameObject.hideFlags != HideFlags.HideAndDontSave &&
  27. identity.gameObject.scene.name != "DontDestroyOnLoad" &&
  28. !Utils.IsPrefab(identity.gameObject));
  29. foreach (NetworkIdentity identity in identities)
  30. {
  31. // if we had a [ConflictComponent] attribute that would be better than this check.
  32. // also there is no context about which scene this is in.
  33. if (identity.GetComponent<NetworkManager>() != null)
  34. {
  35. Debug.LogError("NetworkManager has a NetworkIdentity component. This will cause the NetworkManager object to be disabled, so it is not recommended.");
  36. }
  37. // not spawned before?
  38. // OnPostProcessScene is called after additive scene loads too,
  39. // and we don't want to set main scene's objects inactive again
  40. if (!identity.isClient && !identity.isServer)
  41. {
  42. // valid scene object?
  43. // otherwise it might be an unopened scene that still has null
  44. // sceneIds. builds are interrupted if they contain 0 sceneIds,
  45. // but it's still possible that we call LoadScene in Editor
  46. // for a previously unopened scene.
  47. // (and only do SetActive if this was actually a scene object)
  48. if (identity.sceneId != 0)
  49. {
  50. PrepareSceneObject(identity);
  51. }
  52. // throwing an exception would only show it for one object
  53. // because this function would return afterwards.
  54. else
  55. {
  56. // there are two cases where sceneId == 0:
  57. // * if we have a prefab open in the prefab scene
  58. // * if an unopened scene needs resaving
  59. // show a proper error message in both cases so the user
  60. // knows what to do.
  61. string path = identity.gameObject.scene.path;
  62. if (string.IsNullOrWhiteSpace(path))
  63. Debug.LogError($"{identity.name} is currently open in Prefab Edit Mode. Please open the actual scene before launching Mirror.");
  64. else
  65. Debug.LogError($"Scene {path} needs to be opened and resaved, because the scene object {identity.name} has no valid sceneId yet.");
  66. // either way we shouldn't continue. nothing good will
  67. // happen when trying to launch with invalid sceneIds.
  68. EditorApplication.isPlaying = false;
  69. }
  70. }
  71. }
  72. }
  73. static void PrepareSceneObject(NetworkIdentity identity)
  74. {
  75. // set scene hash
  76. identity.SetSceneIdSceneHashPartInternal();
  77. // disable it
  78. // note: NetworkIdentity.OnDisable adds itself to the
  79. // spawnableObjects dictionary (only if sceneId != 0)
  80. identity.gameObject.SetActive(false);
  81. // safety check for prefabs with more than one NetworkIdentity
  82. #if UNITY_2018_2_OR_NEWER
  83. GameObject prefabGO = PrefabUtility.GetCorrespondingObjectFromSource(identity.gameObject);
  84. #else
  85. GameObject prefabGO = PrefabUtility.GetPrefabParent(identity.gameObject);
  86. #endif
  87. if (prefabGO)
  88. {
  89. #if UNITY_2018_3_OR_NEWER
  90. GameObject prefabRootGO = prefabGO.transform.root.gameObject;
  91. #else
  92. GameObject prefabRootGO = PrefabUtility.FindPrefabRoot(prefabGO);
  93. #endif
  94. if (prefabRootGO != null && prefabRootGO.GetComponentsInChildren<NetworkIdentity>().Length > 1)
  95. {
  96. Debug.LogWarning($"Prefab {prefabRootGO.name} has several NetworkIdentity components attached to itself or its children, this is not supported.");
  97. }
  98. }
  99. }
  100. }
  101. }