explosion minor rework + fix (#21718)
This commit is contained in:
@@ -1,16 +1,11 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using Content.Server.Explosion.Components;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Explosion;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Projectiles;
|
||||
using Robust.Shared.Spawners;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
@@ -55,6 +50,13 @@ public sealed partial class ExplosionSystem
|
||||
/// </summary>
|
||||
private int _previousTileIteration;
|
||||
|
||||
/// <summary>
|
||||
/// This list is used when raising <see cref="BeforeExplodeEvent"/> to avoid allocating a new list per event.
|
||||
/// </summary>
|
||||
private readonly List<EntityUid> _containedEntities = new();
|
||||
|
||||
private readonly List<(EntityUid, DamageSpecifier)> _toDamage = new();
|
||||
|
||||
private List<EntityUid> _anchored = new();
|
||||
|
||||
private void OnMapChanged(MapChangedEvent ev)
|
||||
@@ -84,8 +86,6 @@ public sealed partial class ExplosionSystem
|
||||
Stopwatch.Restart();
|
||||
var x = Stopwatch.Elapsed.TotalMilliseconds;
|
||||
|
||||
var availableTime = MaxProcessingTime;
|
||||
|
||||
var tilesRemaining = TilesPerTick;
|
||||
while (tilesRemaining > 0 && MaxProcessingTime > Stopwatch.Elapsed.TotalMilliseconds)
|
||||
{
|
||||
@@ -369,64 +369,73 @@ public sealed partial class ExplosionSystem
|
||||
return SpaceQueryCallback(ref state, in uid);
|
||||
}
|
||||
|
||||
private DamageSpecifier GetDamage(EntityUid uid,
|
||||
string id, DamageSpecifier damage)
|
||||
{
|
||||
// TODO Explosion Performance
|
||||
// Cache this? I.e., instead of raising an event, check for a component?
|
||||
var resistanceEv = new GetExplosionResistanceEvent(id);
|
||||
RaiseLocalEvent(uid, ref resistanceEv);
|
||||
resistanceEv.DamageCoefficient = Math.Max(0, resistanceEv.DamageCoefficient);
|
||||
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||
if (resistanceEv.DamageCoefficient != 1)
|
||||
damage *= resistanceEv.DamageCoefficient;
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
private void GetEntitiesToDamage(EntityUid uid, DamageSpecifier originalDamage, string prototype)
|
||||
{
|
||||
_toDamage.Clear();
|
||||
_toDamage.Add((uid, GetDamage(uid, prototype, originalDamage)));
|
||||
|
||||
for (var i = 0; i < _toDamage.Count; i++)
|
||||
{
|
||||
var (ent, damage) = _toDamage[i];
|
||||
_containedEntities.Clear();
|
||||
var ev = new BeforeExplodeEvent(damage, prototype, _containedEntities);
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
|
||||
if (_containedEntities.Count == 0)
|
||||
continue;
|
||||
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||
if (ev.DamageCoefficient != 1)
|
||||
damage *= ev.DamageCoefficient;
|
||||
|
||||
_toDamage.EnsureCapacity(_toDamage.Count + _containedEntities.Count);
|
||||
foreach (var contained in _containedEntities)
|
||||
{
|
||||
var newDamage = GetDamage(contained, prototype, damage);
|
||||
_toDamage.Add((contained, newDamage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function actually applies the explosion affects to an entity.
|
||||
/// </summary>
|
||||
private void ProcessEntity(
|
||||
EntityUid uid,
|
||||
MapCoordinates epicenter,
|
||||
DamageSpecifier? damage,
|
||||
DamageSpecifier? originalDamage,
|
||||
float throwForce,
|
||||
string id,
|
||||
TransformComponent? xform)
|
||||
{
|
||||
// damage
|
||||
if (damage != null && _damageQuery.TryGetComponent(uid, out var damageable))
|
||||
if (originalDamage != null)
|
||||
{
|
||||
// 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);
|
||||
|
||||
ev.DamageCoefficient = Math.Max(0, ev.DamageCoefficient);
|
||||
|
||||
// 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))
|
||||
GetEntitiesToDamage(uid, originalDamage, id);
|
||||
foreach (var (entity, damage) in _toDamage)
|
||||
{
|
||||
_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);
|
||||
}
|
||||
|
||||
// if it's a container, try to damage all its contents
|
||||
if (_containersQuery.TryGetComponent(uid, out var containers))
|
||||
{
|
||||
foreach (var container in containers.Containers.Values)
|
||||
{
|
||||
foreach (var ent in container.ContainedEntities)
|
||||
{
|
||||
// setting throw force to 0 to prevent offset items inside containers
|
||||
ProcessEntity(ent, epicenter, damage, 0f, id, _transformQuery.GetComponent(uid));
|
||||
}
|
||||
// TODO EXPLOSIONS turn explosions into entities, and pass the the entity in as the damage origin.
|
||||
_damageableSystem.TryChangeDamage(entity, damage, ignoreResistances: true);
|
||||
}
|
||||
}
|
||||
|
||||
// throw
|
||||
if (xform != null // null implies anchored
|
||||
if (xform != null // null implies anchored or in a container
|
||||
&& !xform.Anchored
|
||||
&& throwForce > 0
|
||||
&& !EntityManager.IsQueuedForDeletion(uid)
|
||||
@@ -442,10 +451,6 @@ public sealed partial class ExplosionSystem
|
||||
_projectileQuery,
|
||||
throwForce);
|
||||
}
|
||||
|
||||
// TODO EXPLOSION puddle / flammable ignite?
|
||||
|
||||
// TODO EXPLOSION deaf/ear damage? other explosion effects?
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -845,4 +850,3 @@ sealed class Explosion
|
||||
_tileUpdateDict.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user