Fix & speed up explosion lookup (#9526)

* Speed up explosion lookup

* Ah. Fuck.
This commit is contained in:
Leon Friedrich
2022-07-08 15:29:43 +12:00
committed by GitHub
parent 93079d522d
commit 3bfb1f0264

View File

@@ -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 // get the entities on a tile. Note that we cannot process them directly, or we get
// enumerator-changed-while-enumerating errors. // enumerator-changed-while-enumerating errors.
List<(EntityUid, TransformComponent?) > list = new(); List<TransformComponent> list = new();
var state = (list, processed, xformQuery);
void AddIntersecting(List<(EntityUid, TransformComponent?)> listy) // get entities:
{ lookup.Tree.QueryAabb(ref state, GridQueryCallback, gridBox, true);
// 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);
// process those entities // process those entities
foreach (var (entity, xform) in list) foreach (var xform in list)
{ {
processed.Add(entity); ProcessEntity(xform.Owner, epicenter, damage, throwForce, id, damageQuery, physicsQuery, xform);
ProcessEntity(entity, epicenter, damage, throwForce, id, damageQuery, physicsQuery, xform);
} }
// process anchored entities // process anchored entities
@@ -261,18 +247,28 @@ public sealed partial class ExplosionSystem : EntitySystem
return !tileBlocked; return !tileBlocked;
list.Clear(); 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 // 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. // 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; return !tileBlocked;
} }
private bool GridQueryCallback(
ref (List<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);
return true;
}
/// <summary> /// <summary>
/// Same as <see cref="ExplodeTile"/>, but for SPAAAAAAACE. /// Same as <see cref="ExplodeTile"/>, but for SPAAAAAAACE.
/// </summary> /// </summary>
@@ -290,44 +286,18 @@ public sealed partial class ExplosionSystem : EntitySystem
EntityQuery<PhysicsComponent> physicsQuery, EntityQuery<PhysicsComponent> physicsQuery,
LookupFlags flags) LookupFlags flags)
{ {
var gridBox = new Box2(tile * DefaultTileSize, (DefaultTileSize, DefaultTileSize)); var gridBox = Box2.FromDimensions(tile * DefaultTileSize, (DefaultTileSize, DefaultTileSize));
var worldBox = spaceMatrix.TransformBox(gridBox); var worldBox = spaceMatrix.TransformBox(gridBox);
List<(EntityUid, TransformComponent)> list = new(); var list = new List<TransformComponent>();
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 processed.Add(xform.Owner);
foreach (var uid in _entityLookup.GetEntitiesIntersecting(lookup, ref worldBox, flags)) ProcessEntity(xform.Owner, epicenter, damage, throwForce, id, damageQuery, physicsQuery, xform);
{
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);
} }
if (throwForce <= 0) 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 // 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. // lookup is relatively minor computational cost, and throwing is disabled for nukes anyways.
list.Clear(); list.Clear();
AddIntersecting(list); lookup.Tree.QueryAabb(ref state, SpaceQueryCallback, worldBox, true);
foreach (var (entity, xform) in list)
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<TransformComponent> List, HashSet<EntityUid> Processed, Matrix3 InvSpaceMatrix, EntityUid LookupOwner, EntityQuery<TransformComponent> 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;
}
/// <summary> /// <summary>
/// This function actually applies the explosion affects to an entity. /// This function actually applies the explosion affects to an entity.
/// </summary> /// </summary>
@@ -497,7 +493,7 @@ sealed class Explosion
public readonly MapCoordinates Epicenter; public readonly MapCoordinates Epicenter;
/// <summary> /// <summary>
/// The matrix that defines the referance frame for the explosion in space. /// The matrix that defines the reference frame for the explosion in space.
/// </summary> /// </summary>
private readonly Matrix3 _spaceMatrix; private readonly Matrix3 _spaceMatrix;