From 3bfb1f0264f2a472ba5a27b51c7937789ccee1d8 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Fri, 8 Jul 2022 15:29:43 +1200 Subject: [PATCH] Fix & speed up explosion lookup (#9526) * Speed up explosion lookup * Ah. Fuck. --- .../ExplosionSystem.Processing.cs | 120 +++++++++--------- 1 file changed, 58 insertions(+), 62 deletions(-) diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs index adc540841c..59aec97094 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs @@ -202,30 +202,16 @@ public sealed partial class ExplosionSystem : EntitySystem // get the entities on a tile. Note that we cannot process them directly, or we get // enumerator-changed-while-enumerating errors. - List<(EntityUid, TransformComponent?) > list = new(); + List list = new(); + var state = (list, processed, xformQuery); - void AddIntersecting(List<(EntityUid, TransformComponent?)> listy) - { - // TODO directly query lookup.Tree - foreach (var uid in _entityLookup.GetLocalEntitiesIntersecting(lookup, ref gridBox, flags)) - { - if (processed.Contains(uid)) - continue; - - if (!xformQuery.TryGetComponent(uid, out var xform)) - continue; - - listy.Add((uid, xform)); - } - } - - AddIntersecting(list); + // get entities: + lookup.Tree.QueryAabb(ref state, GridQueryCallback, gridBox, true); // process those entities - foreach (var (entity, xform) in list) + foreach (var xform in list) { - processed.Add(entity); - ProcessEntity(entity, epicenter, damage, throwForce, id, damageQuery, physicsQuery, xform); + ProcessEntity(xform.Owner, epicenter, damage, throwForce, id, damageQuery, physicsQuery, xform); } // process anchored entities @@ -261,18 +247,28 @@ public sealed partial class ExplosionSystem : EntitySystem return !tileBlocked; list.Clear(); - AddIntersecting(list); + lookup.Tree.QueryAabb(ref state, GridQueryCallback, gridBox, true); - foreach (var (entity, xform) in list) + foreach (var 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(entity, epicenter, null, throwForce, id, damageQuery, physicsQuery, xform); + ProcessEntity(xform.Owner, epicenter, null, throwForce, id, damageQuery, physicsQuery, xform); } return !tileBlocked; } + private bool GridQueryCallback( + ref (List List, HashSet Processed, EntityQuery XformQuery) state, + in EntityUid uid) + { + if (state.Processed.Add(uid) && state.XformQuery.TryGetComponent(uid, out var xform)) + state.List.Add(xform); + + return true; + } + /// /// Same as , but for SPAAAAAAACE. /// @@ -290,44 +286,18 @@ public sealed partial class ExplosionSystem : EntitySystem EntityQuery physicsQuery, LookupFlags flags) { - var gridBox = new Box2(tile * DefaultTileSize, (DefaultTileSize, DefaultTileSize)); + var gridBox = Box2.FromDimensions(tile * DefaultTileSize, (DefaultTileSize, DefaultTileSize)); var worldBox = spaceMatrix.TransformBox(gridBox); - List<(EntityUid, TransformComponent)> list = new(); + var list = new List(); + var state = (list, processed, invSpaceMatrix, lookup.Owner, xformQuery, gridBox); - void AddIntersecting(List<(EntityUid, TransformComponent)> listy) + // get entities: + lookup.Tree.QueryAabb(ref state, SpaceQueryCallback, worldBox, true); + + foreach (var xform in state.Item1) { - // TODO directly query lookup.Tree - foreach (var uid in _entityLookup.GetEntitiesIntersecting(lookup, ref worldBox, flags)) - { - if (processed.Contains(uid)) - return; - - var xform = xformQuery.GetComponent(uid); - - if (xform.ParentUid == lookup.Owner) - { - // parented directly to the map, use local position - if (gridBox.Contains(invSpaceMatrix.Transform(xform.LocalPosition))) - listy.Add((uid, xform)); - - return; - } - - // "worldPos" should be the space/map local position. - var worldPos = _transformSystem.GetWorldPosition(xform, xformQuery); - - // finally check if it intersects our tile - if (gridBox.Contains(invSpaceMatrix.Transform(worldPos))) - listy.Add((uid, xform)); - } - } - - AddIntersecting(list); - - foreach (var (entity, xform) in list) - { - processed.Add(entity); - ProcessEntity(entity, epicenter, damage, throwForce, id, damageQuery, physicsQuery, xform); + processed.Add(xform.Owner); + ProcessEntity(xform.Owner, epicenter, damage, throwForce, id, damageQuery, physicsQuery, xform); } if (throwForce <= 0) @@ -336,13 +306,39 @@ public sealed partial class ExplosionSystem : EntitySystem // Also, throw any entities that were spawned as shrapnel. Compared to entity spawning & destruction, this extra // lookup is relatively minor computational cost, and throwing is disabled for nukes anyways. list.Clear(); - AddIntersecting(list); - foreach (var (entity, xform) in list) + lookup.Tree.QueryAabb(ref state, SpaceQueryCallback, worldBox, true); + + foreach (var xform in list) { - ProcessEntity(entity, epicenter, null, throwForce, id, damageQuery, physicsQuery, xform); + ProcessEntity(xform.Owner, epicenter, null, throwForce, id, damageQuery, physicsQuery, xform); } } + private bool SpaceQueryCallback( + ref (List List, HashSet Processed, Matrix3 InvSpaceMatrix, EntityUid LookupOwner, EntityQuery XformQuery, Box2 GridBox) state, + in EntityUid uid) + { + if (state.Processed.Contains(uid)) + return true; + + var xform = state.XformQuery.GetComponent(uid); + + if (xform.ParentUid == state.LookupOwner) + { + // parented directly to the map, use local position + if (state.GridBox.Contains(state.InvSpaceMatrix.Transform(xform.LocalPosition))) + state.List.Add(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); + + return true; + } + /// /// This function actually applies the explosion affects to an entity. /// @@ -497,7 +493,7 @@ sealed class Explosion public readonly MapCoordinates Epicenter; /// - /// The matrix that defines the referance frame for the explosion in space. + /// The matrix that defines the reference frame for the explosion in space. /// private readonly Matrix3 _spaceMatrix;