Remove most IEntity usages from explosions (#5240)

* Remove most IEntity usages from Destructible and Explosions

* Perform a minute amount of cleanup

* Fix build
This commit is contained in:
Javier Guardia Fernández
2021-11-09 21:24:35 +01:00
committed by GitHub
parent 3a4186f6f6
commit 42aaba9a5d
28 changed files with 294 additions and 277 deletions

View File

@@ -2,12 +2,12 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.Server.AME.Components; using Content.Server.AME.Components;
using Content.Server.Explosion; using Content.Server.Explosion.EntitySystems;
using Content.Server.NodeContainer.NodeGroups; using Content.Server.NodeContainer.NodeGroups;
using Content.Server.NodeContainer.Nodes; using Content.Server.NodeContainer.Nodes;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
@@ -177,7 +177,7 @@ namespace Content.Server.AME
intensity = Math.Min(intensity, 8); intensity = Math.Min(intensity, 8);
epicenter.Owner.SpawnExplosion(intensity / 2, intensity, intensity * 2, intensity * 3); EntitySystem.Get<ExplosionSystem>().SpawnExplosion(epicenter.Owner.Uid, intensity / 2, intensity, intensity * 2, intensity * 3);
} }
} }
} }

View File

@@ -8,7 +8,7 @@ using Content.Server.Chemistry.EntitySystems;
using Content.Server.Configurable; using Content.Server.Configurable;
using Content.Server.Disposal.Tube.Components; using Content.Server.Disposal.Tube.Components;
using Content.Server.EUI; using Content.Server.EUI;
using Content.Server.Explosion; using Content.Server.Explosion.EntitySystems;
using Content.Server.Ghost.Roles; using Content.Server.Ghost.Roles;
using Content.Server.Inventory.Components; using Content.Server.Inventory.Components;
using Content.Server.Mind.Commands; using Content.Server.Mind.Commands;
@@ -40,6 +40,7 @@ namespace Content.Server.Administration
[Dependency] private readonly IAdminManager _adminManager = default!; [Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly EuiManager _euiManager = default!; [Dependency] private readonly EuiManager _euiManager = default!;
[Dependency] private readonly ExplosionSystem _explosions = default!;
[Dependency] private readonly GhostRoleSystem _ghostRoleSystem = default!; [Dependency] private readonly GhostRoleSystem _ghostRoleSystem = default!;
private readonly Dictionary<IPlayerSession, EditSolutionsEui> _openSolutionUis = new(); private readonly Dictionary<IPlayerSession, EditSolutionsEui> _openSolutionUis = new();
@@ -118,7 +119,7 @@ namespace Content.Server.Administration
verb.Act = () => verb.Act = () =>
{ {
var coords = args.Target.Transform.Coordinates; var coords = args.Target.Transform.Coordinates;
Timer.Spawn(_gameTiming.TickPeriod, () => ExplosionHelper.SpawnExplosion(coords, 0, 1, 2, 1), CancellationToken.None); Timer.Spawn(_gameTiming.TickPeriod, () => _explosions.SpawnExplosion(coords, 0, 1, 2, 1), CancellationToken.None);
if (args.Target.TryGetComponent(out SharedBodyComponent? body)) if (args.Target.TryGetComponent(out SharedBodyComponent? body))
{ {
body.Gib(); body.Gib();

View File

@@ -1,10 +1,10 @@
using Content.Server.Explosion; using Content.Server.Explosion.EntitySystems;
using Content.Shared.Administration; using Content.Shared.Administration;
using Robust.Server.Player; using Robust.Server.Player;
using Robust.Shared.Console; using Robust.Shared.Console;
using Robust.Shared.GameObjects;
using Robust.Shared.Map; using Robust.Shared.Map;
namespace Content.Server.Administration.Commands namespace Content.Server.Administration.Commands
{ {
[AdminCommand(AdminFlags.Fun)] [AdminCommand(AdminFlags.Fun)]
@@ -35,7 +35,7 @@ namespace Content.Server.Administration.Commands
var mapTransform = player.AttachedEntity.Transform.GetMapTransform(); var mapTransform = player.AttachedEntity.Transform.GetMapTransform();
var coords = new EntityCoordinates(mapTransform.Owner.Uid, x, y); var coords = new EntityCoordinates(mapTransform.Owner.Uid, x, y);
ExplosionHelper.SpawnExplosion(coords, dev, hvy, lgh, fla); EntitySystem.Get<ExplosionSystem>().SpawnExplosion(coords, dev, hvy, lgh, fla);
} }
} }
} }

View File

@@ -1,9 +1,7 @@
using System; using System;
using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.EntitySystems;
using Content.Server.Body.Respiratory; using Content.Server.Body.Respiratory;
using Content.Server.Explosion; using Content.Server.Explosion.EntitySystems;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.Nodes;
using Content.Server.UserInterface; using Content.Server.UserInterface;
using Content.Shared.ActionBlocker; using Content.Shared.ActionBlocker;
using Content.Shared.Actions; using Content.Shared.Actions;
@@ -12,7 +10,6 @@ using Content.Shared.Actions.Components;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.Atmos.Components; using Content.Shared.Atmos.Components;
using Content.Shared.Audio; using Content.Shared.Audio;
using Content.Shared.DragDrop;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Sound; using Content.Shared.Sound;
@@ -271,7 +268,7 @@ namespace Content.Server.Atmos.Components
range = MaxExplosionRange; range = MaxExplosionRange;
} }
Owner.SpawnExplosion((int) (range * 0.25f), (int) (range * 0.5f), (int) (range * 1.5f), 1); EntitySystem.Get<ExplosionSystem>().SpawnExplosion(OwnerUid, (int) (range * 0.25f), (int) (range * 0.5f), (int) (range * 1.5f), 1);
Owner.QueueDelete(); Owner.QueueDelete();
return; return;

