using System.Collections; using System.Linq; using Unity.BossRoom.Gameplay.GameplayObjects.Character; using Unity.Netcode; using UnityEngine; using DG.Tweening; namespace Unity.Multiplayer.Samples.BossRoom { [RequireComponent(typeof(Collider))] public class Platform : NetworkBehaviour { public NetworkVariable PlatformID = new NetworkVariable(0); public bool IsOccupied { get; private set; } private NetworkVariable occupierId = new NetworkVariable(0, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Server); private Collider platformCollider; private Animator animator; private float occupationTime = 0f; private float penaltyInterval = 3f; // Interval for penalty deduction private Coroutine penaltyCoroutine; [SerializeField] private GameObject barrierObject; private void Awake() { platformCollider = GetComponent(); platformCollider.isTrigger = true; animator = GetComponent(); } private void Start() { if (IsServer) { Invoke(nameof(EnableCollider), 2); // Delay collider enabling for server } } public void AssignID(int id) { if (IsServer) { PlatformID.Value = id; } } private void EnableCollider() { platformCollider.enabled = true; } public void StartRotation() { transform.DOLocalRotate(Vector3.up, 120).SetSpeedBased(true).SetId(PlatformID).SetLoops(-1, LoopType.Incremental); } private void PauseRotation() { DOTween.Pause(PlatformID); } private void ResumeRotation() { DOTween.Play(PlatformID); } public void Pause() { if (IsServer) { animator.speed = 0f; PauseClientRpc(); } } public void Resume() { if (IsServer) { animator.speed = 1f; ResumeClientRpc(); } } [ClientRpc] private void PauseClientRpc() { animator.speed = 0f; } [ClientRpc] private void ResumeClientRpc() { animator.speed = 1f; } public void Occupy(ServerCharacter player) { if (!IsServer || IsOccupied) { return; } Pause(); bool giveScore = player.PreviousPlatformId != PlatformID.Value; int score = (player.TargetPlatformId == PlatformID.Value) ? 10 : 20; if (giveScore) { ScoreManager.Instance.AddPlayerScore(player.OwnerClientId, score); } IsOccupied = true; occupierId.Value = player.OwnerClientId; player.OnArrivalOnPlatform(PlatformID.Value); penaltyCoroutine = StartCoroutine(HandleOccupationPenalty(player)); EnableBarrier(); } private IEnumerator HandleOccupationPenalty(ServerCharacter player) { occupationTime = 0f; while (IsOccupied) { occupationTime += Time.deltaTime; if (occupationTime >= 10f) { yield return new WaitForSeconds(penaltyInterval); // Deduct points ScoreManager.Instance.SubtractPlayerScore(player.OwnerClientId, 10); Debug.Log($"Player {player.OwnerClientId} lost 10 points for occupying the platform too long."); } yield return null; } } public void Vacate(ServerCharacter player) { if (!IsServer || !IsOccupied || occupierId.Value != player.OwnerClientId) { return; } Resume(); IsOccupied = false; occupierId.Value = 0; player.OnLeavingPlatform(PlatformID.Value); DisableBarrier(); if (penaltyCoroutine != null) { StopCoroutine(penaltyCoroutine); penaltyCoroutine = null; } } private void EnableBarrier() { var excludedClient = NetworkManager.Singleton.LocalClientId; var clientRpcParams = new ClientRpcParams { Send = new ClientRpcSendParams { TargetClientIds = NetworkManager.Singleton.ConnectedClientsIds .Where(clientId => clientId != excludedClient) .ToArray() } }; EnableBarrierClientRpc(clientRpcParams); } private void DisableBarrier() { DisableBarrierClientRpc(); } [ClientRpc] private void EnableBarrierClientRpc(ClientRpcParams clientRpcParams = default) { if (barrierObject != null) { barrierObject.SetActive(true); } } [ClientRpc] private void DisableBarrierClientRpc() { if (barrierObject != null) { barrierObject.SetActive(false); } } private void OnTriggerEnter(Collider other) { if (IsServer && other.TryGetComponent(out var player) && !IsOccupied) { Occupy(player); } } private void OnTriggerExit(Collider other) { if (IsServer && other.TryGetComponent(out var player)) { Vacate(player); } } public ulong GetOccupierId() { return occupierId.Value; } } }