Files
RobustToolbox/Robust.Client/Debugging/DebugRayDrawingSystem.cs
T
83c2a1be11 [Dependency] source generator part 2 (#6550)
* [Dependency] source generator

No more reflection, no more codegen at runtime

Also various changes to Roslyn helpers to make this easier to write.

Requires all types with dependencies to be partial and not have readonly dependency fields. An analyzer enforces this at warning level, the previous injection strategies have remained in the code *for now* as a fallback.

No fallback is available for [field: Dependency] properties, due to a Roslyn bug.

Code Fixes exist. We love Roslyn

* Apply dependencies generator changes to all code

* Release notes

* Preprocessor got hands

* Handle nullable dependencies

These are bad but gotta deal with it.

* Apply suggestions from code review

Co-authored-by: Moony <moony@hellomouse.net>

* Fine, let's not use collection expressions

---------

Co-authored-by: Moony <moony@hellomouse.net>
2026-05-08 12:38:33 +02:00

148 lines
4.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Numerics;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
using Robust.Shared.Debugging;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Network.Messages;
using Robust.Shared.Timing;
namespace Robust.Client.Debugging
{
internal sealed partial class DebugRayDrawingSystem : SharedDebugRayDrawingSystem
{
#if DEBUG
[Dependency] private IOverlayManager _overlayManager = default!;
[Dependency] private IGameTiming _gameTimer = default!;
private readonly List<RayWithLifetime> _raysWithLifeTime = new();
private bool _debugDrawRays;
private struct RayWithLifetime
{
public Vector2 RayOrigin;
public Vector2 RayHit;
public TimeSpan LifeTime;
public bool DidActuallyHit;
public bool Server;
public MapId Map;
}
public bool DebugDrawRays
{
get => _debugDrawRays;
set
{
if (value == DebugDrawRays)
{
return;
}
_debugDrawRays = value;
if (value && !_overlayManager.HasOverlay<DebugDrawRayOverlay>())
{
_overlayManager.AddOverlay(new DebugDrawRayOverlay(this));
}
else
{
_overlayManager.RemoveOverlay<DebugDrawRayOverlay>();
}
}
}
public TimeSpan DebugRayLifetime { get; set; } = TimeSpan.FromSeconds(5);
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<MsgRay>(HandleDrawRay);
}
protected override void ReceiveLocalRayAtMainThread(DebugRayData ev)
{
if (!_debugDrawRays)
{
return;
}
var newRayWithLifetime = new RayWithLifetime
{
DidActuallyHit = ev.Results != null,
RayOrigin = ev.Ray.Position,
RayHit = ev.Results?.HitPos ?? ev.Ray.Direction * ev.MaxLength + ev.Ray.Position,
LifeTime = _gameTimer.RealTime + DebugRayLifetime,
Map = ev.Map
};
_raysWithLifeTime.Add(newRayWithLifetime);
}
private void HandleDrawRay(MsgRay msg)
{
// Rays are disposed with DebugDrawRayOverlay.FrameUpdate.
// We don't accept incoming rays when that's off because else they'd pile up constantly.
if (!_debugDrawRays)
{
return;
}
var newRayWithLifetime = new RayWithLifetime
{
DidActuallyHit = msg.DidHit,
RayOrigin = msg.RayOrigin,
RayHit = msg.RayHit,
LifeTime = _gameTimer.RealTime + DebugRayLifetime,
Server = true,
Map = msg.Map
};
_raysWithLifeTime.Add(newRayWithLifetime);
}
private sealed class DebugDrawRayOverlay : Overlay
{
private readonly DebugRayDrawingSystem _owner;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
public DebugDrawRayOverlay(DebugRayDrawingSystem owner)
{
_owner = owner;
}
protected internal override void Draw(in OverlayDrawArgs args)
{
var handle = args.WorldHandle;
foreach (var ray in _owner._raysWithLifeTime)
{
if (args.MapId != ray.Map)
continue;
Color color;
if (ray.Server)
color = ray.DidActuallyHit ? Color.Cyan : Color.Orange;
else
color = ray.DidActuallyHit ? Color.Blue : Color.Red;
handle.DrawLine(
ray.RayOrigin,
ray.RayHit,
color
);
}
}
protected internal override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
_owner._raysWithLifeTime.RemoveAll(r => r.LifeTime < _owner._gameTimer.RealTime);
}
}
#endif
}
}