View File

@@ -1,7 +1,6 @@
using System; using System;
using Content.Server.Chemistry.Components;
using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.Chemistry.Components.SolutionManager;
using Content.Server.Explosion; using Content.Server.Explosion.EntitySystems;
using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Reaction;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -50,7 +49,7 @@ namespace Content.Server.Chemistry.ReactionEffects
var finalHeavyImpactRange = (int)MathF.Round(_heavyImpactRange * floatIntensity); var finalHeavyImpactRange = (int)MathF.Round(_heavyImpactRange * floatIntensity);
var finalLightImpactRange = (int)MathF.Round(_lightImpactRange * floatIntensity); var finalLightImpactRange = (int)MathF.Round(_lightImpactRange * floatIntensity);
var finalFlashRange = (int)MathF.Round(_flashRange * floatIntensity); var finalFlashRange = (int)MathF.Round(_flashRange * floatIntensity);
solutionEntity.SpawnExplosion(finalDevastationRange, EntitySystem.Get<ExplosionSystem>().SpawnExplosion(solutionEntity, finalDevastationRange,
finalHeavyImpactRange, finalLightImpactRange, finalFlashRange); finalHeavyImpactRange, finalLightImpactRange, finalFlashRange);
} }
} }

View File

@@ -1,4 +1,6 @@
using Content.Server.Construction;
using Content.Server.Destructible.Thresholds; using Content.Server.Destructible.Thresholds;
using Content.Server.Explosion.EntitySystems;
using Content.Shared.Acts; using Content.Shared.Acts;
using Content.Shared.Damage; using Content.Shared.Damage;
using JetBrains.Annotations; using JetBrains.Annotations;
@@ -13,8 +15,12 @@ namespace Content.Server.Destructible
public class DestructibleSystem : EntitySystem public class DestructibleSystem : EntitySystem
{ {
[Dependency] public readonly IRobustRandom Random = default!; [Dependency] public readonly IRobustRandom Random = default!;
[Dependency] public readonly AudioSystem AudioSystem = default!; public new IEntityManager EntityManager => base.EntityManager;
[Dependency] public readonly ActSystem ActSystem = default!; [Dependency] public readonly ActSystem ActSystem = default!;
[Dependency] public readonly AudioSystem AudioSystem = default!;
[Dependency] public readonly ConstructionSystem ConstructionSystem = default!;
[Dependency] public readonly ExplosionSystem ExplosionSystem = default!;
public override void Initialize() public override void Initialize()
{ {

View File

@@ -1,5 +1,4 @@
using System; using System;
using Content.Server.Construction;
using Content.Server.Construction.Components; using Content.Server.Construction.Components;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;
@@ -13,12 +12,12 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
[DataField("node")] [DataField("node")]
public string Node { get; private set; } = string.Empty; public string Node { get; private set; } = string.Empty;
public void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager) public void Execute(EntityUid owner, DestructibleSystem system)
{ {
if (string.IsNullOrEmpty(Node) || !entityManager.TryGetComponent(owner, out ConstructionComponent? construction)) if (string.IsNullOrEmpty(Node) || !system.EntityManager.TryGetComponent(owner, out ConstructionComponent? construction))
return; return;
EntitySystem.Get<ConstructionSystem>().ChangeNode(owner, null, Node, true, construction); system.ConstructionSystem.ChangeNode(owner, null, Node, true, construction);
} }
} }
} }

View File

@@ -21,7 +21,7 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
return (Acts & act) != 0; return (Acts & act) != 0;
} }
public void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager) public void Execute(EntityUid owner, DestructibleSystem system)
{ {
if (HasAct(ThresholdActs.Breakage)) if (HasAct(ThresholdActs.Breakage))
{ {

View File

@@ -1,5 +1,4 @@
using System; using System;
using Content.Server.Atmos.Piping.Unary.Components;
using Content.Server.Atmos.Piping.Unary.EntitySystems; using Content.Server.Atmos.Piping.Unary.EntitySystems;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;
@@ -8,13 +7,11 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
{ {
[Serializable] [Serializable]
[DataDefinition] [DataDefinition]
public class DumpCanisterBehavior: IThresholdBehavior public class DumpCanisterBehavior : IThresholdBehavior
{ {
public void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager) public void Execute(EntityUid owner, DestructibleSystem system)
{ {
var gasCanisterSystem = entityManager.EntitySysManager.GetEntitySystem<GasCanisterSystem>(); system.EntityManager.EntitySysManager.GetEntitySystem<GasCanisterSystem>().PurgeContents(owner);
gasCanisterSystem.PurgeContents(owner);
} }
} }
} }

View File

@@ -10,14 +10,14 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
[DataDefinition] [DataDefinition]
public class EmptyAllContainersBehaviour : IThresholdBehavior public class EmptyAllContainersBehaviour : IThresholdBehavior
{ {
public void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager) public void Execute(EntityUid owner, DestructibleSystem system)
{ {
if (!entityManager.TryGetComponent<ContainerManagerComponent>(owner, out var containerManager)) if (!system.EntityManager.TryGetComponent<ContainerManagerComponent>(owner, out var containerManager))
return; return;
foreach (var container in containerManager.GetAllContainers()) foreach (var container in containerManager.GetAllContainers())
{ {
container.EmptyContainer(true, entityManager.GetComponent<TransformComponent>(owner).Coordinates); container.EmptyContainer(true, system.EntityManager.GetComponent<TransformComponent>(owner).Coordinates);
} }
} }
} }

View File

@@ -1,4 +1,3 @@
using Content.Server.Explosion;
using Content.Server.Explosion.Components; using Content.Server.Explosion.Components;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -13,9 +12,9 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
[DataDefinition] [DataDefinition]
public class ExplodeBehavior : IThresholdBehavior public class ExplodeBehavior : IThresholdBehavior
{ {
public void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager) public void Execute(EntityUid owner, DestructibleSystem system)
{ {
owner.SpawnExplosion(entityManager:entityManager); system.ExplosionSystem.SpawnExplosion(owner);
} }
} }
} }

