Fix & speed up explosion lookup (#9526)
* Speed up explosion lookup * Ah. Fuck.
This commit is contained in:
@@ -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<TransformComponent> 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<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>
|
||||
/// Same as <see cref="ExplodeTile"/>, but for SPAAAAAAACE.
|
||||
/// </summary>
|
||||
@@ -290,44 +286,18 @@ public sealed partial class ExplosionSystem : EntitySystem
|
||||
EntityQuery<PhysicsComponent> 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<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
|
||||
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<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>
|
||||
/// This function actually applies the explosion affects to an entity.
|
||||
/// </summary>
|
||||
@@ -497,7 +493,7 @@ sealed class Explosion
|
||||
public readonly MapCoordinates Epicenter;
|
||||
|
||||
/// <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>
|
||||
private readonly Matrix3 _spaceMatrix;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user