203 lines
7.8 KiB
C#
203 lines
7.8 KiB
C#
// SPDX-FileCopyrightText: 2025 Ark
|
|
// SPDX-FileCopyrightText: 2025 Ilya246
|
|
// SPDX-FileCopyrightText: 2025 Redrover1760
|
|
// SPDX-FileCopyrightText: 2025 ark1368
|
|
//
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
using System.Numerics;
|
|
using Content.Shared._Goobstation.Vehicles;
|
|
using Content.Shared._Mono.Radar;
|
|
using Content.Shared.Movement.Components;
|
|
using Content.Shared.Projectiles;
|
|
using Content.Shared.Shuttles.Components;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Physics.Components;
|
|
using Robust.Shared.Physics.Systems;
|
|
|
|
namespace Content.Server._Mono.Radar;
|
|
|
|
public sealed partial class RadarBlipSystem : EntitySystem
|
|
{
|
|
[Dependency] private readonly SharedTransformSystem _xform = default!;
|
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
SubscribeNetworkEvent<RequestBlipsEvent>(OnBlipsRequested);
|
|
SubscribeLocalEvent<RadarBlipComponent, ComponentShutdown>(OnBlipShutdown);
|
|
}
|
|
|
|
private void OnBlipsRequested(RequestBlipsEvent ev, EntitySessionEventArgs args)
|
|
{
|
|
if (!TryGetEntity(ev.Radar, out var radarUid))
|
|
return;
|
|
|
|
if (!TryComp<RadarConsoleComponent>(radarUid, out var radar))
|
|
return;
|
|
|
|
|
|
var blips = AssembleBlipsReport((EntityUid)radarUid, radar);
|
|
var hitscans = AssembleHitscanReport((EntityUid)radarUid, radar);
|
|
|
|
// Combine the blips and hitscan lines
|
|
var giveEv = new GiveBlipsEvent(blips, hitscans);
|
|
RaiseNetworkEvent(giveEv, args.SenderSession);
|
|
|
|
blips.Clear();
|
|
hitscans.Clear();
|
|
}
|
|
|
|
private void OnBlipShutdown(EntityUid blipUid, RadarBlipComponent component, ComponentShutdown args)
|
|
{
|
|
var netBlipUid = GetNetEntity(blipUid);
|
|
var removalEv = new BlipRemovalEvent(netBlipUid);
|
|
RaiseNetworkEvent(removalEv);
|
|
}
|
|
|
|
private List<(NetEntity netUid, NetCoordinates Position, Vector2 Vel, float Scale, Color Color, RadarBlipShape Shape)> AssembleBlipsReport(EntityUid uid, RadarConsoleComponent? component = null)
|
|
{
|
|
var blips = new List<(NetEntity netUid, NetCoordinates Position, Vector2 Vel, float Scale, Color Color, RadarBlipShape Shape)>();
|
|
|
|
if (Resolve(uid, ref component))
|
|
{
|
|
var radarXform = Transform(uid);
|
|
var radarPosition = _xform.GetWorldPosition(uid);
|
|
var radarGrid = _xform.GetGrid(uid);
|
|
var radarMapId = radarXform.MapID;
|
|
|
|
// Check if the radar is on an FTL map
|
|
var isFtlMap = HasComp<FTLComponent>(radarXform.GridUid);
|
|
|
|
var blipQuery = EntityQueryEnumerator<RadarBlipComponent, TransformComponent, PhysicsComponent>();
|
|
|
|
while (blipQuery.MoveNext(out var blipUid, out var blip, out var blipXform, out var blipPhysics))
|
|
{
|
|
if (!blip.Enabled)
|
|
continue;
|
|
|
|
// This prevents blips from showing on radars that are on different maps
|
|
if (blipXform.MapID != radarMapId)
|
|
continue;
|
|
|
|
var netBlipUid = GetNetEntity(blipUid);
|
|
|
|
var blipGrid = blipXform.GridUid;
|
|
|
|
// if (HasComp<CircularShieldRadarComponent>(blipUid))
|
|
// {
|
|
// // Skip if in FTL
|
|
// if (isFtlMap)
|
|
// continue;
|
|
//
|
|
// // Skip if no grid
|
|
// if (blipGrid == null)
|
|
// continue;
|
|
//
|
|
// // Ensure the grid is a valid MapGrid
|
|
// if (!HasComp<MapGridComponent>(blipGrid.Value))
|
|
// continue;
|
|
//
|
|
// // Ensure the shield is a direct child of the grid
|
|
// if (blipXform.ParentUid != blipGrid)
|
|
// continue;
|
|
// }
|
|
|
|
var blipVelocity = _physics.GetMapLinearVelocity(blipUid, blipPhysics, blipXform);
|
|
|
|
var distance = (_xform.GetWorldPosition(blipXform) - radarPosition).Length();
|
|
if (distance > component.MaxRange)
|
|
continue;
|
|
|
|
if (blip.RequireNoGrid && blipGrid != null // if we want no grid but we are on a grid
|
|
|| !blip.VisibleFromOtherGrids && blipGrid != radarGrid) // or if we don't want to be visible from other grids but we're on another grid
|
|
continue; // don't show this blip
|
|
|
|
// due to PVS being a thing, things will break if we try to parent to not the map or a grid
|
|
var coord = blipXform.Coordinates;
|
|
if (blipXform.ParentUid != blipXform.MapUid && blipXform.ParentUid != blipGrid)
|
|
coord = _xform.WithEntityId(coord, blipGrid ?? blipXform.MapUid!.Value);
|
|
// we're parented to either the map or a grid and this is relative velocity so account for grid movement
|
|
if (blipGrid != null)
|
|
blipVelocity -= _physics.GetLinearVelocity(blipGrid.Value, coord.Position);
|
|
|
|
blips.Add((netBlipUid, GetNetCoordinates(coord), blipVelocity, blip.Scale, blip.RadarColor, blip.Shape));
|
|
}
|
|
}
|
|
|
|
return blips;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Assembles trajectory information for hitscan projectiles to be displayed on radar
|
|
/// </summary>
|
|
private List<(Vector2 Start, Vector2 End, float Thickness, Color Color)> AssembleHitscanReport(EntityUid uid, RadarConsoleComponent? component = null)
|
|
{
|
|
var hitscans = new List<(Vector2 Start, Vector2 End, float Thickness, Color Color)>();
|
|
|
|
if (!Resolve(uid, ref component))
|
|
return hitscans;
|
|
|
|
var radarXform = Transform(uid);
|
|
var radarPosition = _xform.GetWorldPosition(uid);
|
|
var radarGrid = _xform.GetGrid(uid);
|
|
var radarMapId = radarXform.MapID;
|
|
|
|
var hitscanQuery = EntityQueryEnumerator<HitscanRadarComponent>();
|
|
|
|
while (hitscanQuery.MoveNext(out var hitscanUid, out var hitscan))
|
|
{
|
|
if (!hitscan.Enabled)
|
|
continue;
|
|
|
|
// Check if either the start or end point is within radar range
|
|
var startDistance = (hitscan.StartPosition - radarPosition).Length();
|
|
var endDistance = (hitscan.EndPosition - radarPosition).Length();
|
|
|
|
if (startDistance > component.MaxRange && endDistance > component.MaxRange)
|
|
continue;
|
|
|
|
hitscans.Add((hitscan.StartPosition, hitscan.EndPosition, hitscan.LineThickness, hitscan.RadarColor));
|
|
}
|
|
|
|
return hitscans;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Configures the radar blip for a jetpack or vehicle entity.
|
|
/// </summary>
|
|
private void SetupRadarBlip(EntityUid uid, Color color, float scale, bool visibleFromOtherGrids = true, bool requireNoGrid = false)
|
|
{
|
|
var blip = EnsureComp<RadarBlipComponent>(uid);
|
|
blip.RadarColor = color;
|
|
blip.Scale = scale;
|
|
blip.VisibleFromOtherGrids = visibleFromOtherGrids;
|
|
blip.RequireNoGrid = requireNoGrid;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds radar blip to jetpacks when they are activated.
|
|
/// </summary>
|
|
private void OnJetpackActivated(EntityUid uid, ActiveJetpackComponent component, ComponentAdd args)
|
|
{
|
|
SetupRadarBlip(uid, Color.Cyan, 1f, true, true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes radar blip from jetpacks when they are deactivated.
|
|
/// </summary>
|
|
private void OnJetpackDeactivated(EntityUid uid, ActiveJetpackComponent component, ComponentRemove args)
|
|
{
|
|
RemComp<RadarBlipComponent>(uid);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Configures the radar blip for a vehicle entity.
|
|
/// </summary>
|
|
public void SetupVehicleRadarBlip(Entity<VehicleComponent> uid)
|
|
{
|
|
SetupRadarBlip(uid, Color.Cyan, 1f, true, true);
|
|
}
|
|
}
|