GameTicker.Lobby.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using System.Linq;
  2. using Content.Shared.GameTicking;
  3. using Content.Server.Station.Components;
  4. using Robust.Shared.Network;
  5. using Robust.Shared.Player;
  6. using System.Text;
  7. namespace Content.Server.GameTicking
  8. {
  9. public sealed partial class GameTicker
  10. {
  11. [ViewVariables]
  12. private readonly Dictionary<NetUserId, PlayerGameStatus> _playerGameStatuses = new();
  13. [ViewVariables]
  14. private TimeSpan _roundStartTime;
  15. /// <summary>
  16. /// How long before RoundStartTime do we load maps.
  17. /// </summary>
  18. [ViewVariables]
  19. public TimeSpan RoundPreloadTime { get; } = TimeSpan.FromSeconds(15);
  20. [ViewVariables]
  21. private TimeSpan _pauseTime;
  22. [ViewVariables]
  23. public new bool Paused { get; set; }
  24. [ViewVariables]
  25. private bool _roundStartCountdownHasNotStartedYetDueToNoPlayers;
  26. /// <summary>
  27. /// The game status of a players user Id. May contain disconnected players
  28. /// </summary>
  29. public IReadOnlyDictionary<NetUserId, PlayerGameStatus> PlayerGameStatuses => _playerGameStatuses;
  30. public void UpdateInfoText()
  31. {
  32. RaiseNetworkEvent(GetInfoMsg(), Filter.Empty().AddPlayers(_playerManager.NetworkedSessions));
  33. }
  34. private string GetInfoText()
  35. {
  36. var preset = CurrentPreset ?? Preset;
  37. if (preset == null)
  38. {
  39. return string.Empty;
  40. }
  41. var playerCount = $"{_playerManager.PlayerCount}";
  42. var readyCount = _playerGameStatuses.Values.Count(x => x == PlayerGameStatus.ReadyToPlay);
  43. var stationNames = new StringBuilder();
  44. var query =
  45. EntityQueryEnumerator<StationJobsComponent, StationSpawningComponent, MetaDataComponent>();
  46. var foundOne = false;
  47. while (query.MoveNext(out _, out _, out var meta))
  48. {
  49. foundOne = true;
  50. if (stationNames.Length > 0)
  51. stationNames.Append('\n');
  52. stationNames.Append(meta.EntityName);
  53. }
  54. if (!foundOne)
  55. {
  56. stationNames.Append(_gameMapManager.GetSelectedMap()?.MapName ??
  57. Loc.GetString("game-ticker-no-map-selected"));
  58. }
  59. var gmTitle = Loc.GetString(preset.ModeTitle);
  60. var desc = Loc.GetString(preset.Description);
  61. return Loc.GetString(
  62. RunLevel == GameRunLevel.PreRoundLobby
  63. ? "game-ticker-get-info-preround-text"
  64. : "game-ticker-get-info-text",
  65. ("roundId", RoundId),
  66. ("playerCount", playerCount),
  67. ("readyCount", readyCount),
  68. ("mapName", stationNames.ToString()),
  69. ("gmTitle", gmTitle),
  70. ("desc", desc));
  71. }
  72. private TickerConnectionStatusEvent GetConnectionStatusMsg()
  73. {
  74. return new TickerConnectionStatusEvent(RoundStartTimeSpan);
  75. }
  76. private TickerLobbyStatusEvent GetStatusMsg(ICommonSession session)
  77. {
  78. _playerGameStatuses.TryGetValue(session.UserId, out var status);
  79. return new TickerLobbyStatusEvent(RunLevel != GameRunLevel.PreRoundLobby, LobbyBackground, status == PlayerGameStatus.ReadyToPlay, _roundStartTime, RoundPreloadTime, RoundStartTimeSpan, Paused);
  80. }
  81. private void SendStatusToAll()
  82. {
  83. foreach (var player in _playerManager.Sessions)
  84. {
  85. RaiseNetworkEvent(GetStatusMsg(player), player.Channel);
  86. }
  87. }
  88. private TickerLobbyInfoEvent GetInfoMsg()
  89. {
  90. return new (GetInfoText());
  91. }
  92. private void UpdateLateJoinStatus()
  93. {
  94. RaiseNetworkEvent(new TickerLateJoinStatusEvent(DisallowLateJoin));
  95. }
  96. public bool PauseStart(bool pause = true)
  97. {
  98. if (Paused == pause)
  99. {
  100. return false;
  101. }
  102. Paused = pause;
  103. if (pause)
  104. {
  105. _pauseTime = _gameTiming.CurTime;
  106. }
  107. else if (_pauseTime != default)
  108. {
  109. _roundStartTime += _gameTiming.CurTime - _pauseTime;
  110. }
  111. RaiseNetworkEvent(new TickerLobbyCountdownEvent(_roundStartTime, Paused));
  112. _chatManager.DispatchServerAnnouncement(Loc.GetString(Paused
  113. ? "game-ticker-pause-start"
  114. : "game-ticker-pause-start-resumed"));
  115. return true;
  116. }
  117. public bool TogglePause()
  118. {
  119. PauseStart(!Paused);
  120. return Paused;
  121. }
  122. public void ToggleReadyAll(bool ready)
  123. {
  124. var status = ready ? PlayerGameStatus.ReadyToPlay : PlayerGameStatus.NotReadyToPlay;
  125. foreach (var playerUserId in _playerGameStatuses.Keys)
  126. {
  127. _playerGameStatuses[playerUserId] = status;
  128. if (!_playerManager.TryGetSessionById(playerUserId, out var playerSession))
  129. continue;
  130. RaiseNetworkEvent(GetStatusMsg(playerSession), playerSession.Channel);
  131. }
  132. }
  133. public void ToggleReady(ICommonSession player, bool ready)
  134. {
  135. if (!_playerGameStatuses.ContainsKey(player.UserId))
  136. return;
  137. if (!_userDb.IsLoadComplete(player))
  138. return;
  139. if (RunLevel != GameRunLevel.PreRoundLobby)
  140. {
  141. return;
  142. }
  143. var status = ready ? PlayerGameStatus.ReadyToPlay : PlayerGameStatus.NotReadyToPlay;
  144. _playerGameStatuses[player.UserId] = ready ? PlayerGameStatus.ReadyToPlay : PlayerGameStatus.NotReadyToPlay;
  145. RaiseNetworkEvent(GetStatusMsg(player), player.Channel);
  146. // update server info to reflect new ready count
  147. UpdateInfoText();
  148. }
  149. public bool UserHasJoinedGame(ICommonSession session)
  150. => UserHasJoinedGame(session.UserId);
  151. public bool UserHasJoinedGame(NetUserId userId)
  152. => PlayerGameStatuses.TryGetValue(userId, out var status) && status == PlayerGameStatus.JoinedGame;
  153. }
  154. }