From f4efaaeb72cea14f24965e434c830b5f22636886 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Sat, 24 May 2025 13:35:17 -0400 Subject: [PATCH] Convert `TimedSpawnerComponent` to use an Update loop (#37785) Convert TimedSpawnerComponent to use an Update loop --- .../Components/TimedSpawnerComponent.cs | 13 ++++--- .../Spawners/EntitySystems/SpawnerSystem.cs | 35 ++++++++++++------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/Content.Server/Spawners/Components/TimedSpawnerComponent.cs b/Content.Server/Spawners/Components/TimedSpawnerComponent.cs index 828e541717..8494a1a2fb 100644 --- a/Content.Server/Spawners/Components/TimedSpawnerComponent.cs +++ b/Content.Server/Spawners/Components/TimedSpawnerComponent.cs @@ -1,6 +1,6 @@ -using System.Threading; -using Robust.Shared.Prototypes; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Spawners.Components; @@ -10,6 +10,7 @@ namespace Content.Server.Spawners.Components; /// and min/max number of entities to spawn. /// [RegisterComponent, EntityCategory("Spawner")] +[AutoGenerateComponentPause] public sealed partial class TimedSpawnerComponent : Component, ISerializationHooks { /// @@ -30,7 +31,7 @@ public sealed partial class TimedSpawnerComponent : Component, ISerializationHoo /// Length of the interval between spawn attempts. /// [DataField] - public int IntervalSeconds = 60; + public TimeSpan IntervalSeconds = TimeSpan.FromSeconds(60); /// /// The minimum number of entities that can be spawned when an interval elapses. @@ -44,7 +45,11 @@ public sealed partial class TimedSpawnerComponent : Component, ISerializationHoo [DataField] public int MaximumEntitiesSpawned = 1; - public CancellationTokenSource? TokenSource; + /// + /// The time at which the current interval will have elapsed and entities may be spawned. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField] + public TimeSpan NextFire = TimeSpan.Zero; void ISerializationHooks.AfterDeserialization() { diff --git a/Content.Server/Spawners/EntitySystems/SpawnerSystem.cs b/Content.Server/Spawners/EntitySystems/SpawnerSystem.cs index c601fdd287..6e0b0f384d 100644 --- a/Content.Server/Spawners/EntitySystems/SpawnerSystem.cs +++ b/Content.Server/Spawners/EntitySystems/SpawnerSystem.cs @@ -1,25 +1,41 @@ -using System.Threading; using Content.Server.Spawners.Components; using Robust.Shared.Random; +using Robust.Shared.Timing; namespace Content.Server.Spawners.EntitySystems; public sealed class SpawnerSystem : EntitySystem { + [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IRobustRandom _random = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnSpawnerInit); - SubscribeLocalEvent(OnTimedSpawnerShutdown); + + SubscribeLocalEvent(OnMapInit); } - private void OnSpawnerInit(EntityUid uid, TimedSpawnerComponent component, ComponentInit args) + public override void Update(float frameTime) { - component.TokenSource?.Cancel(); - component.TokenSource = new CancellationTokenSource(); - uid.SpawnRepeatingTimer(TimeSpan.FromSeconds(component.IntervalSeconds), () => OnTimerFired(uid, component), component.TokenSource.Token); + base.Update(frameTime); + + var curTime = _timing.CurTime; + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var timedSpawner)) + { + if (timedSpawner.NextFire > curTime) + continue; + + OnTimerFired(uid, timedSpawner); + + timedSpawner.NextFire += timedSpawner.IntervalSeconds; + } + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.NextFire = _timing.CurTime + ent.Comp.IntervalSeconds; } private void OnTimerFired(EntityUid uid, TimedSpawnerComponent component) @@ -36,9 +52,4 @@ public sealed class SpawnerSystem : EntitySystem SpawnAtPosition(entity, coordinates); } } - - private void OnTimedSpawnerShutdown(EntityUid uid, TimedSpawnerComponent component, ComponentShutdown args) - { - component.TokenSource?.Cancel(); - } }