using System; using UnityEngine; using Cysharp.Threading.Tasks; using System.Threading; public class EndGameConditionChecker : IDisposable { public event Action OnEndGameCondition; private bool _isDisposed = false; private float startTime; private float endTime; public float TimeRest => limitedByTime ? endTime - Time.time : - 1; private bool limitedByTime; private CancellationTokenSource _cts; private WeaponModel weaponModel; private Health playerHealth; public EndGameConditionChecker(WeaponModel weaponModel, Health playerHealth, int sessionTimeMinutes = 0) { if(weaponModel == null) throw new ArgumentNullException("WeaponModel is null"); if (playerHealth == null) throw new ArgumentNullException("PlayerHealth is null"); this.weaponModel = weaponModel; this.playerHealth = playerHealth; weaponModel.OnNoAmmo += NoAmmoHandler; playerHealth.Died += PlayerDiedHandler; limitedByTime = sessionTimeMinutes > 0; if(limitedByTime ) { startTime = Time.time; endTime = startTime + sessionTimeMinutes * 60; _cts = new CancellationTokenSource(); CheckTimeout(_cts).Forget(); } } public void Dispose() { if(_isDisposed) return; _isDisposed = true; _cts?.Cancel(); _cts?.Dispose(); _cts = null; weaponModel.OnNoAmmo -= NoAmmoHandler; playerHealth.Died -= PlayerDiedHandler; weaponModel = null; playerHealth = null; } private void PlayerDiedHandler(Vector3 obj) => TerminateSession(EndgameReason.Death); private void NoAmmoHandler() => TerminateSession(EndgameReason.NoAmmo); private void TerminateSession(EndgameReason reason) { if (_isDisposed) return; OnEndGameCondition?.Invoke(reason); Dispose(); } private async UniTaskVoid CheckTimeout(CancellationTokenSource cts) { try { while (!cts.IsCancellationRequested) { if (TimeRest <= 0) { TerminateSession(EndgameReason.Timeout); break; } await UniTask.Delay(1000, cancellationToken: cts.Token); } } catch (OperationCanceledException) { // ожидаемая отмена } } public enum EndgameReason { Timeout, Death, NoAmmo } }