diff --git a/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs b/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs index 4acbdf6dcd..3ee54af303 100644 --- a/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs +++ b/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs @@ -234,6 +234,8 @@ public sealed class AddTests : ContentIntegrationTest await server.WaitIdleAsync(); var sDatabase = server.ResolveDependency(); + var sEntities = server.ResolveDependency(); + var sMaps = server.ResolveDependency(); var sSystems = server.ResolveDependency(); var sAdminLogSystem = sSystems.GetEntitySystem(); @@ -243,7 +245,10 @@ public sealed class AddTests : ContentIntegrationTest await server.WaitPost(() => { - sAdminLogSystem.Add(LogType.Unknown, $"test log: {guid}"); + var coordinates = GetMainEntityCoordinates(sMaps); + var entity = sEntities.SpawnEntity(null, coordinates); + + sAdminLogSystem.Add(LogType.Unknown, $"{entity} test log: {guid}"); }); await server.WaitPost(() => @@ -279,7 +284,8 @@ public sealed class AddTests : ContentIntegrationTest await foreach (var json in sDatabase.GetAdminLogsJson(filter)) { var root = json.RootElement; - + + Assert.That(root.TryGetProperty("entity", out _), Is.True); Assert.That(root.TryGetProperty("guid", out _), Is.True); json.Dispose(); diff --git a/Content.Server/GameTicking/GameTicker.CVars.cs b/Content.Server/GameTicking/GameTicker.CVars.cs index ba7aa70468..5c86dc53bd 100644 --- a/Content.Server/GameTicking/GameTicker.CVars.cs +++ b/Content.Server/GameTicking/GameTicker.CVars.cs @@ -27,11 +27,6 @@ namespace Content.Server.GameTicking [ViewVariables] public float MaxStationOffset { get; private set; } = 0f; -#if EXCEPTION_TOLERANCE - [ViewVariables] - public int RoundStartFailShutdownCount { get; private set; } = 0; -#endif - private void InitializeCVars() { _configurationManager.OnValueChanged(CCVars.GameLobbyEnabled, value => LobbyEnabled = value, true); @@ -42,9 +37,6 @@ namespace Content.Server.GameTicking _configurationManager.OnValueChanged(CCVars.StationOffset, value => StationOffset = value, true); _configurationManager.OnValueChanged(CCVars.StationRotation, value => StationRotation = value, true); _configurationManager.OnValueChanged(CCVars.MaxStationOffset, value => MaxStationOffset = value, true); -#if EXCEPTION_TOLERANCE - _configurationManager.OnValueChanged(CCVars.RoundStartFailShutdownCount, value => RoundStartFailShutdownCount = value, true); -#endif } } } diff --git a/Content.Server/GameTicking/GameTicker.JobController.cs b/Content.Server/GameTicking/GameTicker.JobController.cs index 7252a13fa6..e35548a86d 100644 --- a/Content.Server/GameTicking/GameTicker.JobController.cs +++ b/Content.Server/GameTicking/GameTicker.JobController.cs @@ -108,9 +108,6 @@ namespace Content.Server.GameTicking private string? PickBestAvailableJob(IPlayerSession playerSession, HumanoidCharacterProfile profile, StationId station) { - if (station == StationId.Invalid) - return null; - var available = _stationSystem.StationInfo[station].JobList; bool TryPick(JobPriority priority, [NotNullWhen(true)] out string? jobId) diff --git a/Content.Server/GameTicking/GameTicker.RoundFlow.cs b/Content.Server/GameTicking/GameTicker.RoundFlow.cs index dda8f0b2a1..3a782e5994 100644 --- a/Content.Server/GameTicking/GameTicker.RoundFlow.cs +++ b/Content.Server/GameTicking/GameTicker.RoundFlow.cs @@ -1,21 +1,31 @@ +using System; +using System.Collections.Generic; using System.Linq; +using Content.Server.Database; using Content.Server.GameTicking.Events; using Content.Server.Ghost; using Content.Server.Maps; using Content.Server.Mind; using Content.Server.Players; using Content.Server.Station; +using Content.Shared.CCVar; using Content.Shared.Coordinates; using Content.Shared.GameTicking; using Content.Shared.Preferences; using Content.Shared.Station; using Prometheus; using Robust.Server.Player; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Log; using Robust.Shared.Map; +using Robust.Shared.Maths; using Robust.Shared.Network; using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Utility; +using Robust.Shared.ViewVariables; namespace Content.Server.GameTicking { @@ -29,10 +39,7 @@ namespace Content.Server.GameTicking "ss14_round_length", "Round length in seconds."); -#if EXCEPTION_TOLERANCE - [ViewVariables] - private int _roundStartFailCount = 0; -#endif + [Dependency] private readonly IServerDbManager _db = default!; [ViewVariables] private TimeSpan _roundStartTimeSpan; @@ -68,6 +75,7 @@ namespace Content.Server.GameTicking DefaultMap = _mapManager.CreateMap(); _mapManager.AddUninitializedMap(DefaultMap); + _startingRound = false; var startTime = _gameTiming.RealTime; var maps = new List() { _gameMapManager.GetSelectedMapChecked(true) }; @@ -165,113 +173,97 @@ namespace Content.Server.GameTicking } } - public void StartRound(bool force = false) + public async void StartRound(bool force = false) { #if EXCEPTION_TOLERANCE try { #endif - // If this game ticker is a dummy or the round is already being started, do nothing! - if (DummyTicker || _startingRound) - return; + // If this game ticker is a dummy or the round is already being started, do nothing! + if (DummyTicker || _startingRound) + return; - _startingRound = true; + _startingRound = true; - DebugTools.Assert(RunLevel == GameRunLevel.PreRoundLobby); - Logger.InfoS("ticker", "Starting round!"); + DebugTools.Assert(RunLevel == GameRunLevel.PreRoundLobby); + Logger.InfoS("ticker", "Starting round!"); - SendServerMessage(Loc.GetString("game-ticker-start-round")); + SendServerMessage(Loc.GetString("game-ticker-start-round")); - LoadMaps(); + StartGamePresetRules(); - StartGamePresetRules(); + RoundLengthMetric.Set(0); - RoundLengthMetric.Set(0); + var playerIds = _playersInLobby.Keys.Select(player => player.UserId.UserId).ToArray(); + RoundId = await _db.AddNewRound(playerIds); - var playerIds = _playersInLobby.Keys.Select(player => player.UserId.UserId).ToArray(); - RoundId = _db.AddNewRound(playerIds).Result; + var startingEvent = new RoundStartingEvent(); + RaiseLocalEvent(startingEvent); - var startingEvent = new RoundStartingEvent(); - RaiseLocalEvent(startingEvent); - - List readyPlayers; - if (LobbyEnabled) - { - readyPlayers = _playersInLobby.Where(p => p.Value == LobbyPlayerStatus.Ready).Select(p => p.Key) - .ToList(); - } - else - { - readyPlayers = _playersInLobby.Keys.ToList(); - } - - readyPlayers.RemoveAll(p => - { - if (_roleBanManager.GetRoleBans(p.UserId) != null) - return false; - Logger.ErrorS("RoleBans", $"Role bans for player {p} {p.UserId} have not been loaded yet."); - return true; - }); - - // 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)) + List readyPlayers; + if (LobbyEnabled) { - profiles.Add(readyPlayer.UserId, HumanoidCharacterProfile.Random()); + readyPlayers = _playersInLobby.Where(p => p.Value == LobbyPlayerStatus.Ready).Select(p => p.Key) + .ToList(); + } + else + { + readyPlayers = _playersInLobby.Keys.ToList(); } - } - var origReadyPlayers = readyPlayers.ToArray(); + readyPlayers.RemoveAll(p => + { + if (_roleBanManager.GetRoleBans(p.UserId) != null) + return false; + Logger.ErrorS("RoleBans", $"Role bans for player {p} {p.UserId} have not been loaded yet."); + return true; + }); - if (!StartPreset(origReadyPlayers, force)) - return; + // 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); - // MapInitialize *before* spawning players, our codebase is too shit to do it afterwards... - _mapManager.DoMapInitialize(DefaultMap); + foreach (var readyPlayer in readyPlayers) + { + if (!profiles.ContainsKey(readyPlayer.UserId)) + { + profiles.Add(readyPlayer.UserId, HumanoidCharacterProfile.Random()); + } + } - SpawnPlayers(readyPlayers, origReadyPlayers, profiles, force); + var origReadyPlayers = readyPlayers.ToArray(); - _roundStartDateTime = DateTime.UtcNow; - RunLevel = GameRunLevel.InRound; + if (!StartPreset(origReadyPlayers, force)) + return; - _roundStartTimeSpan = _gameTiming.RealTime; - SendStatusToAll(); - ReqWindowAttentionAll(); - UpdateLateJoinStatus(); - UpdateJobsAvailable(); + // MapInitialize *before* spawning players, our codebase is too shit to do it afterwards... + _mapManager.DoMapInitialize(DefaultMap); + + SpawnPlayers(readyPlayers, origReadyPlayers, profiles, force); + + _roundStartDateTime = DateTime.UtcNow; + RunLevel = GameRunLevel.InRound; + + _startingRound = false; + + _roundStartTimeSpan = _gameTiming.RealTime; + SendStatusToAll(); + ReqWindowAttentionAll(); + UpdateLateJoinStatus(); + UpdateJobsAvailable(); #if EXCEPTION_TOLERANCE } - catch (Exception e) + catch(Exception e) { - _roundStartFailCount++; - if (RoundStartFailShutdownCount > 0 && _roundStartFailCount >= RoundStartFailShutdownCount) - { - Logger.FatalS("ticker", - $"Failed to start a round {_roundStartFailCount} time(s) in a row... Shutting down!"); - _runtimeLog.LogException(e, nameof(GameTicker)); - _baseServer.Shutdown("Restarting server"); - return; - } - - Logger.WarningS("ticker", $"Exception caught while trying to start the round! Restarting round..."); + Logger.WarningS("ticker", $"Exception caught while trying to start the round! Restarting..."); _runtimeLog.LogException(e, nameof(GameTicker)); - _startingRound = false; RestartRound(); - return; } - - // Round started successfully! Reset counter... - _roundStartFailCount = 0; #endif - _startingRound = false; } private void RefreshLateJoinAllowed() @@ -381,6 +373,7 @@ namespace Content.Server.GameTicking RunLevel = GameRunLevel.PreRoundLobby; LobbySong = _robustRandom.Pick(_lobbyMusicCollection.PickFiles).ToString(); ResettingCleanup(); + LoadMaps(); if (!LobbyEnabled) { @@ -418,16 +411,18 @@ namespace Content.Server.GameTicking unCastData.ContentData()?.WipeMind(); } - _mapManager.Restart(); - - // Delete all remaining entities. - foreach (var entity in EntityManager.GetEntities().ToArray()) + // Delete all entities. + foreach (var entity in EntityManager.GetEntities().ToList()) { // TODO: Maybe something less naive here? // FIXME: Actually, definitely. EntityManager.DeleteEntity(entity); } + _startingRound = false; + + _mapManager.Restart(); + _roleBanManager.Restart(); // Clear up any game rules. @@ -470,7 +465,8 @@ namespace Content.Server.GameTicking RoundLengthMetric.Inc(frameTime); } - if (RunLevel != GameRunLevel.PreRoundLobby || Paused || + if (RunLevel != GameRunLevel.PreRoundLobby || + Paused || _roundStartTime > _gameTiming.CurTime || _roundStartCountdownHasNotStartedYetDueToNoPlayers) { diff --git a/Content.Server/GameTicking/GameTicker.cs b/Content.Server/GameTicking/GameTicker.cs index a74684a47a..e3b1ef5518 100644 --- a/Content.Server/GameTicking/GameTicker.cs +++ b/Content.Server/GameTicking/GameTicker.cs @@ -2,7 +2,6 @@ using Content.Server.Administration.Logs; using Content.Server.Administration.Managers; using Content.Server.CharacterAppearance.Systems; using Content.Server.Chat.Managers; -using Content.Server.Database; using Content.Server.Ghost; using Content.Server.Maps; using Content.Server.PDA; @@ -90,7 +89,6 @@ namespace Content.Server.GameTicking [Dependency] private readonly IBaseServer _baseServer = default!; [Dependency] private readonly IWatchdogApi _watchdogApi = default!; [Dependency] private readonly IGameMapManager _gameMapManager = default!; - [Dependency] private readonly IServerDbManager _db = default!; #if EXCEPTION_TOLERANCE [Dependency] private readonly IRuntimeLog _runtimeLog = default!; #endif diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index e8ca923a7e..5e0e20d96a 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -60,9 +60,6 @@ namespace Content.Shared.CCVar public static readonly CVarDef EventsEnabled = CVarDef.Create("events.enabled", true, CVar.ARCHIVE | CVar.SERVERONLY); - /// - /// Disables most functionality in the GameTicker. - /// public static readonly CVarDef GameDummyTicker = CVarDef.Create("game.dummyticker", false, CVar.ARCHIVE | CVar.SERVERONLY); @@ -157,15 +154,6 @@ namespace Content.Shared.CCVar public static readonly CVarDef SoftMaxPlayers = CVarDef.Create("game.soft_max_players", 30, CVar.SERVERONLY | CVar.ARCHIVE); -#if EXCEPTION_TOLERANCE - /// - /// Amount of times round start must fail before the server is shut down. - /// Set to 0 or a negative number to disable. - /// - public static readonly CVarDef RoundStartFailShutdownCount = - CVarDef.Create("game.round_start_fail_shutdown_count", 5, CVar.SERVERONLY | CVar.SERVER); -#endif - /* * Discord */