]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Small ExplosionSystem Cleanup (#20817)
authorLeon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Sat, 14 Oct 2023 16:48:25 +0000 (03:48 +1100)
committerGitHub <noreply@github.com>
Sat, 14 Oct 2023 16:48:25 +0000 (03:48 +1100)
Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs
Content.Server/Explosion/EntitySystems/ExplosionSystem.cs

index cce7050e3f436a994328b2bfe6aaf850ad8fdcf9..102b461fe02538a93188f9fc743eb8421a81d8d0 100644 (file)
@@ -1,5 +1,6 @@
 using System.Linq;
 using System.Numerics;
+using System.Reflection;
 using Content.Server.Explosion.Components;
 using Content.Shared.CCVar;
 using Content.Shared.Damage;
@@ -18,11 +19,12 @@ using Robust.Shared.Physics.Components;
 using Robust.Shared.Physics.Dynamics;
 using Robust.Shared.Random;
 using Robust.Shared.Timing;
+using Robust.Shared.Utility;
 using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent;
 
 namespace Content.Server.Explosion.EntitySystems;
 
-public sealed partial class ExplosionSystem : EntitySystem
+public sealed partial class ExplosionSystem
 {
     /// <summary>
     ///     Used to limit explosion processing time. See <see cref="MaxProcessingTime"/>.
@@ -176,12 +178,12 @@ public sealed partial class ExplosionSystem : EntitySystem
     ///     Used for a variation of <see cref="TurfHelpers.IsBlockedTurf()"/> that makes use of the fact that we have
     ///     already done an entity lookup on a tile, and don't need to do so again.
     /// </remarks>
-    public bool IsBlockingTurf(EntityUid uid, EntityQuery<PhysicsComponent> physicsQuery)
+    public bool IsBlockingTurf(EntityUid uid)
     {
         if (EntityManager.IsQueuedForDeletion(uid))
             return false;
 
-        if (!physicsQuery.TryGetComponent(uid, out var physics))
+        if (!_physicsQuery.TryGetComponent(uid, out var physics))
             return false;
 
         return physics.CanCollide && physics.Hard && (physics.CollisionLayer & (int) CollisionGroup.Impassable) != 0;
@@ -198,19 +200,14 @@ public sealed partial class ExplosionSystem : EntitySystem
         DamageSpecifier damage,
         MapCoordinates epicenter,
         HashSet<EntityUid> processed,
-        string id,
-        EntityQuery<TransformComponent> xformQuery,
-        EntityQuery<DamageableComponent> damageQuery,
-        EntityQuery<PhysicsComponent> physicsQuery,
-        EntityQuery<TagComponent> tagQuery,
-        EntityQuery<ProjectileComponent> projectileQuery)
+        string id)
     {
         var gridBox = new Box2(tile * grid.TileSize, (tile + 1) * grid.TileSize);
 
         // get the entities on a tile. Note that we cannot process them directly, or we get
         // enumerator-changed-while-enumerating errors.
-        List<TransformComponent> list = new();
-        var state = (list, processed, xformQuery);
+        List<(EntityUid, TransformComponent)> list = new();
+        var state = (list, processed, _transformQuery);
 
         // get entities:
         lookup.DynamicTree.QueryAabb(ref state, GridQueryCallback, gridBox, true);
@@ -219,9 +216,9 @@ public sealed partial class ExplosionSystem : EntitySystem
         lookup.StaticSundriesTree.QueryAabb(ref state, GridQueryCallback, gridBox, true);
 
         // process those entities
-        foreach (var xform in list)
+        foreach (var (uid, xform) in list)
         {
-            ProcessEntity(xform.Owner, epicenter, damage, throwForce, id, xform, damageQuery, physicsQuery, xformQuery, tagQuery, projectileQuery);
+            ProcessEntity(uid, epicenter, damage, throwForce, id, xform);
         }
 
         // process anchored entities
@@ -230,7 +227,7 @@ public sealed partial class ExplosionSystem : EntitySystem
         foreach (var entity in anchoredList)
         {
             processed.Add(entity);
-            ProcessEntity(entity, epicenter, damage, throwForce, id, null, damageQuery, physicsQuery, xformQuery, tagQuery, projectileQuery);
+            ProcessEntity(entity, epicenter, damage, throwForce, id, null);
         }
 
         // Walls and reinforced walls will break into girders. These girders will also be considered turf-blocking for
@@ -241,7 +238,7 @@ public sealed partial class ExplosionSystem : EntitySystem
         {
             foreach (var entity in grid.GetAnchoredEntities(tile))
             {
-                tileBlocked |= IsBlockingTurf(entity, physicsQuery);
+                tileBlocked |= IsBlockingTurf(entity);
             }
         }
 
@@ -260,28 +257,28 @@ public sealed partial class ExplosionSystem : EntitySystem
         lookup.DynamicTree.QueryAabb(ref state, GridQueryCallback, gridBox, true);
         lookup.SundriesTree.QueryAabb(ref state, GridQueryCallback, gridBox, true);
 
-        foreach (var xform in list)
+        foreach (var (uid, xform) in list)
         {
             // Here we only throw, no dealing damage. Containers n such might drop their entities after being destroyed, but
             // they should handle their own damage pass-through, with their own damage reduction calculation.
-            ProcessEntity(xform.Owner, epicenter, null, throwForce, id, xform, damageQuery, physicsQuery, xformQuery, tagQuery, projectileQuery);
+            ProcessEntity(uid, epicenter, null, throwForce, id, xform);
         }
 
         return !tileBlocked;
     }
 
     private bool GridQueryCallback(
-        ref (List<TransformComponent> List, HashSet<EntityUid> Processed, EntityQuery<TransformComponent> XformQuery) state,
+        ref (List<(EntityUid, TransformComponent)> List, HashSet<EntityUid> Processed, EntityQuery<TransformComponent> XformQuery) state,
         in EntityUid uid)
     {
         if (state.Processed.Add(uid) && state.XformQuery.TryGetComponent(uid, out var xform))
-            state.List.Add(xform);
+            state.List.Add((uid, xform));
 
         return true;
     }
 
     private bool GridQueryCallback(
-        ref (List<TransformComponent> List, HashSet<EntityUid> Processed, EntityQuery<TransformComponent> XformQuery) state,
+        ref (List<(EntityUid, TransformComponent)> List, HashSet<EntityUid> Processed, EntityQuery<TransformComponent> XformQuery) state,
         in FixtureProxy proxy)
     {
         var owner = proxy.Entity;
@@ -299,17 +296,12 @@ public sealed partial class ExplosionSystem : EntitySystem
         DamageSpecifier damage,
         MapCoordinates epicenter,
         HashSet<EntityUid> processed,
-        string id,
-        EntityQuery<TransformComponent> xformQuery,
-        EntityQuery<DamageableComponent> damageQuery,
-        EntityQuery<PhysicsComponent> physicsQuery,
-        EntityQuery<TagComponent> tagQuery,
-        EntityQuery<ProjectileComponent> projectileQuery)
+        string id)
     {
         var gridBox = Box2.FromDimensions(tile * DefaultTileSize, new Vector2(DefaultTileSize, DefaultTileSize));
         var worldBox = spaceMatrix.TransformBox(gridBox);
-        var list = new List<TransformComponent>();
-        var state = (list, processed, invSpaceMatrix, lookup.Owner, xformQuery, gridBox);
+        var list = new List<(EntityUid, TransformComponent)>();
+        var state = (list, processed, invSpaceMatrix, lookup.Owner, _transformQuery, gridBox);
 
         // get entities:
         lookup.DynamicTree.QueryAabb(ref state, SpaceQueryCallback, worldBox, true);
@@ -317,10 +309,10 @@ public sealed partial class ExplosionSystem : EntitySystem
         lookup.SundriesTree.QueryAabb(ref state, SpaceQueryCallback, worldBox, true);
         lookup.StaticSundriesTree.QueryAabb(ref state, SpaceQueryCallback, worldBox, true);
 
-        foreach (var xform in state.Item1)
+        foreach (var (uid, xform) in state.Item1)
         {
-            processed.Add(xform.Owner);
-            ProcessEntity(xform.Owner, epicenter, damage, throwForce, id, xform, damageQuery, physicsQuery, xformQuery, tagQuery, projectileQuery);
+            processed.Add(uid);
+            ProcessEntity(uid, epicenter, damage, throwForce, id, xform);
         }
 
         if (throwForce <= 0)
@@ -332,14 +324,14 @@ public sealed partial class ExplosionSystem : EntitySystem
         lookup.DynamicTree.QueryAabb(ref state, SpaceQueryCallback, worldBox, true);
         lookup.SundriesTree.QueryAabb(ref state, SpaceQueryCallback, worldBox, true);
 
-        foreach (var xform in list)
+        foreach (var (uid, xform) in list)
         {
-            ProcessEntity(xform.Owner, epicenter, null, throwForce, id, xform, damageQuery, physicsQuery, xformQuery, tagQuery, projectileQuery);
+            ProcessEntity(uid, epicenter, null, throwForce, id, xform);
         }
     }
 
     private bool SpaceQueryCallback(
-        ref (List<TransformComponent> List, HashSet<EntityUid> Processed, Matrix3 InvSpaceMatrix, EntityUid LookupOwner, EntityQuery<TransformComponent> XformQuery, Box2 GridBox) state,
+        ref (List<(EntityUid, TransformComponent)> List, HashSet<EntityUid> Processed, Matrix3 InvSpaceMatrix, EntityUid LookupOwner, EntityQuery<TransformComponent> XformQuery, Box2 GridBox) state,
         in EntityUid uid)
     {
         if (state.Processed.Contains(uid))
@@ -351,20 +343,20 @@ public sealed partial class ExplosionSystem : EntitySystem
         {
             // parented directly to the map, use local position
             if (state.GridBox.Contains(state.InvSpaceMatrix.Transform(xform.LocalPosition)))
-                state.List.Add(xform);
+                state.List.Add((uid, xform));
 
             return true;
         }
 
         // finally check if it intersects our tile
         if (state.GridBox.Contains(state.InvSpaceMatrix.Transform(_transformSystem.GetWorldPosition(xform, state.XformQuery))))
-            state.List.Add(xform);
+            state.List.Add((uid, xform));
 
         return true;
     }
 
     private bool SpaceQueryCallback(
-        ref (List<TransformComponent> List, HashSet<EntityUid> Processed, Matrix3 InvSpaceMatrix, EntityUid LookupOwner, EntityQuery<TransformComponent> XformQuery, Box2 GridBox) state,
+        ref (List<(EntityUid, TransformComponent)> List, HashSet<EntityUid> Processed, Matrix3 InvSpaceMatrix, EntityUid LookupOwner, EntityQuery<TransformComponent> XformQuery, Box2 GridBox) state,
         in FixtureProxy proxy)
     {
         var uid = proxy.Entity;
@@ -380,44 +372,38 @@ public sealed partial class ExplosionSystem : EntitySystem
         DamageSpecifier? damage,
         float throwForce,
         string id,
-        TransformComponent? xform,
-        EntityQuery<DamageableComponent> damageQuery,
-        EntityQuery<PhysicsComponent> physicsQuery,
-        EntityQuery<TransformComponent> transformQuery,
-        EntityQuery<TagComponent> tagQuery,
-        EntityQuery<ProjectileComponent> projectileQuery)
+        TransformComponent? xform)
     {
         // damage
-        if (damage != null && damageQuery.TryGetComponent(uid, out var damageable))
+        if (damage != null && _damageQuery.TryGetComponent(uid, out var damageable))
         {
+            // TODO Explosion Performance
+            // Cache this? I.e., instead of raising an event, check for a component?
             var ev = new GetExplosionResistanceEvent(id);
-            RaiseLocalEvent(uid, ref ev, false);
+            RaiseLocalEvent(uid, ref ev);
 
             ev.DamageCoefficient = Math.Max(0, ev.DamageCoefficient);
 
-            //todo need a way to track origin of explosion
-            if (ev.DamageCoefficient == 1)
+            // TODO explosion entity
+            // Move explosion data into the existing explosion visuals entity
+            // Give each explosion a unique name, include in admin logs.
+
+            // TODO Explosion Performance
+            // This creates a new dictionary. Maybe we should just re-use a private local damage specifier and update it.
+            // Though most entities shouldn't have explosion resistance, so maybe its fine.
+            // ReSharper disable once CompareOfFloatsByEqualityOperator
+            if (ev.DamageCoefficient != 1)
+                damage *= ev.DamageCoefficient;
+
+            // Log damage to players. Damage is logged before dealing damage so that the position can be logged before
+            // the entity gets deleted.
+            if (_mindQuery.HasComponent(uid))
             {
-                // no damage-dict multiplication required.
-                _damageableSystem.TryChangeDamage(uid, damage, ignoreResistances: true, damageable: damageable);
-                if (HasComp<MindContainerComponent>(uid) || HasComp<ExplosiveComponent>(uid))
-                {
-                    var damageStr = string.Join(", ", damage.DamageDict.Select(entry => $"{entry.Key}: {entry.Value}"));
-                    _adminLogger.Add(LogType.Explosion, LogImpact.Medium,
-                        $"Explosion caused [{damageStr}] to {ToPrettyString(uid):target} at {Transform(uid).Coordinates}");
-                }
-            }
-            else
-            {
-                var appliedDamage = damage * ev.DamageCoefficient;
-                _damageableSystem.TryChangeDamage(uid, appliedDamage, ignoreResistances: true, damageable: damageable);
-                if (HasComp<MindContainerComponent>(uid) || HasComp<ExplosiveComponent>(uid))
-                {
-                    var damageStr = string.Join(", ", appliedDamage.DamageDict.Select(entry => $"{entry.Key}: {entry.Value}"));
-                    _adminLogger.Add(LogType.Explosion, LogImpact.Medium,
-                        $"Explosion caused [{damageStr}] to {ToPrettyString(uid):target} at {Transform(uid).Coordinates}");
-                }
+                _adminLogger.Add(LogType.Explosion, LogImpact.Medium,
+                    $"Explosion caused [{damage.Total}] damage to {ToPrettyString(uid):target} at {xform?.Coordinates}");
             }
+
+            _damageableSystem.TryChangeDamage(uid, damage, ignoreResistances: true, damageable: damageable);
         }
 
         // throw
@@ -425,16 +411,16 @@ public sealed partial class ExplosionSystem : EntitySystem
             && !xform.Anchored
             && throwForce > 0
             && !EntityManager.IsQueuedForDeletion(uid)
-            && physicsQuery.TryGetComponent(uid, out var physics)
+            && _physicsQuery.TryGetComponent(uid, out var physics)
             && physics.BodyType == BodyType.Dynamic)
         {
-            var pos = _transformSystem.GetWorldPosition(xform, transformQuery);
+            var pos = _transformSystem.GetWorldPosition(xform);
             _throwingSystem.TryThrow(
                 uid,
                  pos - epicenter.Position,
                 physics,
                 xform,
-                projectileQuery,
+                _projectileQuery,
                 throwForce);
         }
 
