From 56168e592e616d76f8bf662e749cd1d581e0de90 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Fri, 1 Apr 2022 15:39:26 +1300 Subject: [PATCH] Explosion refactor (#5230) * Explosions * fix yaml typo and prevent silly UI inputs * oop * Use modified contains() checks And remove IEnumerable * Buff nuke, nerf meteors * optimize the entity lookup stuff a bit * fix tile (0,0) error forgot to do an initial Enumerator.MoveNext(), so the first tile was always the "null" tile. * remove celebration * byte -> int * remove diag edge tile dict * fix one bug but there is another * fix the other bug turns out dividing a ushort leads to rounding errors. Why TF is the grid tile size even a ushort in the first place. * improve edge map * fix minor bug If the initial-explosion tile had an airtight entity on it, the tile was processed twice. * some reviews (transform queries, eye.mapid, and tilesizes in overlays) * Apply suggestions from code review Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * is map paused * GetAllTiles ignores space by default * WriteLine -> WriteError * First -> FirstOrDefault() * default prototype const string * entity query * misc review changes * grid edge max distance * fix fire texture defn bad use of type serializer and ioc-resolves * Remove ExplosionLaunched And allow nukes to throw items towards the outer part of an explosion * no hot-reload disclaimer * replace prototype id string with int index * optimise damage a tiiiiny bit. * entity queries * comments * misc mirror comments * cvars * admin logs * move intensity-per-state to prototype * update tile event to ECS event * git mv * Tweak rpg & minibomb also fix merge bug * you don't exist anymore go away * Fix build Co-authored-by: moonheart08 Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> --- .../SpawnExplosion/ExplosionDebugOverlay.cs | 193 ++++++ .../UI/SpawnExplosion/SpawnExplosionEui.cs | 81 +++ .../SpawnExplosion/SpawnExplosionWindow.xaml | 46 ++ .../SpawnExplosionWindow.xaml.cs | 142 ++++ Content.Client/Entry/IgnoredComponents.cs | 2 +- Content.Client/Explosion/ExplosionOverlay.cs | 119 ++++ .../Explosion/ExplosionOverlaySystem.cs | 211 ++++++ Content.Server/AME/AMENodeGroup.cs | 11 +- .../Administration/AdminVerbSystem.cs | 9 +- .../Commands/ExplosionCommand.cs | 146 +++- .../Administration/UI/SpawnExplosionEui.cs | 39 ++ .../Atmos/Components/GasTankComponent.cs | 4 +- .../Atmos/EntitySystems/AirtightSystem.cs | 5 + .../ExplosionReactionEffect.cs | 90 ++- .../Destructible/DestructibleSystem.cs | 38 ++ .../Thresholds/Behaviors/ExplodeBehavior.cs | 2 +- .../Components/ExplosionLaunchedComponent.cs | 43 -- .../ExplosionResistanceComponent.cs | 30 + .../Components/ExplosiveComponent.cs | 76 ++- .../EntitySystems/ExplosionSystem.Airtight.cs | 181 +++++ .../EntitySystems/ExplosionSystem.CVars.cs | 48 ++ .../EntitySystems/ExplosionSystem.GridMap.cs | 386 +++++++++++ .../ExplosionSystem.Processing.cs | 642 ++++++++++++++++++ .../EntitySystems/ExplosionSystem.TileFill.cs | 337 +++++++++ .../EntitySystems/ExplosionSystem.cs | 635 ++++++++--------- .../Explosion/EntitySystems/GridExplosion.cs | 304 +++++++++ .../Explosion/EntitySystems/SpaceExplosion.cs | 160 +++++ .../Explosion/EntitySystems/TileExplosion.cs | 191 ++++++ .../Explosion/EntitySystems/TriggerSystem.cs | 24 +- .../EntitySystems/NodeGroupSystem.cs | 9 +- Content.Server/Nuke/NukeComponent.cs | 51 +- Content.Server/Nuke/NukeSystem.cs | 25 +- .../Components/RoguePointingArrowComponent.cs | 4 - .../EntitySystems/RoguePointingSystem.cs | 9 +- Content.Server/PowerCell/PowerCellSystem.cs | 6 +- .../Components/EntityStorageComponent.cs | 20 +- .../Components/ServerStorageComponent.cs | 26 +- Content.Shared/Acts/ActSystem.cs | 40 +- .../Administration/SpawnExplosionEuiMsg.cs | 52 ++ Content.Shared/CCVar/CCVars.cs | 100 +++ .../Damage/Components/DamageableComponent.cs | 23 +- .../Damage/Systems/DamageableSystem.cs | 4 +- Content.Shared/Explosion/ExplosionEvents.cs | 85 +++ .../Explosion/ExplosionPrototype.cs | 104 +++ .../Inventory/InventoryComponent.cs | 30 +- .../Inventory/InventorySystem.Relay.cs | 5 +- .../ui/admin-spawn-explosion-eui.ftl | 16 + .../Entities/Clothing/Head/helmets.yml | 2 + .../Entities/Clothing/OuterClothing/suits.yml | 6 +- .../Entities/Effects/explosion_light.yml | 9 + .../Entities/Objects/Devices/nuke.yml | 6 + .../Entities/Objects/Power/powercells.yml | 2 + .../Entities/Objects/Tools/gas_tanks.yml | 3 + .../Weapons/Guns/Projectiles/meteors.yml | 10 +- .../Weapons/Guns/Projectiles/projectiles.yml | 21 +- .../Objects/Weapons/Throwable/grenades.yml | 25 +- .../Prototypes/Entities/Objects/base_item.yml | 1 - .../Structures/Power/Generation/ame.yml | 4 + .../Entities/Structures/Power/substation.yml | 8 +- .../Storage/Closets/Lockers/lockers.yml | 2 + .../Structures/Storage/Tanks/tanks.yml | 8 +- .../Entities/Structures/Walls/barricades.yml | 1 - .../Entities/Structures/Walls/girder.yml | 3 - .../Recipes/Reactions/chemicals.yml | 12 +- .../Recipes/Reactions/pyrotechnic.yml | 10 +- Resources/Prototypes/explosion.yml | 41 ++ .../Textures/Effects/fire_greyscale.rsi/1.png | Bin 0 -> 62870 bytes .../Textures/Effects/fire_greyscale.rsi/2.png | Bin 0 -> 110683 bytes .../Textures/Effects/fire_greyscale.rsi/3.png | Bin 0 -> 18528 bytes .../Effects/fire_greyscale.rsi/meta.json | 1 + 70 files changed, 4209 insertions(+), 770 deletions(-) create mode 100644 Content.Client/Administration/UI/SpawnExplosion/ExplosionDebugOverlay.cs create mode 100644 Content.Client/Administration/UI/SpawnExplosion/SpawnExplosionEui.cs create mode 100644 Content.Client/Administration/UI/SpawnExplosion/SpawnExplosionWindow.xaml create mode 100644 Content.Client/Administration/UI/SpawnExplosion/SpawnExplosionWindow.xaml.cs create mode 100644 Content.Client/Explosion/ExplosionOverlay.cs create mode 100644 Content.Client/Explosion/ExplosionOverlaySystem.cs create mode 100644 Content.Server/Administration/UI/SpawnExplosionEui.cs delete mode 100644 Content.Server/Explosion/Components/ExplosionLaunchedComponent.cs create mode 100644 Content.Server/Explosion/Components/ExplosionResistanceComponent.cs create mode 100644 Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs create mode 100644 Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs create mode 100644 Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs create mode 100644 Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs create mode 100644 Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs create mode 100644 Content.Server/Explosion/EntitySystems/GridExplosion.cs create mode 100644 Content.Server/Explosion/EntitySystems/SpaceExplosion.cs create mode 100644 Content.Server/Explosion/EntitySystems/TileExplosion.cs create mode 100644 Content.Shared/Administration/SpawnExplosionEuiMsg.cs create mode 100644 Content.Shared/Explosion/ExplosionEvents.cs create mode 100644 Content.Shared/Explosion/ExplosionPrototype.cs create mode 100644 Resources/Locale/en-US/administration/ui/admin-spawn-explosion-eui.ftl create mode 100644 Resources/Prototypes/Entities/Effects/explosion_light.yml create mode 100644 Resources/Prototypes/explosion.yml create mode 100644 Resources/Textures/Effects/fire_greyscale.rsi/1.png create mode 100644 Resources/Textures/Effects/fire_greyscale.rsi/2.png create mode 100644 Resources/Textures/Effects/fire_greyscale.rsi/3.png create mode 100644 Resources/Textures/Effects/fire_greyscale.rsi/meta.json diff --git a/Content.Client/Administration/UI/SpawnExplosion/ExplosionDebugOverlay.cs b/Content.Client/Administration/UI/SpawnExplosion/ExplosionDebugOverlay.cs new file mode 100644 index 0000000000..cc00f754a6 --- /dev/null +++ b/Content.Client/Administration/UI/SpawnExplosion/ExplosionDebugOverlay.cs @@ -0,0 +1,193 @@ +using JetBrains.Annotations; +using Robust.Client.Graphics; +using Robust.Client.ResourceManagement; +using Robust.Shared.Enums; +using Robust.Shared.Map; +using System.Linq; + +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!; + + 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); + } + + 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.GridEntityId); + var (_, _, matrix, invMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(xformQuery); + gridBounds = invMatrix.TransformBox(args.WorldBounds); + 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 = ((Vector2) tile + 0.5f) * 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 += (-12, -8); + else + screenCenter += (-8, -8); + + handle.DrawString(_font, screenCenter, Intensity![i].ToString("F2")); + } + } + + if (tileSets.ContainsKey(0)) + { + var epicenter = tileSets[0].First(); + var worldCenter = transform.Transform(((Vector2) epicenter + 0.5f) * tileSize); + var screenCenter = _eyeManager.WorldToScreen(worldCenter) + (-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.GridEntityId); + var (_, _, worldMatrix, invWorldMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(xformQuery); + gridBounds = invWorldMatrix.TransformBox(args.WorldBounds); + handle.SetTransform(worldMatrix); + DrawTiles(handle, gridBounds, tileSets, SpaceTileSize); + } + + if (SpaceTiles == null) + return; + + gridBounds = Matrix3.Invert(SpaceMatrix).TransformBox(args.WorldBounds); + handle.SetTransform(SpaceMatrix); + + DrawTiles(handle, gridBounds, SpaceTiles, SpaceTileSize); + } + + 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 = ((Vector2) tile + 0.5f) * 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; + } +} diff --git a/Content.Client/Administration/UI/SpawnExplosion/SpawnExplosionEui.cs b/Content.Client/Administration/UI/SpawnExplosion/SpawnExplosionEui.cs new file mode 100644 index 0000000000..14eeb06386 --- /dev/null +++ b/Content.Client/Administration/UI/SpawnExplosion/SpawnExplosionEui.cs @@ -0,0 +1,81 @@ +using Content.Client.Eui; +using Content.Shared.Administration; +using Content.Shared.Eui; +using JetBrains.Annotations; +using Robust.Client.Graphics; +using Robust.Shared.Map; + +namespace Content.Client.Administration.UI.SpawnExplosion; + +[UsedImplicitly] +public sealed class SpawnExplosionEui : BaseEui +{ + [Dependency] private readonly IOverlayManager _overlayManager = default!; + + private readonly SpawnExplosionWindow _window; + private ExplosionDebugOverlay? _debugOverlay; + + public SpawnExplosionEui() + { + IoCManager.InjectDependencies(this); + _window = new SpawnExplosionWindow(this); + _window.OnClose += SendClosedMessage; + } + + public override void Opened() + { + base.Opened(); + _window.OpenCentered(); + } + + public override void Closed() + { + base.Closed(); + _window.OnClose -= SendClosedMessage; + _window.Close(); + ClearOverlay(); + } + + public void SendClosedMessage() + { + SendMessage(new SpawnExplosionEuiMsg.Close()); + } + + public void ClearOverlay() + { + if (_overlayManager.HasOverlay()) + _overlayManager.RemoveOverlay(); + _debugOverlay = null; + } + + public void RequestPreviewData(MapCoordinates epicenter, string typeId, float totalIntensity, float intensitySlope, float maxIntensity) + { + var msg = new SpawnExplosionEuiMsg.PreviewRequest(epicenter, typeId, totalIntensity, intensitySlope, maxIntensity); + SendMessage(msg); + } + + /// + /// Receive explosion preview data and add a client-side explosion preview overlay + /// + /// + public override void HandleMessage(EuiMessageBase msg) + { + if (msg is not SpawnExplosionEuiMsg.PreviewData data) + return; + + if (_debugOverlay == null) + { + _debugOverlay = new(); + _overlayManager.AddOverlay(_debugOverlay); + } + + _debugOverlay.Tiles = data.Explosion.Tiles; + _debugOverlay.SpaceTiles = data.Explosion.SpaceTiles; + _debugOverlay.Intensity = data.Explosion.Intensity; + _debugOverlay.Slope = data.Slope; + _debugOverlay.TotalIntensity = data.TotalIntensity; + _debugOverlay.Map = data.Explosion.Epicenter.MapId; + _debugOverlay.SpaceMatrix = data.Explosion.SpaceMatrix; + _debugOverlay.SpaceTileSize = data.Explosion.SpaceTileSize; + } +} diff --git a/Content.Client/Administration/UI/SpawnExplosion/SpawnExplosionWindow.xaml b/Content.Client/Administration/UI/SpawnExplosion/SpawnExplosionWindow.xaml new file mode 100644 index 0000000000..f1dcd35cb8 --- /dev/null +++ b/Content.Client/Administration/UI/SpawnExplosion/SpawnExplosionWindow.xaml @@ -0,0 +1,46 @@ + + + + + + + + + + + + +