2024-10-17 17:23:05 +03:00

99 lines
4.1 KiB
C#

using System.Collections;
using System.IO;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Mirror.Examples.AdditiveLevels
{
public class Portal : NetworkBehaviour
{
[Scene, Tooltip("Which scene to send player from here")]
public string destinationScene;
[Tooltip("Where to spawn player in Destination Scene")]
public Vector3 startPosition;
[Tooltip("Reference to child TextMesh label")]
public TextMesh label; // don't depend on TMPro. 2019 errors.
[SyncVar(hook = nameof(OnLabelTextChanged))]
public string labelText;
public void OnLabelTextChanged(string _, string newValue)
{
label.text = labelText;
}
public override void OnStartServer()
{
labelText = Path.GetFileNameWithoutExtension(destinationScene).Replace("MirrorAdditiveLevels","");
// Simple Regex to insert spaces before capitals, numbers
labelText = Regex.Replace(labelText, @"\B[A-Z0-9]+", " $0");
}
public override void OnStartClient()
{
if (label.TryGetComponent(out LookAtMainCamera lookAtMainCamera))
lookAtMainCamera.enabled = true;
}
// Note that I have created layers called Player(6) and Portal(7) and set them
// up in the Physics collision matrix so only Player collides with Portal.
void OnTriggerEnter(Collider other)
{
// tag check in case you didn't set up the layers and matrix as noted above
if (!other.CompareTag("Player")) return;
// applies to host client on server and remote clients
if (other.TryGetComponent(out PlayerController playerController))
playerController.enabled = false;
if (isServer)
StartCoroutine(SendPlayerToNewScene(other.gameObject));
}
[ServerCallback]
IEnumerator SendPlayerToNewScene(GameObject player)
{
if (player.TryGetComponent(out NetworkIdentity identity))
{
NetworkConnectionToClient conn = identity.connectionToClient;
if (conn == null) yield break;
// Tell client to unload previous subscene with custom handling (see NetworkManager::OnClientChangeScene).
conn.Send(new SceneMessage { sceneName = gameObject.scene.path, sceneOperation = SceneOperation.UnloadAdditive, customHandling = true });
// wait for fader to complete
yield return new WaitForSeconds(AdditiveLevelsNetworkManager.singleton.fadeInOut.GetDuration());
// Remove player after fader has completed
NetworkServer.RemovePlayerForConnection(conn, false);
// reposition player on server and client
player.transform.position = startPosition;
// Rotate player to face center of scene
// Player is 2m tall with pivot at 0,1,0 so we need to look at
// 1m height to not tilt the player down to look at origin
player.transform.LookAt(Vector3.up);
// Move player to new subscene.
SceneManager.MoveGameObjectToScene(player, SceneManager.GetSceneByPath(destinationScene));
// Tell client to load the new subscene with custom handling (see NetworkManager::OnClientChangeScene).
conn.Send(new SceneMessage { sceneName = destinationScene, sceneOperation = SceneOperation.LoadAdditive, customHandling = true });
// Player will be spawned after destination scene is loaded
NetworkServer.AddPlayerForConnection(conn, player);
// host client playerController would have been disabled by OnTriggerEnter above
// Remote client players are respawned with playerController already enabled
if (NetworkClient.localPlayer != null && NetworkClient.localPlayer.TryGetComponent(out PlayerController playerController))
playerController.enabled = true;
}
}
}
}