diff --git a/Content.Server/Communications/CommunicationsConsoleComponent.cs b/Content.Server/Communications/CommunicationsConsoleComponent.cs index 8a0104ea32..7d8b826bcb 100644 --- a/Content.Server/Communications/CommunicationsConsoleComponent.cs +++ b/Content.Server/Communications/CommunicationsConsoleComponent.cs @@ -17,12 +17,11 @@ using Timer = Robust.Shared.Timing.Timer; namespace Content.Server.Communications { [RegisterComponent] - public class CommunicationsConsoleComponent : SharedCommunicationsConsoleComponent, IEntityEventSubscriber + public class CommunicationsConsoleComponent : SharedCommunicationsConsoleComponent { [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IChatManager _chatManager = default!; [Dependency] private readonly IEntityManager _entities = default!; - [Dependency] private readonly IEntityManager _entityManager = default!; private bool Powered => !_entities.TryGetComponent(Owner, out ApcPowerReceiverComponent? receiver) || receiver.Powered; @@ -43,7 +42,10 @@ namespace Content.Server.Communications UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; } - _entityManager.EventBus.SubscribeEvent(EventSource.Local, this, (s) => UpdateBoundInterface()); + RoundEndSystem.OnRoundEndCountdownStarted += UpdateBoundInterface; + RoundEndSystem.OnRoundEndCountdownCancelled += UpdateBoundInterface; + RoundEndSystem.OnRoundEndCountdownFinished += UpdateBoundInterface; + RoundEndSystem.OnCallCooldownEnded += UpdateBoundInterface; } protected override void Startup() @@ -74,7 +76,9 @@ namespace Content.Server.Communications protected override void OnRemove() { - _entityManager.EventBus.UnsubscribeEvent(EventSource.Local, this); + RoundEndSystem.OnRoundEndCountdownStarted -= UpdateBoundInterface; + RoundEndSystem.OnRoundEndCountdownCancelled -= UpdateBoundInterface; + RoundEndSystem.OnRoundEndCountdownFinished -= UpdateBoundInterface; base.OnRemove(); } diff --git a/Content.Server/GameTicking/Commands/RestartRoundCommand.cs b/Content.Server/GameTicking/Commands/RestartRoundCommand.cs index 4341c0ed07..63a6610b26 100644 --- a/Content.Server/GameTicking/Commands/RestartRoundCommand.cs +++ b/Content.Server/GameTicking/Commands/RestartRoundCommand.cs @@ -1,9 +1,10 @@ -using System; +using System; using Content.Server.Administration; using Content.Server.RoundEnd; using Content.Shared.Administration; using Robust.Shared.Console; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; namespace Content.Server.GameTicking.Commands { @@ -12,7 +13,7 @@ namespace Content.Server.GameTicking.Commands { public string Command => "restartround"; public string Description => "Ends the current round and starts the countdown for the next lobby."; - public string Help => string.Empty; + public string Help => String.Empty; public void Execute(IConsoleShell shell, string argStr, string[] args) { diff --git a/Content.Server/RoundEnd/RoundEndSystem.cs b/Content.Server/RoundEnd/RoundEndSystem.cs index 60fa7cf012..51237af694 100644 --- a/Content.Server/RoundEnd/RoundEndSystem.cs +++ b/Content.Server/RoundEnd/RoundEndSystem.cs @@ -19,60 +19,79 @@ namespace Content.Server.RoundEnd { [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IChatManager _chatManager = default!; - [Dependency] private readonly GameTicker _gameTicker = default!; [Dependency] private readonly AdminLogSystem _adminLog = default!; + public const float RestartRoundTime = 20f; - private readonly TimeSpan _cooldownDuration = TimeSpan.FromSeconds(30); - private readonly TimeSpan _countdownDuration = TimeSpan.FromMinutes(4); - private readonly TimeSpan _restartRoundDuration = TimeSpan.FromSeconds(20); + private CancellationTokenSource _roundEndCancellationTokenSource = new(); + private CancellationTokenSource _callCooldownEndedTokenSource = new(); + public bool IsRoundEndCountdownStarted { get; private set; } + public TimeSpan RoundEndCountdownTime { get; set; } = TimeSpan.FromMinutes(4); + public TimeSpan? ExpectedCountdownEnd = null; - private CancellationTokenSource? _countdownTokenSource = null; - private CancellationTokenSource? _cooldownTokenSource = null; - public TimeSpan? ExpectedCountdownEnd { get; set; } = null; + public TimeSpan LastCallTime { get; private set; } + + public TimeSpan CallCooldown { get; } = TimeSpan.FromSeconds(30); + + // TODO: Make these regular eventbus events... + public delegate void RoundEndCountdownStarted(); + public event RoundEndCountdownStarted? OnRoundEndCountdownStarted; + + public delegate void RoundEndCountdownCancelled(); + public event RoundEndCountdownCancelled? OnRoundEndCountdownCancelled; + + public delegate void RoundEndCountdownFinished(); + public event RoundEndCountdownFinished? OnRoundEndCountdownFinished; + + public delegate void CallCooldownEnded(); + public event CallCooldownEnded? OnCallCooldownEnded; public override void Initialize() { base.Initialize(); + SubscribeLocalEvent(Reset); } - private void Reset(RoundRestartCleanupEvent ev) + void Reset(RoundRestartCleanupEvent ev) { - if (_countdownTokenSource != null) - { - _countdownTokenSource.Cancel(); - _countdownTokenSource = null; - } - - if (_cooldownTokenSource != null) - { - _cooldownTokenSource.Cancel(); - _cooldownTokenSource = null; - } - + IsRoundEndCountdownStarted = false; + _roundEndCancellationTokenSource.Cancel(); + _roundEndCancellationTokenSource = new CancellationTokenSource(); + _callCooldownEndedTokenSource.Cancel(); + _callCooldownEndedTokenSource = new CancellationTokenSource(); ExpectedCountdownEnd = null; + LastCallTime = default; } public bool CanCall() { - return _cooldownTokenSource == null; + return _gameTiming.CurTime >= LastCallTime + CallCooldown; + } + + private void ActivateCooldown() + { + _callCooldownEndedTokenSource.Cancel(); + _callCooldownEndedTokenSource = new CancellationTokenSource(); + LastCallTime = _gameTiming.CurTime; + Timer.Spawn(CallCooldown, () => OnCallCooldownEnded?.Invoke(), _callCooldownEndedTokenSource.Token); } public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = true) { - RequestRoundEnd(_countdownDuration, requester, checkCooldown); + RequestRoundEnd(RoundEndCountdownTime, requester, checkCooldown); } public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, bool checkCooldown = true) { - if (_gameTicker.RunLevel != GameRunLevel.InRound) return; + if (IsRoundEndCountdownStarted) + return; - if (checkCooldown && _cooldownTokenSource != null) return; - - if (_countdownTokenSource != null) return; - _countdownTokenSource = new(); + if (checkCooldown && !CanCall()) + { + return; + } if (requester != null) { @@ -83,25 +102,29 @@ namespace Content.Server.RoundEnd _adminLog.Add(LogType.ShuttleCalled, LogImpact.High, $"Shuttle called"); } + IsRoundEndCountdownStarted = true; + _chatManager.DispatchStationAnnouncement(Loc.GetString("round-end-system-shuttle-called-announcement",("minutes", countdownTime.Minutes)), Loc.GetString("Station"), false); SoundSystem.Play(Filter.Broadcast(), "/Audio/Announcements/shuttlecalled.ogg"); ExpectedCountdownEnd = _gameTiming.CurTime + countdownTime; - Timer.Spawn(countdownTime, EndRound, _countdownTokenSource.Token); + Timer.Spawn(countdownTime, EndRound, _roundEndCancellationTokenSource.Token); ActivateCooldown(); - RaiseLocalEvent(RoundEndSystemChangedEvent.Default); + + OnRoundEndCountdownStarted?.Invoke(); } public void CancelRoundEndCountdown(EntityUid? requester = null, bool checkCooldown = true) { - if (_gameTicker.RunLevel != GameRunLevel.InRound) return; - if (checkCooldown && _cooldownTokenSource != null) return; + if (!IsRoundEndCountdownStarted) + return; - if (_countdownTokenSource == null) return; - _countdownTokenSource.Cancel(); - _countdownTokenSource = null; + if (checkCooldown && !CanCall()) + { + return; + } if (requester != null) { @@ -112,47 +135,31 @@ namespace Content.Server.RoundEnd _adminLog.Add(LogType.ShuttleRecalled, LogImpact.High, $"Shuttle recalled"); } + IsRoundEndCountdownStarted = false; + _chatManager.DispatchStationAnnouncement(Loc.GetString("round-end-system-shuttle-recalled-announcement"), Loc.GetString("Station"), false); SoundSystem.Play(Filter.Broadcast(), "/Audio/Announcements/shuttlerecalled.ogg"); + _roundEndCancellationTokenSource.Cancel(); + _roundEndCancellationTokenSource = new CancellationTokenSource(); + ExpectedCountdownEnd = null; + ActivateCooldown(); - RaiseLocalEvent(RoundEndSystemChangedEvent.Default); + + OnRoundEndCountdownCancelled?.Invoke(); } public void EndRound() { - if (_gameTicker.RunLevel != GameRunLevel.InRound) return; - RaiseLocalEvent(RoundEndSystemChangedEvent.Default); - _gameTicker.EndRound(); - _countdownTokenSource?.Cancel(); - _countdownTokenSource = new(); - _chatManager.DispatchServerAnnouncement(Loc.GetString("round-end-system-round-restart-eta-announcement", ("seconds", _restartRoundDuration.Seconds))); - Timer.Spawn(_restartRoundDuration, AfterEndRoundRestart, _countdownTokenSource.Token); - } + OnRoundEndCountdownFinished?.Invoke(); + var gameTicker = Get(); + gameTicker.EndRound(); - private void AfterEndRoundRestart() - { - if (_gameTicker.RunLevel != GameRunLevel.InRound) return; - _gameTicker.RestartRound(); - } + _chatManager.DispatchServerAnnouncement(Loc.GetString("round-end-system-round-restart-eta-announcement", ("seconds", RestartRoundTime))); - private void ActivateCooldown() - { - _cooldownTokenSource?.Cancel(); - _cooldownTokenSource = new(); - Timer.Spawn(_cooldownDuration, () => - { - _cooldownTokenSource.Cancel(); - _cooldownTokenSource = null; - RaiseLocalEvent(RoundEndSystemChangedEvent.Default); - }, _cooldownTokenSource.Token); + Timer.Spawn(TimeSpan.FromSeconds(RestartRoundTime), () => gameTicker.RestartRound(), CancellationToken.None); } } - - public class RoundEndSystemChangedEvent : EntityEventArgs - { - public static RoundEndSystemChangedEvent Default { get; } = new(); - } }