Separate game rule enabling and game rule starting (#6168)
This commit is contained in:
@@ -38,7 +38,7 @@ namespace Content.IntegrationTests.Tests.GameRules
|
|||||||
{
|
{
|
||||||
Assert.That(sGameTicker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby));
|
Assert.That(sGameTicker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby));
|
||||||
|
|
||||||
sGameTicker.AddGameRule(IoCManager.Resolve<IPrototypeManager>().Index<GameRulePrototype>(maxTimeMaxTimeRestartRuleSystem.Prototype));
|
sGameTicker.StartGameRule(IoCManager.Resolve<IPrototypeManager>().Index<GameRulePrototype>(maxTimeMaxTimeRestartRuleSystem.Prototype));
|
||||||
maxTimeMaxTimeRestartRuleSystem.RoundMaxTime = TimeSpan.FromSeconds(3);
|
maxTimeMaxTimeRestartRuleSystem.RoundMaxTime = TimeSpan.FromSeconds(3);
|
||||||
|
|
||||||
sGameTicker.StartRound();
|
sGameTicker.StartRound();
|
||||||
|
|||||||
@@ -85,6 +85,14 @@ namespace Content.Server.GameTicking
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void StartGamePresetRules()
|
||||||
|
{
|
||||||
|
foreach (var rule in _addedGameRules)
|
||||||
|
{
|
||||||
|
StartGameRule(rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool OnGhostAttempt(Mind.Mind mind, bool canReturnGlobal)
|
public bool OnGhostAttempt(Mind.Mind mind, bool canReturnGlobal)
|
||||||
{
|
{
|
||||||
var handleEv = new GhostAttemptHandleEvent(mind, canReturnGlobal);
|
var handleEv = new GhostAttemptHandleEvent(mind, canReturnGlobal);
|
||||||
|
|||||||
@@ -8,35 +8,80 @@ namespace Content.Server.GameTicking
|
|||||||
public partial class GameTicker
|
public partial class GameTicker
|
||||||
{
|
{
|
||||||
// No duplicates.
|
// No duplicates.
|
||||||
[ViewVariables] private readonly HashSet<GameRulePrototype> _gameRules = new();
|
[ViewVariables] private readonly HashSet<GameRulePrototype> _addedGameRules = new();
|
||||||
public IEnumerable<GameRulePrototype> ActiveGameRules => _gameRules;
|
public IEnumerable<GameRulePrototype> AddedGameRules => _addedGameRules;
|
||||||
|
|
||||||
|
[ViewVariables] private readonly HashSet<GameRulePrototype> _startedGameRules = new();
|
||||||
|
public IEnumerable<GameRulePrototype> StartedGameRules => _startedGameRules;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Game rules can be 'started' separately from being added. 'Starting' them usually
|
||||||
|
/// happens at round start while they can be added and removed before then.
|
||||||
|
/// </summary>
|
||||||
|
public void StartGameRule(GameRulePrototype rule)
|
||||||
|
{
|
||||||
|
if (!GameRuleAdded(rule))
|
||||||
|
AddGameRule(rule);
|
||||||
|
|
||||||
|
if (_startedGameRules.Add(rule))
|
||||||
|
RaiseLocalEvent(new GameRuleStartedEvent(rule));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ends a game rule.
|
||||||
|
/// This always includes removing it (removing it from added game rules) so that behavior
|
||||||
|
/// is not separate from this.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rule"></param>
|
||||||
|
public void EndGameRule(GameRulePrototype rule)
|
||||||
|
{
|
||||||
|
if (!GameRuleAdded(rule))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_addedGameRules.Remove(rule);
|
||||||
|
|
||||||
|
if (GameRuleStarted(rule))
|
||||||
|
_startedGameRules.Remove(rule);
|
||||||
|
RaiseLocalEvent(new GameRuleEndedEvent(rule));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a game rule to the list, but does not
|
||||||
|
/// start it yet, instead waiting until roundstart.
|
||||||
|
/// </summary>
|
||||||
public bool AddGameRule(GameRulePrototype rule)
|
public bool AddGameRule(GameRulePrototype rule)
|
||||||
{
|
{
|
||||||
if (!_gameRules.Add(rule))
|
if (!_addedGameRules.Add(rule))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
RaiseLocalEvent(new GameRuleAddedEvent(rule));
|
RaiseLocalEvent(new GameRuleAddedEvent(rule));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool RemoveGameRule(GameRulePrototype rule)
|
public bool GameRuleAdded(GameRulePrototype rule)
|
||||||
{
|
{
|
||||||
if (!_gameRules.Remove(rule))
|
return _addedGameRules.Contains(rule);
|
||||||
return false;
|
|
||||||
|
|
||||||
RaiseLocalEvent(new GameRuleRemovedEvent(rule));
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasGameRule(GameRulePrototype rule)
|
public bool GameRuleAdded(string rule)
|
||||||
{
|
{
|
||||||
return _gameRules.Contains(rule);
|
foreach (var ruleProto in _addedGameRules)
|
||||||
|
{
|
||||||
|
if (ruleProto.ID.Equals(rule))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasGameRule(string rule)
|
public bool GameRuleStarted(GameRulePrototype rule)
|
||||||
{
|
{
|
||||||
foreach (var ruleProto in _gameRules)
|
return _startedGameRules.Contains(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool GameRuleStarted(string rule)
|
||||||
|
{
|
||||||
|
foreach (var ruleProto in _startedGameRules)
|
||||||
{
|
{
|
||||||
if (ruleProto.ID.Equals(rule))
|
if (ruleProto.ID.Equals(rule))
|
||||||
return true;
|
return true;
|
||||||
@@ -47,14 +92,17 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
public void ClearGameRules()
|
public void ClearGameRules()
|
||||||
{
|
{
|
||||||
foreach (var rule in _gameRules.ToArray())
|
foreach (var rule in _addedGameRules.ToArray())
|
||||||
{
|
{
|
||||||
RemoveGameRule(rule);
|
EndGameRule(rule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GameRuleAddedEvent
|
/// <summary>
|
||||||
|
/// Raised broadcast when a game rule is selected, but not started yet.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class GameRuleAddedEvent
|
||||||
{
|
{
|
||||||
public GameRulePrototype Rule { get; }
|
public GameRulePrototype Rule { get; }
|
||||||
|
|
||||||
@@ -64,11 +112,21 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GameRuleRemovedEvent
|
public sealed class GameRuleStartedEvent
|
||||||
{
|
{
|
||||||
public GameRulePrototype Rule { get; }
|
public GameRulePrototype Rule { get; }
|
||||||
|
|
||||||
public GameRuleRemovedEvent(GameRulePrototype rule)
|
public GameRuleStartedEvent(GameRulePrototype rule)
|
||||||
|
{
|
||||||
|
Rule = rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class GameRuleEndedEvent
|
||||||
|
{
|
||||||
|
public GameRulePrototype Rule { get; }
|
||||||
|
|
||||||
|
public GameRuleEndedEvent(GameRulePrototype rule)
|
||||||
{
|
{
|
||||||
Rule = rule;
|
Rule = rule;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
private void PreRoundSetup()
|
private void PreRoundSetup()
|
||||||
{
|
{
|
||||||
|
AddGamePresetRules();
|
||||||
|
|
||||||
DefaultMap = _mapManager.CreateMap();
|
DefaultMap = _mapManager.CreateMap();
|
||||||
_pauseManager.AddUninitializedMap(DefaultMap);
|
_pauseManager.AddUninitializedMap(DefaultMap);
|
||||||
_startingRound = false;
|
_startingRound = false;
|
||||||
@@ -188,7 +190,7 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
SendServerMessage(Loc.GetString("game-ticker-start-round"));
|
SendServerMessage(Loc.GetString("game-ticker-start-round"));
|
||||||
|
|
||||||
AddGamePresetRules();
|
StartGamePresetRules();
|
||||||
|
|
||||||
List<IPlayerSession> readyPlayers;
|
List<IPlayerSession> readyPlayers;
|
||||||
if (LobbyEnabled)
|
if (LobbyEnabled)
|
||||||
@@ -246,6 +248,7 @@ namespace Content.Server.GameTicking
|
|||||||
ClearGameRules();
|
ClearGameRules();
|
||||||
SetGamePreset(_configurationManager.GetCVar(CCVars.GameLobbyFallbackPreset));
|
SetGamePreset(_configurationManager.GetCVar(CCVars.GameLobbyFallbackPreset));
|
||||||
AddGamePresetRules();
|
AddGamePresetRules();
|
||||||
|
StartGamePresetRules();
|
||||||
|
|
||||||
startAttempt.Uncancel();
|
startAttempt.Uncancel();
|
||||||
RaiseLocalEvent(startAttempt);
|
RaiseLocalEvent(startAttempt);
|
||||||
@@ -508,7 +511,7 @@ namespace Content.Server.GameTicking
|
|||||||
// Clear up any game rules.
|
// Clear up any game rules.
|
||||||
ClearGameRules();
|
ClearGameRules();
|
||||||
|
|
||||||
_gameRules.Clear();
|
_addedGameRules.Clear();
|
||||||
|
|
||||||
// Round restart cleanup event, so entity systems can reset.
|
// Round restart cleanup event, so entity systems can reset.
|
||||||
var ev = new RoundRestartCleanupEvent();
|
var ev = new RoundRestartCleanupEvent();
|
||||||
|
|||||||
@@ -35,14 +35,14 @@ public sealed class DeathMatchRuleSystem : GameRuleSystem
|
|||||||
SubscribeLocalEvent<DamageChangedEvent>(OnHealthChanged);
|
SubscribeLocalEvent<DamageChangedEvent>(OnHealthChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Added()
|
public override void Started()
|
||||||
{
|
{
|
||||||
_chatManager.DispatchServerAnnouncement(Loc.GetString("rule-death-match-added-announcement"));
|
_chatManager.DispatchServerAnnouncement(Loc.GetString("rule-death-match-added-announcement"));
|
||||||
|
|
||||||
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Removed()
|
public override void Ended()
|
||||||
{
|
{
|
||||||
_deadCheckTimer = null;
|
_deadCheckTimer = null;
|
||||||
_restartTimer = null;
|
_restartTimer = null;
|
||||||
|
|||||||
@@ -27,8 +27,9 @@ public abstract class GameRuleSystem : EntitySystem
|
|||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<GameRuleAddedEvent>(OnGameRuleAdded);
|
SubscribeLocalEvent<GameRuleAddedEvent>(OnGameRuleAdded);
|
||||||
SubscribeLocalEvent<GameRuleRemovedEvent>(OnGameRuleRemoved);
|
|
||||||
|
|
||||||
|
SubscribeLocalEvent<GameRuleStartedEvent>(OnGameRuleStarted);
|
||||||
|
SubscribeLocalEvent<GameRuleEndedEvent>(OnGameRuleEnded);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGameRuleAdded(GameRuleAddedEvent ev)
|
private void OnGameRuleAdded(GameRuleAddedEvent ev)
|
||||||
@@ -37,25 +38,32 @@ public abstract class GameRuleSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Enabled = true;
|
Enabled = true;
|
||||||
Added();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGameRuleRemoved(GameRuleRemovedEvent ev)
|
private void OnGameRuleStarted(GameRuleStartedEvent ev)
|
||||||
|
{
|
||||||
|
if (ev.Rule.ID != Prototype)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Started();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGameRuleEnded(GameRuleEndedEvent ev)
|
||||||
{
|
{
|
||||||
if (ev.Rule.ID != Prototype)
|
if (ev.Rule.ID != Prototype)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Enabled = false;
|
Enabled = false;
|
||||||
Removed();
|
Ended();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when the game rule has been added and this system has been enabled.
|
/// Called when the game rule has been started..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void Added();
|
public abstract void Started();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when the game rule has been removed and this system has been disabled.
|
/// Called when the game rule has ended..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void Removed();
|
public abstract void Ended();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,12 +28,12 @@ public class InactivityTimeRestartRuleSystem : GameRuleSystem
|
|||||||
SubscribeLocalEvent<GameRunLevelChangedEvent>(RunLevelChanged);
|
SubscribeLocalEvent<GameRunLevelChangedEvent>(RunLevelChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Added()
|
public override void Started()
|
||||||
{
|
{
|
||||||
_playerManager.PlayerStatusChanged += PlayerStatusChanged;
|
_playerManager.PlayerStatusChanged += PlayerStatusChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Removed()
|
public override void Ended()
|
||||||
{
|
{
|
||||||
_playerManager.PlayerStatusChanged -= PlayerStatusChanged;
|
_playerManager.PlayerStatusChanged -= PlayerStatusChanged;
|
||||||
|
|
||||||
|
|||||||
@@ -26,13 +26,13 @@ public sealed class MaxTimeRestartRuleSystem : GameRuleSystem
|
|||||||
SubscribeLocalEvent<GameRunLevelChangedEvent>(RunLevelChanged);
|
SubscribeLocalEvent<GameRunLevelChangedEvent>(RunLevelChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Added()
|
public override void Started()
|
||||||
{
|
{
|
||||||
if(GameTicker.RunLevel == GameRunLevel.InRound)
|
if(GameTicker.RunLevel == GameRunLevel.InRound)
|
||||||
RestartTimer();
|
RestartTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Removed()
|
public override void Ended()
|
||||||
{
|
{
|
||||||
RoundMaxTime = TimeSpan.FromMinutes(5);
|
RoundMaxTime = TimeSpan.FromMinutes(5);
|
||||||
RoundEndDelay = TimeSpan.FromMinutes(10);
|
RoundEndDelay = TimeSpan.FromMinutes(10);
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ public class SandboxRuleSystem : GameRuleSystem
|
|||||||
|
|
||||||
public override string Prototype => "Sandbox";
|
public override string Prototype => "Sandbox";
|
||||||
|
|
||||||
public override void Added()
|
public override void Started()
|
||||||
{
|
{
|
||||||
_sandbox.IsSandboxEnabled = true;
|
_sandbox.IsSandboxEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Removed()
|
public override void Ended()
|
||||||
{
|
{
|
||||||
_sandbox.IsSandboxEnabled = false;
|
_sandbox.IsSandboxEnabled = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ public sealed class SuspicionRuleSystem : GameRuleSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Added()
|
public override void Started()
|
||||||
{
|
{
|
||||||
_playerManager.PlayerStatusChanged += PlayerManagerOnPlayerStatusChanged;
|
_playerManager.PlayerStatusChanged += PlayerManagerOnPlayerStatusChanged;
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ public sealed class SuspicionRuleSystem : GameRuleSystem
|
|||||||
Timer.SpawnRepeating(DeadCheckDelay, CheckWinConditions, _checkTimerCancel.Token);
|
Timer.SpawnRepeating(DeadCheckDelay, CheckWinConditions, _checkTimerCancel.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Removed()
|
public override void Ended()
|
||||||
{
|
{
|
||||||
_doorSystem.AccessType = SharedDoorSystem.AccessTypes.Id;
|
_doorSystem.AccessType = SharedDoorSystem.AccessTypes.Id;
|
||||||
EndTime = null;
|
EndTime = null;
|
||||||
|
|||||||
@@ -202,14 +202,14 @@ public class TraitorDeathMatchRuleSystem : GameRuleSystem
|
|||||||
ev.AddLine(string.Join('\n', lines));
|
ev.AddLine(string.Join('\n', lines));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Added()
|
public override void Started()
|
||||||
{
|
{
|
||||||
_restarter.RoundMaxTime = TimeSpan.FromMinutes(30);
|
_restarter.RoundMaxTime = TimeSpan.FromMinutes(30);
|
||||||
_restarter.RestartTimer();
|
_restarter.RestartTimer();
|
||||||
_safeToEndRound = true;
|
_safeToEndRound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Removed()
|
public override void Ended()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,13 +53,13 @@ public class TraitorRuleSystem : GameRuleSystem
|
|||||||
SubscribeLocalEvent<RoundEndTextAppendEvent>(OnRoundEndText);
|
SubscribeLocalEvent<RoundEndTextAppendEvent>(OnRoundEndText);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Added()
|
public override void Started()
|
||||||
{
|
{
|
||||||
// This seems silly, but I'll leave it.
|
// This seems silly, but I'll leave it.
|
||||||
_chatManager.DispatchServerAnnouncement(Loc.GetString("rule-traitor-added-announcement"));
|
_chatManager.DispatchServerAnnouncement(Loc.GetString("rule-traitor-added-announcement"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Removed()
|
public override void Ended()
|
||||||
{
|
{
|
||||||
_traitors.Clear();
|
_traitors.Clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
using Content.Server.Spawners.Components;
|
using Content.Server.Spawners.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
namespace Content.Server.Spawners.EntitySystems
|
namespace Content.Server.Spawners.EntitySystems
|
||||||
@@ -19,7 +15,7 @@ namespace Content.Server.Spawners.EntitySystems
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<GameRuleAddedEvent>(OnRuleAdded);
|
SubscribeLocalEvent<GameRuleStartedEvent>(OnRuleStarted);
|
||||||
SubscribeLocalEvent<ConditionalSpawnerComponent, MapInitEvent>(OnCondSpawnMapInit);
|
SubscribeLocalEvent<ConditionalSpawnerComponent, MapInitEvent>(OnCondSpawnMapInit);
|
||||||
SubscribeLocalEvent<RandomSpawnerComponent, MapInitEvent>(OnRandSpawnMapInit);
|
SubscribeLocalEvent<RandomSpawnerComponent, MapInitEvent>(OnRandSpawnMapInit);
|
||||||
}
|
}
|
||||||
@@ -35,15 +31,15 @@ namespace Content.Server.Spawners.EntitySystems
|
|||||||
EntityManager.QueueDeleteEntity(uid);
|
EntityManager.QueueDeleteEntity(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRuleAdded(GameRuleAddedEvent args)
|
private void OnRuleStarted(GameRuleStartedEvent args)
|
||||||
{
|
{
|
||||||
foreach (var spawner in EntityManager.EntityQuery<ConditionalSpawnerComponent>())
|
foreach (var spawner in EntityManager.EntityQuery<ConditionalSpawnerComponent>())
|
||||||
{
|
{
|
||||||
RuleAdded(spawner, args);
|
RuleStarted(spawner, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RuleAdded(ConditionalSpawnerComponent component, GameRuleAddedEvent obj)
|
public void RuleStarted(ConditionalSpawnerComponent component, GameRuleStartedEvent obj)
|
||||||
{
|
{
|
||||||
if(component.GameRules.Contains(obj.Rule.ID))
|
if(component.GameRules.Contains(obj.Rule.ID))
|
||||||
Spawn(component);
|
Spawn(component);
|
||||||
@@ -59,7 +55,7 @@ namespace Content.Server.Spawners.EntitySystems
|
|||||||
|
|
||||||
foreach (var rule in component.GameRules)
|
foreach (var rule in component.GameRules)
|
||||||
{
|
{
|
||||||
if (!_ticker.HasGameRule(rule)) continue;
|
if (!_ticker.GameRuleStarted(rule)) continue;
|
||||||
Spawn(component);
|
Spawn(component);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user