using System.Numerics; using Content.Shared._Goobstation.Vehicles; using Content.Shared._NF.Radar; using Content.Shared.GameTicking; using Content.Shared.Movement.Components; using Content.Shared.Shuttles.Components; using Robust.Shared.Network; using Robust.Shared.Timing; namespace Content.Server._NF.Radar; /// /// A system that handles and rate-limits client-made requests for radar blips. /// /// /// Ported from Monolith's RadarBlipsSystem. /// public sealed partial class RadarBlipSystem : SharedRadarBlipSystem { [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly SharedTransformSystem _xform = default!; private Dictionary _nextBlipRequestPerUser = new(); // The minimum amount of time between handled blip requests. private static readonly TimeSpan MinRequestPeriod = TimeSpan.FromSeconds(1); // Maximum distance for blips to be considered visible private const float MaxBlipRenderDistance = 300f; public override void Initialize() { base.Initialize(); SubscribeNetworkEvent(OnBlipsRequested); SubscribeLocalEvent(OnRoundRestart); } /// /// Handles a network request for radar blips and sends the blip data to the requesting client. /// private void OnBlipsRequested(RequestBlipsEvent ev, EntitySessionEventArgs args) { if (!TryGetEntity(ev.Radar, out var radarUid)) return; if (!TryComp(radarUid, out var radar)) return; if (_nextBlipRequestPerUser.TryGetValue(args.SenderSession.UserId, out var requestTime) && _timing.RealTime < requestTime) return; _nextBlipRequestPerUser[args.SenderSession.UserId] = _timing.RealTime + MinRequestPeriod; var blips = AssembleBlipsReport((radarUid.Value, radar)); var giveEv = new GiveBlipsEvent(blips); RaiseNetworkEvent(giveEv, args.SenderSession); } /// /// Clears blip request data between rounds. /// public void OnRoundRestart(RoundRestartCleanupEvent ev) { _nextBlipRequestPerUser.Clear(); } /// /// Assembles a list of radar blips visible to the given radar console. /// private List<(NetEntity? Grid, Vector2 Position, float Scale, Color Color, RadarBlipShape Shape)> AssembleBlipsReport(Entity ent) { var blips = new List<(NetEntity? Grid, Vector2 Position, float Scale, Color Color, RadarBlipShape Shape)>(); if (!TryComp(ent, out TransformComponent? radarXform)) return blips; var radarPosition = _xform.GetWorldPosition(ent); var radarGrid = radarXform.GridUid; var radarMapId = radarXform.MapID; var radarRange = MathF.Min(ent.Comp.MaxRange, MaxBlipRenderDistance); // Non-positive range, nothing to return. if (radarRange <= 0) return blips; var blipQuery = EntityQueryEnumerator(); while (blipQuery.MoveNext(out var blipUid, out var blip, out var blipXform)) { if (!blip.Enabled) { Log.Debug($"Blip {blipUid} skipped: not enabled."); continue; } if (blipXform.MapID != radarMapId) { Log.Debug($"Blip {blipUid} skipped: different map."); continue; } // Run cheaper grid checks before distance checks var blipGrid = blipXform.GridUid; if (blip.RequireNoGrid && blipGrid != null) { Log.Debug($"Blip {blipUid} skipped: has grid but requires none."); continue; } if (!blip.VisibleFromOtherGrids && blipGrid != radarGrid) { Log.Debug($"Blip {blipUid} skipped: not on same grid as radar."); continue; } var blipPosition = _xform.GetWorldPosition(blipUid); var distance = (blipPosition - radarPosition).Length(); if (distance > radarRange) { Log.Debug($"Blip {blipUid} skipped: out of range."); continue; } // Convert blip position to grid coords if needed. NetEntity? blipNetGrid = null; if (blipGrid != null) { blipNetGrid = GetNetEntity(blipGrid.Value); blipPosition = Vector2.Transform(blipPosition, _xform.GetInvWorldMatrix(blipGrid.Value)); } blips.Add((blipNetGrid, blipPosition, blip.Scale, blip.RadarColor, blip.Shape)); } return blips; } /// /// Configures the radar blip for a jetpack or vehicle entity. /// private void SetupRadarBlip(EntityUid uid, Color color, float scale, bool visibleFromOtherGrids = true, bool requireNoGrid = false) { var blip = EnsureComp(uid); blip.RadarColor = color; blip.Scale = scale; blip.VisibleFromOtherGrids = visibleFromOtherGrids; blip.RequireNoGrid = requireNoGrid; } /// /// Configures the radar blip for a vehicle entity. /// public void SetupVehicleRadarBlip(Entity uid) { SetupRadarBlip(uid, Color.Cyan, 1f, true, true); } }