diff --git a/Content.Server/AME/AMENodeGroup.cs b/Content.Server/AME/AMENodeGroup.cs index 2f998742f9..b430b66a59 100644 --- a/Content.Server/AME/AMENodeGroup.cs +++ b/Content.Server/AME/AMENodeGroup.cs @@ -2,12 +2,12 @@ using System; using System.Collections.Generic; using System.Linq; using Content.Server.AME.Components; -using Content.Server.Explosion; +using Content.Server.Explosion.EntitySystems; using Content.Server.NodeContainer.NodeGroups; using Content.Server.NodeContainer.Nodes; +using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; -using Robust.Shared.Maths; using Robust.Shared.Random; using Robust.Shared.ViewVariables; @@ -177,7 +177,7 @@ namespace Content.Server.AME intensity = Math.Min(intensity, 8); - epicenter.Owner.SpawnExplosion(intensity / 2, intensity, intensity * 2, intensity * 3); + EntitySystem.Get().SpawnExplosion(epicenter.Owner.Uid, intensity / 2, intensity, intensity * 2, intensity * 3); } } } diff --git a/Content.Server/Administration/AdminVerbSystem.cs b/Content.Server/Administration/AdminVerbSystem.cs index b84b5e3842..507bd0ddc2 100644 --- a/Content.Server/Administration/AdminVerbSystem.cs +++ b/Content.Server/Administration/AdminVerbSystem.cs @@ -8,7 +8,7 @@ using Content.Server.Chemistry.EntitySystems; using Content.Server.Configurable; using Content.Server.Disposal.Tube.Components; using Content.Server.EUI; -using Content.Server.Explosion; +using Content.Server.Explosion.EntitySystems; using Content.Server.Ghost.Roles; using Content.Server.Inventory.Components; using Content.Server.Mind.Commands; @@ -40,6 +40,7 @@ namespace Content.Server.Administration [Dependency] private readonly IAdminManager _adminManager = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly EuiManager _euiManager = default!; + [Dependency] private readonly ExplosionSystem _explosions = default!; [Dependency] private readonly GhostRoleSystem _ghostRoleSystem = default!; private readonly Dictionary _openSolutionUis = new(); @@ -118,7 +119,7 @@ namespace Content.Server.Administration verb.Act = () => { 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)) { body.Gib(); diff --git a/Content.Server/Administration/Commands/ExplosionCommand.cs b/Content.Server/Administration/Commands/ExplosionCommand.cs index 50d553fd72..d9f9c86912 100644 --- a/Content.Server/Administration/Commands/ExplosionCommand.cs +++ b/Content.Server/Administration/Commands/ExplosionCommand.cs @@ -1,10 +1,10 @@ -using Content.Server.Explosion; +using Content.Server.Explosion.EntitySystems; using Content.Shared.Administration; using Robust.Server.Player; using Robust.Shared.Console; +using Robust.Shared.GameObjects; using Robust.Shared.Map; - namespace Content.Server.Administration.Commands { [AdminCommand(AdminFlags.Fun)] @@ -35,7 +35,7 @@ namespace Content.Server.Administration.Commands var mapTransform = player.AttachedEntity.Transform.GetMapTransform(); var coords = new EntityCoordinates(mapTransform.Owner.Uid, x, y); - ExplosionHelper.SpawnExplosion(coords, dev, hvy, lgh, fla); + EntitySystem.Get().SpawnExplosion(coords, dev, hvy, lgh, fla); } } } diff --git a/Content.Server/Atmos/Components/GasTankComponent.cs b/Content.Server/Atmos/Components/GasTankComponent.cs index 0f970eece3..3434635cea 100644 --- a/Content.Server/Atmos/Components/GasTankComponent.cs +++ b/Content.Server/Atmos/Components/GasTankComponent.cs @@ -1,9 +1,7 @@ using System; using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Respiratory; -using Content.Server.Explosion; -using Content.Server.NodeContainer; -using Content.Server.NodeContainer.Nodes; +using Content.Server.Explosion.EntitySystems; using Content.Server.UserInterface; using Content.Shared.ActionBlocker; using Content.Shared.Actions; @@ -12,7 +10,6 @@ using Content.Shared.Actions.Components; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Audio; -using Content.Shared.DragDrop; using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.Sound; @@ -271,7 +268,7 @@ namespace Content.Server.Atmos.Components range = MaxExplosionRange; } - Owner.SpawnExplosion((int) (range * 0.25f), (int) (range * 0.5f), (int) (range * 1.5f), 1); + EntitySystem.Get().SpawnExplosion(OwnerUid, (int) (range * 0.25f), (int) (range * 0.5f), (int) (range * 1.5f), 1); Owner.QueueDelete(); return; diff --git a/Content.Server/Chemistry/ReactionEffects/ExplosionReactionEffect.cs b/Content.Server/Chemistry/ReactionEffects/ExplosionReactionEffect.cs index 1d6423345a..8c809d83fa 100644 --- a/Content.Server/Chemistry/ReactionEffects/ExplosionReactionEffect.cs +++ b/Content.Server/Chemistry/ReactionEffects/ExplosionReactionEffect.cs @@ -1,7 +1,6 @@ using System; -using Content.Server.Chemistry.Components; using Content.Server.Chemistry.Components.SolutionManager; -using Content.Server.Explosion; +using Content.Server.Explosion.EntitySystems; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reaction; using Robust.Shared.GameObjects; @@ -50,7 +49,7 @@ namespace Content.Server.Chemistry.ReactionEffects var finalHeavyImpactRange = (int)MathF.Round(_heavyImpactRange * floatIntensity); var finalLightImpactRange = (int)MathF.Round(_lightImpactRange * floatIntensity); var finalFlashRange = (int)MathF.Round(_flashRange * floatIntensity); - solutionEntity.SpawnExplosion(finalDevastationRange, + EntitySystem.Get().SpawnExplosion(solutionEntity, finalDevastationRange, finalHeavyImpactRange, finalLightImpactRange, finalFlashRange); } } diff --git a/Content.Server/Destructible/DestructibleSystem.cs b/Content.Server/Destructible/DestructibleSystem.cs index d36575eb45..e4cd326978 100644 --- a/Content.Server/Destructible/DestructibleSystem.cs +++ b/Content.Server/Destructible/DestructibleSystem.cs @@ -1,4 +1,6 @@ +using Content.Server.Construction; using Content.Server.Destructible.Thresholds; +using Content.Server.Explosion.EntitySystems; using Content.Shared.Acts; using Content.Shared.Damage; using JetBrains.Annotations; @@ -13,8 +15,12 @@ namespace Content.Server.Destructible public class DestructibleSystem : EntitySystem { [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 AudioSystem AudioSystem = default!; + [Dependency] public readonly ConstructionSystem ConstructionSystem = default!; + [Dependency] public readonly ExplosionSystem ExplosionSystem = default!; public override void Initialize() { diff --git a/Content.Server/Destructible/Thresholds/Behaviors/ChangeConstructionNodeBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/ChangeConstructionNodeBehavior.cs index e89e6db630..65e255c8d5 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/ChangeConstructionNodeBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/ChangeConstructionNodeBehavior.cs @@ -1,5 +1,4 @@ using System; -using Content.Server.Construction; using Content.Server.Construction.Components; using Robust.Shared.GameObjects; using Robust.Shared.Serialization.Manager.Attributes; @@ -13,12 +12,12 @@ namespace Content.Server.Destructible.Thresholds.Behaviors [DataField("node")] 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; - EntitySystem.Get().ChangeNode(owner, null, Node, true, construction); + system.ConstructionSystem.ChangeNode(owner, null, Node, true, construction); } } } diff --git a/Content.Server/Destructible/Thresholds/Behaviors/DoActsBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/DoActsBehavior.cs index 865c7f5d61..c2cf122078 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/DoActsBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/DoActsBehavior.cs @@ -21,7 +21,7 @@ namespace Content.Server.Destructible.Thresholds.Behaviors return (Acts & act) != 0; } - public void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager) + public void Execute(EntityUid owner, DestructibleSystem system) { if (HasAct(ThresholdActs.Breakage)) { diff --git a/Content.Server/Destructible/Thresholds/Behaviors/DumpCanisterBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/DumpCanisterBehavior.cs index 0036364aaf..efceda22b3 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/DumpCanisterBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/DumpCanisterBehavior.cs @@ -1,5 +1,4 @@ using System; -using Content.Server.Atmos.Piping.Unary.Components; using Content.Server.Atmos.Piping.Unary.EntitySystems; using Robust.Shared.GameObjects; using Robust.Shared.Serialization.Manager.Attributes; @@ -8,13 +7,11 @@ namespace Content.Server.Destructible.Thresholds.Behaviors { [Serializable] [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.PurgeContents(owner); + system.EntityManager.EntitySysManager.GetEntitySystem().PurgeContents(owner); } } } diff --git a/Content.Server/Destructible/Thresholds/Behaviors/EmptyAllContainersBehaviour.cs b/Content.Server/Destructible/Thresholds/Behaviors/EmptyAllContainersBehaviour.cs index 4b763d2b1d..2ed21e013c 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/EmptyAllContainersBehaviour.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/EmptyAllContainersBehaviour.cs @@ -10,14 +10,14 @@ namespace Content.Server.Destructible.Thresholds.Behaviors [DataDefinition] public class EmptyAllContainersBehaviour : IThresholdBehavior { - public void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager) + public void Execute(EntityUid owner, DestructibleSystem system) { - if (!entityManager.TryGetComponent(owner, out var containerManager)) + if (!system.EntityManager.TryGetComponent(owner, out var containerManager)) return; foreach (var container in containerManager.GetAllContainers()) { - container.EmptyContainer(true, entityManager.GetComponent(owner).Coordinates); + container.EmptyContainer(true, system.EntityManager.GetComponent(owner).Coordinates); } } } diff --git a/Content.Server/Destructible/Thresholds/Behaviors/ExplodeBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/ExplodeBehavior.cs index 1f5c162ceb..076da13db7 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/ExplodeBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/ExplodeBehavior.cs @@ -1,4 +1,3 @@ -using Content.Server.Explosion; using Content.Server.Explosion.Components; using JetBrains.Annotations; using Robust.Shared.GameObjects; @@ -13,9 +12,9 @@ namespace Content.Server.Destructible.Thresholds.Behaviors [DataDefinition] 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); } } } diff --git a/Content.Server/Destructible/Thresholds/Behaviors/GibBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/GibBehavior.cs index e7175c9f18..d4fd220ada 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/GibBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/GibBehavior.cs @@ -11,9 +11,9 @@ namespace Content.Server.Destructible.Thresholds.Behaviors { [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); } diff --git a/Content.Server/Destructible/Thresholds/Behaviors/IThresholdBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/IThresholdBehavior.cs index bde671277d..407ba7b21d 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/IThresholdBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/IThresholdBehavior.cs @@ -12,7 +12,6 @@ namespace Content.Server.Destructible.Thresholds.Behaviors /// An instance of to pull dependencies /// and other systems from. /// - /// - void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager); + void Execute(EntityUid owner, DestructibleSystem system); } } diff --git a/Content.Server/Destructible/Thresholds/Behaviors/PlaySoundBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/PlaySoundBehavior.cs index 78fd5f07fc..c1285de14c 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/PlaySoundBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/PlaySoundBehavior.cs @@ -17,9 +17,9 @@ namespace Content.Server.Destructible.Thresholds.Behaviors /// [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(owner).Coordinates; + var pos = system.EntityManager.GetComponent(owner).Coordinates; SoundSystem.Play(Filter.Pvs(pos), Sound.GetSound(), pos, AudioHelpers.WithVariation(0.125f)); } } diff --git a/Content.Server/Destructible/Thresholds/Behaviors/SpawnEntitiesBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/SpawnEntitiesBehavior.cs index ef2821c12e..c607c7ef47 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/SpawnEntitiesBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/SpawnEntitiesBehavior.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using Content.Server.Stack; using Content.Shared.Prototypes; using Content.Shared.Random.Helpers; -using Content.Shared.Stacks; using Robust.Shared.GameObjects; using Robust.Shared.Serialization.Manager.Attributes; @@ -19,9 +18,9 @@ namespace Content.Server.Destructible.Thresholds.Behaviors [DataField("spawn")] public Dictionary Spawn { get; set; } = new(); - public void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager) + public void Execute(EntityUid owner, DestructibleSystem system) { - var position = entityManager.GetComponent(owner).MapPosition; + var position = system.EntityManager.GetComponent(owner).MapPosition; foreach (var (entityId, minMax) in Spawn) { @@ -33,7 +32,7 @@ namespace Content.Server.Destructible.Thresholds.Behaviors if (EntityPrototypeHelpers.HasComponent(entityId)) { - var spawned = entityManager.SpawnEntity(entityId, position); + var spawned = system.EntityManager.SpawnEntity(entityId, position); var stack = spawned.GetComponent(); EntitySystem.Get().SetCount(spawned.Uid, count, stack); spawned.RandomOffset(0.5f); @@ -42,7 +41,7 @@ namespace Content.Server.Destructible.Thresholds.Behaviors { for (var i = 0; i < count; i++) { - var spawned = entityManager.SpawnEntity(entityId, position); + var spawned = system.EntityManager.SpawnEntity(entityId, position); spawned.RandomOffset(0.5f); } } diff --git a/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs index 758885cc0f..a91435657c 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/SpillBehavior.cs @@ -21,13 +21,13 @@ namespace Content.Server.Destructible.Thresholds.Behaviors /// Entity on which behavior is executed /// system calling the behavior /// - public void Execute(EntityUid owner, DestructibleSystem system, IEntityManager entityManager) + public void Execute(EntityUid owner, DestructibleSystem system) { var solutionContainerSystem = EntitySystem.Get(); - var coordinates = entityManager.GetComponent(owner).Coordinates; + var coordinates = system.EntityManager.GetComponent(owner).Coordinates; - if (entityManager.TryGetComponent(owner, out SpillableComponent? spillableComponent) && + if (system.EntityManager.TryGetComponent(owner, out SpillableComponent? spillableComponent) && solutionContainerSystem.TryGetSolution(owner, spillableComponent.SolutionName, out var compSolution)) { diff --git a/Content.Server/Destructible/Thresholds/DamageThreshold.cs b/Content.Server/Destructible/Thresholds/DamageThreshold.cs index 770915ae33..25ffcf26e3 100644 --- a/Content.Server/Destructible/Thresholds/DamageThreshold.cs +++ b/Content.Server/Destructible/Thresholds/DamageThreshold.cs @@ -94,7 +94,7 @@ namespace Content.Server.Destructible.Thresholds if (!entityManager.EntityExists(owner)) return; - behavior.Execute(owner, system, entityManager); + behavior.Execute(owner, system); } } } diff --git a/Content.Server/Explosion/Components/ClusterFlashComponent.cs b/Content.Server/Explosion/Components/ClusterFlashComponent.cs index 47f7c6b98e..064ef79611 100644 --- a/Content.Server/Explosion/Components/ClusterFlashComponent.cs +++ b/Content.Server/Explosion/Components/ClusterFlashComponent.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; +using Content.Server.Explosion.EntitySystems; using Content.Server.Flash.Components; using Content.Server.Throwing; using Content.Shared.Explosion; diff --git a/Content.Server/Explosion/Components/DeleteOnTriggerComponent.cs b/Content.Server/Explosion/Components/DeleteOnTriggerComponent.cs index 22ea289926..2ff07a94f7 100644 --- a/Content.Server/Explosion/Components/DeleteOnTriggerComponent.cs +++ b/Content.Server/Explosion/Components/DeleteOnTriggerComponent.cs @@ -1,3 +1,4 @@ +using Content.Server.Explosion.EntitySystems; using Robust.Shared.GameObjects; namespace Content.Server.Explosion.Components diff --git a/Content.Server/Explosion/Components/ExplosionLaunchedComponent.cs b/Content.Server/Explosion/Components/ExplosionLaunchedComponent.cs index 59c3f726fc..3164e8f856 100644 --- a/Content.Server/Explosion/Components/ExplosionLaunchedComponent.cs +++ b/Content.Server/Explosion/Components/ExplosionLaunchedComponent.cs @@ -15,7 +15,7 @@ namespace Content.Server.Explosion.Components return; var sourceLocation = eventArgs.Source; - var targetLocation = eventArgs.Target.Transform.Coordinates; + var targetLocation = Owner.EntityManager.GetComponent(eventArgs.Target).Coordinates; if (sourceLocation.Equals(targetLocation)) return; @@ -27,7 +27,7 @@ namespace Content.Server.Explosion.Components ExplosionSeverity.Light => 20, _ => 0, }; - + Owner.TryThrow(direction, throwForce); } } diff --git a/Content.Server/Explosion/Components/OnUseTimerTriggerComponent.cs b/Content.Server/Explosion/Components/OnUseTimerTriggerComponent.cs index 84931ed26d..79463b2180 100644 --- a/Content.Server/Explosion/Components/OnUseTimerTriggerComponent.cs +++ b/Content.Server/Explosion/Components/OnUseTimerTriggerComponent.cs @@ -1,4 +1,5 @@ using System; +using Content.Server.Explosion.EntitySystems; using Content.Shared.Interaction; using Content.Shared.Trigger; using Robust.Server.GameObjects; diff --git a/Content.Server/Explosion/Components/SoundOnTriggerComponent.cs b/Content.Server/Explosion/Components/SoundOnTriggerComponent.cs index cf30935438..0db1663588 100644 --- a/Content.Server/Explosion/Components/SoundOnTriggerComponent.cs +++ b/Content.Server/Explosion/Components/SoundOnTriggerComponent.cs @@ -1,3 +1,4 @@ +using Content.Server.Explosion.EntitySystems; using Content.Shared.Sound; using Robust.Shared.GameObjects; using Robust.Shared.Serialization.Manager.Attributes; diff --git a/Content.Server/Explosion/ExplosionHelper.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs similarity index 59% rename from Content.Server/Explosion/ExplosionHelper.cs rename to Content.Server/Explosion/EntitySystems/ExplosionSystem.cs index f4c051937e..d56a8fb32f 100644 --- a/Content.Server/Explosion/ExplosionHelper.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Content.Server.Camera; @@ -21,9 +21,9 @@ using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Timing; -namespace Content.Server.Explosion +namespace Content.Server.Explosion.EntitySystems { - public static class ExplosionHelper + public class ExplosionSystem : EntitySystem { /// /// Distance used for camera shake when distance from explosion is (0.0, 0.0). @@ -34,19 +34,35 @@ namespace Content.Server.Explosion /// /// Chance of a tile breaking if the severity is Light and Heavy /// - private static readonly float LightBreakChance = 0.3f; - private static readonly float HeavyBreakChance = 0.8f; - private static SoundSpecifier _explosionSound = new SoundCollectionSpecifier("explosion"); + private const float LightBreakChance = 0.3f; + private const float HeavyBreakChance = 0.8f; - 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) { return ExplosionSeverity.Destruction; } - else if (distance < heaveyRange) + else if (distance < heavyRange) { return ExplosionSeverity.Heavy; } @@ -56,174 +72,10 @@ namespace Content.Server.Explosion } } - /// - /// Damage entities inside the range. The damage depends on a discrete - /// damage bracket [light, heavy, devastation] and the distance from the epicenter - /// - /// - /// 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. - /// - private static void DamageEntitiesInRange(EntityCoordinates epicenter, Box2 boundingBox, - float devastationRange, - float heaveyRange, - float maxRange, - MapId mapId) + private void CameraShakeInRange(EntityCoordinates epicenter, float maxRange) { - var entityManager = IoCManager.Resolve(); + var players = _players.GetPlayersInRange(epicenter, (int) Math.Ceiling(maxRange)); - var exAct = EntitySystem.Get(); - - var entitiesInRange = IoCManager.Resolve().GetEntitiesInRange(mapId, boundingBox, 0).ToList(); - - var impassableEntities = new List>(); - var nonImpassableEntities = new List>(); - // 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)); - } - } - - /// - /// 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 [, , 1.0]. - /// - /// - private static void DamageTilesInRange(EntityCoordinates epicenter, - GridId gridId, - Box2 boundingBox, - float devastationRange, - float heaveyRange, - float maxRange) - { - var mapManager = IoCManager.Resolve(); - if (!mapManager.TryGetGrid(gridId, out var mapGrid)) - { - return; - } - - var entityManager = IoCManager.Resolve(); - if (!entityManager.TryGetEntity(mapGrid.GridEntityId, out var grid)) - { - return; - } - - var robustRandom = IoCManager.Resolve(); - var tileDefinitionManager = IoCManager.Resolve(); - - 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(); - var players = playerManager.GetPlayersInRange(epicenter, (int) Math.Ceiling(maxRange)); foreach (var player in players) { if (player.AttachedEntity == null || !player.AttachedEntity.TryGetComponent(out CameraRecoilComponent? recoil)) @@ -231,10 +83,8 @@ namespace Content.Server.Explosion continue; } - var entityManager = IoCManager.Resolve(); - 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 if (delta.EqualsApprox((0.0f, 0.0f))) @@ -250,83 +100,250 @@ namespace Content.Server.Explosion } } - private static void FlashInRange(EntityCoordinates epicenter, float flashrange) + /// + /// Damage entities inside the range. The damage depends on a discrete + /// damage bracket [light, heavy, devastation] and the distance from the epicenter + /// + /// + /// 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. + /// + 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(); - var time = IoCManager.Resolve().CurTime; + 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((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)); + } + } + + /// + /// 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 [, , 1.0]. + /// + /// + 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 { EffectSprite = "Effects/explosion.rsi", RsiState = "explosionfast", Born = time, DeathTime = time + TimeSpan.FromSeconds(5), - Size = new Vector2(flashrange / 2, flashrange / 2), + Size = new Vector2(flashRange / 2, flashRange / 2), Coordinates = epicenter, Rotation = 0f, ColorDelta = new Vector4(0, 0, 0, -1500f), Color = Vector4.Multiply(new Vector4(255, 255, 255, 750), 0.5f), Shaded = false }; - entitySystemManager.GetEntitySystem().CreateParticle(message); + + _effects.CreateParticle(message); } } - // TODO: remove this shit - public static void SpawnExplosion(this EntityUid uid, int devastationRange = 0, int heavyImpactRange = 0, - int lightImpactRange = 0, int flashRange = 0, IEntityManager? entityManager = null) + public void SpawnExplosion( + EntityUid entity, + int devastationRange = 0, + int heavyImpactRange = 0, + int lightImpactRange = 0, + int flashRange = 0, + ExplosiveComponent? explosive = null, + TransformComponent? transform = null) { - entityManager ??= IoCManager.Resolve(); - - 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) + if (!Resolve(entity, ref transform)) { - EntitySystem.Get().Explode(entity.Uid, explosive); + return; + } + + Resolve(entity, ref explosive, false); + + if (explosive is { Exploding: false }) + { + _triggers.Explode(entity, explosive); } 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); } } - public static void SpawnExplosion(EntityCoordinates epicenter, int devastationRange = 0, - int heavyImpactRange = 0, int lightImpactRange = 0, int flashRange = 0) + public void SpawnExplosion( + EntityCoordinates epicenter, + int devastationRange = 0, + int heavyImpactRange = 0, + int lightImpactRange = 0, + int flashRange = 0) { - var mapId = epicenter.GetMapId(IoCManager.Resolve()); + var mapId = epicenter.GetMapId(EntityManager); if (mapId == MapId.Nullspace) { return; } var maxRange = MathHelper.Max(devastationRange, heavyImpactRange, lightImpactRange, 0); - - var entityManager = IoCManager.Resolve(); - var mapManager = IoCManager.Resolve(); - - var epicenterMapPos = epicenter.ToMapPos(entityManager); + var epicenterMapPos = epicenter.ToMapPos(EntityManager); var boundingBox = new Box2(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); - var mapGridsNear = mapManager.FindGridsIntersecting(mapId, boundingBox); + var mapGridsNear = _maps.FindGridsIntersecting(mapId, boundingBox); foreach (var gridId in mapGridsNear) { diff --git a/Content.Server/Explosion/TriggerSystem.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs similarity index 94% rename from Content.Server/Explosion/TriggerSystem.cs rename to Content.Server/Explosion/EntitySystems/TriggerSystem.cs index d49a8900b8..d7e21de886 100644 --- a/Content.Server/Explosion/TriggerSystem.cs +++ b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs @@ -3,7 +3,6 @@ using Content.Server.Doors.Components; using Content.Server.Explosion.Components; using Content.Server.Flash; using Content.Server.Flash.Components; -using Content.Shared.Acts; using Content.Shared.Audio; using Content.Shared.Doors; using JetBrains.Annotations; @@ -14,7 +13,7 @@ using Robust.Shared.Physics.Dynamics; using Robust.Shared.Player; using Robust.Shared.Timing; -namespace Content.Server.Explosion +namespace Content.Server.Explosion.EntitySystems { /// /// Raised whenever something is Triggered on the entity. @@ -34,6 +33,7 @@ namespace Content.Server.Explosion [UsedImplicitly] public sealed class TriggerSystem : EntitySystem { + [Dependency] private readonly ExplosionSystem _explosions = default!; [Dependency] private readonly FlashSystem _flashSystem = default!; public override void Initialize() @@ -65,7 +65,7 @@ namespace Content.Server.Explosion } 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); } #endregion diff --git a/Content.Server/MachineLinking/System/TriggerOnSignalReceivedSystem.cs b/Content.Server/MachineLinking/System/TriggerOnSignalReceivedSystem.cs index 8434033e59..17ca92f4b1 100644 --- a/Content.Server/MachineLinking/System/TriggerOnSignalReceivedSystem.cs +++ b/Content.Server/MachineLinking/System/TriggerOnSignalReceivedSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.Explosion; +using Content.Server.Explosion.EntitySystems; using Content.Server.MachineLinking.Components; using Content.Server.MachineLinking.Events; using Robust.Shared.GameObjects; diff --git a/Content.Server/Pointing/EntitySystems/RoguePointingSystem.cs b/Content.Server/Pointing/EntitySystems/RoguePointingSystem.cs index 2047f5678a..ce95d52b8f 100644 --- a/Content.Server/Pointing/EntitySystems/RoguePointingSystem.cs +++ b/Content.Server/Pointing/EntitySystems/RoguePointingSystem.cs @@ -1,5 +1,5 @@ using System.Linq; -using Content.Server.Explosion; +using Content.Server.Explosion.EntitySystems; using Content.Server.Pointing.Components; using Content.Shared.MobState.Components; using Content.Shared.Pointing.Components; @@ -22,6 +22,8 @@ namespace Content.Server.Pointing.EntitySystems [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly ExplosionSystem _explosions = default!; + public override void Initialize() { base.Initialize(); @@ -106,7 +108,7 @@ namespace Content.Server.Pointing.EntitySystems 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); EntityManager.QueueDeleteEntity(uid); diff --git a/Content.Server/PowerCell/Components/PowerCellComponent.cs b/Content.Server/PowerCell/Components/PowerCellComponent.cs index ffe4c45443..5b4509bb05 100644 --- a/Content.Server/PowerCell/Components/PowerCellComponent.cs +++ b/Content.Server/PowerCell/Components/PowerCellComponent.cs @@ -1,8 +1,6 @@ using System; -using Content.Server.Chemistry.Components; -using Content.Server.Explosion; +using Content.Server.Explosion.EntitySystems; using Content.Server.Power.Components; -using Content.Shared.Chemistry; using Content.Shared.Examine; using Content.Shared.PowerCell; using Content.Shared.Rounding; @@ -75,7 +73,7 @@ namespace Content.Server.PowerCell.Components var light = (int) Math.Ceiling(Math.Sqrt(CurrentCharge) / 30); CurrentCharge = 0; - Owner.SpawnExplosion(0, heavy, light, light*2); + EntitySystem.Get().SpawnExplosion(OwnerUid, 0, heavy, light, light*2); Owner.Delete(); } diff --git a/Content.Shared/Acts/ActSystem.cs b/Content.Shared/Acts/ActSystem.cs index b994835ba1..82168335c2 100644 --- a/Content.Shared/Acts/ActSystem.cs +++ b/Content.Shared/Acts/ActSystem.cs @@ -46,7 +46,7 @@ namespace Content.Shared.Acts public class ExplosionEventArgs : EventArgs { public EntityCoordinates Source { get; set; } - public IEntity Target { get; set; } = default!; + public EntityUid Target { get; set; } public ExplosionSeverity Severity { get; set; } } @@ -70,7 +70,7 @@ namespace Content.Shared.Acts 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 { @@ -78,7 +78,7 @@ namespace Content.Shared.Acts Target = target, Severity = severity }; - var exActs = target.GetAllComponents().ToList(); + var exActs = EntityManager.GetComponents(target).ToList(); foreach (var exAct in exActs) {