159 lines
5.0 KiB
C#
159 lines
5.0 KiB
C#
using FishNet.Connection;
|
|
using FishNet.Managing;
|
|
using FishNet.Object;
|
|
using System;
|
|
using UnityEngine;
|
|
using UnityEngine.Serialization;
|
|
|
|
namespace FishNet.Component.Spawning
|
|
{
|
|
|
|
/// <summary>
|
|
/// Spawns a player object for clients when they connect.
|
|
/// Must be placed on or beneath the NetworkManager object.
|
|
/// </summary>
|
|
[AddComponentMenu("FishNet/Component/PlayerSpawner")]
|
|
public class PlayerSpawner : MonoBehaviour
|
|
{
|
|
#region Public.
|
|
/// <summary>
|
|
/// Called on the server when a player is spawned.
|
|
/// </summary>
|
|
public event Action<NetworkObject> OnSpawned;
|
|
#endregion
|
|
|
|
#region Serialized.
|
|
/// <summary>
|
|
/// Prefab to spawn for the player.
|
|
/// </summary>
|
|
[Tooltip("Prefab to spawn for the player.")]
|
|
[SerializeField]
|
|
private NetworkObject _playerPrefab;
|
|
/// <summary>
|
|
/// True to add player to the active scene when no global scenes are specified through the SceneManager.
|
|
/// </summary>
|
|
[Tooltip("True to add player to the active scene when no global scenes are specified through the SceneManager.")]
|
|
[SerializeField]
|
|
private bool _addToDefaultScene = true;
|
|
/// <summary>
|
|
/// Areas in which players may spawn.
|
|
/// </summary>
|
|
[Tooltip("Areas in which players may spawn.")]
|
|
[FormerlySerializedAs("_spawns")]
|
|
public Transform[] Spawns = new Transform[0];
|
|
#endregion
|
|
|
|
#region Private.
|
|
/// <summary>
|
|
/// NetworkManager on this object or within this objects parents.
|
|
/// </summary>
|
|
private NetworkManager _networkManager;
|
|
/// <summary>
|
|
/// Next spawns to use.
|
|
/// </summary>
|
|
private int _nextSpawn;
|
|
#endregion
|
|
|
|
private void Start()
|
|
{
|
|
InitializeOnce();
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (_networkManager != null)
|
|
_networkManager.SceneManager.OnClientLoadedStartScenes -= SceneManager_OnClientLoadedStartScenes;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Initializes this script for use.
|
|
/// </summary>
|
|
private void InitializeOnce()
|
|
{
|
|
_networkManager = InstanceFinder.NetworkManager;
|
|
if (_networkManager == null)
|
|
{
|
|
Debug.LogWarning($"PlayerSpawner on {gameObject.name} cannot work as NetworkManager wasn't found on this object or within parent objects.");
|
|
return;
|
|
}
|
|
|
|
_networkManager.SceneManager.OnClientLoadedStartScenes += SceneManager_OnClientLoadedStartScenes;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when a client loads initial scenes after connecting.
|
|
/// </summary>
|
|
private void SceneManager_OnClientLoadedStartScenes(NetworkConnection conn, bool asServer)
|
|
{
|
|
if (!asServer)
|
|
return;
|
|
if (_playerPrefab == null)
|
|
{
|
|
Debug.LogWarning($"Player prefab is empty and cannot be spawned for connection {conn.ClientId}.");
|
|
return;
|
|
}
|
|
|
|
Vector3 position;
|
|
Quaternion rotation;
|
|
SetSpawn(_playerPrefab.transform, out position, out rotation);
|
|
|
|
NetworkObject nob = _networkManager.GetPooledInstantiated(_playerPrefab, true);
|
|
nob.transform.SetPositionAndRotation(position, rotation);
|
|
_networkManager.ServerManager.Spawn(nob, conn);
|
|
|
|
//If there are no global scenes
|
|
if (_addToDefaultScene)
|
|
_networkManager.SceneManager.AddOwnerToDefaultScene(nob);
|
|
|
|
OnSpawned?.Invoke(nob);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Sets a spawn position and rotation.
|
|
/// </summary>
|
|
/// <param name="pos"></param>
|
|
/// <param name="rot"></param>
|
|
private void SetSpawn(Transform prefab, out Vector3 pos, out Quaternion rot)
|
|
{
|
|
//No spawns specified.
|
|
if (Spawns.Length == 0)
|
|
{
|
|
SetSpawnUsingPrefab(prefab, out pos, out rot);
|
|
return;
|
|
}
|
|
|
|
Transform result = Spawns[_nextSpawn];
|
|
if (result == null)
|
|
{
|
|
SetSpawnUsingPrefab(prefab, out pos, out rot);
|
|
}
|
|
else
|
|
{
|
|
pos = result.position;
|
|
rot = result.rotation;
|
|
}
|
|
|
|
//Increase next spawn and reset if needed.
|
|
_nextSpawn++;
|
|
if (_nextSpawn >= Spawns.Length)
|
|
_nextSpawn = 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets spawn using values from prefab.
|
|
/// </summary>
|
|
/// <param name="prefab"></param>
|
|
/// <param name="pos"></param>
|
|
/// <param name="rot"></param>
|
|
private void SetSpawnUsingPrefab(Transform prefab, out Vector3 pos, out Quaternion rot)
|
|
{
|
|
pos = prefab.position;
|
|
rot = prefab.rotation;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
} |