Portal.cs 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. using System.Collections;
  2. using System.IO;
  3. using System.Text.RegularExpressions;
  4. using UnityEngine;
  5. using UnityEngine.SceneManagement;
  6. namespace Mirror.Examples.AdditiveLevels
  7. {
  8. public class Portal : NetworkBehaviour
  9. {
  10. [Scene, Tooltip("Which scene to send player from here")]
  11. public string destinationScene;
  12. [Tooltip("Where to spawn player in Destination Scene")]
  13. public Vector3 startPosition;
  14. [Tooltip("Reference to child TMP label")]
  15. public TextMesh label; // don't depend on TMPro. 2019 errors.
  16. [SyncVar(hook = nameof(OnLabelTextChanged))]
  17. public string labelText;
  18. public void OnLabelTextChanged(string _, string newValue)
  19. {
  20. label.text = labelText;
  21. }
  22. // This is approximately the fade time
  23. WaitForSeconds waitForFade = new WaitForSeconds(2f);
  24. public override void OnStartServer()
  25. {
  26. labelText = Path.GetFileNameWithoutExtension(destinationScene);
  27. // Simple Regex to insert spaces before capitals, numbers
  28. labelText = Regex.Replace(labelText, @"\B[A-Z0-9]+", " $0");
  29. }
  30. // Note that I have created layers called Player(8) and Portal(9) and set them
  31. // up in the Physics collision matrix so only Player collides with Portal.
  32. void OnTriggerEnter(Collider other)
  33. {
  34. // tag check in case you didn't set up the layers and matrix as noted above
  35. if (!other.CompareTag("Player")) return;
  36. //Debug.Log($"{System.DateTime.Now:HH:mm:ss:fff} Portal::OnTriggerEnter {gameObject.name} in {gameObject.scene.name}");
  37. // applies to host client on server and remote clients
  38. if (other.TryGetComponent<PlayerController>(out PlayerController playerController))
  39. playerController.enabled = false;
  40. if (isServer)
  41. StartCoroutine(SendPlayerToNewScene(other.gameObject));
  42. }
  43. [ServerCallback]
  44. IEnumerator SendPlayerToNewScene(GameObject player)
  45. {
  46. if (player.TryGetComponent<NetworkIdentity>(out NetworkIdentity identity))
  47. {
  48. NetworkConnectionToClient conn = identity.connectionToClient;
  49. if (conn == null) yield break;
  50. // Tell client to unload previous subscene. No custom handling for this.
  51. conn.Send(new SceneMessage { sceneName = gameObject.scene.path, sceneOperation = SceneOperation.UnloadAdditive, customHandling = true });
  52. yield return waitForFade;
  53. //Debug.Log($"SendPlayerToNewScene RemovePlayerForConnection {conn} netId:{conn.identity.netId}");
  54. NetworkServer.RemovePlayerForConnection(conn, false);
  55. // reposition player on server and client
  56. player.transform.position = startPosition;
  57. player.transform.LookAt(Vector3.up);
  58. // Move player to new subscene.
  59. SceneManager.MoveGameObjectToScene(player, SceneManager.GetSceneByPath(destinationScene));
  60. // Tell client to load the new subscene with custom handling (see NetworkManager::OnClientChangeScene).
  61. conn.Send(new SceneMessage { sceneName = destinationScene, sceneOperation = SceneOperation.LoadAdditive, customHandling = true });
  62. //Debug.Log($"SendPlayerToNewScene AddPlayerForConnection {conn} netId:{conn.identity.netId}");
  63. NetworkServer.AddPlayerForConnection(conn, player);
  64. // host client would have been disabled by OnTriggerEnter above
  65. if (NetworkClient.localPlayer != null && NetworkClient.localPlayer.TryGetComponent<PlayerController>(out PlayerController playerController))
  66. playerController.enabled = true;
  67. }
  68. }
  69. }
  70. }