GameTicker watchdog update integration.

This commit is contained in:
Pieter-Jan Briers
2020-04-16 21:23:08 +02:00
parent f9ba0ddf24
commit a1c9ea8bbd

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using Content.Server.GameObjects; using Content.Server.GameObjects;
using Content.Server.GameObjects.Components.Access; using Content.Server.GameObjects.Components.Access;
using Content.Server.GameObjects.Components.Markers; using Content.Server.GameObjects.Components.Markers;
@@ -16,9 +17,11 @@ using Content.Shared;
using Content.Shared.Chat; using Content.Shared.Chat;
using Content.Shared.Jobs; using Content.Shared.Jobs;
using Content.Shared.Preferences; using Content.Shared.Preferences;
using Robust.Server.Interfaces;
using Robust.Server.Interfaces.Maps; using Robust.Server.Interfaces.Maps;
using Robust.Server.Interfaces.Player; using Robust.Server.Interfaces.Player;
using Robust.Server.Player; using Robust.Server.Player;
using Robust.Server.ServerStatus;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Enums; using Robust.Shared.Enums;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -35,16 +38,18 @@ using Robust.Shared.Map;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Timers;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines; using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
using Timer = Robust.Shared.Timers.Timer;
namespace Content.Server.GameTicking namespace Content.Server.GameTicking
{ {
public partial class GameTicker : SharedGameTicker, IGameTicker public partial class GameTicker : SharedGameTicker, IGameTicker
{ {
private static readonly TimeSpan UpdateRestartDelay = TimeSpan.FromSeconds(20);
private const string PlayerPrototypeName = "HumanMob_Content"; private const string PlayerPrototypeName = "HumanMob_Content";
private const string ObserverPrototypeName = "MobObserver"; private const string ObserverPrototypeName = "MobObserver";
private const string MapFile = "Maps/stationstation.yml"; private const string MapFile = "Maps/stationstation.yml";
@@ -67,6 +72,10 @@ namespace Content.Server.GameTicking
[ViewVariables] private bool LobbyEnabled => _configurationManager.GetCVar<bool>("game.lobbyenabled"); [ViewVariables] private bool LobbyEnabled => _configurationManager.GetCVar<bool>("game.lobbyenabled");
[ViewVariables] private bool _updateOnRoundEnd;
private CancellationTokenSource _updateShutdownCts;
[ViewVariables] [ViewVariables]
public GameRunLevel RunLevel public GameRunLevel RunLevel
{ {
@@ -109,6 +118,16 @@ namespace Content.Server.GameTicking
_initialized = true; _initialized = true;
JobControllerInit(); JobControllerInit();
_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();
} }
public void Update(FrameEventArgs frameEventArgs) public void Update(FrameEventArgs frameEventArgs)
@@ -122,6 +141,13 @@ namespace Content.Server.GameTicking
public void RestartRound() public void RestartRound()
{ {
if (_updateOnRoundEnd)
{
_baseServer.Shutdown(
Loc.GetString("Server is shutting down for update and will automatically restart."));
return;
}
Logger.InfoS("ticker", "Restarting round!"); Logger.InfoS("ticker", "Restarting round!");
SendServerMessage("Restarting round..."); SendServerMessage("Restarting round...");
@@ -421,6 +447,11 @@ namespace Content.Server.GameTicking
switch (args.NewStatus) switch (args.NewStatus)
{ {
case SessionStatus.Connecting:
// Cancel shutdown update timer in progress.
_updateShutdownCts?.Cancel();
break;
case SessionStatus.Connected: case SessionStatus.Connected:
{ {
// Always make sure the client has player data. Mind gets assigned on spawn. // Always make sure the client has player data. Mind gets assigned on spawn.
@@ -475,11 +506,43 @@ namespace Content.Server.GameTicking
if (_playersInLobby.ContainsKey(session)) _playersInLobby.Remove(session); if (_playersInLobby.ContainsKey(session)) _playersInLobby.Remove(session);
_chatManager.DispatchServerAnnouncement($"Player {args.Session.SessionId} left server!"); _chatManager.DispatchServerAnnouncement($"Player {args.Session.SessionId} left server!");
ServerEmptyUpdateRestartCheck();
break; break;
} }
} }
} }
/// <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 != null && !_updateShutdownCts.IsCancellationRequested)
{
// 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);
}
private void SpawnPlayer(IPlayerSession session, string jobId = null, bool lateJoin = true) private void SpawnPlayer(IPlayerSession session, string jobId = null, bool lateJoin = true)
{ {
var character = (HumanoidCharacterProfile) _prefsManager var character = (HumanoidCharacterProfile) _prefsManager
@@ -623,6 +686,8 @@ The current game mode is [color=white]{0}[/color]", gameMode);
[Dependency] private readonly ILocalizationManager _localization; [Dependency] private readonly ILocalizationManager _localization;
[Dependency] private readonly IRobustRandom _robustRandom; [Dependency] private readonly IRobustRandom _robustRandom;
[Dependency] private readonly IServerPreferencesManager _prefsManager; [Dependency] private readonly IServerPreferencesManager _prefsManager;
[Dependency] private readonly IBaseServer _baseServer;
[Dependency] private readonly IWatchdogApi _watchdogApi;
#pragma warning restore 649 #pragma warning restore 649
} }