View File

@@ -11,9 +11,9 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
{ {
[DataField("recursive")] private bool _recursive = true; [DataField("recursive")] private bool _recursive = true;
public void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager) public void Execute(EntityUid owner, DestructibleSystem system)
{ {
if (entityManager.TryGetComponent(owner, out SharedBodyComponent? body)) if (system.EntityManager.TryGetComponent(owner, out SharedBodyComponent? body))
{ {
body.Gib(_recursive); body.Gib(_recursive);
} }

View File

@@ -12,7 +12,6 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
/// An instance of <see cref="DestructibleSystem"/> to pull dependencies /// An instance of <see cref="DestructibleSystem"/> to pull dependencies
/// and other systems from. /// and other systems from.
/// </param> /// </param>
/// <param name="entityManager"></param> void Execute(EntityUid owner, DestructibleSystem system);
void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager);
} }
} }

View File

@@ -17,9 +17,9 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
/// </summary> /// </summary>
[DataField("sound", required: true)] public SoundSpecifier Sound { get; set; } = default!; [DataField("sound", required: true)] public SoundSpecifier Sound { get; set; } = default!;
public void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager) public void Execute(EntityUid owner, DestructibleSystem system)
{ {
var pos = entityManager.GetComponent<TransformComponent>(owner).Coordinates; var pos = system.EntityManager.GetComponent<TransformComponent>(owner).Coordinates;
SoundSystem.Play(Filter.Pvs(pos), Sound.GetSound(), pos, AudioHelpers.WithVariation(0.125f)); SoundSystem.Play(Filter.Pvs(pos), Sound.GetSound(), pos, AudioHelpers.WithVariation(0.125f));
} }
} }

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using Content.Server.Stack; using Content.Server.Stack;
using Content.Shared.Prototypes; using Content.Shared.Prototypes;
using Content.Shared.Random.Helpers; using Content.Shared.Random.Helpers;
using Content.Shared.Stacks;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;
@@ -19,9 +18,9 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
[DataField("spawn")] [DataField("spawn")]
public Dictionary<string, MinMax> Spawn { get; set; } = new(); public Dictionary<string, MinMax> Spawn { get; set; } = new();
public void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager) public void Execute(EntityUid owner, DestructibleSystem system)
{ {
var position = entityManager.GetComponent<TransformComponent>(owner).MapPosition; var position = system.EntityManager.GetComponent<TransformComponent>(owner).MapPosition;
foreach (var (entityId, minMax) in Spawn) foreach (var (entityId, minMax) in Spawn)
{ {
@@ -33,7 +32,7 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
if (EntityPrototypeHelpers.HasComponent<StackComponent>(entityId)) if (EntityPrototypeHelpers.HasComponent<StackComponent>(entityId))
{ {
var spawned = entityManager.SpawnEntity(entityId, position); var spawned = system.EntityManager.SpawnEntity(entityId, position);
var stack = spawned.GetComponent<StackComponent>(); var stack = spawned.GetComponent<StackComponent>();
EntitySystem.Get<StackSystem>().SetCount(spawned.Uid, count, stack); EntitySystem.Get<StackSystem>().SetCount(spawned.Uid, count, stack);
spawned.RandomOffset(0.5f); spawned.RandomOffset(0.5f);
@@ -42,7 +41,7 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
{ {
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
var spawned = entityManager.SpawnEntity(entityId, position); var spawned = system.EntityManager.SpawnEntity(entityId, position);
spawned.RandomOffset(0.5f); spawned.RandomOffset(0.5f);
} }
} }

View File

@@ -21,13 +21,13 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
/// <param name="owner">Entity on which behavior is executed</param> /// <param name="owner">Entity on which behavior is executed</param>
/// <param name="system">system calling the behavior</param> /// <param name="system">system calling the behavior</param>
/// <param name="entityManager"></param> /// <param name="entityManager"></param>
public void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager) public void Execute(EntityUid owner, DestructibleSystem system)
{ {
var solutionContainerSystem = EntitySystem.Get<SolutionContainerSystem>(); var solutionContainerSystem = EntitySystem.Get<SolutionContainerSystem>();
var coordinates = entityManager.GetComponent<TransformComponent>(owner).Coordinates; var coordinates = system.EntityManager.GetComponent<TransformComponent>(owner).Coordinates;
if (entityManager.TryGetComponent(owner, out SpillableComponent? spillableComponent) && if (system.EntityManager.TryGetComponent(owner, out SpillableComponent? spillableComponent) &&
solutionContainerSystem.TryGetSolution(owner, spillableComponent.SolutionName, solutionContainerSystem.TryGetSolution(owner, spillableComponent.SolutionName,
out var compSolution)) out var compSolution))
{ {

View File

@@ -94,7 +94,7 @@ namespace Content.Server.Destructible.Thresholds
if (!entityManager.EntityExists(owner)) if (!entityManager.EntityExists(owner))
return; return;
behavior.Execute(owner, system, entityManager); behavior.Execute(owner, system);
} }
} }
} }

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Flash.Components; using Content.Server.Flash.Components;
using Content.Server.Throwing; using Content.Server.Throwing;
using Content.Shared.Explosion; using Content.Shared.Explosion;

View File

@@ -1,3 +1,4 @@
using Content.Server.Explosion.EntitySystems;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
namespace Content.Server.Explosion.Components namespace Content.Server.Explosion.Components

View File

@@ -15,7 +15,7 @@ namespace Content.Server.Explosion.Components
return; return;
var sourceLocation = eventArgs.Source; var sourceLocation = eventArgs.Source;
var targetLocation = eventArgs.Target.Transform.Coordinates; var targetLocation = Owner.EntityManager.GetComponent<TransformComponent>(eventArgs.Target).Coordinates;
if (sourceLocation.Equals(targetLocation)) return; if (sourceLocation.Equals(targetLocation)) return;
@@ -27,7 +27,7 @@ namespace Content.Server.Explosion.Components
ExplosionSeverity.Light => 20, ExplosionSeverity.Light => 20,
_ => 0, _ => 0,
}; };
Owner.TryThrow(direction, throwForce); Owner.TryThrow(direction, throwForce);
} }
} }

