117 lines
3.6 KiB
C#
117 lines
3.6 KiB
C#
using Unity.Netcode;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
public sealed class PlayerSpawnController : NetworkBehaviour, IPlayerSystem
|
|
{
|
|
[Header("Start Room Spawn")]
|
|
[SerializeField, Min(0f)] private float edgePadding = 0.75f;
|
|
[SerializeField, Min(0f)] private float heightAboveFloor = 0.15f;
|
|
|
|
private readonly NetworkVariable<Vector3> assignedSpawnPosition = new(
|
|
Vector3.zero,
|
|
NetworkVariableReadPermission.Everyone,
|
|
NetworkVariableWritePermission.Server);
|
|
|
|
private readonly NetworkVariable<bool> hasAssignedSpawnPosition = new(
|
|
false,
|
|
NetworkVariableReadPermission.Everyone,
|
|
NetworkVariableWritePermission.Server);
|
|
|
|
private int assignedSceneHandle = -1;
|
|
|
|
public void Initialize(PlayerFacade facade) { }
|
|
|
|
public override void OnNetworkSpawn()
|
|
{
|
|
assignedSpawnPosition.OnValueChanged += HandleSpawnPositionChanged;
|
|
hasAssignedSpawnPosition.OnValueChanged += HandleSpawnAssignmentChanged;
|
|
SceneManager.sceneLoaded += HandleSceneLoaded;
|
|
|
|
if (IsServer)
|
|
TryAssignStartRoomPosition(SceneManager.GetActiveScene());
|
|
|
|
if (hasAssignedSpawnPosition.Value)
|
|
ApplySpawnPosition(assignedSpawnPosition.Value);
|
|
}
|
|
|
|
public override void OnNetworkDespawn()
|
|
{
|
|
assignedSpawnPosition.OnValueChanged -= HandleSpawnPositionChanged;
|
|
hasAssignedSpawnPosition.OnValueChanged -= HandleSpawnAssignmentChanged;
|
|
SceneManager.sceneLoaded -= HandleSceneLoaded;
|
|
}
|
|
|
|
private void HandleSceneLoaded(Scene scene, LoadSceneMode _)
|
|
{
|
|
if (IsServer)
|
|
TryAssignStartRoomPosition(scene);
|
|
|
|
if (IsOwner && hasAssignedSpawnPosition.Value)
|
|
ApplySpawnPosition(assignedSpawnPosition.Value);
|
|
}
|
|
|
|
private void TryAssignStartRoomPosition(Scene scene)
|
|
{
|
|
if (!scene.IsValid() || !scene.isLoaded || scene.handle == assignedSceneHandle)
|
|
return;
|
|
|
|
StartRoomZone startRoom = FindStartRoomInScene(scene);
|
|
if (startRoom == null ||
|
|
!startRoom.TryGetRandomSpawnPosition(
|
|
edgePadding,
|
|
heightAboveFloor,
|
|
out Vector3 position))
|
|
{
|
|
return;
|
|
}
|
|
|
|
hasAssignedSpawnPosition.Value = false;
|
|
assignedSpawnPosition.Value = position;
|
|
hasAssignedSpawnPosition.Value = true;
|
|
assignedSceneHandle = scene.handle;
|
|
}
|
|
|
|
private static StartRoomZone FindStartRoomInScene(Scene scene)
|
|
{
|
|
foreach (GameObject rootObject in scene.GetRootGameObjects())
|
|
{
|
|
StartRoomZone startRoom = rootObject.GetComponentInChildren<StartRoomZone>(true);
|
|
if (startRoom != null)
|
|
return startRoom;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private void HandleSpawnPositionChanged(Vector3 _, Vector3 position)
|
|
{
|
|
if (hasAssignedSpawnPosition.Value)
|
|
ApplySpawnPosition(position);
|
|
}
|
|
|
|
private void HandleSpawnAssignmentChanged(bool _, bool isAssigned)
|
|
{
|
|
if (isAssigned)
|
|
ApplySpawnPosition(assignedSpawnPosition.Value);
|
|
}
|
|
|
|
private void ApplySpawnPosition(Vector3 position)
|
|
{
|
|
if (!IsOwner)
|
|
return;
|
|
|
|
CharacterController characterController = GetComponent<CharacterController>();
|
|
bool restoreCharacterController = characterController != null && characterController.enabled;
|
|
|
|
if (restoreCharacterController)
|
|
characterController.enabled = false;
|
|
|
|
transform.position = position;
|
|
Physics.SyncTransforms();
|
|
|
|
if (restoreCharacterController)
|
|
characterController.enabled = true;
|
|
}
|
|
}
|