diff --git a/Content.Server/GameTicking/Commands/SetGamePresetCommand.cs b/Content.Server/GameTicking/Commands/SetGamePresetCommand.cs
index 78e2b452b7be..83736bd92b0e 100644
--- a/Content.Server/GameTicking/Commands/SetGamePresetCommand.cs
+++ b/Content.Server/GameTicking/Commands/SetGamePresetCommand.cs
@@ -2,7 +2,6 @@
using Content.Server.Administration;
using Content.Server.GameTicking.Presets;
using Content.Shared.Administration;
-using Linguini.Shared.Util;
using Robust.Shared.Console;
using Robust.Shared.Prototypes;
@@ -20,9 +19,9 @@ public sealed class SetGamePresetCommand : IConsoleCommand
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
- if (!args.Length.InRange(1, 2))
+ if (args.Length != 1)
{
- shell.WriteError(Loc.GetString("shell-need-between-arguments", ("lower", 1), ("upper", 2), ("currentAmount", args.Length)));
+ shell.WriteError(Loc.GetString("shell-wrong-arguments-number-need-specific", ("properAmount", 1), ("currentAmount", args.Length)));
return;
}
@@ -34,16 +33,8 @@ public void Execute(IConsoleShell shell, string argStr, string[] args)
return;
}
- var rounds = 1;
-
- if (args.Length == 2 && !int.TryParse(args[1], out rounds))
- {
- shell.WriteError(Loc.GetString("set-game-preset-optional-argument-not-integer"));
- return;
- }
-
- ticker.SetGamePreset(preset, false, rounds);
- shell.WriteLine(Loc.GetString("set-game-preset-preset-set-finite", ("preset", preset.ID), ("rounds", rounds.ToString())));
+ ticker.SetGamePreset(preset);
+ shell.WriteLine(Loc.GetString("set-game-preset-preset-set", ("preset", preset.ID)));
}
public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
diff --git a/Content.Server/GameTicking/GameTicker.GamePreset.cs b/Content.Server/GameTicking/GameTicker.GamePreset.cs
index 6c12a2ea27e9..5a2b375dd68c 100644
--- a/Content.Server/GameTicking/GameTicker.GamePreset.cs
+++ b/Content.Server/GameTicking/GameTicker.GamePreset.cs
@@ -16,327 +16,305 @@
using JetBrains.Annotations;
using Robust.Shared.Player;
-namespace Content.Server.GameTicking;
-
-public sealed partial class GameTicker
+namespace Content.Server.GameTicking
{
- [Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!;
-
- public const float PresetFailedCooldownIncrease = 30f;
+ public sealed partial class GameTicker
+ {
+ [Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!;
- ///
- /// The selected preset that will be used at the start of the next round.
- ///
- public GamePresetPrototype? Preset { get; private set; }
+ public const float PresetFailedCooldownIncrease = 30f;
- ///
- /// The preset that's currently active.
- ///
- public GamePresetPrototype? CurrentPreset { get; private set; }
+ ///
+ /// The selected preset that will be used at the start of the next round.
+ ///
+ public GamePresetPrototype? Preset { get; private set; }
- ///
- /// Countdown to the preset being reset to the server default.
- ///
- public int? ResetCountdown;
+ ///
+ /// The preset that's currently active.
+ ///
+ public GamePresetPrototype? CurrentPreset { get; private set; }
- private bool StartPreset(ICommonSession[] origReadyPlayers, bool force)
- {
- var startAttempt = new RoundStartAttemptEvent(origReadyPlayers, force);
- RaiseLocalEvent(startAttempt);
-
- if (!startAttempt.Cancelled)
- return true;
+ private bool StartPreset(ICommonSession[] origReadyPlayers, bool force)
+ {
+ var startAttempt = new RoundStartAttemptEvent(origReadyPlayers, force);
+ RaiseLocalEvent(startAttempt);
- var presetTitle = CurrentPreset != null ? Loc.GetString(CurrentPreset.ModeTitle) : string.Empty;
+ if (!startAttempt.Cancelled)
+ return true;
- void FailedPresetRestart()
- {
- SendServerMessage(Loc.GetString("game-ticker-start-round-cannot-start-game-mode-restart",
- ("failedGameMode", presetTitle)));
- RestartRound();
- DelayStart(TimeSpan.FromSeconds(PresetFailedCooldownIncrease));
- }
+ var presetTitle = CurrentPreset != null ? Loc.GetString(CurrentPreset.ModeTitle) : string.Empty;
- if (_configurationManager.GetCVar(CCVars.GameLobbyFallbackEnabled))
- {
- var fallbackPresets = _configurationManager.GetCVar(CCVars.GameLobbyFallbackPreset).Split(",");
- var startFailed = true;
+ void FailedPresetRestart()
+ {
+ SendServerMessage(Loc.GetString("game-ticker-start-round-cannot-start-game-mode-restart",
+ ("failedGameMode", presetTitle)));
+ RestartRound();
+ DelayStart(TimeSpan.FromSeconds(PresetFailedCooldownIncrease));
+ }
- foreach (var preset in fallbackPresets)
+ if (_configurationManager.GetCVar(CCVars.GameLobbyFallbackEnabled))
{
- ClearGameRules();
- SetGamePreset(preset);
- AddGamePresetRules();
- StartGamePresetRules();
+ var fallbackPresets = _configurationManager.GetCVar(CCVars.GameLobbyFallbackPreset).Split(",");
+ var startFailed = true;
- startAttempt.Uncancel();
- RaiseLocalEvent(startAttempt);
+ foreach (var preset in fallbackPresets)
+ {
+ ClearGameRules();
+ SetGamePreset(preset);
+ AddGamePresetRules();
+ StartGamePresetRules();
+
+ startAttempt.Uncancel();
+ RaiseLocalEvent(startAttempt);
+
+ if (!startAttempt.Cancelled)
+ {
+ _chatManager.SendAdminAnnouncement(
+ Loc.GetString("game-ticker-start-round-cannot-start-game-mode-fallback",
+ ("failedGameMode", presetTitle),
+ ("fallbackMode", Loc.GetString(preset))));
+ RefreshLateJoinAllowed();
+ startFailed = false;
+ break;
+ }
+ }
- if (!startAttempt.Cancelled)
+ if (startFailed)
{
- _chatManager.SendAdminAnnouncement(
- Loc.GetString("game-ticker-start-round-cannot-start-game-mode-fallback",
- ("failedGameMode", presetTitle),
- ("fallbackMode", Loc.GetString(preset))));
- RefreshLateJoinAllowed();
- startFailed = false;
- break;
+ FailedPresetRestart();
+ return false;
}
}
- if (startFailed)
+ else
{
FailedPresetRestart();
return false;
}
+
+ return true;
}
- else
+ private void InitializeGamePreset()
{
- FailedPresetRestart();
- return false;
+ SetGamePreset(LobbyEnabled ? _configurationManager.GetCVar(CCVars.GameLobbyDefaultPreset) : "sandbox");
}
- return true;
- }
+ public void SetGamePreset(GamePresetPrototype? preset, bool force = false)
+ {
+ // Do nothing if this game ticker is a dummy!
+ if (DummyTicker)
+ return;
- private void InitializeGamePreset()
- {
- SetGamePreset(LobbyEnabled ? _configurationManager.GetCVar(CCVars.GameLobbyDefaultPreset) : "sandbox");
- }
+ Preset = preset;
+ ValidateMap();
+ UpdateInfoText();
- public void SetGamePreset(GamePresetPrototype? preset, bool force = false, int? resetDelay = null)
- {
- // Do nothing if this game ticker is a dummy!
- if (DummyTicker)
- return;
-
- if (resetDelay is not null)
- {
- ResetCountdown = resetDelay.Value;
- // Reset counter is checked and changed at the end of each round
- // So if the game is in the lobby, the first requested round will happen before the check, and we need one less check
- if (CurrentPreset is null)
- ResetCountdown = resetDelay.Value -1;
+ if (force)
+ {
+ StartRound(true);
+ }
}
- Preset = preset;
- ValidateMap();
- UpdateInfoText();
-
- if (force)
+ public void SetGamePreset(string preset, bool force = false)
{
- StartRound(true);
+ var proto = FindGamePreset(preset);
+ if(proto != null)
+ SetGamePreset(proto, force);
}
- }
- public void SetGamePreset(string preset, bool force = false)
- {
- var proto = FindGamePreset(preset);
- if(proto != null)
- SetGamePreset(proto, force);
- }
-
- public GamePresetPrototype? FindGamePreset(string preset)
- {
- if (_prototypeManager.TryIndex(preset, out GamePresetPrototype? presetProto))
- return presetProto;
-
- foreach (var proto in _prototypeManager.EnumeratePrototypes())
+ public GamePresetPrototype? FindGamePreset(string preset)
{
- foreach (var alias in proto.Alias)
+ if (_prototypeManager.TryIndex(preset, out GamePresetPrototype? presetProto))
+ return presetProto;
+
+ foreach (var proto in _prototypeManager.EnumeratePrototypes())
{
- if (preset.Equals(alias, StringComparison.InvariantCultureIgnoreCase))
- return proto;
+ foreach (var alias in proto.Alias)
+ {
+ if (preset.Equals(alias, StringComparison.InvariantCultureIgnoreCase))
+ return proto;
+ }
}
- }
-
- return null;
- }
- public bool TryFindGamePreset(string preset, [NotNullWhen(true)] out GamePresetPrototype? prototype)
- {
- prototype = FindGamePreset(preset);
+ return null;
+ }
- return prototype != null;
- }
+ public bool TryFindGamePreset(string preset, [NotNullWhen(true)] out GamePresetPrototype? prototype)
+ {
+ prototype = FindGamePreset(preset);
- public bool IsMapEligible(GameMapPrototype map)
- {
- if (Preset == null)
- return true;
+ return prototype != null;
+ }
- if (Preset.MapPool == null || !_prototypeManager.TryIndex(Preset.MapPool, out var pool))
- return true;
+ public bool IsMapEligible(GameMapPrototype map)
+ {
+ if (Preset == null)
+ return true;
- return pool.Maps.Contains(map.ID);
- }
+ if (Preset.MapPool == null || !_prototypeManager.TryIndex(Preset.MapPool, out var pool))
+ return true;
- private void ValidateMap()
- {
- if (Preset == null || _gameMapManager.GetSelectedMap() is not { } map)
- return;
+ return pool.Maps.Contains(map.ID);
+ }
- if (Preset.MapPool == null ||
- !_prototypeManager.TryIndex(Preset.MapPool, out var pool))
- return;
+ private void ValidateMap()
+ {
+ if (Preset == null || _gameMapManager.GetSelectedMap() is not { } map)
+ return;
- if (pool.Maps.Contains(map.ID))
- return;
+ if (Preset.MapPool == null ||
+ !_prototypeManager.TryIndex(Preset.MapPool, out var pool))
+ return;
- _gameMapManager.SelectMapRandom();
- }
+ if (pool.Maps.Contains(map.ID))
+ return;
- [PublicAPI]
- private bool AddGamePresetRules()
- {
- if (DummyTicker || Preset == null)
- return false;
-
- CurrentPreset = Preset;
- foreach (var rule in Preset.Rules)
- {
- AddGameRule(rule);
+ _gameMapManager.SelectMapRandom();
}
- return true;
- }
+ [PublicAPI]
+ private bool AddGamePresetRules()
+ {
+ if (DummyTicker || Preset == null)
+ return false;
- private void TryResetPreset()
- {
- if (ResetCountdown is null || ResetCountdown-- > 0)
- return;
+ CurrentPreset = Preset;
+ foreach (var rule in Preset.Rules)
+ {
+ AddGameRule(rule);
+ }
- InitializeGamePreset();
- ResetCountdown = null;
- }
+ return true;
+ }
- public void StartGamePresetRules()
- {
- // May be touched by the preset during init.
- var rules = new List(GetAddedGameRules());
- foreach (var rule in rules)
+ public void StartGamePresetRules()
{
- StartGameRule(rule);
+ // May be touched by the preset during init.
+ var rules = new List(GetAddedGameRules());
+ foreach (var rule in rules)
+ {
+ StartGameRule(rule);
+ }
}
- }
- public bool OnGhostAttempt(EntityUid mindId, bool canReturnGlobal, bool viaCommand = false, MindComponent? mind = null)
- {
- if (!Resolve(mindId, ref mind))
- return false;
+ public bool OnGhostAttempt(EntityUid mindId, bool canReturnGlobal, bool viaCommand = false, MindComponent? mind = null)
+ {
+ if (!Resolve(mindId, ref mind))
+ return false;
- var playerEntity = mind.CurrentEntity;
+ var playerEntity = mind.CurrentEntity;
- if (playerEntity != null && viaCommand)
- _adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(playerEntity.Value):player} is attempting to ghost via command");
+ if (playerEntity != null && viaCommand)
+ _adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(playerEntity.Value):player} is attempting to ghost via command");
- var handleEv = new GhostAttemptHandleEvent(mind, canReturnGlobal);
- RaiseLocalEvent(handleEv);
+ var handleEv = new GhostAttemptHandleEvent(mind, canReturnGlobal);
+ RaiseLocalEvent(handleEv);
- // Something else has handled the ghost attempt for us! We return its result.
- if (handleEv.Handled)
- return handleEv.Result;
+ // Something else has handled the ghost attempt for us! We return its result.
+ if (handleEv.Handled)
+ return handleEv.Result;
- if (mind.PreventGhosting)
- {
- if (mind.Session != null) // Logging is suppressed to prevent spam from ghost attempts caused by movement attempts
+ if (mind.PreventGhosting)
{
- _chatManager.DispatchServerMessage(mind.Session, Loc.GetString("comp-mind-ghosting-prevented"),
- true);
+ if (mind.Session != null) // Logging is suppressed to prevent spam from ghost attempts caused by movement attempts
+ {
+ _chatManager.DispatchServerMessage(mind.Session, Loc.GetString("comp-mind-ghosting-prevented"),
+ true);
+ }
+
+ return false;
}
- return false;
- }
+ if (TryComp(playerEntity, out var comp) && !comp.CanGhostInteract)
+ return false;
+
+ if (mind.VisitingEntity != default)
+ {
+ _mind.UnVisit(mindId, mind: mind);
+ }
- if (TryComp(playerEntity, out var comp) && !comp.CanGhostInteract)
- return false;
+ var position = Exists(playerEntity)
+ ? Transform(playerEntity.Value).Coordinates
+ : GetObserverSpawnPoint();
- if (mind.VisitingEntity != default)
- {
- _mind.UnVisit(mindId, mind: mind);
- }
+ if (position == default)
+ return false;
- var position = Exists(playerEntity)
- ? Transform(playerEntity.Value).Coordinates
- : GetObserverSpawnPoint();
-
- if (position == default)
- return false;
-
- // 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.
- // + If CharacterDeadPhysically applies, we're physically dead. Therefore, ghosting OK, and we can return (this is critical for gibbing)
- // Note that we could theoretically be ICly dead and still physically alive and vice versa.
- // (For example, a zombie could be dead ICly, but may retain memories and is definitely physically active)
- // + If we're in a mob that is critical, and we're supposed to be able to return if possible,
- // we're succumbing - the mob is killed. Therefore, character is dead. Ghosting OK.
- // (If the mob survives, that's a bug. Ghosting is kept regardless.)
- var canReturn = canReturnGlobal && _mind.IsCharacterDeadPhysically(mind);
-
- if (_configurationManager.GetCVar(CCVars.GhostKillCrit) &&
- canReturnGlobal &&
- TryComp(playerEntity, out MobStateComponent? mobState))
- {
- if (_mobState.IsCritical(playerEntity.Value, mobState))
+ // 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.
+ // + If CharacterDeadPhysically applies, we're physically dead. Therefore, ghosting OK, and we can return (this is critical for gibbing)
+ // Note that we could theoretically be ICly dead and still physically alive and vice versa.
+ // (For example, a zombie could be dead ICly, but may retain memories and is definitely physically active)
+ // + If we're in a mob that is critical, and we're supposed to be able to return if possible,
+ // we're succumbing - the mob is killed. Therefore, character is dead. Ghosting OK.
+ // (If the mob survives, that's a bug. Ghosting is kept regardless.)
+ var canReturn = canReturnGlobal && _mind.IsCharacterDeadPhysically(mind);
+
+ if (_configurationManager.GetCVar(CCVars.GhostKillCrit) &&
+ canReturnGlobal &&
+ TryComp(playerEntity, out MobStateComponent? mobState))
{
- canReturn = true;
+ if (_mobState.IsCritical(playerEntity.Value, mobState))
+ {
+ canReturn = true;
- //todo: what if they dont breathe lol
- //cry deeply
+ //todo: what if they dont breathe lol
+ //cry deeply
- FixedPoint2 dealtDamage = 200;
- if (TryComp(playerEntity, out var damageable)
- && TryComp(playerEntity, out var thresholds))
- {
- var playerDeadThreshold = _mobThresholdSystem.GetThresholdForState(playerEntity.Value, MobState.Dead, thresholds);
- dealtDamage = playerDeadThreshold - damageable.TotalDamage;
- }
+ FixedPoint2 dealtDamage = 200;
+ if (TryComp(playerEntity, out var damageable)
+ && TryComp(playerEntity, out var thresholds))
+ {
+ var playerDeadThreshold = _mobThresholdSystem.GetThresholdForState(playerEntity.Value, MobState.Dead, thresholds);
+ dealtDamage = playerDeadThreshold - damageable.TotalDamage;
+ }
- DamageSpecifier damage = new(_prototypeManager.Index("Asphyxiation"), dealtDamage);
+ DamageSpecifier damage = new(_prototypeManager.Index("Asphyxiation"), dealtDamage);
- _damageable.TryChangeDamage(playerEntity, damage, true);
+ _damageable.TryChangeDamage(playerEntity, damage, true);
+ }
}
- }
-
- var ghost = _ghost.SpawnGhost((mindId, mind), position, canReturn);
- if (ghost == null)
- return false;
- if (playerEntity != null)
- _adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(playerEntity.Value):player} ghosted{(!canReturn ? " (non-returnable)" : "")}");
+ var ghost = _ghost.SpawnGhost((mindId, mind), position, canReturn);
+ if (ghost == null)
+ return false;
- return true;
- }
+ if (playerEntity != null)
+ _adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(playerEntity.Value):player} ghosted{(!canReturn ? " (non-returnable)" : "")}");
- private void IncrementRoundNumber()
- {
- var playerIds = _playerGameStatuses.Keys.Select(player => player.UserId).ToArray();
- var serverName = _configurationManager.GetCVar(CCVars.AdminLogsServerName);
+ return true;
+ }
- // TODO FIXME AAAAAAAAAAAAAAAAAAAH THIS IS BROKEN
- // Task.Run as a terrible dirty workaround to avoid synchronization context deadlock from .Result here.
- // This whole setup logic should be made asynchronous so we can properly wait on the DB AAAAAAAAAAAAAH
- var task = Task.Run(async () =>
+ private void IncrementRoundNumber()
{
- var server = await _dbEntryManager.ServerEntity;
- return await _db.AddNewRound(server, playerIds);
- });
+ var playerIds = _playerGameStatuses.Keys.Select(player => player.UserId).ToArray();
+ var serverName = _configurationManager.GetCVar(CCVars.AdminLogsServerName);
- _taskManager.BlockWaitOnTask(task);
- RoundId = task.GetAwaiter().GetResult();
- }
-}
+ // TODO FIXME AAAAAAAAAAAAAAAAAAAH THIS IS BROKEN
+ // Task.Run as a terrible dirty workaround to avoid synchronization context deadlock from .Result here.
+ // This whole setup logic should be made asynchronous so we can properly wait on the DB AAAAAAAAAAAAAH
+ var task = Task.Run(async () =>
+ {
+ var server = await _dbEntryManager.ServerEntity;
+ return await _db.AddNewRound(server, playerIds);
+ });
-public sealed class GhostAttemptHandleEvent : HandledEntityEventArgs
-{
- public MindComponent Mind { get; }
- public bool CanReturnGlobal { get; }
- public bool Result { get; set; }
+ _taskManager.BlockWaitOnTask(task);
+ RoundId = task.GetAwaiter().GetResult();
+ }
+ }
- public GhostAttemptHandleEvent(MindComponent mind, bool canReturnGlobal)
+ public sealed class GhostAttemptHandleEvent : HandledEntityEventArgs
{
- Mind = mind;
- CanReturnGlobal = canReturnGlobal;
+ public MindComponent Mind { get; }
+ public bool CanReturnGlobal { get; }
+ public bool Result { get; set; }
+
+ public GhostAttemptHandleEvent(MindComponent mind, bool canReturnGlobal)
+ {
+ Mind = mind;
+ CanReturnGlobal = canReturnGlobal;
+ }
}
}
diff --git a/Content.Server/GameTicking/GameTicker.RoundFlow.cs b/Content.Server/GameTicking/GameTicker.RoundFlow.cs
index dc242fb6c082..ca087c46ed41 100644
--- a/Content.Server/GameTicking/GameTicker.RoundFlow.cs
+++ b/Content.Server/GameTicking/GameTicker.RoundFlow.cs
@@ -487,9 +487,6 @@ public void RestartRound()
if (_serverUpdates.RoundEnded())
return;
- // Check if the GamePreset needs to be reset
- TryResetPreset();
-
_sawmill.Info("Restarting round!");
SendServerMessage(Loc.GetString("game-ticker-restart-round"));
diff --git a/Resources/Locale/en-US/game-ticking/set-game-preset-command.ftl b/Resources/Locale/en-US/game-ticking/set-game-preset-command.ftl
index 323d83aebafa..46049643cb57 100644
--- a/Resources/Locale/en-US/game-ticking/set-game-preset-command.ftl
+++ b/Resources/Locale/en-US/game-ticking/set-game-preset-command.ftl
@@ -1,7 +1,5 @@
-set-game-preset-command-description = Sets the game preset for the specified number of upcoming rounds.
-set-game-preset-command-help-text = setgamepreset [number of rounds, defaulting to 1]
-set-game-preset-optional-argument-not-integer = If argument 2 is provided it must be a number.
+set-game-preset-command-description = Sets the game preset for the current round.
+set-game-preset-command-help-text = setgamepreset
set-game-preset-preset-error = Unable to find game preset "{$preset}"
-#set-game-preset-preset-set = Set game preset to "{$preset}"
-set-game-preset-preset-set-finite = Set game preset to "{$preset}" for the next {$rounds} rounds.
+set-game-preset-preset-set = Set game preset to "{$preset}"