View File

@@ -1,4 +1,5 @@
using System; using System;
using Content.Server.Explosion.EntitySystems;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Trigger; using Content.Shared.Trigger;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;

View File

@@ -1,3 +1,4 @@
using Content.Server.Explosion.EntitySystems;
using Content.Shared.Sound; using Content.Shared.Sound;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;

View File

@@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.Server.Camera; using Content.Server.Camera;
@@ -21,9 +21,9 @@ using Robust.Shared.Player;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Timing; using Robust.Shared.Timing;
namespace Content.Server.Explosion namespace Content.Server.Explosion.EntitySystems
{ {
public static class ExplosionHelper public class ExplosionSystem : EntitySystem
{ {
/// <summary> /// <summary>
/// Distance used for camera shake when distance from explosion is (0.0, 0.0). /// Distance used for camera shake when distance from explosion is (0.0, 0.0).
@@ -34,19 +34,35 @@ namespace Content.Server.Explosion
/// <summary> /// <summary>
/// Chance of a tile breaking if the severity is Light and Heavy /// Chance of a tile breaking if the severity is Light and Heavy
/// </summary> /// </summary>
private static readonly float LightBreakChance = 0.3f; private const float LightBreakChance = 0.3f;
private static readonly float HeavyBreakChance = 0.8f; private const float HeavyBreakChance = 0.8f;
private static SoundSpecifier _explosionSound = new SoundCollectionSpecifier("explosion");
private static bool IgnoreExplosivePassable(IEntity e) => e.HasTag("ExplosivePassable"); // TODO move this to the component
private static readonly SoundSpecifier ExplosionSound = new SoundCollectionSpecifier("explosion");
private static ExplosionSeverity CalculateSeverity(float distance, float devastationRange, float heaveyRange) [Dependency] private readonly IEntityLookup _entityLookup = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IMapManager _maps = default!;
[Dependency] private readonly IPlayerManager _players = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ITileDefinitionManager _tiles = default!;
[Dependency] private readonly ActSystem _acts = default!;
[Dependency] private readonly EffectSystem _effects = default!;
[Dependency] private readonly TriggerSystem _triggers = default!;
private bool IgnoreExplosivePassable(IEntity e)
{
return e.HasTag("ExplosivePassable");
}
private ExplosionSeverity CalculateSeverity(float distance, float devastationRange, float heavyRange)
{ {
if (distance < devastationRange) if (distance < devastationRange)
{ {
return ExplosionSeverity.Destruction; return ExplosionSeverity.Destruction;
} }
else if (distance < heaveyRange) else if (distance < heavyRange)
{ {
return ExplosionSeverity.Heavy; return ExplosionSeverity.Heavy;
} }
@@ -56,174 +72,10 @@ namespace Content.Server.Explosion
} }
} }
/// <summary> private void CameraShakeInRange(EntityCoordinates epicenter, float maxRange)
/// Damage entities inside the range. The damage depends on a discrete
/// damage bracket [light, heavy, devastation] and the distance from the epicenter
/// </summary>
/// <returns>
/// A dictionary of coordinates relative to the parents of every grid of entities that survived the explosion,
/// have an airtight component and are currently blocking air. Like a wall.
/// </returns>
private static void DamageEntitiesInRange(EntityCoordinates epicenter, Box2 boundingBox,
float devastationRange,
float heaveyRange,
float maxRange,
MapId mapId)
{ {
var entityManager = IoCManager.Resolve<IEntityManager>(); var players = _players.GetPlayersInRange(epicenter, (int) Math.Ceiling(maxRange));
var exAct = EntitySystem.Get<ActSystem>();
var entitiesInRange = IoCManager.Resolve<IEntityLookup>().GetEntitiesInRange(mapId, boundingBox, 0).ToList();
var impassableEntities = new List<Tuple<IEntity, float>>();
var nonImpassableEntities = new List<Tuple<IEntity, float>>();
// TODO: Given this seems to rely on physics it should just query directly like everything else.
// The entities are paired with their distance to the epicenter
// and splitted into two lists based on if they are Impassable or not
foreach (var entity in entitiesInRange)
{
if (entity.Deleted || entity.IsInContainer())
{
continue;
}
if (!entity.Transform.Coordinates.TryDistance(entityManager, epicenter, out var distance) || distance > maxRange)
{
continue;
}
if (!entity.TryGetComponent(out PhysicsComponent? body) || body.Fixtures.Count < 1)
{
continue;
}
if ((body.CollisionLayer & (int) CollisionGroup.Impassable) != 0)
{
impassableEntities.Add(Tuple.Create(entity, distance));
}
else
{
nonImpassableEntities.Add(Tuple.Create(entity, distance));
}
}
// The Impassable entities are sorted in descending order
// Entities closer to the epicenter are first
impassableEntities.Sort((x, y) => x.Item2.CompareTo(y.Item2));
// Impassable entities are handled first. If they are damaged enough, they are destroyed and they may
// be able to spawn a new entity. I.e Wall -> Girder.
// Girder has a tag ExplosivePassable, and the predicate make it so the entities with this tag are ignored
var epicenterMapPos = epicenter.ToMap(entityManager);
foreach (var (entity, distance) in impassableEntities)
{
if (!entity.InRangeUnobstructed(epicenterMapPos, maxRange, ignoreInsideBlocker: true, predicate: IgnoreExplosivePassable))
{
continue;
}
exAct.HandleExplosion(epicenter, entity, CalculateSeverity(distance, devastationRange, heaveyRange));
}
// Impassable entities were handled first so NonImpassable entities have a bigger chance to get hit. As now
// there are probably more ExplosivePassable entities around
foreach (var (entity, distance) in nonImpassableEntities)
{
if (!entity.InRangeUnobstructed(epicenterMapPos, maxRange, ignoreInsideBlocker: true, predicate: IgnoreExplosivePassable))
{
continue;
}
exAct.HandleExplosion(epicenter, entity, CalculateSeverity(distance, devastationRange, heaveyRange));
}
}
/// <summary>
/// Damage tiles inside the range. The type of tile can change depending on a discrete
/// damage bracket [light, heavy, devastation], the distance from the epicenter and
/// a probabilty bracket [<see cref="LightBreakChance"/>, <see cref="HeavyBreakChance"/>, 1.0].
/// </summary>
///
private static void DamageTilesInRange(EntityCoordinates epicenter,
GridId gridId,
Box2 boundingBox,
float devastationRange,
float heaveyRange,
float maxRange)
{
var mapManager = IoCManager.Resolve<IMapManager>();
if (!mapManager.TryGetGrid(gridId, out var mapGrid))
{
return;
}
var entityManager = IoCManager.Resolve<IEntityManager>();
if (!entityManager.TryGetEntity(mapGrid.GridEntityId, out var grid))
{
return;
}
var robustRandom = IoCManager.Resolve<IRobustRandom>();
var tileDefinitionManager = IoCManager.Resolve<ITileDefinitionManager>();
var tilesInGridAndCircle = mapGrid.GetTilesIntersecting(boundingBox);
var epicenterMapPos = epicenter.ToMap(entityManager);
foreach (var tile in tilesInGridAndCircle)
{
var tileLoc = mapGrid.GridTileToLocal(tile.GridIndices);
if (!tileLoc.TryDistance(entityManager, epicenter, out var distance) || distance > maxRange)
{
continue;
}
if (tile.IsBlockedTurf(false))
{
continue;
}
if (!tileLoc.ToMap(entityManager).InRangeUnobstructed(epicenterMapPos, maxRange, ignoreInsideBlocker: false, predicate: IgnoreExplosivePassable))
{
continue;
}
var tileDef = (ContentTileDefinition) tileDefinitionManager[tile.Tile.TypeId];
var baseTurfs = tileDef.BaseTurfs;
if (baseTurfs.Count == 0)
{
continue;
}
var zeroTile = new Robust.Shared.Map.Tile(tileDefinitionManager[baseTurfs[0]].TileId);
var previousTile = new Robust.Shared.Map.Tile(tileDefinitionManager[baseTurfs[^1]].TileId);
var severity = CalculateSeverity(distance, devastationRange, heaveyRange);
switch (severity)
{
case ExplosionSeverity.Light:
if (!previousTile.IsEmpty && robustRandom.Prob(LightBreakChance))
{
mapGrid.SetTile(tileLoc, previousTile);
}
break;
case ExplosionSeverity.Heavy:
if (!previousTile.IsEmpty && robustRandom.Prob(HeavyBreakChance))
{
mapGrid.SetTile(tileLoc, previousTile);
}
break;
case ExplosionSeverity.Destruction:
mapGrid.SetTile(tileLoc, zeroTile);
break;
}
}
}
private static void CameraShakeInRange(EntityCoordinates epicenter, float maxRange)
{
var playerManager = IoCManager.Resolve<IPlayerManager>();
var players = playerManager.GetPlayersInRange(epicenter, (int) Math.Ceiling(maxRange));
foreach (var player in players) foreach (var player in players)
{ {
if (player.AttachedEntity == null || !player.AttachedEntity.TryGetComponent(out CameraRecoilComponent? recoil)) if (player.AttachedEntity == null || !player.AttachedEntity.TryGetComponent(out CameraRecoilComponent? recoil))
@@ -231,10 +83,8 @@ namespace Content.Server.Explosion
continue; continue;
} }
var entityManager = IoCManager.Resolve<IEntityManager>();
var playerPos = player.AttachedEntity.Transform.WorldPosition; var playerPos = player.AttachedEntity.Transform.WorldPosition;
var delta = epicenter.ToMapPos(entityManager) - playerPos; var delta = epicenter.ToMapPos(EntityManager) - playerPos;
//Change if zero. Will result in a NaN later breaking camera shake if not changed //Change if zero. Will result in a NaN later breaking camera shake if not changed
if (delta.EqualsApprox((0.0f, 0.0f))) if (delta.EqualsApprox((0.0f, 0.0f)))
@@ -250,83 +100,250 @@ namespace Content.Server.Explosion
} }
} }
private static void FlashInRange(EntityCoordinates epicenter, float flashrange) /// <summary>
/// Damage entities inside the range. The damage depends on a discrete
/// damage bracket [light, heavy, devastation] and the distance from the epicenter
/// </summary>
/// <returns>
/// A dictionary of coordinates relative to the parents of every grid of entities that survived the explosion,
/// have an airtight component and are currently blocking air. Like a wall.
/// </returns>
private void DamageEntitiesInRange(
EntityCoordinates epicenter,
Box2 boundingBox,
float devastationRange,
float heavyRange,
float maxRange,
MapId mapId)
{ {
if (flashrange > 0) var entitiesInRange = _entityLookup.GetEntitiesInRange(mapId, boundingBox, 0).ToList();
var impassableEntities = new List<(IEntity, float)>();
var nonImpassableEntities = new List<(IEntity, float)>();
// TODO: Given this seems to rely on physics it should just query directly like everything else.
// The entities are paired with their distance to the epicenter
// and splitted into two lists based on if they are Impassable or not
foreach (var entity in entitiesInRange)
{ {
var entitySystemManager = IoCManager.Resolve<IEntitySystemManager>(); if (entity.Deleted || entity.IsInContainer())
var time = IoCManager.Resolve<IGameTiming>().CurTime; {
continue;
}
if (!entity.Transform.Coordinates.TryDistance(EntityManager, epicenter, out var distance) ||
distance > maxRange)
{
continue;
}
if (!entity.TryGetComponent(out PhysicsComponent? body) || body.Fixtures.Count < 1)
{
continue;
}
if ((body.CollisionLayer & (int) CollisionGroup.Impassable) != 0)
{
impassableEntities.Add((entity, distance));
}
else
{
nonImpassableEntities.Add((entity, distance));
}
}
// The Impassable entities are sorted in descending order
// Entities closer to the epicenter are first
impassableEntities.Sort((x, y) => x.Item2.CompareTo(y.Item2));
// Impassable entities are handled first. If they are damaged enough, they are destroyed and they may
// be able to spawn a new entity. I.e Wall -> Girder.
// Girder has a tag ExplosivePassable, and the predicate make it so the entities with this tag are ignored
var epicenterMapPos = epicenter.ToMap(EntityManager);
foreach (var (entity, distance) in impassableEntities)
{
if (!entity.InRangeUnobstructed(epicenterMapPos, maxRange, ignoreInsideBlocker: true, predicate: IgnoreExplosivePassable))
{
continue;
}
_acts.HandleExplosion(epicenter, entity.Uid, CalculateSeverity(distance, devastationRange, heavyRange));
}
// Impassable entities were handled first so NonImpassable entities have a bigger chance to get hit. As now
// there are probably more ExplosivePassable entities around
foreach (var (entity, distance) in nonImpassableEntities)
{
if (!entity.InRangeUnobstructed(epicenterMapPos, maxRange, ignoreInsideBlocker: true, predicate: IgnoreExplosivePassable))
{
continue;
}
_acts.HandleExplosion(epicenter, entity.Uid, CalculateSeverity(distance, devastationRange, heavyRange));
}
}
/// <summary>
/// Damage tiles inside the range. The type of tile can change depending on a discrete
/// damage bracket [light, heavy, devastation], the distance from the epicenter and
/// a probability bracket [<see cref="LightBreakChance"/>, <see cref="HeavyBreakChance"/>, 1.0].
/// </summary>
///
private void DamageTilesInRange(EntityCoordinates epicenter,
GridId gridId,
Box2 boundingBox,
float devastationRange,
float heaveyRange,
float maxRange)
{
if (!_maps.TryGetGrid(gridId, out var mapGrid))
{
return;
}
if (!EntityManager.EntityExists(mapGrid.GridEntityId))
{
return;
}
var tilesInGridAndCircle = mapGrid.GetTilesIntersecting(boundingBox);
var epicenterMapPos = epicenter.ToMap(EntityManager);
foreach (var tile in tilesInGridAndCircle)
{
var tileLoc = mapGrid.GridTileToLocal(tile.GridIndices);
if (!tileLoc.TryDistance(EntityManager, epicenter, out var distance) ||
distance > maxRange)
{
continue;
}
if (tile.IsBlockedTurf(false))
{
continue;
}
if (!tileLoc.ToMap(EntityManager).InRangeUnobstructed(epicenterMapPos, maxRange, ignoreInsideBlocker: false, predicate: IgnoreExplosivePassable))
{
continue;
}
var tileDef = (ContentTileDefinition) _tiles[tile.Tile.TypeId];
var baseTurfs = tileDef.BaseTurfs;
if (baseTurfs.Count == 0)
{
continue;
}
var zeroTile = new Tile(_tiles[baseTurfs[0]].TileId);
var previousTile = new Tile(_tiles[baseTurfs[^1]].TileId);
var severity = CalculateSeverity(distance, devastationRange, heaveyRange);
switch (severity)
{
case ExplosionSeverity.Light:
if (!previousTile.IsEmpty && _random.Prob(LightBreakChance))
{
mapGrid.SetTile(tileLoc, previousTile);
}
break;
case ExplosionSeverity.Heavy:
if (!previousTile.IsEmpty && _random.Prob(HeavyBreakChance))
{
mapGrid.SetTile(tileLoc, previousTile);
}
break;
case ExplosionSeverity.Destruction:
mapGrid.SetTile(tileLoc, zeroTile);
break;
}
}
}
private void FlashInRange(EntityCoordinates epicenter, float flashRange)
{
if (flashRange > 0)
{
var time = _timing.CurTime;
var message = new EffectSystemMessage var message = new EffectSystemMessage
{ {
EffectSprite = "Effects/explosion.rsi", EffectSprite = "Effects/explosion.rsi",
RsiState = "explosionfast", RsiState = "explosionfast",
Born = time, Born = time,
DeathTime = time + TimeSpan.FromSeconds(5), DeathTime = time + TimeSpan.FromSeconds(5),
Size = new Vector2(flashrange / 2, flashrange / 2), Size = new Vector2(flashRange / 2, flashRange / 2),
Coordinates = epicenter, Coordinates = epicenter,
Rotation = 0f, Rotation = 0f,
ColorDelta = new Vector4(0, 0, 0, -1500f), ColorDelta = new Vector4(0, 0, 0, -1500f),
Color = Vector4.Multiply(new Vector4(255, 255, 255, 750), 0.5f), Color = Vector4.Multiply(new Vector4(255, 255, 255, 750), 0.5f),
Shaded = false Shaded = false
}; };
entitySystemManager.GetEntitySystem<EffectSystem>().CreateParticle(message);
_effects.CreateParticle(message);
} }
} }
// TODO: remove this shit public void SpawnExplosion(
public static void SpawnExplosion(this EntityUid uid, int devastationRange = 0, int heavyImpactRange = 0, EntityUid entity,
int lightImpactRange = 0, int flashRange = 0, IEntityManager? entityManager = null) int devastationRange = 0,
int heavyImpactRange = 0,
int lightImpactRange = 0,
int flashRange = 0,
ExplosiveComponent? explosive = null,
TransformComponent? transform = null)
{ {
entityManager ??= IoCManager.Resolve<IEntityManager>(); if (!Resolve(entity, ref transform))
SpawnExplosion(entityManager.GetEntity(uid), devastationRange, heavyImpactRange, lightImpactRange, flashRange);
}
public static void SpawnExplosion(this IEntity entity, int devastationRange = 0, int heavyImpactRange = 0,
int lightImpactRange = 0, int flashRange = 0)
{
// TODO: Need to refactor this stufferino
// If you want to directly set off the explosive
if (!entity.Deleted && entity.TryGetComponent(out ExplosiveComponent? explosive) && !explosive.Exploding)
{ {
EntitySystem.Get<TriggerSystem>().Explode(entity.Uid, explosive); return;
}
Resolve(entity, ref explosive, false);
if (explosive is { Exploding: false })
{
_triggers.Explode(entity, explosive);
} }
else else
{ {
while (entity.TryGetContainer(out var cont)) while (EntityManager.TryGetComponent(entity, out ContainerManagerComponent? container))
{ {
entity = cont.Owner; entity = container.OwnerUid;
} }
var epicenter = entity.Transform.Coordinates; if (!EntityManager.TryGetComponent(entity, out transform))
{
return;
}
var epicenter = transform.Coordinates;
SpawnExplosion(epicenter, devastationRange, heavyImpactRange, lightImpactRange, flashRange); SpawnExplosion(epicenter, devastationRange, heavyImpactRange, lightImpactRange, flashRange);
} }
} }
public static void SpawnExplosion(EntityCoordinates epicenter, int devastationRange = 0, public void SpawnExplosion(
int heavyImpactRange = 0, int lightImpactRange = 0, int flashRange = 0) EntityCoordinates epicenter,
int devastationRange = 0,
int heavyImpactRange = 0,
int lightImpactRange = 0,
int flashRange = 0)
{ {
var mapId = epicenter.GetMapId(IoCManager.Resolve<IEntityManager>()); var mapId = epicenter.GetMapId(EntityManager);
if (mapId == MapId.Nullspace) if (mapId == MapId.Nullspace)
{ {
return; return;
} }
var maxRange = MathHelper.Max(devastationRange, heavyImpactRange, lightImpactRange, 0); var maxRange = MathHelper.Max(devastationRange, heavyImpactRange, lightImpactRange, 0);
var epicenterMapPos = epicenter.ToMapPos(EntityManager);
var entityManager = IoCManager.Resolve<IEntityManager>();
var mapManager = IoCManager.Resolve<IMapManager>();
var epicenterMapPos = epicenter.ToMapPos(entityManager);
var boundingBox = new Box2(epicenterMapPos - new Vector2(maxRange, maxRange), var boundingBox = new Box2(epicenterMapPos - new Vector2(maxRange, maxRange),
epicenterMapPos + new Vector2(maxRange, maxRange)); epicenterMapPos + new Vector2(maxRange, maxRange));
SoundSystem.Play(Filter.Broadcast(), _explosionSound.GetSound(), epicenter); SoundSystem.Play(Filter.Broadcast(), ExplosionSound.GetSound(), epicenter);
DamageEntitiesInRange(epicenter, boundingBox, devastationRange, heavyImpactRange, maxRange, mapId); DamageEntitiesInRange(epicenter, boundingBox, devastationRange, heavyImpactRange, maxRange, mapId);
var mapGridsNear = mapManager.FindGridsIntersecting(mapId, boundingBox); var mapGridsNear = _maps.FindGridsIntersecting(mapId, boundingBox);
foreach (var gridId in mapGridsNear) foreach (var gridId in mapGridsNear)
{ {

View File

@@ -3,7 +3,6 @@ using Content.Server.Doors.Components;
using Content.Server.Explosion.Components; using Content.Server.Explosion.Components;
using Content.Server.Flash; using Content.Server.Flash;
using Content.Server.Flash.Components; using Content.Server.Flash.Components;
using Content.Shared.Acts;
using Content.Shared.Audio; using Content.Shared.Audio;
using Content.Shared.Doors; using Content.Shared.Doors;
using JetBrains.Annotations; using JetBrains.Annotations;
@@ -14,7 +13,7 @@ using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Timing; using Robust.Shared.Timing;
namespace Content.Server.Explosion namespace Content.Server.Explosion.EntitySystems
{ {
/// <summary> /// <summary>
/// Raised whenever something is Triggered on the entity. /// Raised whenever something is Triggered on the entity.
@@ -34,6 +33,7 @@ namespace Content.Server.Explosion
[UsedImplicitly] [UsedImplicitly]
public sealed class TriggerSystem : EntitySystem public sealed class TriggerSystem : EntitySystem
{ {
[Dependency] private readonly ExplosionSystem _explosions = default!;
[Dependency] private readonly FlashSystem _flashSystem = default!; [Dependency] private readonly FlashSystem _flashSystem = default!;
public override void Initialize() public override void Initialize()
@@ -65,7 +65,7 @@ namespace Content.Server.Explosion
} }
component.Exploding = true; component.Exploding = true;
component.Owner.SpawnExplosion(component.DevastationRange, component.HeavyImpactRange, component.LightImpactRange, component.FlashRange); _explosions.SpawnExplosion(uid, component.DevastationRange, component.HeavyImpactRange, component.LightImpactRange, component.FlashRange);
EntityManager.QueueDeleteEntity(uid); EntityManager.QueueDeleteEntity(uid);
} }
#endregion #endregion

View File

@@ -1,4 +1,4 @@
using Content.Server.Explosion; using Content.Server.Explosion.EntitySystems;
using Content.Server.MachineLinking.Components; using Content.Server.MachineLinking.Components;
using Content.Server.MachineLinking.Events; using Content.Server.MachineLinking.Events;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;

View File

@@ -1,5 +1,5 @@
using System.Linq; using System.Linq;
using Content.Server.Explosion; using Content.Server.Explosion.EntitySystems;
using Content.Server.Pointing.Components; using Content.Server.Pointing.Components;
using Content.Shared.MobState.Components; using Content.Shared.MobState.Components;
using Content.Shared.Pointing.Components; using Content.Shared.Pointing.Components;
@@ -22,6 +22,8 @@ namespace Content.Server.Pointing.EntitySystems
[Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ExplosionSystem _explosions = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
@@ -106,7 +108,7 @@ namespace Content.Server.Pointing.EntitySystems
return; return;
} }
component.Owner.SpawnExplosion(0, 2, 1, 1); _explosions.SpawnExplosion(uid, 0, 2, 1, 1);
SoundSystem.Play(Filter.Pvs(uid, entityManager: EntityManager), component.ExplosionSound.GetSound(), uid); SoundSystem.Play(Filter.Pvs(uid, entityManager: EntityManager), component.ExplosionSound.GetSound(), uid);
EntityManager.QueueDeleteEntity(uid); EntityManager.QueueDeleteEntity(uid);

View File

@@ -1,8 +1,6 @@
using System; using System;
using Content.Server.Chemistry.Components; using Content.Server.Explosion.EntitySystems;
using Content.Server.Explosion;
using Content.Server.Power.Components; using Content.Server.Power.Components;
using Content.Shared.Chemistry;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.PowerCell; using Content.Shared.PowerCell;
using Content.Shared.Rounding; using Content.Shared.Rounding;
@@ -75,7 +73,7 @@ namespace Content.Server.PowerCell.Components
var light = (int) Math.Ceiling(Math.Sqrt(CurrentCharge) / 30); var light = (int) Math.Ceiling(Math.Sqrt(CurrentCharge) / 30);
CurrentCharge = 0; CurrentCharge = 0;
Owner.SpawnExplosion(0, heavy, light, light*2); EntitySystem.Get<ExplosionSystem>().SpawnExplosion(OwnerUid, 0, heavy, light, light*2);
Owner.Delete(); Owner.Delete();
} }

View File

@@ -46,7 +46,7 @@ namespace Content.Shared.Acts
public class ExplosionEventArgs : EventArgs public class ExplosionEventArgs : EventArgs
{ {
public EntityCoordinates Source { get; set; } public EntityCoordinates Source { get; set; }
public IEntity Target { get; set; } = default!; public EntityUid Target { get; set; }
public ExplosionSeverity Severity { get; set; } public ExplosionSeverity Severity { get; set; }
} }
@@ -70,7 +70,7 @@ namespace Content.Shared.Acts
EntityManager.QueueDeleteEntity(owner); EntityManager.QueueDeleteEntity(owner);
} }
public void HandleExplosion(EntityCoordinates source, IEntity target, ExplosionSeverity severity) public void HandleExplosion(EntityCoordinates source, EntityUid target, ExplosionSeverity severity)
{ {
var eventArgs = new ExplosionEventArgs var eventArgs = new ExplosionEventArgs
{ {
@@ -78,7 +78,7 @@ namespace Content.Shared.Acts
Target = target, Target = target,
Severity = severity Severity = severity
}; };
var exActs = target.GetAllComponents<IExAct>().ToList(); var exActs = EntityManager.GetComponents<IExAct>(target).ToList();
foreach (var exAct in exActs) foreach (var exAct in exActs)
{ {