-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;
/// and min/max number of entities to spawn.
/// </summary>
[RegisterComponent, EntityCategory("Spawner")]
+[AutoGenerateComponentPause]
public sealed partial class TimedSpawnerComponent : Component, ISerializationHooks
{
/// <summary>
/// Length of the interval between spawn attempts.
/// </summary>
[DataField]
- public int IntervalSeconds = 60;
+ public TimeSpan IntervalSeconds = TimeSpan.FromSeconds(60);
/// <summary>
/// The minimum number of entities that can be spawned when an interval elapses.
[DataField]
public int MaximumEntitiesSpawned = 1;
- public CancellationTokenSource? TokenSource;
+ /// <summary>
+ /// The time at which the current interval will have elapsed and entities may be spawned.
+ /// </summary>
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField]
+ public TimeSpan NextFire = TimeSpan.Zero;
void ISerializationHooks.AfterDeserialization()
{
-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<TimedSpawnerComponent, ComponentInit>(OnSpawnerInit);
- SubscribeLocalEvent<TimedSpawnerComponent, ComponentShutdown>(OnTimedSpawnerShutdown);
+
+ SubscribeLocalEvent<TimedSpawnerComponent, MapInitEvent>(OnMapInit);
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var curTime = _timing.CurTime;
+ var query = EntityQueryEnumerator<TimedSpawnerComponent>();
+ while (query.MoveNext(out var uid, out var timedSpawner))
+ {
+ if (timedSpawner.NextFire > curTime)
+ continue;
+
+ OnTimerFired(uid, timedSpawner);
+
+ timedSpawner.NextFire += timedSpawner.IntervalSeconds;
+ }
}
- private void OnSpawnerInit(EntityUid uid, TimedSpawnerComponent component, ComponentInit args)
+ private void OnMapInit(Entity<TimedSpawnerComponent> ent, ref MapInitEvent args)
{
- component.TokenSource?.Cancel();
- component.TokenSource = new CancellationTokenSource();
- uid.SpawnRepeatingTimer(TimeSpan.FromSeconds(component.IntervalSeconds), () => OnTimerFired(uid, component), component.TokenSource.Token);
+ ent.Comp.NextFire = _timing.CurTime + ent.Comp.IntervalSeconds;
}
private void OnTimerFired(EntityUid uid, TimedSpawnerComponent component)
SpawnAtPosition(entity, coordinates);
}
}
-
- private void OnTimedSpawnerShutdown(EntityUid uid, TimedSpawnerComponent component, ComponentShutdown args)
- {
- component.TokenSource?.Cancel();
- }
}