using System.Collections; using System.Collections.Generic; using TMPro; using Unity.Netcode; using UnityEngine; public struct PlayerScore : INetworkSerializable, System.IEquatable { public ulong ClientId; public int Score; public bool Equals(PlayerScore _other) { return ClientId == _other.ClientId && Score == _other.Score; } public void NetworkSerialize(BufferSerializer serializer) where T : IReaderWriter { serializer.SerializeValue(ref ClientId); serializer.SerializeValue(ref Score); } } public class RoundManager : NetworkBehaviour { public static RoundManager Current { get; private set; } [SerializeField] private float roundStartDelay = 3f; [SerializeField] private Transform[] spawnPoints; private NetworkVariable roundDuration = new NetworkVariable(180f); private NetworkVariable roundTimeRemaining = new NetworkVariable(0f); private NetworkVariable currentRound = new NetworkVariable(0); private NetworkVariable isRoundActive = new NetworkVariable(false); private List alivePlayers = new List(); private NetworkList playerScores; private bool isTimerRunning = false; public override void OnNetworkSpawn() { currentRound.OnValueChanged += OnRoundChanged; isRoundActive.OnValueChanged += OnRoundStateChanged; // roundTimeRemaining.OnValueChanged += OnTimerChanged; if (IsServer) { // StartTimerServerRPC(); StartCoroutine(StartRoundWithDelay()); } } private void Update() { if (!IsServer) return; if(!IsRoundActive) return; roundTimeRemaining.Value = Mathf.Max(0f, roundTimeRemaining.Value - Time.deltaTime); if(roundTimeRemaining.Value <= 0f) { StartCoroutine(EndRound(0ul)); } } // public void OnTimerChanged(float _previousValue, float _newValue) void Awake() { Current = this; playerScores = new NetworkList(); roundTimeRemaining.Value = roundDuration.Value; } public void OnPlayerFellIntoPit(ulong _winnerClientId) { if (!IsServer) return; if(!isRoundActive.Value) return; for (int _i = 0; _i < playerScores.Count; _i++) { playerScores[_i] = new PlayerScore { ClientId = _winnerClientId, Score = playerScores[_i].Score + 1 }; break; } StartCoroutine(EndRound(_winnerClientId)); } public void OnPlayerDied(PlayerHealth _playerHealth) { // if (!IsServer) return; // alivePlayers.Remove(_playerHealth); // if (alivePlayers.Count <= 1) // { // StartCoroutine(EndRound()); // } } public void RegisterPlayer(ulong _clientId) { if (!IsServer) return; foreach (var _s in playerScores) if (_s.ClientId == _clientId) return; playerScores.Add(new PlayerScore { ClientId = _clientId, Score = 0 }); } private IEnumerator EndRound(ulong _winnerClientId) { isRoundActive.Value = false; string _winner = _winnerClientId != 0 ? $"Player {_winnerClientId} wins!" : "No winner"; RoundEndedClientRPC(_winner); yield return new WaitForSeconds(roundStartDelay); currentRound.Value++; StartCoroutine(StartRoundWithDelay()); } private void RespawnAllPlayers() { if (!IsServer) return; var _allPlayers = FindObjectsByType(FindObjectsSortMode.None); alivePlayers.Clear(); for (int _q = 0; _q < _allPlayers.Length; _q++) { Vector3 _spawnPosition = spawnPoints[_q % spawnPoints.Length].position; _allPlayers[_q].Respawn(_spawnPosition); alivePlayers.Add(_allPlayers[_q]); } } private IEnumerator StartRoundWithDelay() { yield return new WaitForSeconds(1f); yield return new WaitUntil(() => FindObjectsByType(FindObjectsSortMode.None).Length >= 2); RespawnAllPlayers(); isRoundActive.Value = true; RoundStartedClientRPC(currentRound.Value); } [ClientRpc] private void RoundStartedClientRPC(int _round) { Debug.Log($"Round {_round} started"); } [ClientRpc] private void RoundEndedClientRPC(string _winnerText) { Debug.Log($"Round ended: {_winnerText}"); } public bool IsRoundActive => isRoundActive.Value; public override void OnNetworkDespawn() { if (IsServer && Current == this) Current = null; currentRound.OnValueChanged -= OnRoundChanged; isRoundActive.OnValueChanged -= OnRoundStateChanged; } private void OnRoundChanged(int _previousValue, int _newValue) { } private void OnRoundStateChanged(bool _previousValue, bool _newValue) { } }