@@ -564,6 +550,9 @@ sealed class Explosion
 
     // Variables used for enumerating over tiles, grids, etc
     private DamageSpecifier _currentDamage = default!;
+#if DEBUG
+    private DamageSpecifier? _expectedDamage;
+#endif
     private BroadphaseComponent _currentLookup = default!;
     private MapGridComponent? _currentGrid;
     private float _currentIntensity;
@@ -683,6 +672,16 @@ sealed class Explosion
         while (CurrentIteration < _tileSetIntensity.Count)
         {
             _currentIntensity = _tileSetIntensity[CurrentIteration];
+
+            #if DEBUG
+            if (_expectedDamage != null)
+            {
+                // Check that explosion processing hasn't somehow accidentally mutated the damage set.
+                DebugTools.Assert(_expectedDamage.Equals(_currentDamage));
+                _expectedDamage = ExplosionType.DamagePerIntensity * _currentIntensity;
+            }
+            #endif
+
             _currentDamage = ExplosionType.DamagePerIntensity * _currentIntensity;
 
             // only throw if either the explosion is small, or if this is the outer ring of a large explosion.
@@ -780,12 +779,7 @@ sealed class Explosion
                     _currentDamage,
                     Epicenter,
                     ProcessedEntities,
-                    ExplosionType.ID,
-                    _xformQuery,
-                    _damageQuery,
-                    _physicsQuery,
-                    _tagQuery,
-                    _projectileQuery);
+                    ExplosionType.ID);
 
                 // If the floor is not blocked by some dense object, damage the floor tiles.
                 if (canDamageFloor)
