Turns GameTicker into an EntitySystem. (#4197)
* GameTicker turned into an EntitySystem * Turns ClientGameTicker into an EntitySystem, turn NetMessages into events * Change event names to be more consistent with the rest. * YAML linter uses the dummy gameticker CVar override. * Fix game ticker initialization order * Dummy ticker won't spawn players. * Fix character creation test
This commit is contained in:
committed by
GitHub
parent
15fb554c28
commit
d3a611164b
@@ -26,7 +26,6 @@ namespace Content.Client.Audio
|
|||||||
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
||||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||||
[Dependency] private readonly IBaseClient _client = default!;
|
[Dependency] private readonly IBaseClient _client = default!;
|
||||||
[Dependency] private readonly IClientGameTicker _clientGameTicker = default!;
|
|
||||||
|
|
||||||
private SoundCollectionPrototype _ambientCollection = default!;
|
private SoundCollectionPrototype _ambientCollection = default!;
|
||||||
|
|
||||||
@@ -50,7 +49,7 @@ namespace Content.Client.Audio
|
|||||||
_client.PlayerJoinedServer += OnJoin;
|
_client.PlayerJoinedServer += OnJoin;
|
||||||
_client.PlayerLeaveServer += OnLeave;
|
_client.PlayerLeaveServer += OnLeave;
|
||||||
|
|
||||||
_clientGameTicker.LobbyStatusUpdated += LobbySongReceived;
|
Get<ClientGameTicker>().LobbyStatusUpdated += LobbySongReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Shutdown()
|
public override void Shutdown()
|
||||||
@@ -62,7 +61,7 @@ namespace Content.Client.Audio
|
|||||||
_client.PlayerJoinedServer -= OnJoin;
|
_client.PlayerJoinedServer -= OnJoin;
|
||||||
_client.PlayerLeaveServer -= OnLeave;
|
_client.PlayerLeaveServer -= OnLeave;
|
||||||
|
|
||||||
_clientGameTicker.LobbyStatusUpdated -= LobbySongReceived;
|
Get<ClientGameTicker>().LobbyStatusUpdated -= LobbySongReceived;
|
||||||
|
|
||||||
EndAmbience();
|
EndAmbience();
|
||||||
EndLobbyMusic();
|
EndLobbyMusic();
|
||||||
@@ -167,7 +166,7 @@ namespace Content.Client.Audio
|
|||||||
private void StartLobbyMusic()
|
private void StartLobbyMusic()
|
||||||
{
|
{
|
||||||
EndLobbyMusic();
|
EndLobbyMusic();
|
||||||
var file = _clientGameTicker.LobbySong;
|
var file = Get<ClientGameTicker>().LobbySong;
|
||||||
if (file == null) // We have not received the lobby song yet.
|
if (file == null) // We have not received the lobby song yet.
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -167,7 +167,6 @@ namespace Content.Client.Entry
|
|||||||
|
|
||||||
IoCManager.Resolve<IGameHud>().Initialize();
|
IoCManager.Resolve<IGameHud>().Initialize();
|
||||||
IoCManager.Resolve<IClientNotifyManager>().Initialize();
|
IoCManager.Resolve<IClientNotifyManager>().Initialize();
|
||||||
IoCManager.Resolve<IClientGameTicker>().Initialize();
|
|
||||||
|
|
||||||
var overlayMgr = IoCManager.Resolve<IOverlayManager>();
|
var overlayMgr = IoCManager.Resolve<IOverlayManager>();
|
||||||
overlayMgr.AddOverlay(new ParallaxOverlay());
|
overlayMgr.AddOverlay(new ParallaxOverlay());
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Content.Client.RoundEnd;
|
|||||||
using Content.Client.Viewport;
|
using Content.Client.Viewport;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.GameWindow;
|
using Content.Shared.GameWindow;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.State;
|
using Robust.Client.State;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
@@ -14,10 +15,11 @@ using Robust.Shared.ViewVariables;
|
|||||||
|
|
||||||
namespace Content.Client.GameTicking.Managers
|
namespace Content.Client.GameTicking.Managers
|
||||||
{
|
{
|
||||||
public class ClientGameTicker : SharedGameTicker, IClientGameTicker
|
[UsedImplicitly]
|
||||||
|
public class ClientGameTicker : SharedGameTicker
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IClientNetManager _netManager = default!;
|
|
||||||
[Dependency] private readonly IStateManager _stateManager = default!;
|
[Dependency] private readonly IStateManager _stateManager = default!;
|
||||||
|
[Dependency] private readonly IClientNetManager _netManager = default!;
|
||||||
|
|
||||||
[ViewVariables] private bool _initialized;
|
[ViewVariables] private bool _initialized;
|
||||||
private readonly List<string> _jobsAvailable = new();
|
private readonly List<string> _jobsAvailable = new();
|
||||||
@@ -29,7 +31,7 @@ namespace Content.Client.GameTicking.Managers
|
|||||||
[ViewVariables] public string? ServerInfoBlob { get; private set; }
|
[ViewVariables] public string? ServerInfoBlob { get; private set; }
|
||||||
[ViewVariables] public TimeSpan StartTime { get; private set; }
|
[ViewVariables] public TimeSpan StartTime { get; private set; }
|
||||||
[ViewVariables] public bool Paused { get; private set; }
|
[ViewVariables] public bool Paused { get; private set; }
|
||||||
[ViewVariables] public Dictionary<NetUserId, PlayerStatus> Status { get; private set; } = new();
|
[ViewVariables] public Dictionary<NetUserId, LobbyPlayerStatus> Status { get; private set; } = new();
|
||||||
[ViewVariables] public IReadOnlyList<string> JobsAvailable => _jobsAvailable;
|
[ViewVariables] public IReadOnlyList<string> JobsAvailable => _jobsAvailable;
|
||||||
|
|
||||||
public event Action? InfoBlobUpdated;
|
public event Action? InfoBlobUpdated;
|
||||||
@@ -38,47 +40,47 @@ namespace Content.Client.GameTicking.Managers
|
|||||||
public event Action? LobbyLateJoinStatusUpdated;
|
public event Action? LobbyLateJoinStatusUpdated;
|
||||||
public event Action<IReadOnlyList<string>>? LobbyJobsAvailableUpdated;
|
public event Action<IReadOnlyList<string>>? LobbyJobsAvailableUpdated;
|
||||||
|
|
||||||
public void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
DebugTools.Assert(!_initialized);
|
DebugTools.Assert(!_initialized);
|
||||||
|
|
||||||
_netManager.RegisterNetMessage<MsgTickerJoinLobby>(nameof(MsgTickerJoinLobby), JoinLobby);
|
SubscribeNetworkEvent<TickerJoinLobbyEvent>(JoinLobby);
|
||||||
_netManager.RegisterNetMessage<MsgTickerJoinGame>(nameof(MsgTickerJoinGame), JoinGame);
|
SubscribeNetworkEvent<TickerJoinGameEvent>(JoinGame);
|
||||||
_netManager.RegisterNetMessage<MsgTickerLobbyStatus>(nameof(MsgTickerLobbyStatus), LobbyStatus);
|
SubscribeNetworkEvent<TickerLobbyStatusEvent>(LobbyStatus);
|
||||||
_netManager.RegisterNetMessage<MsgTickerLobbyInfo>(nameof(MsgTickerLobbyInfo), LobbyInfo);
|
SubscribeNetworkEvent<TickerLobbyInfoEvent>(LobbyInfo);
|
||||||
_netManager.RegisterNetMessage<MsgTickerLobbyCountdown>(nameof(MsgTickerLobbyCountdown), LobbyCountdown);
|
SubscribeNetworkEvent<TickerLobbyCountdownEvent>(LobbyCountdown);
|
||||||
_netManager.RegisterNetMessage<MsgTickerLobbyReady>(nameof(MsgTickerLobbyReady), LobbyReady);
|
SubscribeNetworkEvent<TickerLobbyReadyEvent>(LobbyReady);
|
||||||
_netManager.RegisterNetMessage<MsgRoundEndMessage>(nameof(MsgRoundEndMessage), RoundEnd);
|
SubscribeNetworkEvent<RoundEndMessageEvent>(RoundEnd);
|
||||||
_netManager.RegisterNetMessage<MsgRequestWindowAttention>(nameof(MsgRequestWindowAttention), msg =>
|
SubscribeNetworkEvent<RequestWindowAttentionEvent>(msg =>
|
||||||
{
|
{
|
||||||
IoCManager.Resolve<IClyde>().RequestWindowAttention();
|
IoCManager.Resolve<IClyde>().RequestWindowAttention();
|
||||||
});
|
});
|
||||||
_netManager.RegisterNetMessage<MsgTickerLateJoinStatus>(nameof(MsgTickerLateJoinStatus), LateJoinStatus);
|
SubscribeNetworkEvent<TickerLateJoinStatusEvent>(LateJoinStatus);
|
||||||
_netManager.RegisterNetMessage<MsgTickerJobsAvailable>(nameof(MsgTickerJobsAvailable), UpdateJobsAvailable);
|
SubscribeNetworkEvent<TickerJobsAvailableEvent>(UpdateJobsAvailable);
|
||||||
|
|
||||||
Status = new Dictionary<NetUserId, PlayerStatus>();
|
Status = new Dictionary<NetUserId, LobbyPlayerStatus>();
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LateJoinStatus(MsgTickerLateJoinStatus message)
|
private void LateJoinStatus(TickerLateJoinStatusEvent message)
|
||||||
{
|
{
|
||||||
DisallowedLateJoin = message.Disallowed;
|
DisallowedLateJoin = message.Disallowed;
|
||||||
LobbyLateJoinStatusUpdated?.Invoke();
|
LobbyLateJoinStatusUpdated?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateJobsAvailable(MsgTickerJobsAvailable message)
|
private void UpdateJobsAvailable(TickerJobsAvailableEvent message)
|
||||||
{
|
{
|
||||||
_jobsAvailable.Clear();
|
_jobsAvailable.Clear();
|
||||||
_jobsAvailable.AddRange(message.JobsAvailable);
|
_jobsAvailable.AddRange(message.JobsAvailable);
|
||||||
LobbyJobsAvailableUpdated?.Invoke(JobsAvailable);
|
LobbyJobsAvailableUpdated?.Invoke(JobsAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void JoinLobby(MsgTickerJoinLobby message)
|
private void JoinLobby(TickerJoinLobbyEvent message)
|
||||||
{
|
{
|
||||||
_stateManager.RequestStateChange<LobbyState>();
|
_stateManager.RequestStateChange<LobbyState>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LobbyStatus(MsgTickerLobbyStatus message)
|
private void LobbyStatus(TickerLobbyStatusEvent message)
|
||||||
{
|
{
|
||||||
StartTime = message.StartTime;
|
StartTime = message.StartTime;
|
||||||
IsGameStarted = message.IsRoundStarted;
|
IsGameStarted = message.IsRoundStarted;
|
||||||
@@ -91,35 +93,35 @@ namespace Content.Client.GameTicking.Managers
|
|||||||
LobbyStatusUpdated?.Invoke();
|
LobbyStatusUpdated?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LobbyInfo(MsgTickerLobbyInfo message)
|
private void LobbyInfo(TickerLobbyInfoEvent message)
|
||||||
{
|
{
|
||||||
ServerInfoBlob = message.TextBlob;
|
ServerInfoBlob = message.TextBlob;
|
||||||
|
|
||||||
InfoBlobUpdated?.Invoke();
|
InfoBlobUpdated?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void JoinGame(MsgTickerJoinGame message)
|
private void JoinGame(TickerJoinGameEvent message)
|
||||||
{
|
{
|
||||||
_stateManager.RequestStateChange<GameScreen>();
|
_stateManager.RequestStateChange<GameScreen>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LobbyCountdown(MsgTickerLobbyCountdown message)
|
private void LobbyCountdown(TickerLobbyCountdownEvent message)
|
||||||
{
|
{
|
||||||
StartTime = message.StartTime;
|
StartTime = message.StartTime;
|
||||||
Paused = message.Paused;
|
Paused = message.Paused;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LobbyReady(MsgTickerLobbyReady message)
|
private void LobbyReady(TickerLobbyReadyEvent message)
|
||||||
{
|
{
|
||||||
// Merge the Dictionaries
|
// Merge the Dictionaries
|
||||||
foreach (var p in message.PlayerStatus)
|
foreach (var p in message.Status)
|
||||||
{
|
{
|
||||||
Status[p.Key] = p.Value;
|
Status[p.Key] = p.Value;
|
||||||
}
|
}
|
||||||
LobbyReadyUpdated?.Invoke();
|
LobbyReadyUpdated?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RoundEnd(MsgRoundEndMessage message)
|
private void RoundEnd(RoundEndMessageEvent message)
|
||||||
{
|
{
|
||||||
//This is not ideal at all, but I don't see an immediately better fit anywhere else.
|
//This is not ideal at all, but I don't see an immediately better fit anywhere else.
|
||||||
var roundEnd = new RoundEndSummaryWindow(message.GamemodeTitle, message.RoundEndText, message.RoundDuration, message.AllPlayersEndInfo);
|
var roundEnd = new RoundEndSummaryWindow(message.GamemodeTitle, message.RoundEndText, message.RoundDuration, message.AllPlayersEndInfo);
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Robust.Shared.Network;
|
|
||||||
using static Content.Shared.GameTicking.SharedGameTicker;
|
|
||||||
|
|
||||||
namespace Content.Client.GameTicking.Managers
|
|
||||||
{
|
|
||||||
public interface IClientGameTicker
|
|
||||||
{
|
|
||||||
bool IsGameStarted { get; }
|
|
||||||
string? ServerInfoBlob { get; }
|
|
||||||
bool AreWeReady { get; }
|
|
||||||
string? LobbySong { get; }
|
|
||||||
bool DisallowedLateJoin { get; }
|
|
||||||
TimeSpan StartTime { get; }
|
|
||||||
bool Paused { get; }
|
|
||||||
Dictionary<NetUserId, PlayerStatus> Status { get; }
|
|
||||||
IReadOnlyList<string> JobsAvailable { get; }
|
|
||||||
|
|
||||||
void Initialize();
|
|
||||||
event Action InfoBlobUpdated;
|
|
||||||
event Action LobbyStatusUpdated;
|
|
||||||
event Action LobbyReadyUpdated;
|
|
||||||
event Action LobbyLateJoinStatusUpdated;
|
|
||||||
event Action<IReadOnlyList<string>> LobbyJobsAvailableUpdated;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -33,7 +33,6 @@ namespace Content.Client.IoC
|
|||||||
IoCManager.Register<IGameHud, GameHud>();
|
IoCManager.Register<IGameHud, GameHud>();
|
||||||
IoCManager.Register<IClientNotifyManager, ClientNotifyManager>();
|
IoCManager.Register<IClientNotifyManager, ClientNotifyManager>();
|
||||||
IoCManager.Register<ISharedNotifyManager, ClientNotifyManager>();
|
IoCManager.Register<ISharedNotifyManager, ClientNotifyManager>();
|
||||||
IoCManager.Register<IClientGameTicker, ClientGameTicker>();
|
|
||||||
IoCManager.Register<IParallaxManager, ParallaxManager>();
|
IoCManager.Register<IParallaxManager, ParallaxManager>();
|
||||||
IoCManager.Register<IChatManager, ChatManager>();
|
IoCManager.Register<IChatManager, ChatManager>();
|
||||||
IoCManager.Register<IEscapeMenuOwner, EscapeMenuOwner>();
|
IoCManager.Register<IEscapeMenuOwner, EscapeMenuOwner>();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using Robust.Client.UserInterface;
|
|||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Client.Utility;
|
using Robust.Client.Utility;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Log;
|
using Robust.Shared.Log;
|
||||||
@@ -22,7 +23,6 @@ namespace Content.Client.LateJoin
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
|
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
|
||||||
[Dependency] private readonly IClientGameTicker _gameTicker = default!;
|
|
||||||
|
|
||||||
public event Action<string>? SelectedId;
|
public event Action<string>? SelectedId;
|
||||||
|
|
||||||
@@ -34,6 +34,8 @@ namespace Content.Client.LateJoin
|
|||||||
MinSize = SetSize = (360, 560);
|
MinSize = SetSize = (360, 560);
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
|
|
||||||
|
var gameTicker = EntitySystem.Get<ClientGameTicker>();
|
||||||
|
|
||||||
Title = Loc.GetString("Late Join");
|
Title = Loc.GetString("Late Join");
|
||||||
|
|
||||||
var jobList = new VBoxContainer();
|
var jobList = new VBoxContainer();
|
||||||
@@ -131,7 +133,7 @@ namespace Content.Client.LateJoin
|
|||||||
SelectedId?.Invoke(jobButton.JobId);
|
SelectedId?.Invoke(jobButton.JobId);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!_gameTicker.JobsAvailable.Contains(job.ID))
|
if (!gameTicker.JobsAvailable.Contains(job.ID))
|
||||||
{
|
{
|
||||||
jobButton.Disabled = true;
|
jobButton.Disabled = true;
|
||||||
}
|
}
|
||||||
@@ -147,7 +149,7 @@ namespace Content.Client.LateJoin
|
|||||||
Close();
|
Close();
|
||||||
};
|
};
|
||||||
|
|
||||||
_gameTicker.LobbyJobsAvailableUpdated += JobsAvailableUpdated;
|
gameTicker.LobbyJobsAvailableUpdated += JobsAvailableUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void JobsAvailableUpdated(IReadOnlyList<string> jobs)
|
private void JobsAvailableUpdated(IReadOnlyList<string> jobs)
|
||||||
@@ -164,7 +166,7 @@ namespace Content.Client.LateJoin
|
|||||||
|
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
_gameTicker.LobbyJobsAvailableUpdated -= JobsAvailableUpdated;
|
EntitySystem.Get<ClientGameTicker>().LobbyJobsAvailableUpdated -= JobsAvailableUpdated;
|
||||||
_jobButtons.Clear();
|
_jobButtons.Clear();
|
||||||
_jobCategories.Clear();
|
_jobCategories.Clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ using Content.Client.Preferences.UI;
|
|||||||
using Content.Client.Viewport;
|
using Content.Client.Viewport;
|
||||||
using Content.Client.Voting;
|
using Content.Client.Voting;
|
||||||
using Content.Shared.Chat;
|
using Content.Shared.Chat;
|
||||||
|
using Content.Shared.GameObjects.Components;
|
||||||
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.Input;
|
using Content.Shared.Input;
|
||||||
using Robust.Client;
|
using Robust.Client;
|
||||||
using Robust.Client.Console;
|
using Robust.Client.Console;
|
||||||
@@ -38,7 +40,6 @@ namespace Content.Client.Lobby
|
|||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||||
[Dependency] private readonly IClientGameTicker _clientGameTicker = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||||
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
|
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
|
||||||
@@ -50,6 +51,7 @@ namespace Content.Client.Lobby
|
|||||||
|
|
||||||
public override void Startup()
|
public override void Startup()
|
||||||
{
|
{
|
||||||
|
var gameTicker = EntitySystem.Get<ClientGameTicker>();
|
||||||
_characterSetup = new CharacterSetupGui(_entityManager, _resourceCache, _preferencesManager,
|
_characterSetup = new CharacterSetupGui(_entityManager, _resourceCache, _preferencesManager,
|
||||||
_prototypeManager);
|
_prototypeManager);
|
||||||
LayoutContainer.SetAnchorPreset(_characterSetup, LayoutContainer.LayoutPreset.Wide);
|
LayoutContainer.SetAnchorPreset(_characterSetup, LayoutContainer.LayoutPreset.Wide);
|
||||||
@@ -105,7 +107,7 @@ namespace Content.Client.Lobby
|
|||||||
_lobby.ObserveButton.OnPressed += _ => _consoleHost.ExecuteCommand("observe");
|
_lobby.ObserveButton.OnPressed += _ => _consoleHost.ExecuteCommand("observe");
|
||||||
_lobby.ReadyButton.OnPressed += _ =>
|
_lobby.ReadyButton.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
if (!_clientGameTicker.IsGameStarted)
|
if (!gameTicker.IsGameStarted)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -124,29 +126,23 @@ namespace Content.Client.Lobby
|
|||||||
UpdatePlayerList();
|
UpdatePlayerList();
|
||||||
|
|
||||||
_playerManager.PlayerListUpdated += PlayerManagerOnPlayerListUpdated;
|
_playerManager.PlayerListUpdated += PlayerManagerOnPlayerListUpdated;
|
||||||
_clientGameTicker.InfoBlobUpdated += UpdateLobbyUi;
|
gameTicker.InfoBlobUpdated += UpdateLobbyUi;
|
||||||
_clientGameTicker.LobbyStatusUpdated += LobbyStatusUpdated;
|
gameTicker.LobbyStatusUpdated += LobbyStatusUpdated;
|
||||||
_clientGameTicker.LobbyReadyUpdated += LobbyReadyUpdated;
|
gameTicker.LobbyReadyUpdated += LobbyReadyUpdated;
|
||||||
_clientGameTicker.LobbyLateJoinStatusUpdated += LobbyLateJoinStatusUpdated;
|
gameTicker.LobbyLateJoinStatusUpdated += LobbyLateJoinStatusUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Shutdown()
|
public override void Shutdown()
|
||||||
{
|
{
|
||||||
_playerManager.PlayerListUpdated -= PlayerManagerOnPlayerListUpdated;
|
_playerManager.PlayerListUpdated -= PlayerManagerOnPlayerListUpdated;
|
||||||
_clientGameTicker.InfoBlobUpdated -= UpdateLobbyUi;
|
|
||||||
_clientGameTicker.LobbyStatusUpdated -= LobbyStatusUpdated;
|
|
||||||
_clientGameTicker.LobbyReadyUpdated -= LobbyReadyUpdated;
|
|
||||||
_clientGameTicker.LobbyLateJoinStatusUpdated -= LobbyLateJoinStatusUpdated;
|
|
||||||
|
|
||||||
_clientGameTicker.Status.Clear();
|
|
||||||
|
|
||||||
_lobby.Dispose();
|
_lobby.Dispose();
|
||||||
_characterSetup.Dispose();
|
_characterSetup.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void FrameUpdate(FrameEventArgs e)
|
public override void FrameUpdate(FrameEventArgs e)
|
||||||
{
|
{
|
||||||
if (_clientGameTicker.IsGameStarted)
|
var gameTicker = EntitySystem.Get<ClientGameTicker>();
|
||||||
|
if (gameTicker.IsGameStarted)
|
||||||
{
|
{
|
||||||
_lobby.StartTime.Text = "";
|
_lobby.StartTime.Text = "";
|
||||||
return;
|
return;
|
||||||
@@ -154,13 +150,13 @@ namespace Content.Client.Lobby
|
|||||||
|
|
||||||
string text;
|
string text;
|
||||||
|
|
||||||
if (_clientGameTicker.Paused)
|
if (gameTicker.Paused)
|
||||||
{
|
{
|
||||||
text = Loc.GetString("Paused");
|
text = Loc.GetString("Paused");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var difference = _clientGameTicker.StartTime - _gameTiming.CurTime;
|
var difference = gameTicker.StartTime - _gameTiming.CurTime;
|
||||||
var seconds = difference.TotalSeconds;
|
var seconds = difference.TotalSeconds;
|
||||||
if (seconds < 0)
|
if (seconds < 0)
|
||||||
{
|
{
|
||||||
@@ -177,15 +173,16 @@ namespace Content.Client.Lobby
|
|||||||
|
|
||||||
private void PlayerManagerOnPlayerListUpdated(object? sender, EventArgs e)
|
private void PlayerManagerOnPlayerListUpdated(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
var gameTicker = EntitySystem.Get<ClientGameTicker>();
|
||||||
// Remove disconnected sessions from the Ready Dict
|
// Remove disconnected sessions from the Ready Dict
|
||||||
foreach (var p in _clientGameTicker.Status)
|
foreach (var p in gameTicker.Status)
|
||||||
{
|
{
|
||||||
if (!_playerManager.SessionsDict.TryGetValue(p.Key, out _))
|
if (!_playerManager.SessionsDict.TryGetValue(p.Key, out _))
|
||||||
{
|
{
|
||||||
// This is a shitty fix. Observers can rejoin because they are already in the game.
|
// This is a shitty fix. Observers can rejoin because they are already in the game.
|
||||||
// So we don't delete them, but keep them if they decide to rejoin
|
// So we don't delete them, but keep them if they decide to rejoin
|
||||||
if (p.Value != PlayerStatus.Observer)
|
if (p.Value != LobbyPlayerStatus.Observer)
|
||||||
_clientGameTicker.Status.Remove(p.Key);
|
gameTicker.Status.Remove(p.Key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +199,7 @@ namespace Content.Client.Lobby
|
|||||||
|
|
||||||
private void LobbyLateJoinStatusUpdated()
|
private void LobbyLateJoinStatusUpdated()
|
||||||
{
|
{
|
||||||
_lobby.ReadyButton.Disabled = _clientGameTicker.DisallowedLateJoin;
|
_lobby.ReadyButton.Disabled = EntitySystem.Get<ClientGameTicker>().DisallowedLateJoin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateLobbyUi()
|
private void UpdateLobbyUi()
|
||||||
@@ -212,7 +209,9 @@ namespace Content.Client.Lobby
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_clientGameTicker.IsGameStarted)
|
var gameTicker = EntitySystem.Get<ClientGameTicker>();
|
||||||
|
|
||||||
|
if (gameTicker.IsGameStarted)
|
||||||
{
|
{
|
||||||
_lobby.ReadyButton.Text = Loc.GetString("Join");
|
_lobby.ReadyButton.Text = Loc.GetString("Join");
|
||||||
_lobby.ReadyButton.ToggleMode = false;
|
_lobby.ReadyButton.ToggleMode = false;
|
||||||
@@ -224,36 +223,37 @@ namespace Content.Client.Lobby
|
|||||||
_lobby.ReadyButton.Text = Loc.GetString("Ready Up");
|
_lobby.ReadyButton.Text = Loc.GetString("Ready Up");
|
||||||
_lobby.ReadyButton.ToggleMode = true;
|
_lobby.ReadyButton.ToggleMode = true;
|
||||||
_lobby.ReadyButton.Disabled = false;
|
_lobby.ReadyButton.Disabled = false;
|
||||||
_lobby.ReadyButton.Pressed = _clientGameTicker.AreWeReady;
|
_lobby.ReadyButton.Pressed = gameTicker.AreWeReady;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_clientGameTicker.ServerInfoBlob != null)
|
if (gameTicker.ServerInfoBlob != null)
|
||||||
{
|
{
|
||||||
_lobby.ServerInfo.SetInfoBlob(_clientGameTicker.ServerInfoBlob);
|
_lobby.ServerInfo.SetInfoBlob(gameTicker.ServerInfoBlob);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdatePlayerList()
|
private void UpdatePlayerList()
|
||||||
{
|
{
|
||||||
_lobby.OnlinePlayerList.Clear();
|
_lobby.OnlinePlayerList.Clear();
|
||||||
|
var gameTicker = EntitySystem.Get<ClientGameTicker>();
|
||||||
|
|
||||||
foreach (var session in _playerManager.Sessions.OrderBy(s => s.Name))
|
foreach (var session in _playerManager.Sessions.OrderBy(s => s.Name))
|
||||||
{
|
{
|
||||||
var readyState = "";
|
var readyState = "";
|
||||||
// Don't show ready state if we're ingame
|
// Don't show ready state if we're ingame
|
||||||
if (!_clientGameTicker.IsGameStarted)
|
if (!gameTicker.IsGameStarted)
|
||||||
{
|
{
|
||||||
PlayerStatus status;
|
LobbyPlayerStatus status;
|
||||||
if (session.UserId == _playerManager.LocalPlayer?.UserId)
|
if (session.UserId == _playerManager.LocalPlayer?.UserId)
|
||||||
status = _clientGameTicker.AreWeReady ? PlayerStatus.Ready : PlayerStatus.NotReady;
|
status = gameTicker.AreWeReady ? LobbyPlayerStatus.Ready : LobbyPlayerStatus.NotReady;
|
||||||
else
|
else
|
||||||
_clientGameTicker.Status.TryGetValue(session.UserId, out status);
|
gameTicker.Status.TryGetValue(session.UserId, out status);
|
||||||
|
|
||||||
readyState = status switch
|
readyState = status switch
|
||||||
{
|
{
|
||||||
PlayerStatus.NotReady => Loc.GetString("Not Ready"),
|
LobbyPlayerStatus.NotReady => Loc.GetString("Not Ready"),
|
||||||
PlayerStatus.Ready => Loc.GetString("Ready"),
|
LobbyPlayerStatus.Ready => Loc.GetString("Ready"),
|
||||||
PlayerStatus.Observer => Loc.GetString("Observer"),
|
LobbyPlayerStatus.Observer => Loc.GetString("Observer"),
|
||||||
_ => "",
|
_ => "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -264,7 +264,7 @@ namespace Content.Client.Lobby
|
|||||||
|
|
||||||
private void SetReady(bool newReady)
|
private void SetReady(bool newReady)
|
||||||
{
|
{
|
||||||
if (_clientGameTicker.IsGameStarted)
|
if (EntitySystem.Get<ClientGameTicker>().IsGameStarted)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Client.Message;
|
using Content.Client.Message;
|
||||||
|
using Content.Shared.GameTicking;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
@@ -15,7 +16,7 @@ namespace Content.Client.RoundEnd
|
|||||||
private VBoxContainer PlayerManifestoTab { get; }
|
private VBoxContainer PlayerManifestoTab { get; }
|
||||||
private TabContainer RoundEndWindowTabs { get; }
|
private TabContainer RoundEndWindowTabs { get; }
|
||||||
|
|
||||||
public RoundEndSummaryWindow(string gm, string roundEnd, TimeSpan roundTimeSpan, List<RoundEndPlayerInfo> info)
|
public RoundEndSummaryWindow(string gm, string roundEnd, TimeSpan roundTimeSpan, RoundEndMessageEvent.RoundEndPlayerInfo[] info)
|
||||||
{
|
{
|
||||||
MinSize = SetSize = (520, 580);
|
MinSize = SetSize = (520, 580);
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ using Content.Client.Parallax.Managers;
|
|||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
using Content.Server.IoC;
|
using Content.Server.IoC;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Robust.Server.Maps;
|
using Robust.Server.Maps;
|
||||||
using Robust.Shared;
|
using Robust.Shared;
|
||||||
using Robust.Shared.ContentPack;
|
using Robust.Shared.ContentPack;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Log;
|
using Robust.Shared.Log;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
@@ -57,7 +59,7 @@ namespace Content.IntegrationTests
|
|||||||
|
|
||||||
// Connecting to Discord is a massive waste of time.
|
// Connecting to Discord is a massive waste of time.
|
||||||
// Basically just makes the CI logs a mess.
|
// Basically just makes the CI logs a mess.
|
||||||
options.CVarOverrides["discord.enabled"] = "false";
|
options.CVarOverrides[CVars.DiscordEnabled.Name] = "false";
|
||||||
|
|
||||||
// Avoid preloading textures in tests.
|
// Avoid preloading textures in tests.
|
||||||
options.CVarOverrides.TryAdd(CVars.TexturePreloadingEnabled.Name, "false");
|
options.CVarOverrides.TryAdd(CVars.TexturePreloadingEnabled.Name, "false");
|
||||||
@@ -112,16 +114,9 @@ namespace Content.IntegrationTests
|
|||||||
protected ServerIntegrationInstance StartServerDummyTicker(ServerIntegrationOptions options = null)
|
protected ServerIntegrationInstance StartServerDummyTicker(ServerIntegrationOptions options = null)
|
||||||
{
|
{
|
||||||
options ??= new ServerIntegrationOptions();
|
options ??= new ServerIntegrationOptions();
|
||||||
options.BeforeStart += () =>
|
|
||||||
{
|
// Dummy game ticker.
|
||||||
IoCManager.Resolve<IModLoader>().SetModuleBaseCallbacks(new ServerModuleTestingCallbacks
|
options.CVarOverrides[CCVars.GameDummyTicker.Name] = "true";
|
||||||
{
|
|
||||||
ServerBeforeIoC = () =>
|
|
||||||
{
|
|
||||||
IoCManager.Register<IGameTicker, DummyGameTicker>(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return StartServer(options);
|
return StartServer(options);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,140 +0,0 @@
|
|||||||
#nullable enable
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using Content.Server.GameTicking;
|
|
||||||
using Content.Server.GameTicking.Rules;
|
|
||||||
using Content.Server.Mind;
|
|
||||||
using Content.Shared.Preferences;
|
|
||||||
using Content.Shared.Roles;
|
|
||||||
using Robust.Server.Player;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
namespace Content.IntegrationTests
|
|
||||||
{
|
|
||||||
public class DummyGameTicker : GameTickerBase, IGameTicker
|
|
||||||
{
|
|
||||||
public GameRunLevel RunLevel { get; } = GameRunLevel.InRound;
|
|
||||||
|
|
||||||
public MapId DefaultMap { get; } = MapId.Nullspace;
|
|
||||||
public GridId DefaultGridId { get; } = GridId.Invalid;
|
|
||||||
|
|
||||||
public event Action<GameRunLevelChangedEventArgs> OnRunLevelChanged
|
|
||||||
{
|
|
||||||
add { }
|
|
||||||
remove { }
|
|
||||||
}
|
|
||||||
|
|
||||||
public event Action<GameRuleAddedEventArgs> OnRuleAdded
|
|
||||||
{
|
|
||||||
add{ }
|
|
||||||
remove { }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update(FrameEventArgs frameEventArgs)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RestartRound()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StartRound(bool force = false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EndRound(string roundEnd)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Respawn(IPlayerSession targetPlayer)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool OnGhostAttempt(Mind mind, bool canReturnGlobal)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MakeObserve(IPlayerSession player)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MakeJoinGame(IPlayerSession player, string? jobId)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ToggleReady(IPlayerSession player, bool ready)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ToggleDisallowLateJoin(bool disallowLateJoin)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityCoordinates GetLateJoinSpawnPoint() => EntityCoordinates.Invalid;
|
|
||||||
public EntityCoordinates GetJobSpawnPoint(string jobId) => EntityCoordinates.Invalid;
|
|
||||||
public EntityCoordinates GetObserverSpawnPoint() => EntityCoordinates.Invalid;
|
|
||||||
|
|
||||||
public void EquipStartingGear(IEntity entity, StartingGearPrototype startingGear, HumanoidCharacterProfile? profile)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public T AddGameRule<T>() where T : GameRule, new()
|
|
||||||
{
|
|
||||||
return new();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasGameRule(string? type)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasGameRule(Type? type)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveGameRule(GameRule rule)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<GameRule> ActiveGameRules { get; } = Array.Empty<GameRule>();
|
|
||||||
|
|
||||||
public bool TryGetPreset(string name, [NotNullWhen(true)] out Type? type)
|
|
||||||
{
|
|
||||||
type = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetStartPreset(Type type, bool force = false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetStartPreset(string name, bool force = false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DelayStart(TimeSpan time)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool PauseStart(bool pause = true)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TogglePause()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<string, int> GetAvailablePositions()
|
|
||||||
{
|
|
||||||
return new();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -24,9 +24,9 @@ namespace Content.IntegrationTests.Tests.Commands
|
|||||||
|
|
||||||
await server.WaitIdleAsync();
|
await server.WaitIdleAsync();
|
||||||
|
|
||||||
var gameTicker = server.ResolveDependency<IGameTicker>();
|
|
||||||
var configManager = server.ResolveDependency<IConfigurationManager>();
|
var configManager = server.ResolveDependency<IConfigurationManager>();
|
||||||
var entityManager = server.ResolveDependency<IEntityManager>();
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
|
var gameTicker = entityManager.EntitySysManager.GetEntitySystem<GameTicker>();
|
||||||
|
|
||||||
await server.WaitRunTicks(30);
|
await server.WaitRunTicks(30);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
|
|||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
using Content.Server.GameTicking.Rules;
|
using Content.Server.GameTicking.Rules;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.IntegrationTests.Tests.GameRules
|
namespace Content.IntegrationTests.Tests.GameRules
|
||||||
@@ -25,7 +26,7 @@ namespace Content.IntegrationTests.Tests.GameRules
|
|||||||
|
|
||||||
await server.WaitIdleAsync();
|
await server.WaitIdleAsync();
|
||||||
|
|
||||||
var sGameTicker = server.ResolveDependency<IGameTicker>();
|
var sGameTicker = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<GameTicker>();
|
||||||
var sGameTiming = server.ResolveDependency<IGameTiming>();
|
var sGameTiming = server.ResolveDependency<IGameTiming>();
|
||||||
|
|
||||||
RuleMaxTimeRestart maxTimeRule = null;
|
RuleMaxTimeRestart maxTimeRule = null;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using Content.Shared.Preferences;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Robust.Client.State;
|
using Robust.Client.State;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
namespace Content.IntegrationTests.Tests.Lobby
|
namespace Content.IntegrationTests.Tests.Lobby
|
||||||
@@ -32,7 +33,7 @@ namespace Content.IntegrationTests.Tests.Lobby
|
|||||||
var clientPrefManager = client.ResolveDependency<IClientPreferencesManager>();
|
var clientPrefManager = client.ResolveDependency<IClientPreferencesManager>();
|
||||||
|
|
||||||
var serverConfig = server.ResolveDependency<IConfigurationManager>();
|
var serverConfig = server.ResolveDependency<IConfigurationManager>();
|
||||||
var serverTicker = server.ResolveDependency<IGameTicker>();
|
var serverTicker = server.ResolveDependency<IEntitySystemManager>().GetEntitySystem<GameTicker>();
|
||||||
var serverPrefManager = server.ResolveDependency<IServerPreferencesManager>();
|
var serverPrefManager = server.ResolveDependency<IServerPreferencesManager>();
|
||||||
|
|
||||||
await server.WaitIdleAsync();
|
await server.WaitIdleAsync();
|
||||||
@@ -40,12 +41,16 @@ namespace Content.IntegrationTests.Tests.Lobby
|
|||||||
|
|
||||||
await server.WaitAssertion(() =>
|
await server.WaitAssertion(() =>
|
||||||
{
|
{
|
||||||
|
serverConfig.SetCVar(CCVars.GameDummyTicker, false);
|
||||||
serverConfig.SetCVar(CCVars.GameLobbyEnabled, true);
|
serverConfig.SetCVar(CCVars.GameLobbyEnabled, true);
|
||||||
serverTicker.RestartRound();
|
serverTicker.RestartRound();
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.That(serverTicker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby));
|
Assert.That(serverTicker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby));
|
||||||
|
|
||||||
|
// Need to run them in sync to receive the messages.
|
||||||
|
await RunTicksSync(client, server, 1);
|
||||||
|
|
||||||
await WaitUntil(client, () => clientStateManager.CurrentState is LobbyState, maxTicks: 60);
|
await WaitUntil(client, () => clientStateManager.CurrentState is LobbyState, maxTicks: 60);
|
||||||
|
|
||||||
Assert.NotNull(clientNetManager.ServerChannel);
|
Assert.NotNull(clientNetManager.ServerChannel);
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ namespace Content.IntegrationTests.Tests
|
|||||||
|
|
||||||
await server.WaitIdleAsync();
|
await server.WaitIdleAsync();
|
||||||
|
|
||||||
var gameTicker = server.ResolveDependency<IGameTicker>();
|
|
||||||
var entitySystemManager = server.ResolveDependency<IEntitySystemManager>();
|
var entitySystemManager = server.ResolveDependency<IEntitySystemManager>();
|
||||||
|
var gameTicker = entitySystemManager.GetEntitySystem<GameTicker>();
|
||||||
|
|
||||||
await server.WaitAssertion(() =>
|
await server.WaitAssertion(() =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.IntegrationTests.Tests
|
namespace Content.IntegrationTests.Tests
|
||||||
@@ -15,7 +16,7 @@ namespace Content.IntegrationTests.Tests
|
|||||||
|
|
||||||
server.Post(() =>
|
server.Post(() =>
|
||||||
{
|
{
|
||||||
IoCManager.Resolve<IGameTicker>().RestartRound();
|
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<GameTicker>().RestartRound();
|
||||||
});
|
});
|
||||||
|
|
||||||
await RunTicksSync(client, server, 10);
|
await RunTicksSync(client, server, 10);
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ namespace Content.Server.AI.Components
|
|||||||
|
|
||||||
if (StartingGearPrototype != null)
|
if (StartingGearPrototype != null)
|
||||||
{
|
{
|
||||||
var gameTicker = IoCManager.Resolve<IGameTicker>();
|
var gameTicker = EntitySystem.Get<GameTicker>();
|
||||||
var protoManager = IoCManager.Resolve<IPrototypeManager>();
|
var protoManager = IoCManager.Resolve<IPrototypeManager>();
|
||||||
|
|
||||||
var startingGear = protoManager.Index<StartingGearPrototype>(StartingGearPrototype);
|
var startingGear = protoManager.Index<StartingGearPrototype>(StartingGearPrototype);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace Content.Server.Administration.Commands
|
|||||||
var canReturn = mind.CurrentEntity != null;
|
var canReturn = mind.CurrentEntity != null;
|
||||||
var ghost = IoCManager.Resolve<IEntityManager>()
|
var ghost = IoCManager.Resolve<IEntityManager>()
|
||||||
.SpawnEntity("AdminObserver", player.AttachedEntity?.Transform.Coordinates
|
.SpawnEntity("AdminObserver", player.AttachedEntity?.Transform.Coordinates
|
||||||
?? IoCManager.Resolve<IGameTicker>().GetObserverSpawnPoint());
|
?? EntitySystem.Get<GameTicker>().GetObserverSpawnPoint());
|
||||||
|
|
||||||
if (canReturn)
|
if (canReturn)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Content.Server.GameTicking;
|
|||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.Administration.Commands
|
namespace Content.Server.Administration.Commands
|
||||||
@@ -22,7 +23,7 @@ namespace Content.Server.Administration.Commands
|
|||||||
ready = bool.Parse(args[0]);
|
ready = bool.Parse(args[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var gameTicker = IoCManager.Resolve<IGameTicker>();
|
var gameTicker = EntitySystem.Get<GameTicker>();
|
||||||
var playerManager = IoCManager.Resolve<IPlayerManager>();
|
var playerManager = IoCManager.Resolve<IPlayerManager>();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ namespace Content.Server.Body
|
|||||||
public class BodyComponent : SharedBodyComponent, IRelayMoveInput, IGhostOnMove
|
public class BodyComponent : SharedBodyComponent, IRelayMoveInput, IGhostOnMove
|
||||||
{
|
{
|
||||||
private Container _partContainer = default!;
|
private Container _partContainer = default!;
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
|
||||||
|
|
||||||
protected override bool CanAddPart(string slotId, SharedBodyPartComponent part)
|
protected override bool CanAddPart(string slotId, SharedBodyPartComponent part)
|
||||||
{
|
{
|
||||||
@@ -94,7 +93,7 @@ namespace Content.Server.Body
|
|||||||
Owner.TryGetComponent(out MindComponent? mind) &&
|
Owner.TryGetComponent(out MindComponent? mind) &&
|
||||||
mind.HasMind)
|
mind.HasMind)
|
||||||
{
|
{
|
||||||
_gameTicker.OnGhostAttempt(mind.Mind!, true);
|
EntitySystem.Get<GameTicker>().OnGhostAttempt(mind.Mind!, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ namespace Content.Server.Chat.Commands
|
|||||||
|
|
||||||
// Prevent the player from returning to the body.
|
// Prevent the player from returning to the body.
|
||||||
// Note that mind cannot be null because otherwise owner would be null.
|
// Note that mind cannot be null because otherwise owner would be null.
|
||||||
IoCManager.Resolve<IGameTicker>().OnGhostAttempt(mind!, false);
|
EntitySystem.Get<GameTicker>().OnGhostAttempt(mind!, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ using Content.Server.Notification.Managers;
|
|||||||
using Content.Server.PDA.Managers;
|
using Content.Server.PDA.Managers;
|
||||||
using Content.Server.Preferences.Managers;
|
using Content.Server.Preferences.Managers;
|
||||||
using Content.Server.Sandbox;
|
using Content.Server.Sandbox;
|
||||||
using Content.Server.Shell;
|
|
||||||
using Content.Server.Speech;
|
using Content.Server.Speech;
|
||||||
using Content.Server.Voting.Managers;
|
using Content.Server.Voting.Managers;
|
||||||
using Content.Shared.Actions;
|
using Content.Shared.Actions;
|
||||||
@@ -31,9 +30,7 @@ namespace Content.Server.Entry
|
|||||||
{
|
{
|
||||||
public class EntryPoint : GameServer
|
public class EntryPoint : GameServer
|
||||||
{
|
{
|
||||||
private IGameTicker _gameTicker = default!;
|
|
||||||
private EuiManager _euiManager = default!;
|
private EuiManager _euiManager = default!;
|
||||||
private StatusShell _statusShell = default!;
|
|
||||||
private IVoteManager _voteManager = default!;
|
private IVoteManager _voteManager = default!;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -60,7 +57,6 @@ namespace Content.Server.Entry
|
|||||||
|
|
||||||
IoCManager.BuildGraph();
|
IoCManager.BuildGraph();
|
||||||
|
|
||||||
_gameTicker = IoCManager.Resolve<IGameTicker>();
|
|
||||||
_euiManager = IoCManager.Resolve<EuiManager>();
|
_euiManager = IoCManager.Resolve<EuiManager>();
|
||||||
_voteManager = IoCManager.Resolve<IVoteManager>();
|
_voteManager = IoCManager.Resolve<IVoteManager>();
|
||||||
|
|
||||||
@@ -69,8 +65,6 @@ namespace Content.Server.Entry
|
|||||||
|
|
||||||
var playerManager = IoCManager.Resolve<IPlayerManager>();
|
var playerManager = IoCManager.Resolve<IPlayerManager>();
|
||||||
|
|
||||||
_statusShell = new StatusShell();
|
|
||||||
|
|
||||||
var logManager = IoCManager.Resolve<ILogManager>();
|
var logManager = IoCManager.Resolve<ILogManager>();
|
||||||
logManager.GetSawmill("Storage").Level = LogLevel.Info;
|
logManager.GetSawmill("Storage").Level = LogLevel.Info;
|
||||||
logManager.GetSawmill("db.ef").Level = LogLevel.Info;
|
logManager.GetSawmill("db.ef").Level = LogLevel.Info;
|
||||||
@@ -79,7 +73,6 @@ namespace Content.Server.Entry
|
|||||||
IoCManager.Resolve<IServerDbManager>().Init();
|
IoCManager.Resolve<IServerDbManager>().Init();
|
||||||
IoCManager.Resolve<IServerPreferencesManager>().Init();
|
IoCManager.Resolve<IServerPreferencesManager>().Init();
|
||||||
IoCManager.Resolve<INodeGroupFactory>().Initialize();
|
IoCManager.Resolve<INodeGroupFactory>().Initialize();
|
||||||
IoCManager.Resolve<ISandboxManager>().Initialize();
|
|
||||||
IoCManager.Resolve<IAccentManager>().Initialize();
|
IoCManager.Resolve<IAccentManager>().Initialize();
|
||||||
_voteManager.Initialize();
|
_voteManager.Initialize();
|
||||||
}
|
}
|
||||||
@@ -89,7 +82,7 @@ namespace Content.Server.Entry
|
|||||||
base.PostInit();
|
base.PostInit();
|
||||||
|
|
||||||
IoCManager.Resolve<IHolidayManager>().Initialize();
|
IoCManager.Resolve<IHolidayManager>().Initialize();
|
||||||
_gameTicker.Initialize();
|
IoCManager.Resolve<ISandboxManager>().Initialize();
|
||||||
IoCManager.Resolve<RecipeManager>().Initialize();
|
IoCManager.Resolve<RecipeManager>().Initialize();
|
||||||
IoCManager.Resolve<AlertManager>().Initialize();
|
IoCManager.Resolve<AlertManager>().Initialize();
|
||||||
IoCManager.Resolve<ActionManager>().Initialize();
|
IoCManager.Resolve<ActionManager>().Initialize();
|
||||||
@@ -99,6 +92,8 @@ namespace Content.Server.Entry
|
|||||||
IoCManager.Resolve<IAdminManager>().Initialize();
|
IoCManager.Resolve<IAdminManager>().Initialize();
|
||||||
IoCManager.Resolve<INpcBehaviorManager>().Initialize();
|
IoCManager.Resolve<INpcBehaviorManager>().Initialize();
|
||||||
_euiManager.Initialize();
|
_euiManager.Initialize();
|
||||||
|
|
||||||
|
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<GameTicker>().PostInitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(ModUpdateLevel level, FrameEventArgs frameEventArgs)
|
public override void Update(ModUpdateLevel level, FrameEventArgs frameEventArgs)
|
||||||
@@ -107,11 +102,6 @@ namespace Content.Server.Entry
|
|||||||
|
|
||||||
switch (level)
|
switch (level)
|
||||||
{
|
{
|
||||||
case ModUpdateLevel.PreEngine:
|
|
||||||
{
|
|
||||||
_gameTicker.Update(frameEventArgs);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ModUpdateLevel.PostEngine:
|
case ModUpdateLevel.PostEngine:
|
||||||
{
|
{
|
||||||
_euiManager.SendUpdates();
|
_euiManager.SendUpdates();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using Content.Server.Administration;
|
using Content.Server.Administration;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Commands
|
namespace Content.Server.GameTicking.Commands
|
||||||
@@ -15,7 +16,7 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
|
|
||||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
var ticker = IoCManager.Resolve<IGameTicker>();
|
var ticker = EntitySystem.Get<GameTicker>();
|
||||||
if (ticker.RunLevel != GameRunLevel.PreRoundLobby)
|
if (ticker.RunLevel != GameRunLevel.PreRoundLobby)
|
||||||
{
|
{
|
||||||
shell.WriteLine("This can only be executed while the game is in the pre-round lobby.");
|
shell.WriteLine("This can only be executed while the game is in the pre-round lobby.");
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using Content.Server.Administration;
|
using Content.Server.Administration;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Commands
|
namespace Content.Server.GameTicking.Commands
|
||||||
@@ -15,7 +16,7 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
|
|
||||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
var ticker = IoCManager.Resolve<IGameTicker>();
|
var ticker = EntitySystem.Get<GameTicker>();
|
||||||
|
|
||||||
if (ticker.RunLevel != GameRunLevel.InRound)
|
if (ticker.RunLevel != GameRunLevel.InRound)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Content.Server.Administration;
|
using Content.Server.Administration;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Commands
|
namespace Content.Server.GameTicking.Commands
|
||||||
@@ -14,7 +15,7 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
|
|
||||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
var ticker = IoCManager.Resolve<IGameTicker>();
|
var ticker = EntitySystem.Get<GameTicker>();
|
||||||
if (ticker.RunLevel != GameRunLevel.PreRoundLobby)
|
if (ticker.RunLevel != GameRunLevel.PreRoundLobby)
|
||||||
{
|
{
|
||||||
shell.WriteLine("This can only be executed while the game is in the pre-round lobby.");
|
shell.WriteLine("This can only be executed while the game is in the pre-round lobby.");
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Content.Shared.Administration;
|
|||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Commands
|
namespace Content.Server.GameTicking.Commands
|
||||||
@@ -21,7 +22,7 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
Type? preset = null;
|
Type? preset = null;
|
||||||
var presetName = string.Join(" ", args);
|
var presetName = string.Join(" ", args);
|
||||||
|
|
||||||
var ticker = IoCManager.Resolve<IGameTicker>();
|
var ticker = EntitySystem.Get<GameTicker>();
|
||||||
|
|
||||||
if (args.Length > 0)
|
if (args.Length > 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Content.Server.Administration;
|
|||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ticker = IoCManager.Resolve<IGameTicker>();
|
var ticker = EntitySystem.Get<GameTicker>();
|
||||||
if (ticker.RunLevel == GameRunLevel.PreRoundLobby)
|
if (ticker.RunLevel == GameRunLevel.PreRoundLobby)
|
||||||
{
|
{
|
||||||
shell.WriteLine("Round has not started.");
|
shell.WriteLine("Round has not started.");
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using Content.Server.Administration;
|
using Content.Server.Administration;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Commands
|
namespace Content.Server.GameTicking.Commands
|
||||||
@@ -15,7 +16,7 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
|
|
||||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
var ticker = IoCManager.Resolve<IGameTicker>();
|
var ticker = EntitySystem.Get<GameTicker>();
|
||||||
ticker.RestartRound();
|
ticker.RestartRound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Content.Server.Administration;
|
using Content.Server.Administration;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Commands
|
namespace Content.Server.GameTicking.Commands
|
||||||
@@ -20,7 +21,7 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ticker = IoCManager.Resolve<IGameTicker>();
|
var ticker = EntitySystem.Get<GameTicker>();
|
||||||
ticker.MakeObserve(player);
|
ticker.MakeObserve(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
}
|
}
|
||||||
|
|
||||||
var playerMgr = IoCManager.Resolve<IPlayerManager>();
|
var playerMgr = IoCManager.Resolve<IPlayerManager>();
|
||||||
var ticker = IoCManager.Resolve<IGameTicker>();
|
var ticker = EntitySystem.Get<GameTicker>();
|
||||||
|
|
||||||
NetUserId userId;
|
NetUserId userId;
|
||||||
if (args.Length == 0)
|
if (args.Length == 0)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Content.Server.Administration;
|
using Content.Server.Administration;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Commands
|
namespace Content.Server.GameTicking.Commands
|
||||||
@@ -20,7 +21,7 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ticker = IoCManager.Resolve<IGameTicker>();
|
var ticker = EntitySystem.Get<GameTicker>();
|
||||||
|
|
||||||
ticker.SetStartPreset(args[0]);
|
ticker.SetStartPreset(args[0]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using Content.Server.Administration;
|
using Content.Server.Administration;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Commands
|
namespace Content.Server.GameTicking.Commands
|
||||||
@@ -15,7 +16,7 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
|
|
||||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
var ticker = IoCManager.Resolve<IGameTicker>();
|
var ticker = EntitySystem.Get<GameTicker>();
|
||||||
|
|
||||||
if (ticker.RunLevel != GameRunLevel.PreRoundLobby)
|
if (ticker.RunLevel != GameRunLevel.PreRoundLobby)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
using Content.Server.Administration;
|
using Content.Server.Administration;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Commands
|
namespace Content.Server.GameTicking.Commands
|
||||||
@@ -20,11 +23,11 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ticker = IoCManager.Resolve<IGameTicker>();
|
var cfgMan = IoCManager.Resolve<IConfigurationManager>();
|
||||||
|
|
||||||
if (bool.TryParse(args[0], out var result))
|
if (bool.TryParse(args[0], out var result))
|
||||||
{
|
{
|
||||||
ticker.ToggleDisallowLateJoin(bool.Parse(args[0]));
|
cfgMan.SetCVar(CCVars.GameDisallowLateJoins, bool.Parse(args[0]));
|
||||||
shell.WriteLine(result ? "Late joining has been disabled." : "Late joining has been enabled.");
|
shell.WriteLine(result ? "Late joining has been disabled." : "Late joining has been enabled.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Content.Server.Administration;
|
using Content.Server.Administration;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Commands
|
namespace Content.Server.GameTicking.Commands
|
||||||
@@ -20,7 +21,7 @@ namespace Content.Server.GameTicking.Commands
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ticker = IoCManager.Resolve<IGameTicker>();
|
var ticker = EntitySystem.Get<GameTicker>();
|
||||||
ticker.ToggleReady(player, bool.Parse(args[0]));
|
ticker.ToggleReady(player, bool.Parse(args[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
34
Content.Server/GameTicking/GameTicker.CVars.cs
Normal file
34
Content.Server/GameTicking/GameTicker.CVars.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameTicking
|
||||||
|
{
|
||||||
|
public partial class GameTicker
|
||||||
|
{
|
||||||
|
[ViewVariables]
|
||||||
|
public bool LobbyEnabled { get; private set; } = false;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public bool DummyTicker { get; private set; } = false;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public string ChosenMap { get; private set; } = string.Empty;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public TimeSpan LobbyDuration { get; private set; } = TimeSpan.Zero;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public bool DisallowLateJoin { get; private set; } = false;
|
||||||
|
|
||||||
|
private void InitializeCVars()
|
||||||
|
{
|
||||||
|
_configurationManager.OnValueChanged(CCVars.GameLobbyEnabled, value => LobbyEnabled = value, true);
|
||||||
|
_configurationManager.OnValueChanged(CCVars.GameDummyTicker, value => DummyTicker = value, true);
|
||||||
|
_configurationManager.OnValueChanged(CCVars.GameMap, value => ChosenMap = value, true);
|
||||||
|
_configurationManager.OnValueChanged(CCVars.GameLobbyDuration, value => LobbyDuration = TimeSpan.FromSeconds(value), true);
|
||||||
|
_configurationManager.OnValueChanged(CCVars.GameDisallowLateJoins, invokeImmediately:true,
|
||||||
|
onValueChanged:value => { DisallowLateJoin = value; UpdateLateJoinStatus(); UpdateJobsAvailable(); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
98
Content.Server/GameTicking/GameTicker.GamePreset.cs
Normal file
98
Content.Server/GameTicking/GameTicker.GamePreset.cs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Reflection;
|
||||||
|
using Content.Server.GameTicking.Presets;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Shared.Preferences;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
|
namespace Content.Server.GameTicking
|
||||||
|
{
|
||||||
|
public partial class GameTicker
|
||||||
|
{
|
||||||
|
public const float PresetFailedCooldownIncrease = 30f;
|
||||||
|
|
||||||
|
[ViewVariables] private Type? _presetType;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public GamePreset? Preset
|
||||||
|
{
|
||||||
|
get => _preset ?? MakeGamePreset(new Dictionary<NetUserId, HumanoidCharacterProfile>());
|
||||||
|
set => _preset = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImmutableDictionary<string, Type> Presets { get; private set; } = default!;
|
||||||
|
|
||||||
|
private GamePreset? _preset;
|
||||||
|
|
||||||
|
private void InitializeGamePreset()
|
||||||
|
{
|
||||||
|
var presets = new Dictionary<string, Type>();
|
||||||
|
|
||||||
|
foreach (var type in _reflectionManager.FindTypesWithAttribute<GamePresetAttribute>())
|
||||||
|
{
|
||||||
|
var attribute = type.GetCustomAttribute<GamePresetAttribute>();
|
||||||
|
|
||||||
|
presets.Add(attribute!.Id.ToLowerInvariant(), type);
|
||||||
|
|
||||||
|
foreach (var alias in attribute.Aliases)
|
||||||
|
{
|
||||||
|
presets.Add(alias.ToLowerInvariant(), type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Presets = presets.ToImmutableDictionary();
|
||||||
|
|
||||||
|
SetStartPreset(_configurationManager.GetCVar(CCVars.GameLobbyDefaultPreset));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnGhostAttempt(Mind.Mind mind, bool canReturnGlobal)
|
||||||
|
{
|
||||||
|
return Preset?.OnGhostAttempt(mind, canReturnGlobal) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetPreset(string name, [NotNullWhen(true)] out Type? type)
|
||||||
|
{
|
||||||
|
name = name.ToLowerInvariant();
|
||||||
|
return Presets.TryGetValue(name, out type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetStartPreset(Type type, bool force = false)
|
||||||
|
{
|
||||||
|
// Do nothing if this game ticker is a dummy!
|
||||||
|
if (DummyTicker)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!typeof(GamePreset).IsAssignableFrom(type)) throw new ArgumentException("type must inherit GamePreset");
|
||||||
|
|
||||||
|
_presetType = type;
|
||||||
|
UpdateInfoText();
|
||||||
|
|
||||||
|
if (force)
|
||||||
|
{
|
||||||
|
StartRound(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetStartPreset(string name, bool force = false)
|
||||||
|
{
|
||||||
|
if (!TryGetPreset(name, out var type))
|
||||||
|
{
|
||||||
|
throw new NotSupportedException($"No preset found with name {name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
SetStartPreset(type, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
private GamePreset MakeGamePreset(Dictionary<NetUserId, HumanoidCharacterProfile> readyProfiles)
|
||||||
|
{
|
||||||
|
var preset = _dynamicTypeFactory.CreateInstance<GamePreset>(_presetType ?? typeof(PresetSandbox));
|
||||||
|
preset.ReadyProfiles = readyProfiles;
|
||||||
|
return preset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
74
Content.Server/GameTicking/GameTicker.GameRule.cs
Normal file
74
Content.Server/GameTicking/GameTicker.GameRule.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Server.GameTicking.Rules;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameTicking
|
||||||
|
{
|
||||||
|
public partial class GameTicker
|
||||||
|
{
|
||||||
|
[ViewVariables] private readonly List<GameRule> _gameRules = new();
|
||||||
|
public IEnumerable<GameRule> ActiveGameRules => _gameRules;
|
||||||
|
|
||||||
|
public T AddGameRule<T>() where T : GameRule, new()
|
||||||
|
{
|
||||||
|
var instance = _dynamicTypeFactory.CreateInstance<T>();
|
||||||
|
|
||||||
|
_gameRules.Add(instance);
|
||||||
|
instance.Added();
|
||||||
|
|
||||||
|
RaiseLocalEvent(new GameRuleAddedEvent(instance));
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasGameRule(string? name)
|
||||||
|
{
|
||||||
|
if (name == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach (var rule in _gameRules)
|
||||||
|
{
|
||||||
|
if (rule.GetType().Name == name)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasGameRule(Type? type)
|
||||||
|
{
|
||||||
|
if (type == null || !typeof(GameRule).IsAssignableFrom(type))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
foreach (var rule in _gameRules)
|
||||||
|
{
|
||||||
|
if (rule.GetType().IsAssignableFrom(type))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveGameRule(GameRule rule)
|
||||||
|
{
|
||||||
|
if (_gameRules.Contains(rule)) return;
|
||||||
|
|
||||||
|
rule.Removed();
|
||||||
|
|
||||||
|
_gameRules.Remove(rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GameRuleAddedEvent
|
||||||
|
{
|
||||||
|
public GameRule Rule { get; }
|
||||||
|
|
||||||
|
public GameRuleAddedEvent(GameRule rule)
|
||||||
|
{
|
||||||
|
Rule = rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,11 +3,13 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
@@ -17,6 +19,9 @@ namespace Content.Server.GameTicking
|
|||||||
// This code is responsible for the assigning & picking of jobs.
|
// This code is responsible for the assigning & picking of jobs.
|
||||||
public partial class GameTicker
|
public partial class GameTicker
|
||||||
{
|
{
|
||||||
|
[ViewVariables]
|
||||||
|
private readonly List<ManifestEntry> _manifest = new();
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private readonly Dictionary<string, int> _spawnedPositions = new();
|
private readonly Dictionary<string, int> _spawnedPositions = new();
|
||||||
|
|
||||||
@@ -187,7 +192,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Conditional("DEBUG")]
|
[Conditional("DEBUG")]
|
||||||
private void JobControllerInit()
|
private void InitializeJobController()
|
||||||
{
|
{
|
||||||
// Verify that the overflow role exists and has the correct name.
|
// Verify that the overflow role exists and has the correct name.
|
||||||
var role = _prototypeManager.Index<JobPrototype>(OverflowJob);
|
var role = _prototypeManager.Index<JobPrototype>(OverflowJob);
|
||||||
@@ -202,10 +207,23 @@ namespace Content.Server.GameTicking
|
|||||||
_spawnedPositions[jobId] = _spawnedPositions.GetValueOrDefault(jobId, 0) + 1;
|
_spawnedPositions[jobId] = _spawnedPositions.GetValueOrDefault(jobId, 0) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TickerJobsAvailableEvent GetJobsAvailable()
|
||||||
|
{
|
||||||
|
// If late join is disallowed, return no available jobs.
|
||||||
|
if (DisallowLateJoin)
|
||||||
|
return new TickerJobsAvailableEvent(Array.Empty<string>());
|
||||||
|
|
||||||
|
var jobs = GetAvailablePositions()
|
||||||
|
.Where(e => e.Value > 0)
|
||||||
|
.Select(e => e.Key)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return new TickerJobsAvailableEvent(jobs);
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateJobsAvailable()
|
private void UpdateJobsAvailable()
|
||||||
{
|
{
|
||||||
var lobbyPlayers = _playersInLobby.Keys.Select(p => p.ConnectedClient).ToList();
|
RaiseNetworkEvent(GetJobsAvailable(), Filter.Empty().AddPlayers(_playersInLobby.Keys));
|
||||||
_netManager.ServerSendToMany(GetJobsAvailable(), lobbyPlayers);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
139
Content.Server/GameTicking/GameTicker.Lobby.cs
Normal file
139
Content.Server/GameTicking/GameTicker.Lobby.cs
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Content.Shared.GameTicking;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Players;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameTicking
|
||||||
|
{
|
||||||
|
public partial class GameTicker
|
||||||
|
{
|
||||||
|
[ViewVariables]
|
||||||
|
private readonly Dictionary<IPlayerSession, LobbyPlayerStatus> _playersInLobby = new();
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private TimeSpan _roundStartTime;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private TimeSpan _pauseTime;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public bool Paused { get; set; }
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private bool _roundStartCountdownHasNotStartedYetDueToNoPlayers;
|
||||||
|
|
||||||
|
private void UpdateInfoText()
|
||||||
|
{
|
||||||
|
RaiseNetworkEvent(GetInfoMsg(), Filter.Empty().AddPlayers(_playersInLobby.Keys));
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetInfoText()
|
||||||
|
{
|
||||||
|
if (Preset == null)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var gmTitle = Preset.ModeTitle;
|
||||||
|
var desc = Preset.Description;
|
||||||
|
return Loc.GetString(@"Hi and welcome to [color=white]Space Station 14![/color]
|
||||||
|
|
||||||
|
The current game mode is: [color=white]{0}[/color].
|
||||||
|
[color=yellow]{1}[/color]", gmTitle, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TickerLobbyReadyEvent GetStatusSingle(ICommonSession player, LobbyPlayerStatus status)
|
||||||
|
{
|
||||||
|
return new (new Dictionary<NetUserId, LobbyPlayerStatus> { { player.UserId, status } });
|
||||||
|
}
|
||||||
|
|
||||||
|
private TickerLobbyReadyEvent GetPlayerStatus()
|
||||||
|
{
|
||||||
|
var players = new Dictionary<NetUserId, LobbyPlayerStatus>();
|
||||||
|
foreach (var player in _playersInLobby.Keys)
|
||||||
|
{
|
||||||
|
_playersInLobby.TryGetValue(player, out var status);
|
||||||
|
players.Add(player.UserId, status);
|
||||||
|
}
|
||||||
|
return new TickerLobbyReadyEvent(players);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TickerLobbyStatusEvent GetStatusMsg(IPlayerSession session)
|
||||||
|
{
|
||||||
|
_playersInLobby.TryGetValue(session, out var status);
|
||||||
|
return new TickerLobbyStatusEvent(RunLevel != GameRunLevel.PreRoundLobby, LobbySong, status == LobbyPlayerStatus.Ready, _roundStartTime, Paused);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendStatusToAll()
|
||||||
|
{
|
||||||
|
foreach (var player in _playersInLobby.Keys)
|
||||||
|
{
|
||||||
|
RaiseNetworkEvent(GetStatusMsg(player), player.ConnectedClient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TickerLobbyInfoEvent GetInfoMsg()
|
||||||
|
{
|
||||||
|
return new (GetInfoText());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateLateJoinStatus()
|
||||||
|
{
|
||||||
|
RaiseNetworkEvent(new TickerLateJoinStatusEvent(DisallowLateJoin));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PauseStart(bool pause = true)
|
||||||
|
{
|
||||||
|
if (Paused == pause)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Paused = pause;
|
||||||
|
|
||||||
|
if (pause)
|
||||||
|
{
|
||||||
|
_pauseTime = _gameTiming.CurTime;
|
||||||
|
}
|
||||||
|
else if (_pauseTime != default)
|
||||||
|
{
|
||||||
|
_roundStartTime += _gameTiming.CurTime - _pauseTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
RaiseNetworkEvent(new TickerLobbyCountdownEvent(_roundStartTime, Paused));
|
||||||
|
|
||||||
|
_chatManager.DispatchServerAnnouncement(Paused
|
||||||
|
? "Round start has been paused."
|
||||||
|
: "Round start countdown is now resumed.");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TogglePause()
|
||||||
|
{
|
||||||
|
PauseStart(!Paused);
|
||||||
|
return Paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToggleReady(IPlayerSession player, bool ready)
|
||||||
|
{
|
||||||
|
if (!_playersInLobby.ContainsKey(player)) return;
|
||||||
|
|
||||||
|
if (!_prefsManager.HavePreferencesLoaded(player))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var status = ready ? LobbyPlayerStatus.Ready : LobbyPlayerStatus.NotReady;
|
||||||
|
_playersInLobby[player] = ready ? LobbyPlayerStatus.Ready : LobbyPlayerStatus.NotReady;
|
||||||
|
RaiseNetworkEvent(GetStatusMsg(player), player.ConnectedClient);
|
||||||
|
RaiseNetworkEvent(GetStatusSingle(player, status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
78
Content.Server/GameTicking/GameTicker.LobbyMusic.cs
Normal file
78
Content.Server/GameTicking/GameTicker.LobbyMusic.cs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
using Content.Shared.Audio;
|
||||||
|
using Robust.Shared.ContentPack;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameTicking
|
||||||
|
{
|
||||||
|
public partial class GameTicker
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IResourceManager _resourceManager = default!;
|
||||||
|
private const string LobbyMusicCollection = "LobbyMusic";
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private bool _lobbyMusicInitialized = false;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private SoundCollectionPrototype _lobbyMusicCollection = default!;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public string? LobbySong { get; private set; }
|
||||||
|
|
||||||
|
private void InitializeLobbyMusic()
|
||||||
|
{
|
||||||
|
DebugTools.Assert(!_lobbyMusicInitialized);
|
||||||
|
_lobbyMusicCollection = _prototypeManager.Index<SoundCollectionPrototype>(LobbyMusicCollection);
|
||||||
|
|
||||||
|
// Now that the collection is set, the lobby music has been initialized and we can choose a random song.
|
||||||
|
_lobbyMusicInitialized = true;
|
||||||
|
|
||||||
|
ChooseRandomLobbySong();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the current lobby song, or stops it if null.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="song">The lobby song to play, or null to stop any lobby songs.</param>
|
||||||
|
public void SetLobbySong(string? song)
|
||||||
|
{
|
||||||
|
DebugTools.Assert(_lobbyMusicInitialized);
|
||||||
|
|
||||||
|
if (song == null)
|
||||||
|
{
|
||||||
|
LobbySong = null;
|
||||||
|
return;
|
||||||
|
// TODO GAMETICKER send song stop event
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_resourceManager.ContentFileExists(song))
|
||||||
|
{
|
||||||
|
Logger.ErrorS("ticker", $"Tried to set lobby song to \"{song}\", which doesn't exist!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LobbySong = song;
|
||||||
|
// TODO GAMETICKER send song change event
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Plays a random song from the LobbyMusic sound collection.
|
||||||
|
/// </summary>
|
||||||
|
public void ChooseRandomLobbySong()
|
||||||
|
{
|
||||||
|
DebugTools.Assert(_lobbyMusicInitialized);
|
||||||
|
SetLobbySong(_robustRandom.Pick(_lobbyMusicCollection.PickFiles));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stops the current lobby song being played.
|
||||||
|
/// </summary>
|
||||||
|
public void StopLobbySong()
|
||||||
|
{
|
||||||
|
SetLobbySong(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
144
Content.Server/GameTicking/GameTicker.Player.cs
Normal file
144
Content.Server/GameTicking/GameTicker.Player.cs
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
using Content.Server.Players;
|
||||||
|
using Content.Shared.GameTicking;
|
||||||
|
using Content.Shared.GameWindow;
|
||||||
|
using Content.Shared.Preferences;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.Enums;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Server.GameTicking
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
public partial class GameTicker
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
|
||||||
|
private void InitializePlayer()
|
||||||
|
{
|
||||||
|
_playerManager.PlayerStatusChanged += PlayerStatusChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayerStatusChanged(object? sender, SessionStatusEventArgs args)
|
||||||
|
{
|
||||||
|
var session = args.Session;
|
||||||
|
|
||||||
|
switch (args.NewStatus)
|
||||||
|
{
|
||||||
|
case SessionStatus.Connecting:
|
||||||
|
// Cancel shutdown update timer in progress.
|
||||||
|
_updateShutdownCts?.Cancel();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SessionStatus.Connected:
|
||||||
|
{
|
||||||
|
// Always make sure the client has player data. Mind gets assigned on spawn.
|
||||||
|
if (session.Data.ContentDataUncast == null)
|
||||||
|
session.Data.ContentDataUncast = new PlayerData(session.UserId);
|
||||||
|
|
||||||
|
// Make the player actually join the game.
|
||||||
|
// timer time must be > tick length
|
||||||
|
Timer.Spawn(0, args.Session.JoinGame);
|
||||||
|
|
||||||
|
_chatManager.SendAdminAnnouncement(Loc.GetString("player-join-message", ("name", args.Session.Name)));
|
||||||
|
|
||||||
|
if (LobbyEnabled && _roundStartCountdownHasNotStartedYetDueToNoPlayers)
|
||||||
|
{
|
||||||
|
_roundStartCountdownHasNotStartedYetDueToNoPlayers = false;
|
||||||
|
_roundStartTime = _gameTiming.CurTime + LobbyDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SessionStatus.InGame:
|
||||||
|
{
|
||||||
|
_prefsManager.OnClientConnected(session);
|
||||||
|
|
||||||
|
var data = session.ContentData();
|
||||||
|
|
||||||
|
DebugTools.AssertNotNull(data);
|
||||||
|
|
||||||
|
if (data!.Mind == null)
|
||||||
|
{
|
||||||
|
if (LobbyEnabled)
|
||||||
|
{
|
||||||
|
PlayerJoinLobby(session);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SpawnWaitPrefs();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (data.Mind.CurrentEntity == null)
|
||||||
|
{
|
||||||
|
SpawnWaitPrefs();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
session.AttachToEntity(data.Mind.CurrentEntity);
|
||||||
|
PlayerJoinGame(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SessionStatus.Disconnected:
|
||||||
|
{
|
||||||
|
if (_playersInLobby.ContainsKey(session)) _playersInLobby.Remove(session);
|
||||||
|
|
||||||
|
_chatManager.SendAdminAnnouncement(Loc.GetString("player-leave-message", ("name", args.Session.Name)));
|
||||||
|
|
||||||
|
ServerEmptyUpdateRestartCheck();
|
||||||
|
_prefsManager.OnClientDisconnected(session);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async void SpawnWaitPrefs()
|
||||||
|
{
|
||||||
|
await _prefsManager.WaitPreferencesLoaded(session);
|
||||||
|
SpawnPlayer(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HumanoidCharacterProfile GetPlayerProfile(IPlayerSession p)
|
||||||
|
{
|
||||||
|
return (HumanoidCharacterProfile) _prefsManager.GetPreferences(p.UserId).SelectedCharacter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayerJoinGame(IPlayerSession session)
|
||||||
|
{
|
||||||
|
_chatManager.DispatchServerMessage(session,
|
||||||
|
"Welcome to Space Station 14! If this is your first time checking out the game, be sure to check out the tutorial in the top left!");
|
||||||
|
|
||||||
|
if (_playersInLobby.ContainsKey(session))
|
||||||
|
_playersInLobby.Remove(session);
|
||||||
|
|
||||||
|
RaiseNetworkEvent(new TickerJoinGameEvent(), session.ConnectedClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlayerJoinLobby(IPlayerSession session)
|
||||||
|
{
|
||||||
|
_playersInLobby[session] = LobbyPlayerStatus.NotReady;
|
||||||
|
|
||||||
|
var client = session.ConnectedClient;
|
||||||
|
RaiseNetworkEvent(new TickerJoinLobbyEvent(), client);
|
||||||
|
RaiseNetworkEvent(GetStatusMsg(session), client);
|
||||||
|
RaiseNetworkEvent(GetInfoMsg(), client);
|
||||||
|
RaiseNetworkEvent(GetPlayerStatus(), client);
|
||||||
|
RaiseNetworkEvent(GetJobsAvailable(), client);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReqWindowAttentionAll()
|
||||||
|
{
|
||||||
|
RaiseNetworkEvent(new RequestWindowAttentionEvent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
363
Content.Server/GameTicking/GameTicker.RoundFlow.cs
Normal file
363
Content.Server/GameTicking/GameTicker.RoundFlow.cs
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Content.Server.Players;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Shared.Coordinates;
|
||||||
|
using Content.Shared.GameTicking;
|
||||||
|
using Content.Shared.Preferences;
|
||||||
|
using Prometheus;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameTicking
|
||||||
|
{
|
||||||
|
public partial class GameTicker
|
||||||
|
{
|
||||||
|
private static readonly Counter RoundNumberMetric = Metrics.CreateCounter(
|
||||||
|
"ss14_round_number",
|
||||||
|
"Round number.");
|
||||||
|
|
||||||
|
private static readonly Gauge RoundLengthMetric = Metrics.CreateGauge(
|
||||||
|
"ss14_round_length",
|
||||||
|
"Round length in seconds.");
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private TimeSpan _roundStartTimeSpan;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private GameRunLevel _runLevel;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public GameRunLevel RunLevel
|
||||||
|
{
|
||||||
|
get => _runLevel;
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
if (_runLevel == value) return;
|
||||||
|
|
||||||
|
var old = _runLevel;
|
||||||
|
_runLevel = value;
|
||||||
|
|
||||||
|
RaiseLocalEvent(new GameRunLevelChangedEvent(old, value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PreRoundSetup()
|
||||||
|
{
|
||||||
|
DefaultMap = _mapManager.CreateMap();
|
||||||
|
var startTime = _gameTiming.RealTime;
|
||||||
|
var map = ChosenMap;
|
||||||
|
var grid = _mapLoader.LoadBlueprint(DefaultMap, map);
|
||||||
|
|
||||||
|
if (grid == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"No grid found for map {map}");
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultGridId = grid.Index;
|
||||||
|
_spawnPoint = grid.ToCoordinates();
|
||||||
|
|
||||||
|
var timeSpan = _gameTiming.RealTime - startTime;
|
||||||
|
Logger.InfoS("ticker", $"Loaded map in {timeSpan.TotalMilliseconds:N2}ms.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartRound(bool force = false)
|
||||||
|
{
|
||||||
|
// If this game ticker is a dummy, do nothing!
|
||||||
|
if (DummyTicker)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DebugTools.Assert(RunLevel == GameRunLevel.PreRoundLobby);
|
||||||
|
Logger.InfoS("ticker", "Starting round!");
|
||||||
|
|
||||||
|
SendServerMessage("The round is starting now...");
|
||||||
|
|
||||||
|
List<IPlayerSession> readyPlayers;
|
||||||
|
if (LobbyEnabled)
|
||||||
|
{
|
||||||
|
readyPlayers = _playersInLobby.Where(p => p.Value == LobbyPlayerStatus.Ready).Select(p => p.Key).ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
readyPlayers = _playersInLobby.Keys.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
RunLevel = GameRunLevel.InRound;
|
||||||
|
|
||||||
|
RoundLengthMetric.Set(0);
|
||||||
|
|
||||||
|
// Get the profiles for each player for easier lookup.
|
||||||
|
var profiles = _prefsManager.GetSelectedProfilesForPlayers(
|
||||||
|
readyPlayers
|
||||||
|
.Select(p => p.UserId).ToList())
|
||||||
|
.ToDictionary(p => p.Key, p => (HumanoidCharacterProfile) p.Value);
|
||||||
|
|
||||||
|
foreach (var readyPlayer in readyPlayers)
|
||||||
|
{
|
||||||
|
if (!profiles.ContainsKey(readyPlayer.UserId))
|
||||||
|
{
|
||||||
|
profiles.Add(readyPlayer.UserId, HumanoidCharacterProfile.Random());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var assignedJobs = AssignJobs(readyPlayers, profiles);
|
||||||
|
|
||||||
|
// For players without jobs, give them the overflow job if they have that set...
|
||||||
|
foreach (var player in readyPlayers)
|
||||||
|
{
|
||||||
|
if (assignedJobs.ContainsKey(player))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var profile = profiles[player.UserId];
|
||||||
|
if (profile.PreferenceUnavailable == PreferenceUnavailableMode.SpawnAsOverflow)
|
||||||
|
{
|
||||||
|
assignedJobs.Add(player, OverflowJob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn everybody in!
|
||||||
|
foreach (var (player, job) in assignedJobs)
|
||||||
|
{
|
||||||
|
SpawnPlayer(player, profiles[player.UserId], job, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time to start the preset.
|
||||||
|
Preset = MakeGamePreset(profiles);
|
||||||
|
|
||||||
|
DisallowLateJoin |= Preset.DisallowLateJoin;
|
||||||
|
|
||||||
|
if (!Preset.Start(assignedJobs.Keys.ToList(), force))
|
||||||
|
{
|
||||||
|
if (_configurationManager.GetCVar(CCVars.GameLobbyFallbackEnabled))
|
||||||
|
{
|
||||||
|
SetStartPreset(_configurationManager.GetCVar(CCVars.GameLobbyFallbackPreset));
|
||||||
|
var newPreset = MakeGamePreset(profiles);
|
||||||
|
_chatManager.DispatchServerAnnouncement(
|
||||||
|
$"Failed to start {Preset.ModeTitle} mode! Defaulting to {newPreset.ModeTitle}...");
|
||||||
|
if (!newPreset.Start(readyPlayers, force))
|
||||||
|
{
|
||||||
|
throw new ApplicationException("Fallback preset failed to start!");
|
||||||
|
}
|
||||||
|
|
||||||
|
DisallowLateJoin = false;
|
||||||
|
DisallowLateJoin |= newPreset.DisallowLateJoin;
|
||||||
|
Preset = newPreset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SendServerMessage($"Failed to start {Preset.ModeTitle} mode! Restarting round...");
|
||||||
|
RestartRound();
|
||||||
|
DelayStart(TimeSpan.FromSeconds(PresetFailedCooldownIncrease));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Preset.OnGameStarted();
|
||||||
|
|
||||||
|
_roundStartTimeSpan = IoCManager.Resolve<IGameTiming>().RealTime;
|
||||||
|
SendStatusToAll();
|
||||||
|
ReqWindowAttentionAll();
|
||||||
|
UpdateLateJoinStatus();
|
||||||
|
UpdateJobsAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EndRound(string text = "")
|
||||||
|
{
|
||||||
|
// If this game ticker is a dummy, do nothing!
|
||||||
|
if (DummyTicker)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DebugTools.Assert(RunLevel == GameRunLevel.InRound);
|
||||||
|
Logger.InfoS("ticker", "Ending round!");
|
||||||
|
|
||||||
|
RunLevel = GameRunLevel.PostRound;
|
||||||
|
|
||||||
|
//Tell every client the round has ended.
|
||||||
|
var gamemodeTitle = Preset?.ModeTitle ?? string.Empty;
|
||||||
|
var roundEndText = text + $"\n{Preset?.GetRoundEndDescription() ?? string.Empty}";
|
||||||
|
|
||||||
|
//Get the timespan of the round.
|
||||||
|
var roundDuration = IoCManager.Resolve<IGameTiming>().RealTime.Subtract(_roundStartTimeSpan);
|
||||||
|
|
||||||
|
//Generate a list of basic player info to display in the end round summary.
|
||||||
|
var listOfPlayerInfo = new List<RoundEndMessageEvent.RoundEndPlayerInfo>();
|
||||||
|
foreach (var ply in _playerManager.GetAllPlayers().OrderBy(p => p.Name))
|
||||||
|
{
|
||||||
|
var mind = ply.ContentData()?.Mind;
|
||||||
|
|
||||||
|
if (mind != null)
|
||||||
|
{
|
||||||
|
_playersInLobby.TryGetValue(ply, out var status);
|
||||||
|
var antag = mind.AllRoles.Any(role => role.Antagonist);
|
||||||
|
var playerEndRoundInfo = new RoundEndMessageEvent.RoundEndPlayerInfo()
|
||||||
|
{
|
||||||
|
PlayerOOCName = ply.Name,
|
||||||
|
PlayerICName = mind.CurrentEntity?.Name,
|
||||||
|
Role = antag
|
||||||
|
? mind.AllRoles.First(role => role.Antagonist).Name
|
||||||
|
: mind.AllRoles.FirstOrDefault()?.Name ?? Loc.GetString("Unknown"),
|
||||||
|
Antag = antag,
|
||||||
|
Observer = status == LobbyPlayerStatus.Observer,
|
||||||
|
};
|
||||||
|
listOfPlayerInfo.Add(playerEndRoundInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RaiseNetworkEvent(new RoundEndMessageEvent(gamemodeTitle, roundEndText, roundDuration, listOfPlayerInfo.Count, listOfPlayerInfo.ToArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RestartRound()
|
||||||
|
{
|
||||||
|
// If this game ticker is a dummy, do nothing!
|
||||||
|
if (DummyTicker)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_updateOnRoundEnd)
|
||||||
|
{
|
||||||
|
_baseServer.Shutdown(
|
||||||
|
Loc.GetString("Server is shutting down for update and will automatically restart."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.InfoS("ticker", "Restarting round!");
|
||||||
|
|
||||||
|
SendServerMessage("Restarting round...");
|
||||||
|
|
||||||
|
RoundNumberMetric.Inc();
|
||||||
|
|
||||||
|
RunLevel = GameRunLevel.PreRoundLobby;
|
||||||
|
LobbySong = _robustRandom.Pick(_lobbyMusicCollection.PickFiles);
|
||||||
|
ResettingCleanup();
|
||||||
|
PreRoundSetup();
|
||||||
|
|
||||||
|
if (!LobbyEnabled)
|
||||||
|
{
|
||||||
|
StartRound();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Preset = null;
|
||||||
|
|
||||||
|
if (_playerManager.PlayerCount == 0)
|
||||||
|
_roundStartCountdownHasNotStartedYetDueToNoPlayers = true;
|
||||||
|
else
|
||||||
|
_roundStartTime = _gameTiming.CurTime + LobbyDuration;
|
||||||
|
|
||||||
|
SendStatusToAll();
|
||||||
|
|
||||||
|
ReqWindowAttentionAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cleanup that has to run to clear up anything from the previous round.
|
||||||
|
/// Stuff like wiping the previous map clean.
|
||||||
|
/// </summary>
|
||||||
|
private void ResettingCleanup()
|
||||||
|
{
|
||||||
|
// Move everybody currently in the server to lobby.
|
||||||
|
foreach (var player in _playerManager.GetAllPlayers())
|
||||||
|
{
|
||||||
|
PlayerJoinLobby(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the minds of everybody.
|
||||||
|
// TODO: Maybe move this into a separate manager?
|
||||||
|
foreach (var unCastData in _playerManager.GetAllPlayerData())
|
||||||
|
{
|
||||||
|
unCastData.ContentData()?.WipeMind();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete all entities.
|
||||||
|
foreach (var entity in _entityManager.GetEntities().ToList())
|
||||||
|
{
|
||||||
|
// TODO: Maybe something less naive here?
|
||||||
|
// FIXME: Actually, definitely.
|
||||||
|
entity.Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
_mapManager.Restart();
|
||||||
|
|
||||||
|
// Clear up any game rules.
|
||||||
|
foreach (var rule in _gameRules)
|
||||||
|
{
|
||||||
|
rule.Removed();
|
||||||
|
}
|
||||||
|
|
||||||
|
_gameRules.Clear();
|
||||||
|
|
||||||
|
foreach (var system in _entitySystemManager.AllSystems)
|
||||||
|
{
|
||||||
|
if (system is IResettingEntitySystem resetting)
|
||||||
|
{
|
||||||
|
resetting.Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_spawnedPositions.Clear();
|
||||||
|
_manifest.Clear();
|
||||||
|
DisallowLateJoin = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DelayStart(TimeSpan time)
|
||||||
|
{
|
||||||
|
if (_runLevel != GameRunLevel.PreRoundLobby)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_roundStartTime += time;
|
||||||
|
|
||||||
|
RaiseNetworkEvent(new TickerLobbyCountdownEvent(_roundStartTime, Paused));
|
||||||
|
|
||||||
|
_chatManager.DispatchServerAnnouncement($"Round start has been delayed for {time.TotalSeconds} seconds.");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateRoundFlow(float frameTime)
|
||||||
|
{
|
||||||
|
if (RunLevel == GameRunLevel.InRound)
|
||||||
|
{
|
||||||
|
RoundLengthMetric.Inc(frameTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RunLevel != GameRunLevel.PreRoundLobby ||
|
||||||
|
Paused ||
|
||||||
|
_roundStartTime > _gameTiming.CurTime ||
|
||||||
|
_roundStartCountdownHasNotStartedYetDueToNoPlayers)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StartRound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum GameRunLevel
|
||||||
|
{
|
||||||
|
PreRoundLobby = 0,
|
||||||
|
InRound = 1,
|
||||||
|
PostRound = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GameRunLevelChangedEvent
|
||||||
|
{
|
||||||
|
public GameRunLevel Old { get; }
|
||||||
|
public GameRunLevel New { get; }
|
||||||
|
|
||||||
|
public GameRunLevelChangedEvent(GameRunLevel old, GameRunLevel @new)
|
||||||
|
{
|
||||||
|
Old = old;
|
||||||
|
New = @new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
296
Content.Server/GameTicking/GameTicker.Spawning.cs
Normal file
296
Content.Server/GameTicking/GameTicker.Spawning.cs
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using Content.Server.Access.Components;
|
||||||
|
using Content.Server.CharacterAppearance.Components;
|
||||||
|
using Content.Server.Ghost.Components;
|
||||||
|
using Content.Server.Hands.Components;
|
||||||
|
using Content.Server.Inventory.Components;
|
||||||
|
using Content.Server.Items;
|
||||||
|
using Content.Server.PDA;
|
||||||
|
using Content.Server.Players;
|
||||||
|
using Content.Server.Roles;
|
||||||
|
using Content.Server.Spawners.Components;
|
||||||
|
using Content.Server.Speech.Components;
|
||||||
|
using Content.Shared.GameTicking;
|
||||||
|
using Content.Shared.Inventory;
|
||||||
|
using Content.Shared.Preferences;
|
||||||
|
using Content.Shared.Roles;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameTicking
|
||||||
|
{
|
||||||
|
public partial class GameTicker
|
||||||
|
{
|
||||||
|
private const string PlayerPrototypeName = "HumanMob_Content";
|
||||||
|
private const string ObserverPrototypeName = "MobObserver";
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
private EntityCoordinates _spawnPoint;
|
||||||
|
|
||||||
|
// Mainly to avoid allocations.
|
||||||
|
private readonly List<EntityCoordinates> _possiblePositions = new();
|
||||||
|
|
||||||
|
private void SpawnPlayer(IPlayerSession player, string? jobId = null, bool lateJoin = true)
|
||||||
|
{
|
||||||
|
var character = GetPlayerProfile(player);
|
||||||
|
|
||||||
|
SpawnPlayer(player, character, jobId, lateJoin);
|
||||||
|
UpdateJobsAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SpawnPlayer(IPlayerSession player, HumanoidCharacterProfile character, string? jobId = null, bool lateJoin = true)
|
||||||
|
{
|
||||||
|
// Can't spawn players with a dummy ticker!
|
||||||
|
if (DummyTicker)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (lateJoin && DisallowLateJoin)
|
||||||
|
{
|
||||||
|
MakeObserve(player);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerJoinGame(player);
|
||||||
|
|
||||||
|
var data = player.ContentData();
|
||||||
|
|
||||||
|
DebugTools.AssertNotNull(data);
|
||||||
|
|
||||||
|
data!.WipeMind();
|
||||||
|
data.Mind = new Mind.Mind(player.UserId)
|
||||||
|
{
|
||||||
|
CharacterName = character.Name
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pick best job best on prefs.
|
||||||
|
jobId ??= PickBestAvailableJob(character);
|
||||||
|
|
||||||
|
var jobPrototype = _prototypeManager.Index<JobPrototype>(jobId);
|
||||||
|
var job = new Job(data.Mind, jobPrototype);
|
||||||
|
data.Mind.AddRole(job);
|
||||||
|
|
||||||
|
if (lateJoin)
|
||||||
|
{
|
||||||
|
_chatManager.DispatchStationAnnouncement(Loc.GetString(
|
||||||
|
"latejoin-arrival-announcement",
|
||||||
|
("character", character.Name),
|
||||||
|
("job", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(job.Name))
|
||||||
|
), Loc.GetString("latejoin-arrival-sender"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var mob = SpawnPlayerMob(job, character, lateJoin);
|
||||||
|
data.Mind.TransferTo(mob);
|
||||||
|
|
||||||
|
if (player.UserId == new Guid("{e887eb93-f503-4b65-95b6-2f282c014192}"))
|
||||||
|
{
|
||||||
|
mob.AddComponent<OwOAccentComponent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
AddManifestEntry(character.Name, jobId);
|
||||||
|
AddSpawnedPosition(jobId);
|
||||||
|
EquipIdCard(mob, character.Name, jobPrototype);
|
||||||
|
jobPrototype.Special?.AfterEquip(mob);
|
||||||
|
|
||||||
|
Preset?.OnSpawnPlayerCompleted(player, mob, lateJoin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Respawn(IPlayerSession player)
|
||||||
|
{
|
||||||
|
player.ContentData()?.WipeMind();
|
||||||
|
|
||||||
|
if (LobbyEnabled)
|
||||||
|
PlayerJoinLobby(player);
|
||||||
|
else
|
||||||
|
SpawnPlayer(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MakeJoinGame(IPlayerSession player, string? jobId = null)
|
||||||
|
{
|
||||||
|
if (!_playersInLobby.ContainsKey(player)) return;
|
||||||
|
|
||||||
|
if (!_prefsManager.HavePreferencesLoaded(player))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpawnPlayer(player, jobId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MakeObserve(IPlayerSession player)
|
||||||
|
{
|
||||||
|
// Can't spawn players with a dummy ticker!
|
||||||
|
if (DummyTicker)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_playersInLobby.ContainsKey(player)) return;
|
||||||
|
|
||||||
|
PlayerJoinGame(player);
|
||||||
|
|
||||||
|
var name = GetPlayerProfile(player).Name;
|
||||||
|
|
||||||
|
var data = player.ContentData();
|
||||||
|
|
||||||
|
DebugTools.AssertNotNull(data);
|
||||||
|
|
||||||
|
data!.WipeMind();
|
||||||
|
data.Mind = new Mind.Mind(player.UserId);
|
||||||
|
|
||||||
|
var mob = SpawnObserverMob();
|
||||||
|
mob.Name = name;
|
||||||
|
mob.GetComponent<GhostComponent>().CanReturnToBody = false;
|
||||||
|
data.Mind.TransferTo(mob);
|
||||||
|
|
||||||
|
_playersInLobby[player] = LobbyPlayerStatus.Observer;
|
||||||
|
RaiseNetworkEvent(GetStatusSingle(player, LobbyPlayerStatus.Observer));
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Mob Spawning Helpers
|
||||||
|
private IEntity SpawnPlayerMob(Job job, HumanoidCharacterProfile? profile, bool lateJoin = true)
|
||||||
|
{
|
||||||
|
var coordinates = lateJoin ? GetLateJoinSpawnPoint() : GetJobSpawnPoint(job.Prototype.ID);
|
||||||
|
var entity = _entityManager.SpawnEntity(PlayerPrototypeName, coordinates);
|
||||||
|
|
||||||
|
if (job.StartingGear != null)
|
||||||
|
{
|
||||||
|
var startingGear = _prototypeManager.Index<StartingGearPrototype>(job.StartingGear);
|
||||||
|
EquipStartingGear(entity, startingGear, profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profile != null)
|
||||||
|
{
|
||||||
|
entity.GetComponent<HumanoidAppearanceComponent>().UpdateFromProfile(profile);
|
||||||
|
entity.Name = profile.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEntity SpawnObserverMob()
|
||||||
|
{
|
||||||
|
var coordinates = GetObserverSpawnPoint();
|
||||||
|
return _entityManager.SpawnEntity(ObserverPrototypeName, coordinates);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Equip Helpers
|
||||||
|
public void EquipStartingGear(IEntity entity, StartingGearPrototype startingGear, HumanoidCharacterProfile? profile)
|
||||||
|
{
|
||||||
|
if (entity.TryGetComponent(out InventoryComponent? inventory))
|
||||||
|
{
|
||||||
|
foreach (var slot in EquipmentSlotDefines.AllSlots)
|
||||||
|
{
|
||||||
|
var equipmentStr = startingGear.GetGear(slot, profile);
|
||||||
|
if (equipmentStr != "")
|
||||||
|
{
|
||||||
|
var equipmentEntity = _entityManager.SpawnEntity(equipmentStr, entity.Transform.Coordinates);
|
||||||
|
inventory.Equip(slot, equipmentEntity.GetComponent<ItemComponent>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity.TryGetComponent(out HandsComponent? handsComponent))
|
||||||
|
{
|
||||||
|
var inhand = startingGear.Inhand;
|
||||||
|
foreach (var (hand, prototype) in inhand)
|
||||||
|
{
|
||||||
|
var inhandEntity = _entityManager.SpawnEntity(prototype, entity.Transform.Coordinates);
|
||||||
|
handsComponent.PutInHand(inhandEntity.GetComponent<ItemComponent>(), hand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EquipIdCard(IEntity entity, string characterName, JobPrototype jobPrototype)
|
||||||
|
{
|
||||||
|
if (!entity.TryGetComponent(out InventoryComponent? inventory))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!inventory.TryGetSlotItem(EquipmentSlotDefines.Slots.IDCARD, out ItemComponent? item))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemEntity = item.Owner;
|
||||||
|
|
||||||
|
if (!itemEntity.TryGetComponent(out PDAComponent? pdaComponent) || pdaComponent.ContainedID == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var card = pdaComponent.ContainedID;
|
||||||
|
card.FullName = characterName;
|
||||||
|
card.JobTitle = jobPrototype.Name;
|
||||||
|
|
||||||
|
var access = card.Owner.GetComponent<AccessComponent>();
|
||||||
|
var accessTags = access.Tags;
|
||||||
|
accessTags.UnionWith(jobPrototype.Access);
|
||||||
|
pdaComponent.SetPDAOwner(characterName);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private void AddManifestEntry(string characterName, string jobId)
|
||||||
|
{
|
||||||
|
_manifest.Add(new ManifestEntry(characterName, jobId));
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Spawn Points
|
||||||
|
public EntityCoordinates GetJobSpawnPoint(string jobId)
|
||||||
|
{
|
||||||
|
var location = _spawnPoint;
|
||||||
|
|
||||||
|
_possiblePositions.Clear();
|
||||||
|
|
||||||
|
foreach (var (point, transform) in ComponentManager.EntityQuery<SpawnPointComponent, ITransformComponent>())
|
||||||
|
{
|
||||||
|
if (point.SpawnType == SpawnPointType.Job && point.Job?.ID == jobId)
|
||||||
|
_possiblePositions.Add(transform.Coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_possiblePositions.Count != 0)
|
||||||
|
location = _robustRandom.Pick(_possiblePositions);
|
||||||
|
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityCoordinates GetLateJoinSpawnPoint()
|
||||||
|
{
|
||||||
|
var location = _spawnPoint;
|
||||||
|
|
||||||
|
_possiblePositions.Clear();
|
||||||
|
|
||||||
|
foreach (var (point, transform) in ComponentManager.EntityQuery<SpawnPointComponent, ITransformComponent>())
|
||||||
|
{
|
||||||
|
if (point.SpawnType == SpawnPointType.LateJoin) _possiblePositions.Add(transform.Coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_possiblePositions.Count != 0)
|
||||||
|
location = _robustRandom.Pick(_possiblePositions);
|
||||||
|
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public EntityCoordinates GetObserverSpawnPoint()
|
||||||
|
{
|
||||||
|
var location = _spawnPoint;
|
||||||
|
|
||||||
|
_possiblePositions.Clear();
|
||||||
|
|
||||||
|
foreach (var (point, transform) in ComponentManager.EntityQuery<SpawnPointComponent, ITransformComponent>())
|
||||||
|
{
|
||||||
|
if (point.SpawnType == SpawnPointType.Observer)
|
||||||
|
_possiblePositions.Add(transform.Coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_possiblePositions.Count != 0)
|
||||||
|
location = _robustRandom.Pick(_possiblePositions);
|
||||||
|
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
34
Content.Server/GameTicking/GameTicker.StatusShell.cs
Normal file
34
Content.Server/GameTicking/GameTicker.StatusShell.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using Robust.Server.ServerStatus;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
|
namespace Content.Server.GameTicking
|
||||||
|
{
|
||||||
|
public partial class GameTicker
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Used for thread safety, given <see cref="IStatusHost.OnStatusRequest"/> is called from another thread.
|
||||||
|
/// </summary>
|
||||||
|
private readonly object _statusShellLock = new();
|
||||||
|
|
||||||
|
private void InitializeStatusShell()
|
||||||
|
{
|
||||||
|
IoCManager.Resolve<IStatusHost>().OnStatusRequest += GetStatusResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetStatusResponse(JObject jObject)
|
||||||
|
{
|
||||||
|
// This method is raised from another thread, so this better be thread safe!
|
||||||
|
lock (_statusShellLock)
|
||||||
|
{
|
||||||
|
jObject["name"] = _baseServer.ServerName;
|
||||||
|
jObject["players"] = _playerManager.PlayerCount;
|
||||||
|
jObject["run_level"] = (int) _runLevel;
|
||||||
|
if (_runLevel >= GameRunLevel.InRound)
|
||||||
|
{
|
||||||
|
jObject["round_start_time"] = _roundStartTime.ToString("o");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
63
Content.Server/GameTicking/GameTicker.Updates.cs
Normal file
63
Content.Server/GameTicking/GameTicker.Updates.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using Robust.Shared.Enums;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using Timer = Robust.Shared.Timing.Timer;
|
||||||
|
|
||||||
|
namespace Content.Server.GameTicking
|
||||||
|
{
|
||||||
|
public partial class GameTicker
|
||||||
|
{
|
||||||
|
private static readonly TimeSpan UpdateRestartDelay = TimeSpan.FromSeconds(20);
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private bool _updateOnRoundEnd;
|
||||||
|
private CancellationTokenSource? _updateShutdownCts;
|
||||||
|
|
||||||
|
private void InitializeUpdates()
|
||||||
|
{
|
||||||
|
_watchdogApi.UpdateReceived += WatchdogApiOnUpdateReceived;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WatchdogApiOnUpdateReceived()
|
||||||
|
{
|
||||||
|
_chatManager.DispatchServerAnnouncement(Loc.GetString(
|
||||||
|
"Update has been received, server will automatically restart for update at the end of this round."));
|
||||||
|
_updateOnRoundEnd = true;
|
||||||
|
ServerEmptyUpdateRestartCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether there are still players on the server,
|
||||||
|
/// and if not starts a timer to automatically reboot the server if an update is available.
|
||||||
|
/// </summary>
|
||||||
|
private void ServerEmptyUpdateRestartCheck()
|
||||||
|
{
|
||||||
|
// Can't simple check the current connected player count since that doesn't update
|
||||||
|
// before PlayerStatusChanged gets fired.
|
||||||
|
// So in the disconnect handler we'd still see a single player otherwise.
|
||||||
|
var playersOnline = _playerManager.GetAllPlayers().Any(p => p.Status != SessionStatus.Disconnected);
|
||||||
|
if (playersOnline || !_updateOnRoundEnd)
|
||||||
|
{
|
||||||
|
// Still somebody online.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_updateShutdownCts is {IsCancellationRequested: false})
|
||||||
|
{
|
||||||
|
// Do nothing because I guess we already have a timer running..?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateShutdownCts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
Timer.Spawn(UpdateRestartDelay, () =>
|
||||||
|
{
|
||||||
|
_baseServer.Shutdown(
|
||||||
|
Loc.GetString("Server is shutting down for update and will automatically restart."));
|
||||||
|
}, _updateShutdownCts.Token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,40 +0,0 @@
|
|||||||
using Content.Server.Players;
|
|
||||||
using Content.Shared.GameTicking;
|
|
||||||
using Robust.Server.Player;
|
|
||||||
using Robust.Shared.Enums;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
#nullable enable
|
|
||||||
|
|
||||||
namespace Content.Server.GameTicking
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Handles some low-level GameTicker behavior such as setting up clients when they connect.
|
|
||||||
/// Does not contain lobby/round handling mechanisms.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class GameTickerBase : SharedGameTicker
|
|
||||||
{
|
|
||||||
[Dependency] protected readonly IPlayerManager PlayerManager = default!;
|
|
||||||
|
|
||||||
public virtual void Initialize()
|
|
||||||
{
|
|
||||||
PlayerManager.PlayerStatusChanged += PlayerStatusChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void PlayerStatusChanged(object? sender, SessionStatusEventArgs args)
|
|
||||||
{
|
|
||||||
var session = args.Session;
|
|
||||||
|
|
||||||
if (args.NewStatus == SessionStatus.Connected)
|
|
||||||
{
|
|
||||||
// Always make sure the client has player data. Mind gets assigned on spawn.
|
|
||||||
if (session.Data.ContentDataUncast == null)
|
|
||||||
session.Data.ContentDataUncast = new PlayerData(session.UserId);
|
|
||||||
|
|
||||||
// timer time must be > tick length
|
|
||||||
Timer.Spawn(0, args.Session.JoinGame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using Content.Server.GameTicking.Rules;
|
|
||||||
using Content.Shared.Preferences;
|
|
||||||
using Content.Shared.Roles;
|
|
||||||
using Robust.Server.Player;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
namespace Content.Server.GameTicking
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The game ticker is responsible for managing the round-by-round system of the game.
|
|
||||||
/// </summary>
|
|
||||||
public interface IGameTicker
|
|
||||||
{
|
|
||||||
GameRunLevel RunLevel { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The map loaded by the GameTicker on round start.
|
|
||||||
/// </summary>
|
|
||||||
MapId DefaultMap { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The GridId loaded by the GameTicker on round start.
|
|
||||||
/// </summary>
|
|
||||||
GridId DefaultGridId { get; }
|
|
||||||
|
|
||||||
event Action<GameRunLevelChangedEventArgs> OnRunLevelChanged;
|
|
||||||
event Action<GameRuleAddedEventArgs> OnRuleAdded;
|
|
||||||
|
|
||||||
void Initialize();
|
|
||||||
void Update(FrameEventArgs frameEventArgs);
|
|
||||||
|
|
||||||
void RestartRound();
|
|
||||||
void StartRound(bool force = false);
|
|
||||||
void EndRound(string roundEndText = "");
|
|
||||||
|
|
||||||
void Respawn(IPlayerSession targetPlayer);
|
|
||||||
void MakeObserve(IPlayerSession player);
|
|
||||||
void MakeJoinGame(IPlayerSession player, string? jobId = null);
|
|
||||||
void ToggleReady(IPlayerSession player, bool ready);
|
|
||||||
void ToggleDisallowLateJoin(bool disallowLateJoin);
|
|
||||||
|
|
||||||
/// <summary>proxy to GamePreset (actual handler)</summary>
|
|
||||||
bool OnGhostAttempt(Mind.Mind mind, bool canReturnGlobal);
|
|
||||||
|
|
||||||
EntityCoordinates GetLateJoinSpawnPoint();
|
|
||||||
EntityCoordinates GetJobSpawnPoint(string jobId);
|
|
||||||
EntityCoordinates GetObserverSpawnPoint();
|
|
||||||
|
|
||||||
void EquipStartingGear(IEntity entity, StartingGearPrototype startingGear, HumanoidCharacterProfile? profile);
|
|
||||||
|
|
||||||
// GameRule system.
|
|
||||||
T AddGameRule<T>() where T : GameRule, new();
|
|
||||||
bool HasGameRule(string? type);
|
|
||||||
bool HasGameRule(Type? type);
|
|
||||||
void RemoveGameRule(GameRule rule);
|
|
||||||
IEnumerable<GameRule> ActiveGameRules { get; }
|
|
||||||
|
|
||||||
bool TryGetPreset(string name, [NotNullWhen(true)] out Type? type);
|
|
||||||
void SetStartPreset(Type type, bool force = false);
|
|
||||||
void SetStartPreset(string name, bool force = false);
|
|
||||||
|
|
||||||
/// <returns>true if changed, false otherwise</returns>
|
|
||||||
bool PauseStart(bool pause = true);
|
|
||||||
|
|
||||||
/// <returns>true if paused, false otherwise</returns>
|
|
||||||
bool TogglePause();
|
|
||||||
|
|
||||||
bool DelayStart(TimeSpan time);
|
|
||||||
|
|
||||||
Dictionary<string, int> GetAvailablePositions();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -45,7 +45,7 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
mind.UnVisit();
|
mind.UnVisit();
|
||||||
}
|
}
|
||||||
|
|
||||||
var position = playerEntity?.Transform.Coordinates ?? IoCManager.Resolve<IGameTicker>().GetObserverSpawnPoint();
|
var position = playerEntity?.Transform.Coordinates ?? EntitySystem.Get<GameTicker>().GetObserverSpawnPoint();
|
||||||
// Ok, so, this is the master place for the logic for if ghosting is "too cheaty" to allow returning.
|
// Ok, so, this is the master place for the logic for if ghosting is "too cheaty" to allow returning.
|
||||||
// There's no reason at this time to move it to any other place, especially given that the 'side effects required' situations would also have to be moved.
|
// There's no reason at this time to move it to any other place, especially given that the 'side effects required' situations would also have to be moved.
|
||||||
// + If CharacterDeadPhysically applies, we're physically dead. Therefore, ghosting OK, and we can return (this is critical for gibbing)
|
// + If CharacterDeadPhysically applies, we're physically dead. Therefore, ghosting OK, and we can return (this is critical for gibbing)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Server.GameTicking.Rules;
|
using Content.Server.GameTicking.Rules;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Presets
|
namespace Content.Server.GameTicking.Presets
|
||||||
@@ -8,11 +9,9 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
[GamePreset("deathmatch")]
|
[GamePreset("deathmatch")]
|
||||||
public sealed class PresetDeathMatch : GamePreset
|
public sealed class PresetDeathMatch : GamePreset
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
|
||||||
|
|
||||||
public override bool Start(IReadOnlyList<IPlayerSession> readyPlayers, bool force = false)
|
public override bool Start(IReadOnlyList<IPlayerSession> readyPlayers, bool force = false)
|
||||||
{
|
{
|
||||||
_gameTicker.AddGameRule<RuleDeathMatch>();
|
EntitySystem.Get<GameTicker>().AddGameRule<RuleDeathMatch>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
public class PresetSuspicion : GamePreset
|
public class PresetSuspicion : GamePreset
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
@@ -149,7 +148,7 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
traitor.GreetSuspicion(traitors, _chatManager);
|
traitor.GreetSuspicion(traitors, _chatManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
_gameTicker.AddGameRule<RuleSuspicion>();
|
EntitySystem.Get<GameTicker>().AddGameRule<RuleSuspicion>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ using Content.Shared.Inventory;
|
|||||||
using Content.Shared.PDA;
|
using Content.Shared.PDA;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Log;
|
using Robust.Shared.Log;
|
||||||
@@ -29,7 +30,6 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
[GamePreset("traitor")]
|
[GamePreset("traitor")]
|
||||||
public class PresetTraitor : GamePreset
|
public class PresetTraitor : GamePreset
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
@@ -159,7 +159,7 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
traitor.GreetTraitor(codewords);
|
traitor.GreetTraitor(codewords);
|
||||||
}
|
}
|
||||||
|
|
||||||
_gameTicker.AddGameRule<RuleTraitor>();
|
EntitySystem.Get<GameTicker>().AddGameRule<RuleTraitor>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||||
@@ -50,8 +49,9 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
|
|
||||||
public override bool Start(IReadOnlyList<IPlayerSession> readyPlayers, bool force = false)
|
public override bool Start(IReadOnlyList<IPlayerSession> readyPlayers, bool force = false)
|
||||||
{
|
{
|
||||||
_gameTicker.AddGameRule<RuleTraitorDeathMatch>();
|
var gameTicker = EntitySystem.Get<GameTicker>();
|
||||||
_restarter = _gameTicker.AddGameRule<RuleMaxTimeRestart>();
|
gameTicker.AddGameRule<RuleTraitorDeathMatch>();
|
||||||
|
_restarter = gameTicker.AddGameRule<RuleMaxTimeRestart>();
|
||||||
_restarter.RoundMaxTime = TimeSpan.FromMinutes(30);
|
_restarter.RoundMaxTime = TimeSpan.FromMinutes(30);
|
||||||
_restarter.RestartTimer();
|
_restarter.RestartTimer();
|
||||||
_safeToEndRound = true;
|
_safeToEndRound = true;
|
||||||
@@ -207,7 +207,7 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
var session = mind.Session;
|
var session = mind.Session;
|
||||||
if (session == null)
|
if (session == null)
|
||||||
return false;
|
return false;
|
||||||
_gameTicker.Respawn(session);
|
EntitySystem.Get<GameTicker>().Respawn(session);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Rules
|
namespace Content.Server.GameTicking.Rules
|
||||||
{
|
{
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public abstract class GameRule
|
public abstract class GameRule : IEntityEventSubscriber
|
||||||
{
|
{
|
||||||
public virtual void Added()
|
public virtual void Added()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ namespace Content.Server.GameTicking.Rules
|
|||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
|
|
||||||
private CancellationTokenSource? _checkTimerCancel;
|
private CancellationTokenSource? _checkTimerCancel;
|
||||||
@@ -91,7 +90,7 @@ namespace Content.Server.GameTicking.Rules
|
|||||||
|
|
||||||
_chatManager.DispatchServerAnnouncement(Loc.GetString("Restarting in {0} seconds.", restartDelay));
|
_chatManager.DispatchServerAnnouncement(Loc.GetString("Restarting in {0} seconds.", restartDelay));
|
||||||
|
|
||||||
Timer.Spawn(TimeSpan.FromSeconds(restartDelay), () => _gameTicker.RestartRound());
|
Timer.Spawn(TimeSpan.FromSeconds(restartDelay), () => EntitySystem.Get<GameTicker>().RestartRound());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PlayerManagerOnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
private void PlayerManagerOnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Content.Server.Chat.Managers;
|
using Content.Server.Chat.Managers;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Timer = Robust.Shared.Timing.Timer;
|
using Timer = Robust.Shared.Timing.Timer;
|
||||||
@@ -11,9 +12,9 @@ namespace Content.Server.GameTicking.Rules
|
|||||||
{
|
{
|
||||||
public class RuleInactivityTimeRestart : GameRule
|
public class RuleInactivityTimeRestart : GameRule
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
|
||||||
private CancellationTokenSource _timerCancel = new();
|
private CancellationTokenSource _timerCancel = new();
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ namespace Content.Server.GameTicking.Rules
|
|||||||
{
|
{
|
||||||
base.Added();
|
base.Added();
|
||||||
|
|
||||||
_gameTicker.OnRunLevelChanged += RunLevelChanged;
|
_entityManager.EventBus.SubscribeEvent<GameRunLevelChangedEvent>(EventSource.Local, this, RunLevelChanged);
|
||||||
_playerManager.PlayerStatusChanged += PlayerStatusChanged;
|
_playerManager.PlayerStatusChanged += PlayerStatusChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ namespace Content.Server.GameTicking.Rules
|
|||||||
{
|
{
|
||||||
base.Removed();
|
base.Removed();
|
||||||
|
|
||||||
_gameTicker.OnRunLevelChanged -= RunLevelChanged;
|
_entityManager.EventBus.UnsubscribeEvents(this);
|
||||||
_playerManager.PlayerStatusChanged -= PlayerStatusChanged;
|
_playerManager.PlayerStatusChanged -= PlayerStatusChanged;
|
||||||
|
|
||||||
StopTimer();
|
StopTimer();
|
||||||
@@ -52,16 +53,17 @@ namespace Content.Server.GameTicking.Rules
|
|||||||
|
|
||||||
private void TimerFired()
|
private void TimerFired()
|
||||||
{
|
{
|
||||||
_gameTicker.EndRound(Loc.GetString("Time has run out!"));
|
var gameticker = EntitySystem.Get<GameTicker>();
|
||||||
|
gameticker.EndRound(Loc.GetString("Time has run out!"));
|
||||||
|
|
||||||
_chatManager.DispatchServerAnnouncement(Loc.GetString("Restarting in {0} seconds.", (int) RoundEndDelay.TotalSeconds));
|
_chatManager.DispatchServerAnnouncement(Loc.GetString("Restarting in {0} seconds.", (int) RoundEndDelay.TotalSeconds));
|
||||||
|
|
||||||
Timer.Spawn(RoundEndDelay, () => _gameTicker.RestartRound());
|
Timer.Spawn(RoundEndDelay, () => gameticker.RestartRound());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RunLevelChanged(GameRunLevelChangedEventArgs args)
|
private void RunLevelChanged(GameRunLevelChangedEvent args)
|
||||||
{
|
{
|
||||||
switch (args.NewRunLevel)
|
switch (args.New)
|
||||||
{
|
{
|
||||||
case GameRunLevel.InRound:
|
case GameRunLevel.InRound:
|
||||||
RestartTimer();
|
RestartTimer();
|
||||||
@@ -75,7 +77,7 @@ namespace Content.Server.GameTicking.Rules
|
|||||||
|
|
||||||
private void PlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
private void PlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||||
{
|
{
|
||||||
if (_gameTicker.RunLevel != GameRunLevel.InRound)
|
if (EntitySystem.Get<GameTicker>().RunLevel != GameRunLevel.InRound)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Content.Server.Chat.Managers;
|
using Content.Server.Chat.Managers;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Timer = Robust.Shared.Timing.Timer;
|
using Timer = Robust.Shared.Timing.Timer;
|
||||||
@@ -9,8 +10,8 @@ namespace Content.Server.GameTicking.Rules
|
|||||||
{
|
{
|
||||||
public sealed class RuleMaxTimeRestart : GameRule
|
public sealed class RuleMaxTimeRestart : GameRule
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
|
||||||
private CancellationTokenSource _timerCancel = new();
|
private CancellationTokenSource _timerCancel = new();
|
||||||
|
|
||||||
@@ -21,14 +22,14 @@ namespace Content.Server.GameTicking.Rules
|
|||||||
{
|
{
|
||||||
base.Added();
|
base.Added();
|
||||||
|
|
||||||
_gameTicker.OnRunLevelChanged += RunLevelChanged;
|
_entityManager.EventBus.SubscribeEvent<GameRunLevelChangedEvent>(EventSource.Local, this, RunLevelChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Removed()
|
public override void Removed()
|
||||||
{
|
{
|
||||||
base.Removed();
|
base.Removed();
|
||||||
|
|
||||||
_gameTicker.OnRunLevelChanged -= RunLevelChanged;
|
_entityManager.EventBus.UnsubscribeEvents(this);
|
||||||
StopTimer();
|
StopTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,16 +47,16 @@ namespace Content.Server.GameTicking.Rules
|
|||||||
|
|
||||||
private void TimerFired()
|
private void TimerFired()
|
||||||
{
|
{
|
||||||
_gameTicker.EndRound(Loc.GetString("Time has run out!"));
|
EntitySystem.Get<GameTicker>().EndRound(Loc.GetString("Time has run out!"));
|
||||||
|
|
||||||
_chatManager.DispatchServerAnnouncement(Loc.GetString("Restarting in {0} seconds.", (int) RoundEndDelay.TotalSeconds));
|
_chatManager.DispatchServerAnnouncement(Loc.GetString("Restarting in {0} seconds.", (int) RoundEndDelay.TotalSeconds));
|
||||||
|
|
||||||
Timer.Spawn(RoundEndDelay, () => _gameTicker.RestartRound());
|
Timer.Spawn(RoundEndDelay, () => EntitySystem.Get<GameTicker>().RestartRound());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RunLevelChanged(GameRunLevelChangedEventArgs args)
|
private void RunLevelChanged(GameRunLevelChangedEvent args)
|
||||||
{
|
{
|
||||||
switch (args.NewRunLevel)
|
switch (args.New)
|
||||||
{
|
{
|
||||||
case GameRunLevel.InRound:
|
case GameRunLevel.InRound:
|
||||||
RestartTimer();
|
RestartTimer();
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ namespace Content.Server.GameTicking.Rules
|
|||||||
|
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
|
||||||
@@ -152,12 +151,13 @@ namespace Content.Server.GameTicking.Rules
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_gameTicker.EndRound(text);
|
var gameTicker = EntitySystem.Get<GameTicker>();
|
||||||
|
gameTicker.EndRound(text);
|
||||||
|
|
||||||
_chatManager.DispatchServerAnnouncement(Loc.GetString("Restarting in {0} seconds.", (int) RoundEndDelay.TotalSeconds));
|
_chatManager.DispatchServerAnnouncement(Loc.GetString("Restarting in {0} seconds.", (int) RoundEndDelay.TotalSeconds));
|
||||||
_checkTimerCancel.Cancel();
|
_checkTimerCancel.Cancel();
|
||||||
|
|
||||||
Timer.Spawn(RoundEndDelay, () => _gameTicker.RestartRound());
|
Timer.Spawn(RoundEndDelay, () => gameTicker.RestartRound());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ namespace Content.Server.Ghost.Components
|
|||||||
public class GhostOnMoveComponent : Component, IRelayMoveInput, IGhostOnMove
|
public class GhostOnMoveComponent : Component, IRelayMoveInput, IGhostOnMove
|
||||||
{
|
{
|
||||||
public override string Name => "GhostOnMove";
|
public override string Name => "GhostOnMove";
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
|
||||||
|
|
||||||
[DataField("canReturn")] public bool CanReturn { get; set; } = true;
|
[DataField("canReturn")] public bool CanReturn { get; set; } = true;
|
||||||
|
|
||||||
@@ -24,7 +23,7 @@ namespace Content.Server.Ghost.Components
|
|||||||
if (Owner.HasComponent<VisitingMindComponent>()) return;
|
if (Owner.HasComponent<VisitingMindComponent>()) return;
|
||||||
if (!Owner.TryGetComponent(out MindComponent? mind) || !mind.HasMind || mind.Mind!.IsVisitingEntity) return;
|
if (!Owner.TryGetComponent(out MindComponent? mind) || !mind.HasMind || mind.Mind!.IsVisitingEntity) return;
|
||||||
|
|
||||||
_gameTicker.OnGhostAttempt(mind.Mind!, CanReturn);
|
EntitySystem.Get<GameTicker>().OnGhostAttempt(mind.Mind!, CanReturn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Content.Server.GameTicking;
|
|||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.Ghost
|
namespace Content.Server.Ghost
|
||||||
@@ -31,7 +32,7 @@ namespace Content.Server.Ghost
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IoCManager.Resolve<IGameTicker>().OnGhostAttempt(mind, true))
|
if (!EntitySystem.Get<GameTicker>().OnGhostAttempt(mind, true))
|
||||||
{
|
{
|
||||||
shell?.WriteLine("You can't ghost right now.");
|
shell?.WriteLine("You can't ghost right now.");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Content.Server.Holiday.Interfaces;
|
|||||||
using Content.Shared;
|
using Content.Shared;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
@@ -13,11 +14,11 @@ using Robust.Shared.ViewVariables;
|
|||||||
namespace Content.Server.Holiday
|
namespace Content.Server.Holiday
|
||||||
{
|
{
|
||||||
// ReSharper disable once ClassNeverInstantiated.Global
|
// ReSharper disable once ClassNeverInstantiated.Global
|
||||||
public class HolidayManager : IHolidayManager
|
public class HolidayManager : IHolidayManager, IEntityEventSubscriber
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
@@ -74,7 +75,7 @@ namespace Content.Server.Holiday
|
|||||||
{
|
{
|
||||||
_configManager.OnValueChanged(CCVars.HolidaysEnabled, OnHolidaysEnableChange, true);
|
_configManager.OnValueChanged(CCVars.HolidaysEnabled, OnHolidaysEnableChange, true);
|
||||||
|
|
||||||
_gameTicker.OnRunLevelChanged += OnRunLevelChanged;
|
_entityManager.EventBus.SubscribeEvent<GameRunLevelChangedEvent>(EventSource.Local, this, OnRunLevelChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnHolidaysEnableChange(bool enabled)
|
private void OnHolidaysEnableChange(bool enabled)
|
||||||
@@ -84,11 +85,11 @@ namespace Content.Server.Holiday
|
|||||||
RefreshCurrentHolidays();
|
RefreshCurrentHolidays();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRunLevelChanged(GameRunLevelChangedEventArgs eventArgs)
|
private void OnRunLevelChanged(GameRunLevelChangedEvent eventArgs)
|
||||||
{
|
{
|
||||||
if (!_enabled) return;
|
if (!_enabled) return;
|
||||||
|
|
||||||
switch (eventArgs.NewRunLevel)
|
switch (eventArgs.New)
|
||||||
{
|
{
|
||||||
case GameRunLevel.PreRoundLobby:
|
case GameRunLevel.PreRoundLobby:
|
||||||
RefreshCurrentHolidays();
|
RefreshCurrentHolidays();
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ namespace Content.Server.IoC
|
|||||||
{
|
{
|
||||||
IoCManager.Register<ISharedNotifyManager, ServerNotifyManager>();
|
IoCManager.Register<ISharedNotifyManager, ServerNotifyManager>();
|
||||||
IoCManager.Register<IServerNotifyManager, ServerNotifyManager>();
|
IoCManager.Register<IServerNotifyManager, ServerNotifyManager>();
|
||||||
IoCManager.Register<IGameTicker, GameTicker>();
|
|
||||||
IoCManager.Register<IChatManager, ChatManager>();
|
IoCManager.Register<IChatManager, ChatManager>();
|
||||||
IoCManager.Register<IMoMMILink, MoMMILink>();
|
IoCManager.Register<IMoMMILink, MoMMILink>();
|
||||||
IoCManager.Register<ISandboxManager, SandboxManager>();
|
IoCManager.Register<ISandboxManager, SandboxManager>();
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ namespace Content.Server.Mind.Components
|
|||||||
base.Shutdown();
|
base.Shutdown();
|
||||||
|
|
||||||
// Let's not create ghosts if not in the middle of the round.
|
// Let's not create ghosts if not in the middle of the round.
|
||||||
if (IoCManager.Resolve<IGameTicker>().RunLevel != GameRunLevel.InRound)
|
if (EntitySystem.Get<GameTicker>().RunLevel != GameRunLevel.InRound)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (HasMind)
|
if (HasMind)
|
||||||
@@ -104,7 +104,7 @@ namespace Content.Server.Mind.Components
|
|||||||
var gridId = spawnPosition.GetGridId(Owner.EntityManager);
|
var gridId = spawnPosition.GetGridId(Owner.EntityManager);
|
||||||
if (gridId == GridId.Invalid || !mapMan.GridExists(gridId))
|
if (gridId == GridId.Invalid || !mapMan.GridExists(gridId))
|
||||||
{
|
{
|
||||||
spawnPosition = IoCManager.Resolve<IGameTicker>().GetObserverSpawnPoint();
|
spawnPosition = EntitySystem.Get<GameTicker>().GetObserverSpawnPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
var ghost = Owner.EntityManager.SpawnEntity("MobObserver", spawnPosition);
|
var ghost = Owner.EntityManager.SpawnEntity("MobObserver", spawnPosition);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace Content.Server.Mind
|
|||||||
|
|
||||||
if (mind == null) return;
|
if (mind == null) return;
|
||||||
|
|
||||||
IoCManager.Resolve<IGameTicker>().OnGhostAttempt(mind, canReturn);
|
EntitySystem.Get<GameTicker>().OnGhostAttempt(mind, canReturn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ namespace Content.Server.Morgue.Components
|
|||||||
|
|
||||||
if (mind != null)
|
if (mind != null)
|
||||||
{
|
{
|
||||||
IoCManager.Resolve<IGameTicker>().OnGhostAttempt(mind, false);
|
EntitySystem.Get<GameTicker>().OnGhostAttempt(mind, false);
|
||||||
mind.OwnedEntity?.PopupMessage(Loc.GetString("You cremate yourself!"));
|
mind.OwnedEntity?.PopupMessage(Loc.GetString("You cremate yourself!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
using Content.Shared.GameWindow;
|
|
||||||
using Robust.Server.Player;
|
|
||||||
|
|
||||||
namespace Content.Server.Players
|
|
||||||
{
|
|
||||||
public static class PlayerSessionExt
|
|
||||||
{
|
|
||||||
public static void RequestWindowAttention(this IPlayerSession session)
|
|
||||||
{
|
|
||||||
var msg = session.ConnectedClient.CreateNetMessage<MsgRequestWindowAttention>();
|
|
||||||
session.ConnectedClient.SendMessage(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -153,7 +153,7 @@ namespace Content.Server.Recycling.Components
|
|||||||
|
|
||||||
if (mind != null)
|
if (mind != null)
|
||||||
{
|
{
|
||||||
IoCManager.Resolve<IGameTicker>().OnGhostAttempt(mind, false);
|
EntitySystem.Get<GameTicker>().OnGhostAttempt(mind, false);
|
||||||
mind.OwnedEntity?.PopupMessage(Loc.GetString("You recycle yourself!"));
|
mind.OwnedEntity?.PopupMessage(Loc.GetString("You recycle yourself!"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ namespace Content.Server.RoundEnd
|
|||||||
{
|
{
|
||||||
public class RoundEndSystem : EntitySystem, IResettingEntitySystem
|
public class RoundEndSystem : EntitySystem, IResettingEntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
|
|
||||||
@@ -120,11 +119,12 @@ namespace Content.Server.RoundEnd
|
|||||||
private void EndRound()
|
private void EndRound()
|
||||||
{
|
{
|
||||||
OnRoundEndCountdownFinished?.Invoke();
|
OnRoundEndCountdownFinished?.Invoke();
|
||||||
_gameTicker.EndRound();
|
var gameTicker = EntitySystem.Get<GameTicker>();
|
||||||
|
gameTicker.EndRound();
|
||||||
|
|
||||||
_chatManager.DispatchServerAnnouncement(Loc.GetString("Restarting the round in {0} seconds...", RestartRoundTime));
|
_chatManager.DispatchServerAnnouncement(Loc.GetString("Restarting the round in {0} seconds...", RestartRoundTime));
|
||||||
|
|
||||||
Timer.Spawn(TimeSpan.FromSeconds(RestartRoundTime), () => _gameTicker.RestartRound(), CancellationToken.None);
|
Timer.Spawn(TimeSpan.FromSeconds(RestartRoundTime), () => gameTicker.RestartRound(), CancellationToken.None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,11 +21,10 @@ using static Content.Shared.Inventory.EquipmentSlotDefines;
|
|||||||
|
|
||||||
namespace Content.Server.Sandbox
|
namespace Content.Server.Sandbox
|
||||||
{
|
{
|
||||||
internal sealed class SandboxManager : SharedSandboxManager, ISandboxManager
|
internal sealed class SandboxManager : SharedSandboxManager, ISandboxManager, IEntityEventSubscriber
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IServerNetManager _netManager = default!;
|
[Dependency] private readonly IServerNetManager _netManager = default!;
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
|
||||||
[Dependency] private readonly IPlacementManager _placementManager = default!;
|
[Dependency] private readonly IPlacementManager _placementManager = default!;
|
||||||
[Dependency] private readonly IConGroupController _conGroupController = default!;
|
[Dependency] private readonly IConGroupController _conGroupController = default!;
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
@@ -53,7 +52,7 @@ namespace Content.Server.Sandbox
|
|||||||
_netManager.RegisterNetMessage<MsgSandboxSuicide>(nameof(MsgSandboxSuicide), SandboxSuicideReceived);
|
_netManager.RegisterNetMessage<MsgSandboxSuicide>(nameof(MsgSandboxSuicide), SandboxSuicideReceived);
|
||||||
|
|
||||||
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||||
_gameTicker.OnRunLevelChanged += GameTickerOnOnRunLevelChanged;
|
_entityManager.EventBus.SubscribeEvent<GameRunLevelChangedEvent>(EventSource.Local, this, GameTickerOnOnRunLevelChanged);
|
||||||
|
|
||||||
_placementManager.AllowPlacementFunc = placement =>
|
_placementManager.AllowPlacementFunc = placement =>
|
||||||
{
|
{
|
||||||
@@ -74,10 +73,10 @@ namespace Content.Server.Sandbox
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GameTickerOnOnRunLevelChanged(GameRunLevelChangedEventArgs obj)
|
private void GameTickerOnOnRunLevelChanged(GameRunLevelChangedEvent obj)
|
||||||
{
|
{
|
||||||
// Automatically clear sandbox state when round resets.
|
// Automatically clear sandbox state when round resets.
|
||||||
if (obj.NewRunLevel == GameRunLevel.PreRoundLobby)
|
if (obj.New == GameRunLevel.PreRoundLobby)
|
||||||
{
|
{
|
||||||
IsSandboxEnabled = false;
|
IsSandboxEnabled = false;
|
||||||
}
|
}
|
||||||
@@ -103,7 +102,7 @@ namespace Content.Server.Sandbox
|
|||||||
}
|
}
|
||||||
|
|
||||||
var player = _playerManager.GetSessionByChannel(message.MsgChannel);
|
var player = _playerManager.GetSessionByChannel(message.MsgChannel);
|
||||||
_gameTicker.Respawn(player);
|
EntitySystem.Get<GameTicker>().Respawn(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SandboxGiveAccessReceived(MsgSandboxGiveAccess message)
|
private void SandboxGiveAccessReceived(MsgSandboxGiveAccess message)
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Content.Server.GameTicking;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using Robust.Server;
|
|
||||||
using Robust.Server.Player;
|
|
||||||
using Robust.Server.ServerStatus;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
|
|
||||||
namespace Content.Server.Shell
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Tiny helper class to handle status messages. Nothing too complicated.
|
|
||||||
/// </summary>
|
|
||||||
public class StatusShell
|
|
||||||
{
|
|
||||||
private readonly IPlayerManager _playerManager;
|
|
||||||
private readonly string _name;
|
|
||||||
private GameRunLevel _runLevel;
|
|
||||||
private DateTime _roundStartTime;
|
|
||||||
|
|
||||||
public StatusShell()
|
|
||||||
{
|
|
||||||
_playerManager = IoCManager.Resolve<IPlayerManager>();
|
|
||||||
var baseServer = IoCManager.Resolve<IBaseServer>();
|
|
||||||
var gameTicker = IoCManager.Resolve<IGameTicker>();
|
|
||||||
|
|
||||||
gameTicker.OnRunLevelChanged += _runLevelChanged;
|
|
||||||
|
|
||||||
_name = baseServer.ServerName;
|
|
||||||
IoCManager.Resolve<IStatusHost>().OnStatusRequest += _getResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void _getResponse(JObject jObject)
|
|
||||||
{
|
|
||||||
lock (this)
|
|
||||||
{
|
|
||||||
jObject["name"] = _name;
|
|
||||||
jObject["players"] = _playerManager.PlayerCount;
|
|
||||||
jObject["run_level"] = (int) _runLevel;
|
|
||||||
if (_runLevel >= GameRunLevel.InRound)
|
|
||||||
{
|
|
||||||
jObject["round_start_time"] = _roundStartTime.ToString("o");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void _runLevelChanged(GameRunLevelChangedEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
lock (this)
|
|
||||||
{
|
|
||||||
_runLevel = eventArgs.NewRunLevel;
|
|
||||||
if (eventArgs.NewRunLevel == GameRunLevel.InRound)
|
|
||||||
{
|
|
||||||
_roundStartTime = DateTime.UtcNow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,7 +12,6 @@ namespace Content.Server.Spawners.Components
|
|||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public class ConditionalSpawnerComponent : Component, IMapInit
|
public class ConditionalSpawnerComponent : Component, IMapInit
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
|
||||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||||
|
|
||||||
public override string Name => "ConditionalSpawner";
|
public override string Name => "ConditionalSpawner";
|
||||||
@@ -29,9 +28,9 @@ namespace Content.Server.Spawners.Components
|
|||||||
[DataField("chance")]
|
[DataField("chance")]
|
||||||
public float Chance { get; set; } = 1.0f;
|
public float Chance { get; set; } = 1.0f;
|
||||||
|
|
||||||
private void RuleAdded(GameRuleAddedEventArgs obj)
|
public void RuleAdded(GameRuleAddedEvent obj)
|
||||||
{
|
{
|
||||||
if(_gameRules.Contains(obj.GameRule.GetType().Name))
|
if(_gameRules.Contains(obj.Rule.GetType().Name))
|
||||||
Spawn();
|
Spawn();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +44,7 @@ namespace Content.Server.Spawners.Components
|
|||||||
|
|
||||||
foreach (var rule in _gameRules)
|
foreach (var rule in _gameRules)
|
||||||
{
|
{
|
||||||
if (!_gameTicker.HasGameRule(rule)) continue;
|
if (!EntitySystem.Get<GameTicker>().HasGameRule(rule)) continue;
|
||||||
Spawn();
|
Spawn();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -68,8 +67,6 @@ namespace Content.Server.Spawners.Components
|
|||||||
|
|
||||||
public virtual void MapInit()
|
public virtual void MapInit()
|
||||||
{
|
{
|
||||||
_gameTicker.OnRuleAdded += RuleAdded;
|
|
||||||
|
|
||||||
TrySpawn();
|
TrySpawn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using Content.Server.GameTicking;
|
||||||
|
using Content.Server.Spawners.Components;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.Spawners.EntitySystems
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
public class ConditionalSpawnerSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<GameRuleAddedEvent>(OnRuleAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRuleAdded(GameRuleAddedEvent args)
|
||||||
|
{
|
||||||
|
foreach (var spawner in ComponentManager.EntityQuery<ConditionalSpawnerComponent>())
|
||||||
|
{
|
||||||
|
spawner.RuleAdded(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -167,7 +167,7 @@ namespace Content.Server.StationEvents.Events
|
|||||||
private bool TryFindRandomTile(out Vector2i tile, IRobustRandom? robustRandom = null)
|
private bool TryFindRandomTile(out Vector2i tile, IRobustRandom? robustRandom = null)
|
||||||
{
|
{
|
||||||
tile = default;
|
tile = default;
|
||||||
var defaultGridId = IoCManager.Resolve<IGameTicker>().DefaultGridId;
|
var defaultGridId = EntitySystem.Get<GameTicker>().DefaultGridId;
|
||||||
|
|
||||||
if (!IoCManager.Resolve<IMapManager>().TryGetGrid(defaultGridId, out var grid) ||
|
if (!IoCManager.Resolve<IMapManager>().TryGetGrid(defaultGridId, out var grid) ||
|
||||||
!IoCManager.Resolve<IEntityManager>().TryGetEntity(grid.GridEntityId, out _targetGrid)) return false;
|
!IoCManager.Resolve<IEntityManager>().TryGetEntity(grid.GridEntityId, out _targetGrid)) return false;
|
||||||
|
|||||||
@@ -66,8 +66,7 @@ namespace Content.Server.StationEvents.Events
|
|||||||
if (_timeUntilPulse <= 0.0f)
|
if (_timeUntilPulse <= 0.0f)
|
||||||
{
|
{
|
||||||
var pauseManager = IoCManager.Resolve<IPauseManager>();
|
var pauseManager = IoCManager.Resolve<IPauseManager>();
|
||||||
var gameTicker = IoCManager.Resolve<IGameTicker>();
|
var defaultGrid = IoCManager.Resolve<IMapManager>().GetGrid(EntitySystem.Get<GameTicker>().DefaultGridId);
|
||||||
var defaultGrid = IoCManager.Resolve<IMapManager>().GetGrid(gameTicker.DefaultGridId);
|
|
||||||
|
|
||||||
if (pauseManager.IsGridPaused(defaultGrid))
|
if (pauseManager.IsGridPaused(defaultGrid))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ namespace Content.Server.StationEvents
|
|||||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||||
[Dependency] private readonly IServerNetManager _netManager = default!;
|
[Dependency] private readonly IServerNetManager _netManager = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IGameTicker _gameTicker = default!;
|
|
||||||
[Dependency] private readonly IConGroupController _conGroupController = default!;
|
[Dependency] private readonly IConGroupController _conGroupController = default!;
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
@@ -214,7 +213,7 @@ namespace Content.Server.StationEvents
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Stop events from happening in lobby and force active event to end if the round ends
|
// Stop events from happening in lobby and force active event to end if the round ends
|
||||||
if (_gameTicker.RunLevel != GameRunLevel.InRound)
|
if (Get<GameTicker>().RunLevel != GameRunLevel.InRound)
|
||||||
{
|
{
|
||||||
if (CurrentEvent != null)
|
if (CurrentEvent != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Content.Server.GameTicking;
|
||||||
using Content.Shared;
|
using Content.Shared;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
@@ -46,7 +48,7 @@ namespace Content.Server.Voting.Managers
|
|||||||
if (votesYes / (float) total >= ratioRequired)
|
if (votesYes / (float) total >= ratioRequired)
|
||||||
{
|
{
|
||||||
_chatManager.DispatchServerAnnouncement(Loc.GetString("ui-vote-restart-succeeded"));
|
_chatManager.DispatchServerAnnouncement(Loc.GetString("ui-vote-restart-succeeded"));
|
||||||
_ticker.RestartRound();
|
EntitySystem.Get<GameTicker>().RestartRound();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -109,7 +111,7 @@ namespace Content.Server.Voting.Managers
|
|||||||
Loc.GetString("ui-vote-gamemode-win", ("winner", Loc.GetString(presets[picked]))));
|
Loc.GetString("ui-vote-gamemode-win", ("winner", Loc.GetString(presets[picked]))));
|
||||||
}
|
}
|
||||||
|
|
||||||
_ticker.SetStartPreset(picked);
|
EntitySystem.Get<GameTicker>().SetStartPreset(picked);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ namespace Content.Server.Voting.Managers
|
|||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[Dependency] private readonly IGameTicker _ticker = default!;
|
|
||||||
[Dependency] private readonly IAdminManager _adminMgr = default!;
|
[Dependency] private readonly IAdminManager _adminMgr = default!;
|
||||||
|
|
||||||
private int _nextVoteId = 1;
|
private int _nextVoteId = 1;
|
||||||
|
|||||||
@@ -26,12 +26,18 @@ namespace Content.Shared.CCVar
|
|||||||
public static readonly CVarDef<bool>
|
public static readonly CVarDef<bool>
|
||||||
EventsEnabled = CVarDef.Create("events.enabled", false, CVar.ARCHIVE | CVar.SERVERONLY);
|
EventsEnabled = CVarDef.Create("events.enabled", false, CVar.ARCHIVE | CVar.SERVERONLY);
|
||||||
|
|
||||||
|
public static readonly CVarDef<bool>
|
||||||
|
GameDummyTicker = CVarDef.Create("game.dummyticker", false, CVar.ARCHIVE | CVar.SERVERONLY);
|
||||||
|
|
||||||
public static readonly CVarDef<bool>
|
public static readonly CVarDef<bool>
|
||||||
GameLobbyEnabled = CVarDef.Create("game.lobbyenabled", false, CVar.ARCHIVE);
|
GameLobbyEnabled = CVarDef.Create("game.lobbyenabled", false, CVar.ARCHIVE);
|
||||||
|
|
||||||
public static readonly CVarDef<int>
|
public static readonly CVarDef<int>
|
||||||
GameLobbyDuration = CVarDef.Create("game.lobbyduration", 60, CVar.ARCHIVE);
|
GameLobbyDuration = CVarDef.Create("game.lobbyduration", 60, CVar.ARCHIVE);
|
||||||
|
|
||||||
|
public static readonly CVarDef<bool>
|
||||||
|
GameDisallowLateJoins = CVarDef.Create("game.disallowlatejoins", false, CVar.ARCHIVE | CVar.SERVERONLY);
|
||||||
|
|
||||||
public static readonly CVarDef<string>
|
public static readonly CVarDef<string>
|
||||||
GameLobbyDefaultPreset = CVarDef.Create("game.defaultpreset", "Suspicion", CVar.ARCHIVE);
|
GameLobbyDefaultPreset = CVarDef.Create("game.defaultpreset", "Suspicion", CVar.ARCHIVE);
|
||||||
|
|
||||||
|
|||||||
@@ -2,278 +2,126 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using Robust.Shared.GameObjects;
|
||||||
using Lidgren.Network;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
namespace Content.Shared.GameTicking
|
namespace Content.Shared.GameTicking
|
||||||
{
|
{
|
||||||
public abstract class SharedGameTicker
|
public abstract class SharedGameTicker : EntitySystem
|
||||||
{
|
{
|
||||||
// See ideally these would be pulled from the job definition or something.
|
// See ideally these would be pulled from the job definition or something.
|
||||||
// But this is easier, and at least it isn't hardcoded.
|
// But this is easier, and at least it isn't hardcoded.
|
||||||
public const string OverflowJob = "Assistant";
|
public const string OverflowJob = "Assistant";
|
||||||
public const string OverflowJobName = "assistant";
|
public const string OverflowJobName = "assistant";
|
||||||
|
}
|
||||||
|
|
||||||
protected class MsgTickerJoinLobby : NetMessage
|
[Serializable, NetSerializable]
|
||||||
|
public class TickerJoinLobbyEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class TickerJoinGameEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class TickerLateJoinStatusEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
// TODO: Make this a replicated CVar, honestly.
|
||||||
|
public bool Disallowed { get; }
|
||||||
|
|
||||||
|
public TickerLateJoinStatusEvent(bool disallowed)
|
||||||
{
|
{
|
||||||
#region REQUIRED
|
Disallowed = disallowed;
|
||||||
|
|
||||||
public const MsgGroups GROUP = MsgGroups.Command;
|
|
||||||
public const string NAME = nameof(MsgTickerJoinLobby);
|
|
||||||
public MsgTickerJoinLobby(INetChannel channel) : base(NAME, GROUP) { }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected class MsgTickerJoinGame : NetMessage
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class TickerLobbyStatusEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public bool IsRoundStarted { get; }
|
||||||
|
public string? LobbySong { get; }
|
||||||
|
public bool YouAreReady { get; }
|
||||||
|
// UTC.
|
||||||
|
public TimeSpan StartTime { get; }
|
||||||
|
public bool Paused { get; }
|
||||||
|
|
||||||
|
public TickerLobbyStatusEvent(bool isRoundStarted, string? lobbySong, bool youAreReady, TimeSpan startTime, bool paused)
|
||||||
{
|
{
|
||||||
#region REQUIRED
|
IsRoundStarted = isRoundStarted;
|
||||||
|
LobbySong = lobbySong;
|
||||||
public const MsgGroups GROUP = MsgGroups.Command;
|
YouAreReady = youAreReady;
|
||||||
public const string NAME = nameof(MsgTickerJoinGame);
|
StartTime = startTime;
|
||||||
public MsgTickerJoinGame(INetChannel channel) : base(NAME, GROUP) { }
|
Paused = paused;
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected class MsgTickerLateJoinStatus : NetMessage
|
[Serializable, NetSerializable]
|
||||||
|
public class TickerLobbyInfoEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public string TextBlob { get; }
|
||||||
|
|
||||||
|
public TickerLobbyInfoEvent(string textBlob)
|
||||||
{
|
{
|
||||||
#region REQUIRED
|
TextBlob = textBlob;
|
||||||
|
|
||||||
public const MsgGroups GROUP = MsgGroups.Command;
|
|
||||||
public const string NAME = nameof(MsgTickerLateJoinStatus);
|
|
||||||
|
|
||||||
public bool Disallowed { get; set; }
|
|
||||||
|
|
||||||
public MsgTickerLateJoinStatus(INetChannel channel) : base(NAME, GROUP) { }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
|
||||||
{
|
|
||||||
Disallowed = buffer.ReadBoolean();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
|
||||||
{
|
|
||||||
buffer.Write(Disallowed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class TickerLobbyCountdownEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The game time that the game will start at.
|
||||||
|
/// </summary>
|
||||||
|
public TimeSpan StartTime { get; }
|
||||||
|
|
||||||
protected class MsgTickerLobbyStatus : NetMessage
|
/// <summary>
|
||||||
|
/// Whether or not the countdown is paused
|
||||||
|
/// </summary>
|
||||||
|
public bool Paused { get; }
|
||||||
|
|
||||||
|
public TickerLobbyCountdownEvent(TimeSpan startTime, bool paused)
|
||||||
{
|
{
|
||||||
#region REQUIRED
|
StartTime = startTime;
|
||||||
|
Paused = paused;
|
||||||
public const MsgGroups GROUP = MsgGroups.Command;
|
|
||||||
public const string NAME = nameof(MsgTickerLobbyStatus);
|
|
||||||
public MsgTickerLobbyStatus(INetChannel channel) : base(NAME, GROUP) { }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public bool IsRoundStarted { get; set; }
|
|
||||||
public string? LobbySong { get; set; }
|
|
||||||
public bool YouAreReady { get; set; }
|
|
||||||
// UTC.
|
|
||||||
public TimeSpan StartTime { get; set; }
|
|
||||||
public bool Paused { get; set; }
|
|
||||||
|
|
||||||
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
|
||||||
{
|
|
||||||
IsRoundStarted = buffer.ReadBoolean();
|
|
||||||
LobbySong = buffer.ReadString();
|
|
||||||
|
|
||||||
if (IsRoundStarted)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
YouAreReady = buffer.ReadBoolean();
|
|
||||||
StartTime = new TimeSpan(buffer.ReadInt64());
|
|
||||||
Paused = buffer.ReadBoolean();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
|
||||||
{
|
|
||||||
buffer.Write(IsRoundStarted);
|
|
||||||
buffer.Write(LobbySong);
|
|
||||||
|
|
||||||
if (IsRoundStarted)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.Write(YouAreReady);
|
|
||||||
buffer.Write(StartTime.Ticks);
|
|
||||||
buffer.Write(Paused);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected class MsgTickerLobbyInfo : NetMessage
|
[Serializable, NetSerializable]
|
||||||
|
public class TickerLobbyReadyEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The Status of the Player in the lobby (ready, observer, ...)
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<NetUserId, LobbyPlayerStatus> Status { get; }
|
||||||
|
|
||||||
|
public TickerLobbyReadyEvent(Dictionary<NetUserId, LobbyPlayerStatus> status)
|
||||||
{
|
{
|
||||||
#region REQUIRED
|
Status = status;
|
||||||
|
|
||||||
public const MsgGroups GROUP = MsgGroups.Command;
|
|
||||||
public const string NAME = nameof(MsgTickerLobbyInfo);
|
|
||||||
public MsgTickerLobbyInfo(INetChannel channel) : base(NAME, GROUP) { }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public string TextBlob { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
|
||||||
{
|
|
||||||
TextBlob = buffer.ReadString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
|
||||||
{
|
|
||||||
buffer.Write(TextBlob);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected class MsgTickerLobbyCountdown : NetMessage
|
[Serializable, NetSerializable]
|
||||||
|
public class TickerJobsAvailableEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The Status of the Player in the lobby (ready, observer, ...)
|
||||||
|
/// </summary>
|
||||||
|
public string[] JobsAvailable { get; }
|
||||||
|
|
||||||
|
public TickerJobsAvailableEvent(string[] jobsAvailable)
|
||||||
{
|
{
|
||||||
#region REQUIRED
|
JobsAvailable = jobsAvailable;
|
||||||
|
|
||||||
public const MsgGroups GROUP = MsgGroups.Command;
|
|
||||||
public const string NAME = nameof(MsgTickerLobbyCountdown);
|
|
||||||
public MsgTickerLobbyCountdown(INetChannel channel) : base(NAME, GROUP) { }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The game time that the game will start at.
|
|
||||||
/// </summary>
|
|
||||||
public TimeSpan StartTime { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether or not the countdown is paused
|
|
||||||
/// </summary>
|
|
||||||
public bool Paused { get; set; }
|
|
||||||
|
|
||||||
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
|
||||||
{
|
|
||||||
StartTime = new TimeSpan(buffer.ReadInt64());
|
|
||||||
Paused = buffer.ReadBoolean();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
|
||||||
{
|
|
||||||
buffer.Write(StartTime.Ticks);
|
|
||||||
buffer.Write(Paused);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class MsgTickerLobbyReady : NetMessage
|
|
||||||
{
|
|
||||||
#region REQUIRED
|
|
||||||
|
|
||||||
public const MsgGroups GROUP = MsgGroups.Command;
|
|
||||||
public const string NAME = nameof(MsgTickerLobbyReady);
|
|
||||||
public MsgTickerLobbyReady(INetChannel channel) : base(NAME, GROUP) { }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The Status of the Player in the lobby (ready, observer, ...)
|
|
||||||
/// </summary>
|
|
||||||
public Dictionary<NetUserId, PlayerStatus> PlayerStatus { get; set; } = new();
|
|
||||||
|
|
||||||
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
|
||||||
{
|
|
||||||
PlayerStatus = new Dictionary<NetUserId, PlayerStatus>();
|
|
||||||
var length = buffer.ReadInt32();
|
|
||||||
for (int i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
var serializer = IoCManager.Resolve<IRobustSerializer>();
|
|
||||||
var byteLength = buffer.ReadVariableInt32();
|
|
||||||
NetUserId userId;
|
|
||||||
using (var stream = buffer.ReadAlignedMemory(byteLength))
|
|
||||||
{
|
|
||||||
serializer.DeserializeDirect(stream, out userId);
|
|
||||||
}
|
|
||||||
var status = (PlayerStatus)buffer.ReadByte();
|
|
||||||
PlayerStatus.Add(userId, status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
|
||||||
{
|
|
||||||
var serializer = IoCManager.Resolve<IRobustSerializer>();
|
|
||||||
buffer.Write(PlayerStatus.Count);
|
|
||||||
foreach (var p in PlayerStatus)
|
|
||||||
{
|
|
||||||
using (var stream = new MemoryStream())
|
|
||||||
{
|
|
||||||
serializer.SerializeDirect(stream, p.Key);
|
|
||||||
buffer.WriteVariableInt32((int) stream.Length);
|
|
||||||
stream.TryGetBuffer(out var segment);
|
|
||||||
buffer.Write(segment);
|
|
||||||
}
|
|
||||||
buffer.Write((byte)p.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class MsgTickerJobsAvailable : NetMessage
|
|
||||||
{
|
|
||||||
#region REQUIRED
|
|
||||||
|
|
||||||
public const MsgGroups GROUP = MsgGroups.Command;
|
|
||||||
public const string NAME = nameof(MsgTickerJobsAvailable);
|
|
||||||
public MsgTickerJobsAvailable(INetChannel channel) : base(NAME, GROUP) { }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The Status of the Player in the lobby (ready, observer, ...)
|
|
||||||
/// </summary>
|
|
||||||
public string[] JobsAvailable { get; set; } = Array.Empty<string>();
|
|
||||||
|
|
||||||
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
|
||||||
{
|
|
||||||
var amount = buffer.ReadInt32();
|
|
||||||
JobsAvailable = new string[amount];
|
|
||||||
|
|
||||||
for (var i = 0; i < amount; i++)
|
|
||||||
{
|
|
||||||
JobsAvailable[i] = buffer.ReadString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
|
||||||
{
|
|
||||||
buffer.Write(JobsAvailable.Length);
|
|
||||||
|
|
||||||
foreach (var job in JobsAvailable)
|
|
||||||
{
|
|
||||||
buffer.Write(job);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class RoundEndMessageEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
public struct RoundEndPlayerInfo
|
public struct RoundEndPlayerInfo
|
||||||
{
|
{
|
||||||
public string PlayerOOCName;
|
public string PlayerOOCName;
|
||||||
@@ -283,81 +131,30 @@ namespace Content.Shared.GameTicking
|
|||||||
public bool Observer;
|
public bool Observer;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class MsgRoundEndMessage : NetMessage
|
public string GamemodeTitle { get; }
|
||||||
|
public string RoundEndText { get; }
|
||||||
|
public TimeSpan RoundDuration { get; }
|
||||||
|
public int PlayerCount { get; }
|
||||||
|
public RoundEndPlayerInfo[] AllPlayersEndInfo { get; }
|
||||||
|
|
||||||
|
public RoundEndMessageEvent(string gamemodeTitle, string roundEndText, TimeSpan roundDuration, int playerCount,
|
||||||
|
RoundEndPlayerInfo[] allPlayersEndInfo)
|
||||||
{
|
{
|
||||||
|
GamemodeTitle = gamemodeTitle;
|
||||||
#region REQUIRED
|
RoundEndText = roundEndText;
|
||||||
|
RoundDuration = roundDuration;
|
||||||
public const MsgGroups GROUP = MsgGroups.Command;
|
PlayerCount = playerCount;
|
||||||
public const string NAME = nameof(MsgRoundEndMessage);
|
AllPlayersEndInfo = allPlayersEndInfo;
|
||||||
public MsgRoundEndMessage(INetChannel channel) : base(NAME, GROUP) { }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public string GamemodeTitle = string.Empty;
|
|
||||||
public string RoundEndText = string.Empty;
|
|
||||||
public TimeSpan RoundDuration;
|
|
||||||
|
|
||||||
|
|
||||||
public int PlayerCount;
|
|
||||||
|
|
||||||
public List<RoundEndPlayerInfo> AllPlayersEndInfo = new();
|
|
||||||
|
|
||||||
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
|
||||||
{
|
|
||||||
GamemodeTitle = buffer.ReadString();
|
|
||||||
RoundEndText = buffer.ReadString();
|
|
||||||
|
|
||||||
var hours = buffer.ReadInt32();
|
|
||||||
var mins = buffer.ReadInt32();
|
|
||||||
var seconds = buffer.ReadInt32();
|
|
||||||
RoundDuration = new TimeSpan(hours, mins, seconds);
|
|
||||||
|
|
||||||
PlayerCount = buffer.ReadInt32();
|
|
||||||
AllPlayersEndInfo = new List<RoundEndPlayerInfo>();
|
|
||||||
for(var i = 0; i < PlayerCount; i++)
|
|
||||||
{
|
|
||||||
var readPlayerData = new RoundEndPlayerInfo
|
|
||||||
{
|
|
||||||
PlayerOOCName = buffer.ReadString(),
|
|
||||||
PlayerICName = buffer.ReadString(),
|
|
||||||
Role = buffer.ReadString(),
|
|
||||||
Antag = buffer.ReadBoolean(),
|
|
||||||
Observer = buffer.ReadBoolean(),
|
|
||||||
};
|
|
||||||
|
|
||||||
AllPlayersEndInfo.Add(readPlayerData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
|
||||||
{
|
|
||||||
buffer.Write(GamemodeTitle);
|
|
||||||
buffer.Write(RoundEndText);
|
|
||||||
buffer.Write(RoundDuration.Hours);
|
|
||||||
buffer.Write(RoundDuration.Minutes);
|
|
||||||
buffer.Write(RoundDuration.Seconds);
|
|
||||||
|
|
||||||
|
|
||||||
buffer.Write(AllPlayersEndInfo.Count);
|
|
||||||
foreach(var playerEndInfo in AllPlayersEndInfo)
|
|
||||||
{
|
|
||||||
buffer.Write(playerEndInfo.PlayerOOCName);
|
|
||||||
buffer.Write(playerEndInfo.PlayerICName);
|
|
||||||
buffer.Write(playerEndInfo.Role);
|
|
||||||
buffer.Write(playerEndInfo.Antag);
|
|
||||||
buffer.Write(playerEndInfo.Observer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum PlayerStatus : byte
|
|
||||||
{
|
[Serializable, NetSerializable]
|
||||||
NotReady = 0,
|
public enum LobbyPlayerStatus : sbyte
|
||||||
Ready,
|
{
|
||||||
Observer,
|
NotReady = 0,
|
||||||
}
|
Ready,
|
||||||
|
Observer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
#nullable enable
|
|
||||||
using Lidgren.Network;
|
|
||||||
using Robust.Shared.Network;
|
|
||||||
|
|
||||||
namespace Content.Shared.GameWindow
|
|
||||||
{
|
|
||||||
public sealed class MsgRequestWindowAttention : NetMessage
|
|
||||||
{
|
|
||||||
#region REQUIRED
|
|
||||||
|
|
||||||
public const MsgGroups GROUP = MsgGroups.Command;
|
|
||||||
public const string NAME = nameof(MsgRequestWindowAttention);
|
|
||||||
public MsgRequestWindowAttention(INetChannel channel) : base(NAME, GROUP) { }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
|
||||||
{
|
|
||||||
// Nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
|
||||||
{
|
|
||||||
// Nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
12
Content.Shared/GameWindow/RequestWindowAttentionEvent.cs
Normal file
12
Content.Shared/GameWindow/RequestWindowAttentionEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#nullable enable
|
||||||
|
using System;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.GameWindow
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class RequestWindowAttentionEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.IntegrationTests;
|
using Content.IntegrationTests;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization.Markdown.Validation;
|
using Robust.Shared.Serialization.Markdown.Validation;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
@@ -69,6 +70,7 @@ namespace Content.YAMLLinter
|
|||||||
var server = StartServer(new ServerContentIntegrationOption()
|
var server = StartServer(new ServerContentIntegrationOption()
|
||||||
{
|
{
|
||||||
FailureLogLevel = null,
|
FailureLogLevel = null,
|
||||||
|
CVarOverrides = { {CCVars.GameDummyTicker.Name, "true"} }
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.WaitIdleAsync();
|
await server.WaitIdleAsync();
|
||||||
|
|||||||
Reference in New Issue
Block a user