using JetBrains.Annotations; using Robust.Client.Graphics; using Robust.Client.ResourceManagement; using Robust.Shared.Enums; using Robust.Shared.Map; using System.Linq; using System.Numerics; namespace Content.Client.Administration.UI.SpawnExplosion; [UsedImplicitly] public sealed class ExplosionDebugOverlay : Overlay { [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IEyeManager _eyeManager = default!; [Dependency] private readonly IMapManager _mapManager = default!; private readonly SharedTransformSystem _transform; public Dictionary>? SpaceTiles; public Dictionary>> Tiles = new(); public List Intensity = new(); public float TotalIntensity; public float Slope; public ushort SpaceTileSize; public override OverlaySpace Space => OverlaySpace.WorldSpace | OverlaySpace.ScreenSpace; public Matrix3 SpaceMatrix; public MapId Map; private readonly Font _font; public ExplosionDebugOverlay() { IoCManager.InjectDependencies(this); var cache = IoCManager.Resolve(); _font = new VectorFont(cache.GetResource("/Fonts/NotoSans/NotoSans-Regular.ttf"), 8); _transform = _entityManager.System(); } protected override void Draw(in OverlayDrawArgs args) { if (Map != args.Viewport.Eye?.Position.MapId) return; if (Tiles.Count == 0 && SpaceTiles == null) return; switch (args.Space) { case OverlaySpace.ScreenSpace: DrawScreen(args); break; case OverlaySpace.WorldSpace: DrawWorld(args); break; } } private void DrawScreen(OverlayDrawArgs args) { var handle = args.ScreenHandle; Box2 gridBounds; var xformQuery = _entityManager.GetEntityQuery(); foreach (var (gridId, tileSets) in Tiles) { if (!_mapManager.TryGetGrid(gridId, out var grid)) continue; var gridXform = xformQuery.GetComponent(grid.Owner); var (_, _, matrix, invMatrix) = _transform.GetWorldPositionRotationMatrixWithInv(gridXform, xformQuery); gridBounds = invMatrix.TransformBox(args.WorldBounds).Enlarged(grid.TileSize * 2); DrawText(handle, gridBounds, matrix, tileSets, grid.TileSize); } if (SpaceTiles == null) return; gridBounds = Matrix3.Invert(SpaceMatrix).TransformBox(args.WorldBounds); DrawText(handle, gridBounds, SpaceMatrix, SpaceTiles, SpaceTileSize); } private void DrawText( DrawingHandleScreen handle, Box2 gridBounds, Matrix3 transform, Dictionary> tileSets, ushort tileSize) { for (var i = 1; i < Intensity.Count; i++) { if (!tileSets.TryGetValue(i, out var tiles)) continue; foreach (var tile in tiles) { var centre = (tile + Vector2Helpers.Half) * tileSize; // is the center of this tile visible to the user? if (!gridBounds.Contains(centre)) continue; var worldCenter = transform.Transform(centre); var screenCenter = _eyeManager.WorldToScreen(worldCenter); if (Intensity[i] > 9) screenCenter += new Vector2(-12, -8); else screenCenter += new Vector2(-8, -8); handle.DrawString(_font, screenCenter, Intensity[i].ToString("F2")); } } if (tileSets.ContainsKey(0)) { var epicenter = tileSets[0].First(); var worldCenter = transform.Transform((epicenter + Vector2Helpers.Half) * tileSize); var screenCenter = _eyeManager.WorldToScreen(worldCenter) + new Vector2(-24, -24); var text = $"{Intensity[0]:F2}\nΣ={TotalIntensity:F1}\nΔ={Slope:F1}"; handle.DrawString(_font, screenCenter, text); } } private void DrawWorld(in OverlayDrawArgs args) { var handle = args.WorldHandle; Box2 gridBounds; var xformQuery = _entityManager.GetEntityQuery(); foreach (var (gridId, tileSets) in Tiles) { if (!_mapManager.TryGetGrid(gridId, out var grid)) continue; var gridXform = xformQuery.GetComponent(grid.Owner); var (_, _, worldMatrix, invWorldMatrix) = _transform.GetWorldPositionRotationMatrixWithInv(gridXform, xformQuery); gridBounds = invWorldMatrix.TransformBox(args.WorldBounds).Enlarged(grid.TileSize * 2); handle.SetTransform(worldMatrix); DrawTiles(handle, gridBounds, tileSets, SpaceTileSize); } if (SpaceTiles == null) return; gridBounds = Matrix3.Invert(SpaceMatrix).TransformBox(args.WorldBounds).Enlarged(2); handle.SetTransform(SpaceMatrix); DrawTiles(handle, gridBounds, SpaceTiles, SpaceTileSize); handle.SetTransform(Matrix3.Identity); } private void DrawTiles( DrawingHandleWorld handle, Box2 gridBounds, Dictionary> tileSets, ushort tileSize) { for (var i = 0; i < Intensity.Count; i++) { var color = ColorMap(Intensity[i]); var colorTransparent = color; colorTransparent.A = 0.2f; if (!tileSets.TryGetValue(i, out var tiles)) continue; foreach (var tile in tiles) { var centre = (tile + Vector2Helpers.Half) * tileSize; // is the center of this tile visible to the user? if (!gridBounds.Contains(centre)) continue; var box = Box2.UnitCentered.Translated(centre); handle.DrawRect(box, color, false); handle.DrawRect(box, colorTransparent); } } } private Color ColorMap(float intensity) { var frac = 1 - intensity / Intensity[0]; Color result; if (frac < 0.5f) result = Color.InterpolateBetween(Color.Red, Color.Orange, frac * 2); else result = Color.InterpolateBetween(Color.Orange, Color.Yellow, (frac - 0.5f) * 2); return result; } }