@@ -802,12 +796,7 @@ sealed class Explosion
                     _currentDamage,
                     Epicenter,
                     ProcessedEntities,
-                    ExplosionType.ID,
-                    _xformQuery,
-                    _damageQuery,
-                    _physicsQuery,
-                    _tagQuery,
-                    _projectileQuery);
+                    ExplosionType.ID);
             }
 
             if (!MoveNext())
index 5e5af03c17b3d37c93f17db8b8dd549fea953eba..aa1ad71b16c188796cff6595265251fedeca2803 100644 (file)
@@ -14,12 +14,15 @@ using Content.Shared.Database;
 using Content.Shared.Explosion;
 using Content.Shared.GameTicking;
 using Content.Shared.Inventory;
+using Content.Shared.Mind;
+using Content.Shared.Projectiles;
 using Content.Shared.Throwing;
 using Robust.Server.GameStates;
 using Robust.Server.Player;
 using Robust.Shared.Audio;
 using Robust.Shared.Configuration;
 using Robust.Shared.Map;
+using Robust.Shared.Physics.Components;
 using Robust.Shared.Player;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
@@ -47,6 +50,12 @@ public sealed partial class ExplosionSystem : EntitySystem
     [Dependency] private readonly PvsOverrideSystem _pvsSys = default!;
     [Dependency] private readonly SharedTransformSystem _transformSystem = default!;
 
+    private EntityQuery<TransformComponent> _transformQuery;
+    private EntityQuery<DamageableComponent> _damageQuery;
+    private EntityQuery<PhysicsComponent> _physicsQuery;
+    private EntityQuery<ProjectileComponent> _projectileQuery;
+    private EntityQuery<MindComponent> _mindQuery;
+
     /// <summary>
     ///     "Tile-size" for space when there are no nearby grids to use as a reference.
     /// </summary>
@@ -93,6 +102,12 @@ public sealed partial class ExplosionSystem : EntitySystem
         SubscribeCvars();
         InitAirtightMap();
         InitVisuals();
+
+        _transformQuery = GetEntityQuery<TransformComponent>();
+        _damageQuery = GetEntityQuery<DamageableComponent>();
+        _physicsQuery = GetEntityQuery<PhysicsComponent>();
+        _projectileQuery = GetEntityQuery<ProjectileComponent>();
+        _mindQuery = GetEntityQuery<MindComponent>();
     }
 
     private void OnReset(RoundRestartCleanupEvent ev)