SharedGameTicker.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. using Content.Shared.Roles;
  2. using Robust.Shared.Network;
  3. using Robust.Shared.Prototypes;
  4. using Robust.Shared.Replays;
  5. using Robust.Shared.Serialization;
  6. using Robust.Shared.Serialization.Markdown.Mapping;
  7. using Robust.Shared.Serialization.Markdown.Value;
  8. using Robust.Shared.Timing;
  9. using Robust.Shared.Audio;
  10. namespace Content.Shared.GameTicking
  11. {
  12. public abstract class SharedGameTicker : EntitySystem
  13. {
  14. [Dependency] private readonly IReplayRecordingManager _replay = default!;
  15. [Dependency] private readonly IGameTiming _gameTiming = default!;
  16. // See ideally these would be pulled from the job definition or something.
  17. // But this is easier, and at least it isn't hardcoded.
  18. //TODO: Move these, they really belong in StationJobsSystem or a cvar.
  19. [ValidatePrototypeId<JobPrototype>]
  20. public const string FallbackOverflowJob = "Passenger";
  21. public const string FallbackOverflowJobName = "job-name-passenger";
  22. // TODO network.
  23. // Probably most useful for replays, round end info, and probably things like lobby menus.
  24. [ViewVariables]
  25. public int RoundId { get; protected set; }
  26. [ViewVariables] public TimeSpan RoundStartTimeSpan { get; protected set; }
  27. public override void Initialize()
  28. {
  29. base.Initialize();
  30. _replay.RecordingStarted += OnRecordingStart;
  31. }
  32. public override void Shutdown()
  33. {
  34. _replay.RecordingStarted -= OnRecordingStart;
  35. }
  36. private void OnRecordingStart(MappingDataNode metadata, List<object> events)
  37. {
  38. if (RoundId != 0)
  39. {
  40. metadata["roundId"] = new ValueDataNode(RoundId.ToString());
  41. }
  42. }
  43. public TimeSpan RoundDuration()
  44. {
  45. return _gameTiming.CurTime.Subtract(RoundStartTimeSpan);
  46. }
  47. }
  48. [Serializable, NetSerializable]
  49. public sealed class TickerJoinLobbyEvent : EntityEventArgs
  50. {
  51. }
  52. [Serializable, NetSerializable]
  53. public sealed class TickerJoinGameEvent : EntityEventArgs
  54. {
  55. }
  56. [Serializable, NetSerializable]
  57. public sealed class TickerLateJoinStatusEvent : EntityEventArgs
  58. {
  59. // TODO: Make this a replicated CVar, honestly.
  60. public bool Disallowed { get; }
  61. public TickerLateJoinStatusEvent(bool disallowed)
  62. {
  63. Disallowed = disallowed;
  64. }
  65. }
  66. [Serializable, NetSerializable]
  67. public sealed class TickerConnectionStatusEvent : EntityEventArgs
  68. {
  69. public TimeSpan RoundStartTimeSpan { get; }
  70. public TickerConnectionStatusEvent(TimeSpan roundStartTimeSpan)
  71. {
  72. RoundStartTimeSpan = roundStartTimeSpan;
  73. }
  74. }
  75. [Serializable, NetSerializable]
  76. public sealed class TickerLobbyStatusEvent : EntityEventArgs
  77. {
  78. public bool IsRoundStarted { get; }
  79. public string? LobbyBackground { get; }
  80. public bool YouAreReady { get; }
  81. // UTC.
  82. public TimeSpan StartTime { get; }
  83. public TimeSpan RoundStartTimeSpan { get; }
  84. public bool Paused { get; }
  85. public TickerLobbyStatusEvent(bool isRoundStarted, string? lobbyBackground, bool youAreReady, TimeSpan startTime, TimeSpan preloadTime, TimeSpan roundStartTimeSpan, bool paused)
  86. {
  87. IsRoundStarted = isRoundStarted;
  88. LobbyBackground = lobbyBackground;
  89. YouAreReady = youAreReady;
  90. StartTime = startTime;
  91. RoundStartTimeSpan = roundStartTimeSpan;
  92. Paused = paused;
  93. }
  94. }
  95. [Serializable, NetSerializable]
  96. public sealed class TickerLobbyInfoEvent : EntityEventArgs
  97. {
  98. public string TextBlob { get; }
  99. public TickerLobbyInfoEvent(string textBlob)
  100. {
  101. TextBlob = textBlob;
  102. }
  103. }
  104. [Serializable, NetSerializable]
  105. public sealed class TickerLobbyCountdownEvent : EntityEventArgs
  106. {
  107. /// <summary>
  108. /// The game time that the game will start at.
  109. /// </summary>
  110. public TimeSpan StartTime { get; }
  111. /// <summary>
  112. /// Whether or not the countdown is paused
  113. /// </summary>
  114. public bool Paused { get; }
  115. public TickerLobbyCountdownEvent(TimeSpan startTime, bool paused)
  116. {
  117. StartTime = startTime;
  118. Paused = paused;
  119. }
  120. }
  121. [Serializable, NetSerializable]
  122. public sealed class TickerJobsAvailableEvent(
  123. Dictionary<NetEntity, string> stationNames,
  124. Dictionary<NetEntity, Dictionary<ProtoId<JobPrototype>, int?>> jobsAvailableByStation)
  125. : EntityEventArgs
  126. {
  127. /// <summary>
  128. /// The Status of the Player in the lobby (ready, observer, ...)
  129. /// </summary>
  130. public Dictionary<NetEntity, Dictionary<ProtoId<JobPrototype>, int?>> JobsAvailableByStation { get; } = jobsAvailableByStation;
  131. public Dictionary<NetEntity, string> StationNames { get; } = stationNames;
  132. }
  133. [Serializable, NetSerializable, DataDefinition]
  134. public sealed partial class RoundEndMessageEvent : EntityEventArgs
  135. {
  136. [Serializable, NetSerializable, DataDefinition]
  137. public partial struct RoundEndPlayerInfo
  138. {
  139. [DataField]
  140. public string PlayerOOCName;
  141. [DataField]
  142. public string? PlayerICName;
  143. [DataField, NonSerialized]
  144. public NetUserId? PlayerGuid;
  145. public string Role;
  146. [DataField, NonSerialized]
  147. public string[] JobPrototypes;
  148. [DataField, NonSerialized]
  149. public string[] AntagPrototypes;
  150. public NetEntity? PlayerNetEntity;
  151. [DataField]
  152. public bool Antag;
  153. [DataField]
  154. public bool Observer;
  155. public bool Connected;
  156. }
  157. public string GamemodeTitle { get; }
  158. public string RoundEndText { get; }
  159. public TimeSpan RoundDuration { get; }
  160. public int RoundId { get; }
  161. public int PlayerCount { get; }
  162. public RoundEndPlayerInfo[] AllPlayersEndInfo { get; }
  163. /// <summary>
  164. /// Sound gets networked due to how entity lifecycle works between client / server and to avoid clipping.
  165. /// </summary>
  166. public ResolvedSoundSpecifier? RestartSound;
  167. public RoundEndMessageEvent(
  168. string gamemodeTitle,
  169. string roundEndText,
  170. TimeSpan roundDuration,
  171. int roundId,
  172. int playerCount,
  173. RoundEndPlayerInfo[] allPlayersEndInfo,
  174. ResolvedSoundSpecifier? restartSound)
  175. {
  176. GamemodeTitle = gamemodeTitle;
  177. RoundEndText = roundEndText;
  178. RoundDuration = roundDuration;
  179. RoundId = roundId;
  180. PlayerCount = playerCount;
  181. AllPlayersEndInfo = allPlayersEndInfo;
  182. RestartSound = restartSound;
  183. }
  184. }
  185. [Serializable, NetSerializable]
  186. public enum PlayerGameStatus : sbyte
  187. {
  188. NotReadyToPlay = 0,
  189. ReadyToPlay,
  190. JoinedGame,
  191. }
  192. }