using Robust.Server.GameObjects; using Robust.Shared.Map; using Robust.Shared.Timing; namespace Content.Server._NF.DangerTether; /// /// A system to handle tethering dangerous objects, and deleting them when out of range of any tether. /// Runs periodic checks to handle deletion. /// public sealed class DangerTetherSystem : EntitySystem { [Dependency] private IGameTiming _timing = default!; [Dependency] private TransformSystem _transform = default!; private readonly TimeSpan _scanPeriod = TimeSpan.FromSeconds(0.5); private TimeSpan _nextScan = TimeSpan.Zero; private List<(MapCoordinates Position, float Distance)> _tethers = new(); public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnTetheredMapInit); } /// /// Update: periodically, check that all DangerTethered entities are in range of a tether. /// If they aren't, delete them. /// public override void Update(float frameTime) { base.Update(frameTime); if (_timing.CurTime < _nextScan) return; _nextScan += _scanPeriod; PopulateTetherList(); var tetheredQuery = EntityQueryEnumerator(); while (tetheredQuery.MoveNext(out var targetUid, out _)) { if (!AnyTetherInRange(targetUid)) QueueDel(targetUid); } } /// /// DangerTethered MapInit: must be in range of a tether, otherwise delete it. /// private void OnTetheredMapInit(Entity ent, ref MapInitEvent args) { PopulateTetherList(); if (!AnyTetherInRange(ent)) QueueDel(ent); } private void PopulateTetherList() { _tethers.Clear(); var tetherQuery = EntityQueryEnumerator(); while (tetherQuery.MoveNext(out var tetherUid, out var tether)) { _tethers.Add((_transform.GetMapCoordinates(tetherUid), tether.MaxDistance)); } } public bool AnyTetherInRange(EntityUid ent) { var targetCoords = _transform.GetMapCoordinates(ent); foreach (var tetherEntry in _tethers) { if (tetherEntry.Position.MapId != targetCoords.MapId) continue; if (tetherEntry.Position.InRange(targetCoords, tetherEntry.Distance)) return true; } return false; } }