Add delaystart and forcepreset commands (#1163)
* Add extendroundstart message to extend lobby start timer * Rename StartExtend to DelayStart * Fix delaystart amounts above 59 not working * Change delaystart seconds type from int to uint * Change delaystart wrong args amount message * Add forcegamepreset command * Rename forcegamepreset to forcepreset and merged start and forcestart preset methods * Fix index out of bounds exception when forcing suspicion to start * Change game preset to match regardless of casing * Add forcepreset unknown preset message * Add and move in lobby checks * Remove testing changes * Change delaystart to pause/resume the timer when no seconds are specified * Change pause message * Remove testing code * Change 0 seconds to not be a valid amount of seconds * Replace MsgTickerLobbyCountdown Seconds with DateTime instead of uint * Add one entire dot * Replace Math.Min + Math.Max with Math.Clamp Co-authored-by: ComicIronic <comicironic@gmail.com> Co-authored-by: ComicIronic <comicironic@gmail.com>
This commit is contained in:
@@ -24,6 +24,7 @@ namespace Content.Client.GameTicking
|
|||||||
[ViewVariables] public bool IsGameStarted { get; private set; }
|
[ViewVariables] public bool IsGameStarted { get; private set; }
|
||||||
[ViewVariables] public string ServerInfoBlob { get; private set; }
|
[ViewVariables] public string ServerInfoBlob { get; private set; }
|
||||||
[ViewVariables] public DateTime StartTime { get; private set; }
|
[ViewVariables] public DateTime StartTime { get; private set; }
|
||||||
|
[ViewVariables] public bool Paused { get; private set; }
|
||||||
|
|
||||||
public event Action InfoBlobUpdated;
|
public event Action InfoBlobUpdated;
|
||||||
public event Action LobbyStatusUpdated;
|
public event Action LobbyStatusUpdated;
|
||||||
@@ -36,6 +37,7 @@ namespace Content.Client.GameTicking
|
|||||||
_netManager.RegisterNetMessage<MsgTickerJoinGame>(nameof(MsgTickerJoinGame), JoinGame);
|
_netManager.RegisterNetMessage<MsgTickerJoinGame>(nameof(MsgTickerJoinGame), JoinGame);
|
||||||
_netManager.RegisterNetMessage<MsgTickerLobbyStatus>(nameof(MsgTickerLobbyStatus), LobbyStatus);
|
_netManager.RegisterNetMessage<MsgTickerLobbyStatus>(nameof(MsgTickerLobbyStatus), LobbyStatus);
|
||||||
_netManager.RegisterNetMessage<MsgTickerLobbyInfo>(nameof(MsgTickerLobbyInfo), LobbyInfo);
|
_netManager.RegisterNetMessage<MsgTickerLobbyInfo>(nameof(MsgTickerLobbyInfo), LobbyInfo);
|
||||||
|
_netManager.RegisterNetMessage<MsgTickerLobbyCountdown>(nameof(MsgTickerLobbyCountdown), LobbyCountdown);
|
||||||
_netManager.RegisterNetMessage<MsgRoundEndMessage>(nameof(MsgRoundEndMessage), RoundEnd);
|
_netManager.RegisterNetMessage<MsgRoundEndMessage>(nameof(MsgRoundEndMessage), RoundEnd);
|
||||||
|
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
@@ -69,6 +71,12 @@ namespace Content.Client.GameTicking
|
|||||||
_stateManager.RequestStateChange<GameScreen>();
|
_stateManager.RequestStateChange<GameScreen>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LobbyCountdown(MsgTickerLobbyCountdown message)
|
||||||
|
{
|
||||||
|
StartTime = message.StartTime;
|
||||||
|
Paused = message.Paused;
|
||||||
|
}
|
||||||
|
|
||||||
private void RoundEnd(MsgRoundEndMessage message)
|
private void RoundEnd(MsgRoundEndMessage message)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ namespace Content.Client.Interfaces
|
|||||||
string ServerInfoBlob { get; }
|
string ServerInfoBlob { get; }
|
||||||
bool AreWeReady { get; }
|
bool AreWeReady { get; }
|
||||||
DateTime StartTime { get; }
|
DateTime StartTime { get; }
|
||||||
|
bool Paused { get; }
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
event Action InfoBlobUpdated;
|
event Action InfoBlobUpdated;
|
||||||
|
|||||||
@@ -123,21 +123,29 @@ namespace Content.Client.State
|
|||||||
}
|
}
|
||||||
|
|
||||||
string text;
|
string text;
|
||||||
var difference = _clientGameTicker.StartTime - DateTime.UtcNow;
|
|
||||||
if (difference.Ticks < 0)
|
if (_clientGameTicker.Paused)
|
||||||
{
|
{
|
||||||
if (difference.TotalSeconds < -5)
|
text = Loc.GetString("Paused");
|
||||||
{
|
|
||||||
text = Loc.GetString("Right Now?");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
text = Loc.GetString("Right Now");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
text = $"{(int) Math.Floor(difference.TotalMinutes)}:{difference.Seconds:D2}";
|
var difference = _clientGameTicker.StartTime - DateTime.UtcNow;
|
||||||
|
if (difference.Ticks < 0)
|
||||||
|
{
|
||||||
|
if (difference.TotalSeconds < -5)
|
||||||
|
{
|
||||||
|
text = Loc.GetString("Right Now?");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text = Loc.GetString("Right Now");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text = $"{(int) Math.Floor(difference.TotalMinutes)}:{difference.Seconds:D2}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_lobby.StartTime.Text = Loc.GetString("Round Starts In: {0}", text);
|
_lobby.StartTime.Text = Loc.GetString("Round Starts In: {0}", text);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace Content.IntegrationTests
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartRound()
|
public void StartRound(bool force = false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,12 +81,33 @@ namespace Content.IntegrationTests
|
|||||||
|
|
||||||
public IEnumerable<GameRule> ActiveGameRules { get; } = Array.Empty<GameRule>();
|
public IEnumerable<GameRule> ActiveGameRules { get; } = Array.Empty<GameRule>();
|
||||||
|
|
||||||
public void SetStartPreset(Type type)
|
public bool TryGetPreset(string name, out Type type)
|
||||||
|
{
|
||||||
|
type = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetStartPreset(Type type, bool force = false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetStartPreset(string type)
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Content.Server.GameTicking
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class GamePreset
|
public abstract class GamePreset
|
||||||
{
|
{
|
||||||
public abstract bool Start(IReadOnlyList<IPlayerSession> players);
|
public abstract bool Start(IReadOnlyList<IPlayerSession> readyPlayers, bool force = false);
|
||||||
public virtual string ModeTitle => "Sandbox";
|
public virtual string ModeTitle => "Sandbox";
|
||||||
public virtual string Description => "Secret!";
|
public virtual string Description => "Secret!";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Content.Server.GameTicking.GamePresets
|
|||||||
[Dependency] private readonly IGameTicker _gameTicker;
|
[Dependency] private readonly IGameTicker _gameTicker;
|
||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
|
|
||||||
public override bool Start(IReadOnlyList<IPlayerSession> readyPlayers)
|
public override bool Start(IReadOnlyList<IPlayerSession> readyPlayers, bool force = false)
|
||||||
{
|
{
|
||||||
_gameTicker.AddGameRule<RuleDeathMatch>();
|
_gameTicker.AddGameRule<RuleDeathMatch>();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace Content.Server.GameTicking.GamePresets
|
|||||||
[Dependency] private readonly ISandboxManager _sandboxManager;
|
[Dependency] private readonly ISandboxManager _sandboxManager;
|
||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
|
|
||||||
public override bool Start(IReadOnlyList<IPlayerSession> readyPlayers)
|
public override bool Start(IReadOnlyList<IPlayerSession> readyPlayers, bool force = false)
|
||||||
{
|
{
|
||||||
_sandboxManager.IsSandboxEnabled = true;
|
_sandboxManager.IsSandboxEnabled = true;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using Content.Server.GameTicking.GameRules;
|
using Content.Server.GameTicking.GameRules;
|
||||||
using Content.Server.Interfaces.Chat;
|
using Content.Server.Interfaces.Chat;
|
||||||
using Content.Server.Interfaces.GameTicking;
|
using Content.Server.Interfaces.GameTicking;
|
||||||
@@ -28,16 +27,17 @@ namespace Content.Server.GameTicking.GamePresets
|
|||||||
public int MinTraitors { get; set; } = 2;
|
public int MinTraitors { get; set; } = 2;
|
||||||
public int PlayersPerTraitor { get; set; } = 5;
|
public int PlayersPerTraitor { get; set; } = 5;
|
||||||
|
|
||||||
public override bool Start(IReadOnlyList<IPlayerSession> readyPlayers)
|
public override bool Start(IReadOnlyList<IPlayerSession> readyPlayers, bool force = false)
|
||||||
{
|
{
|
||||||
if (readyPlayers.Count < MinPlayers)
|
if (!force && readyPlayers.Count < MinPlayers)
|
||||||
{
|
{
|
||||||
_chatManager.DispatchServerAnnouncement($"Not enough players readied up for the game! There were {readyPlayers.Count} players readied up out of {MinPlayers} needed.");
|
_chatManager.DispatchServerAnnouncement($"Not enough players readied up for the game! There were {readyPlayers.Count} players readied up out of {MinPlayers} needed.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = new List<IPlayerSession>(readyPlayers);
|
var list = new List<IPlayerSession>(readyPlayers);
|
||||||
var numTraitors = Math.Max(readyPlayers.Count() % PlayersPerTraitor, MinTraitors);
|
var numTraitors = Math.Clamp(readyPlayers.Count % PlayersPerTraitor,
|
||||||
|
MinTraitors, readyPlayers.Count);
|
||||||
|
|
||||||
for (var i = 0; i < numTraitors; i++)
|
for (var i = 0; i < numTraitors; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
[ViewVariables] private Type _presetType;
|
[ViewVariables] private Type _presetType;
|
||||||
|
|
||||||
|
[ViewVariables] private DateTime _pauseTime;
|
||||||
[ViewVariables] private bool _roundStartCountdownHasNotStartedYetDueToNoPlayers;
|
[ViewVariables] private bool _roundStartCountdownHasNotStartedYetDueToNoPlayers;
|
||||||
private DateTime _roundStartTimeUtc;
|
private DateTime _roundStartTimeUtc;
|
||||||
[ViewVariables] private GameRunLevel _runLevel;
|
[ViewVariables] private GameRunLevel _runLevel;
|
||||||
@@ -92,6 +93,8 @@ namespace Content.Server.GameTicking
|
|||||||
private CancellationTokenSource _updateShutdownCts;
|
private CancellationTokenSource _updateShutdownCts;
|
||||||
|
|
||||||
|
|
||||||
|
[ViewVariables] public bool Paused { get; private set; }
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public GameRunLevel RunLevel
|
public GameRunLevel RunLevel
|
||||||
{
|
{
|
||||||
@@ -128,6 +131,7 @@ namespace Content.Server.GameTicking
|
|||||||
_netManager.RegisterNetMessage<MsgTickerJoinGame>(nameof(MsgTickerJoinGame));
|
_netManager.RegisterNetMessage<MsgTickerJoinGame>(nameof(MsgTickerJoinGame));
|
||||||
_netManager.RegisterNetMessage<MsgTickerLobbyStatus>(nameof(MsgTickerLobbyStatus));
|
_netManager.RegisterNetMessage<MsgTickerLobbyStatus>(nameof(MsgTickerLobbyStatus));
|
||||||
_netManager.RegisterNetMessage<MsgTickerLobbyInfo>(nameof(MsgTickerLobbyInfo));
|
_netManager.RegisterNetMessage<MsgTickerLobbyInfo>(nameof(MsgTickerLobbyInfo));
|
||||||
|
_netManager.RegisterNetMessage<MsgTickerLobbyCountdown>(nameof(MsgTickerLobbyCountdown));
|
||||||
_netManager.RegisterNetMessage<MsgRoundEndMessage>(nameof(MsgRoundEndMessage));
|
_netManager.RegisterNetMessage<MsgRoundEndMessage>(nameof(MsgRoundEndMessage));
|
||||||
|
|
||||||
SetStartPreset(_configurationManager.GetCVar<string>("game.defaultpreset"));
|
SetStartPreset(_configurationManager.GetCVar<string>("game.defaultpreset"));
|
||||||
@@ -156,9 +160,13 @@ namespace Content.Server.GameTicking
|
|||||||
RoundLengthMetric.Inc(frameEventArgs.DeltaSeconds);
|
RoundLengthMetric.Inc(frameEventArgs.DeltaSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RunLevel != GameRunLevel.PreRoundLobby || _roundStartTimeUtc > DateTime.UtcNow ||
|
if (RunLevel != GameRunLevel.PreRoundLobby ||
|
||||||
|
Paused ||
|
||||||
|
_roundStartTimeUtc > DateTime.UtcNow ||
|
||||||
_roundStartCountdownHasNotStartedYetDueToNoPlayers)
|
_roundStartCountdownHasNotStartedYetDueToNoPlayers)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
StartRound();
|
StartRound();
|
||||||
}
|
}
|
||||||
@@ -197,7 +205,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartRound()
|
public void StartRound(bool force = false)
|
||||||
{
|
{
|
||||||
DebugTools.Assert(RunLevel == GameRunLevel.PreRoundLobby);
|
DebugTools.Assert(RunLevel == GameRunLevel.PreRoundLobby);
|
||||||
Logger.InfoS("ticker", "Starting round!");
|
Logger.InfoS("ticker", "Starting round!");
|
||||||
@@ -247,13 +255,15 @@ namespace Content.Server.GameTicking
|
|||||||
// Time to start the preset.
|
// Time to start the preset.
|
||||||
var preset = MakeGamePreset();
|
var preset = MakeGamePreset();
|
||||||
|
|
||||||
if (!preset.Start(assignedJobs.Keys.ToList()))
|
if (!preset.Start(assignedJobs.Keys.ToList(), force))
|
||||||
{
|
{
|
||||||
SetStartPreset(_configurationManager.GetCVar<string>("game.fallbackpreset"));
|
SetStartPreset(_configurationManager.GetCVar<string>("game.fallbackpreset"));
|
||||||
var newPreset = MakeGamePreset();
|
var newPreset = MakeGamePreset();
|
||||||
_chatManager.DispatchServerAnnouncement($"Failed to start {preset.ModeTitle} mode! Defaulting to {newPreset.ModeTitle}...");
|
_chatManager.DispatchServerAnnouncement($"Failed to start {preset.ModeTitle} mode! Defaulting to {newPreset.ModeTitle}...");
|
||||||
if(!newPreset.Start(readyPlayers))
|
if (!newPreset.Start(readyPlayers, force))
|
||||||
|
{
|
||||||
throw new ApplicationException("Fallback preset failed to start!");
|
throw new ApplicationException("Fallback preset failed to start!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_roundStartTimeSpan = IoCManager.Resolve<IGameTiming>().RealTime;
|
_roundStartTimeSpan = IoCManager.Resolve<IGameTiming>().RealTime;
|
||||||
@@ -297,7 +307,7 @@ namespace Content.Server.GameTicking
|
|||||||
{
|
{
|
||||||
PlayerOOCName = ply.Name,
|
PlayerOOCName = ply.Name,
|
||||||
PlayerICName = mind.CurrentEntity.Name,
|
PlayerICName = mind.CurrentEntity.Name,
|
||||||
Role = antag ? mind.AllRoles.First(role => role.Antag).Name : mind.AllRoles.FirstOrDefault()?.Name ?? Loc.GetString("Unkown"),
|
Role = antag ? mind.AllRoles.First(role => role.Antag).Name : mind.AllRoles.FirstOrDefault()?.Name ?? Loc.GetString("Unknown"),
|
||||||
Antag = antag
|
Antag = antag
|
||||||
};
|
};
|
||||||
listOfPlayerInfo.Add(playerEndRoundInfo);
|
listOfPlayerInfo.Add(playerEndRoundInfo);
|
||||||
@@ -377,22 +387,90 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
public IEnumerable<GameRule> ActiveGameRules => _gameRules;
|
public IEnumerable<GameRule> ActiveGameRules => _gameRules;
|
||||||
|
|
||||||
public void SetStartPreset(Type type)
|
public bool TryGetPreset(string name, out Type type)
|
||||||
|
{
|
||||||
|
type = name.ToLower() switch
|
||||||
|
{
|
||||||
|
"sandbox" => typeof(PresetSandbox),
|
||||||
|
"deathmatch" => typeof(PresetDeathMatch),
|
||||||
|
"suspicion" => typeof(PresetSuspicion),
|
||||||
|
_ => default
|
||||||
|
};
|
||||||
|
|
||||||
|
return type != default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetStartPreset(Type type, bool force = false)
|
||||||
{
|
{
|
||||||
if (!typeof(GamePreset).IsAssignableFrom(type)) throw new ArgumentException("type must inherit GamePreset");
|
if (!typeof(GamePreset).IsAssignableFrom(type)) throw new ArgumentException("type must inherit GamePreset");
|
||||||
|
|
||||||
_presetType = type;
|
_presetType = type;
|
||||||
UpdateInfoText();
|
UpdateInfoText();
|
||||||
|
|
||||||
|
if (force)
|
||||||
|
{
|
||||||
|
StartRound(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetStartPreset(string type) =>
|
public void SetStartPreset(string name, bool force = false)
|
||||||
SetStartPreset(type switch
|
{
|
||||||
|
if (!TryGetPreset(name, out var type))
|
||||||
{
|
{
|
||||||
"Sandbox" => typeof(PresetSandbox),
|
throw new NotSupportedException();
|
||||||
"DeathMatch" => typeof(PresetDeathMatch),
|
}
|
||||||
"Suspicion" => typeof(PresetSuspicion),
|
|
||||||
_ => throw new NotSupportedException()
|
SetStartPreset(type, force);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
public bool DelayStart(TimeSpan time)
|
||||||
|
{
|
||||||
|
if (_runLevel != GameRunLevel.PreRoundLobby)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_roundStartTimeUtc += time;
|
||||||
|
|
||||||
|
var lobbyCountdownMessage = _netManager.CreateNetMessage<MsgTickerLobbyCountdown>();
|
||||||
|
lobbyCountdownMessage.StartTime = _roundStartTimeUtc;
|
||||||
|
lobbyCountdownMessage.Paused = Paused;
|
||||||
|
_netManager.ServerSendToAll(lobbyCountdownMessage);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PauseStart(bool pause = true)
|
||||||
|
{
|
||||||
|
if (Paused == pause)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Paused = pause;
|
||||||
|
|
||||||
|
if (pause)
|
||||||
|
{
|
||||||
|
_pauseTime = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
else if (_pauseTime != default)
|
||||||
|
{
|
||||||
|
_roundStartTimeUtc += DateTime.UtcNow - _pauseTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lobbyCountdownMessage = _netManager.CreateNetMessage<MsgTickerLobbyCountdown>();
|
||||||
|
lobbyCountdownMessage.StartTime = _roundStartTimeUtc;
|
||||||
|
lobbyCountdownMessage.Paused = Paused;
|
||||||
|
_netManager.ServerSendToAll(lobbyCountdownMessage);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TogglePause()
|
||||||
|
{
|
||||||
|
PauseStart(!Paused);
|
||||||
|
return Paused;
|
||||||
|
}
|
||||||
|
|
||||||
private IEntity _spawnPlayerMob(Job job, bool lateJoin = true)
|
private IEntity _spawnPlayerMob(Job job, bool lateJoin = true)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,6 +9,47 @@ using Robust.Shared.Network;
|
|||||||
|
|
||||||
namespace Content.Server.GameTicking
|
namespace Content.Server.GameTicking
|
||||||
{
|
{
|
||||||
|
class DelayStartCommand : IClientCommand
|
||||||
|
{
|
||||||
|
public string Command => "delaystart";
|
||||||
|
public string Description => "Delays the round start.";
|
||||||
|
public string Help => $"Usage: {Command} <seconds>\nPauses/Resumes the countdown if no argument is provided.";
|
||||||
|
|
||||||
|
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
|
||||||
|
{
|
||||||
|
var ticker = IoCManager.Resolve<IGameTicker>();
|
||||||
|
if (ticker.RunLevel != GameRunLevel.PreRoundLobby)
|
||||||
|
{
|
||||||
|
shell.SendText(player, "This can only be executed while the game is in the pre-round lobby.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.Length == 0)
|
||||||
|
{
|
||||||
|
var paused = ticker.TogglePause();
|
||||||
|
shell.SendText(player, paused ? "Paused the countdown." : "Resumed the countdown.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.Length != 1)
|
||||||
|
{
|
||||||
|
shell.SendText(player, "Need zero or one arguments.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uint.TryParse(args[0], out var seconds) || seconds == 0)
|
||||||
|
{
|
||||||
|
shell.SendText(player, $"{args[0]} isn't a valid amount of seconds.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var time = TimeSpan.FromSeconds(seconds);
|
||||||
|
if (!ticker.DelayStart(time))
|
||||||
|
{
|
||||||
|
shell.SendText(player, "An unknown error has occurred.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class StartRoundCommand : IClientCommand
|
class StartRoundCommand : IClientCommand
|
||||||
{
|
{
|
||||||
@@ -193,4 +234,37 @@ namespace Content.Server.GameTicking
|
|||||||
ticker.SetStartPreset(args[0]);
|
ticker.SetStartPreset(args[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ForcePresetCommand : IClientCommand
|
||||||
|
{
|
||||||
|
public string Command => "forcepreset";
|
||||||
|
public string Description => "Forces a specific game preset to start for the current lobby.";
|
||||||
|
public string Help => $"Usage: {Command} <preset>";
|
||||||
|
|
||||||
|
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
|
||||||
|
{
|
||||||
|
var ticker = IoCManager.Resolve<IGameTicker>();
|
||||||
|
if (ticker.RunLevel != GameRunLevel.PreRoundLobby)
|
||||||
|
{
|
||||||
|
shell.SendText(player, "This can only be executed while the game is in the pre-round lobby.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.Length != 1)
|
||||||
|
{
|
||||||
|
shell.SendText(player, "Need exactly one argument.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var name = args[0];
|
||||||
|
if (!ticker.TryGetPreset(name, out var type))
|
||||||
|
{
|
||||||
|
shell.SendText(player, $"No preset exists with name {name}.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ticker.SetStartPreset(type, true);
|
||||||
|
shell.SendText(player, $"Forced the game to start with preset {name}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace Content.Server.Interfaces.GameTicking
|
|||||||
void Update(FrameEventArgs frameEventArgs);
|
void Update(FrameEventArgs frameEventArgs);
|
||||||
|
|
||||||
void RestartRound();
|
void RestartRound();
|
||||||
void StartRound();
|
void StartRound(bool force = false);
|
||||||
void EndRound();
|
void EndRound();
|
||||||
|
|
||||||
void Respawn(IPlayerSession targetPlayer);
|
void Respawn(IPlayerSession targetPlayer);
|
||||||
@@ -39,7 +39,16 @@ namespace Content.Server.Interfaces.GameTicking
|
|||||||
void RemoveGameRule(GameRule rule);
|
void RemoveGameRule(GameRule rule);
|
||||||
IEnumerable<GameRule> ActiveGameRules { get; }
|
IEnumerable<GameRule> ActiveGameRules { get; }
|
||||||
|
|
||||||
void SetStartPreset(Type type);
|
bool TryGetPreset(string name, out Type type);
|
||||||
void SetStartPreset(string 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,6 +116,40 @@ namespace Content.Shared
|
|||||||
buffer.Write(TextBlob);
|
buffer.Write(TextBlob);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected class MsgTickerLobbyCountdown : NetMessage
|
||||||
|
{
|
||||||
|
#region REQUIRED
|
||||||
|
|
||||||
|
public const MsgGroups GROUP = MsgGroups.Command;
|
||||||
|
public const string NAME = nameof(MsgTickerLobbyCountdown);
|
||||||
|
public MsgTickerLobbyCountdown(INetChannel channel) : base(NAME, GROUP) { }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The total amount of seconds to go until the countdown finishes
|
||||||
|
/// </summary>
|
||||||
|
public DateTime 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 DateTime(buffer.ReadInt64(), DateTimeKind.Utc);
|
||||||
|
Paused = buffer.ReadBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
||||||
|
{
|
||||||
|
buffer.Write(StartTime.Ticks);
|
||||||
|
buffer.Write(Paused);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public struct RoundEndPlayerInfo
|
public struct RoundEndPlayerInfo
|
||||||
{
|
{
|
||||||
public string PlayerOOCName;
|
public string PlayerOOCName;
|
||||||
|
|||||||
@@ -55,6 +55,8 @@
|
|||||||
- tp
|
- tp
|
||||||
- tpgrid
|
- tpgrid
|
||||||
- setgamepreset
|
- setgamepreset
|
||||||
|
- forcepreset
|
||||||
|
- delaystart
|
||||||
- startround
|
- startround
|
||||||
- endround
|
- endround
|
||||||
- restartround
|
- restartround
|
||||||
@@ -98,6 +100,8 @@
|
|||||||
- tp
|
- tp
|
||||||
- tpgrid
|
- tpgrid
|
||||||
- setgamepreset
|
- setgamepreset
|
||||||
|
- forcepreset
|
||||||
|
- delaystart
|
||||||
- startround
|
- startround
|
||||||
- endround
|
- endround
|
||||||
- restartround
|
- restartround
|
||||||
|
|||||||
Reference in New Issue
Block a user