Added UI and more
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
using System.Collections.Generic;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Обычный MonoBehaviour (не сетевой) — вся логика чисто серверная.
|
||||
/// Повесь на тот же объект, что и RoundManager (или на любой объект сцены).
|
||||
/// Хранит архив записей, спавнит клонов на старте раунда и тикает их в FixedUpdate.
|
||||
/// </summary>
|
||||
public class GhostRoundManager : MonoBehaviour
|
||||
{
|
||||
public static GhostRoundManager Current { get; private set; }
|
||||
|
||||
[SerializeField] private GameObject ghostPrefab; // префаб клона (см. чеклист настройки)
|
||||
[SerializeField] private int maxGhostsPerPlayer = 3; // сколько прошлых раундов помним на игрока
|
||||
|
||||
// ClientId -> записи его прошлых раундов
|
||||
private readonly Dictionary<ulong, List<GhostRecording>> archive = new Dictionary<ulong, List<GhostRecording>>();
|
||||
private readonly List<GhostPlayer> activeGhosts = new List<GhostPlayer>();
|
||||
|
||||
private int roundTick;
|
||||
private bool roundRunning;
|
||||
|
||||
private bool IsServer => NetworkManager.Singleton != null && NetworkManager.Singleton.IsServer;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Current = this;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (Current == this) Current = null;
|
||||
}
|
||||
|
||||
/// <summary> Вызывается из RoundManager.StartRoundWithDelay после RespawnAllPlayers. </summary>
|
||||
public void ServerStartRound()
|
||||
{
|
||||
if (!IsServer) return;
|
||||
|
||||
roundTick = 0;
|
||||
activeGhosts.Clear();
|
||||
|
||||
// Спавним клонов из архива
|
||||
foreach (KeyValuePair<ulong, List<GhostRecording>> _kvp in archive)
|
||||
{
|
||||
foreach (GhostRecording _recording in _kvp.Value)
|
||||
{
|
||||
if (_recording.positions.Count == 0) continue;
|
||||
|
||||
GameObject _go = Instantiate(ghostPrefab, _recording.positions[0], _recording.rotations[0]);
|
||||
_go.GetComponent<NetworkObject>().Spawn();
|
||||
|
||||
GhostPlayer _ghost = _go.GetComponent<GhostPlayer>();
|
||||
_ghost.Init(_recording);
|
||||
activeGhosts.Add(_ghost);
|
||||
}
|
||||
}
|
||||
|
||||
// Включаем запись у всех живых игроков
|
||||
foreach (NetworkClient _client in NetworkManager.Singleton.ConnectedClientsList)
|
||||
{
|
||||
_client.PlayerObject?.GetComponent<GhostRecorder>()?.BeginRecording();
|
||||
}
|
||||
|
||||
roundRunning = true;
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (!IsServer || !roundRunning) return;
|
||||
if (RoundManager.Current == null || !RoundManager.Current.IsRoundActive) return;
|
||||
|
||||
foreach (GhostPlayer _ghost in activeGhosts)
|
||||
{
|
||||
if (_ghost != null && _ghost.IsSpawned)
|
||||
_ghost.Step(roundTick);
|
||||
}
|
||||
|
||||
roundTick++;
|
||||
}
|
||||
|
||||
/// <summary> Вызывается из RoundManager.EndRound первой строкой (до WaitForSeconds). </summary>
|
||||
public void ServerEndRound()
|
||||
{
|
||||
if (!IsServer || !roundRunning) return;
|
||||
roundRunning = false;
|
||||
|
||||
// Убираем клонов со сцены
|
||||
foreach (GhostPlayer _ghost in activeGhosts)
|
||||
{
|
||||
if (_ghost != null && _ghost.IsSpawned)
|
||||
_ghost.NetworkObject.Despawn();
|
||||
}
|
||||
activeGhosts.Clear();
|
||||
|
||||
// Останавливаем запись и складываем раунд в архив
|
||||
foreach (NetworkClient _client in NetworkManager.Singleton.ConnectedClientsList)
|
||||
{
|
||||
GhostRecorder _recorder = _client.PlayerObject?.GetComponent<GhostRecorder>();
|
||||
if (_recorder == null || _recorder.Recording == null) continue;
|
||||
|
||||
_recorder.StopRecording();
|
||||
|
||||
if (!archive.TryGetValue(_client.ClientId, out List<GhostRecording> _list))
|
||||
{
|
||||
_list = new List<GhostRecording>();
|
||||
archive[_client.ClientId] = _list;
|
||||
}
|
||||
|
||||
_list.Add(_recorder.Recording);
|
||||
if (_list.Count > maxGhostsPerPlayer) _list.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user