From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Fri, 29 Mar 2024 23:46:05 +0000 (+0000) Subject: combine same-tile explosions in the same tick (#25664) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=355d00a0f2529a5beac6426837fad129d45a41a6;p=space-station-14.git combine same-tile explosions in the same tick (#25664) * combine same-tile explosions in the same tick * ! --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs index 60db6bdf5b..6e100fe656 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs @@ -38,8 +38,15 @@ public sealed partial class ExplosionSystem /// Queue for delayed processing of explosions. If there is an explosion that covers more than tiles, other explosions will actually be delayed slightly. Unless it's a station /// nuke, this delay should never really be noticeable. + /// This is also used to combine explosion intensities of the same kind. /// - private Queue> _explosionQueue = new(); + private Queue _explosionQueue = new(); + + /// + /// All queued explosions that will be processed in . + /// These always have the same contents. + /// + private HashSet _queuedExplosions = new(); /// /// The explosion currently being processed. @@ -93,10 +100,11 @@ public sealed partial class ExplosionSystem if (MathF.Max(MaxProcessingTime - 1, 0.1f) < Stopwatch.Elapsed.TotalMilliseconds) break; - if (!_explosionQueue.TryDequeue(out var spawnNextExplosion)) + if (!_explosionQueue.TryDequeue(out var queued)) break; - _activeExplosion = spawnNextExplosion(); + _queuedExplosions.Remove(queued); + _activeExplosion = SpawnExplosion(queued); // explosion spawning can be null if something somewhere went wrong. (e.g., negative explosion // intensity). @@ -867,3 +875,15 @@ sealed class Explosion _tileUpdateDict.Clear(); } } + +/// +/// Data needed to spawn an explosion with . +/// +public sealed class QueuedExplosion +{ + public MapCoordinates Epicenter; + public ExplosionPrototype Proto = new(); + public float TotalIntensity, Slope, MaxTileIntensity, TileBreakScale; + public int MaxTileBreak; + public bool CanCreateVacuum; +} diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs index 46238fd7c5..23543895e6 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs @@ -112,6 +112,7 @@ public sealed partial class ExplosionSystem : EntitySystem private void OnReset(RoundRestartCleanupEvent ev) { _explosionQueue.Clear(); + _queuedExplosions.Clear(); if (_activeExplosion != null) QueueDel(_activeExplosion.VisualEnt); _activeExplosion = null; @@ -297,8 +298,36 @@ public sealed partial class ExplosionSystem : EntitySystem if (addLog) // dont log if already created a separate, more detailed, log. _adminLogger.Add(LogType.Explosion, LogImpact.High, $"Explosion ({typeId}) spawned at {epicenter:coordinates} with intensity {totalIntensity} slope {slope}"); - _explosionQueue.Enqueue(() => SpawnExplosion(epicenter, type, totalIntensity, - slope, maxTileIntensity, tileBreakScale, maxTileBreak, canCreateVacuum)); + // try to combine explosions on the same tile if they are the same type + foreach (var queued in _queuedExplosions) + { + // ignore different types or those on different maps + if (queued.Proto.ID != type.ID || queued.Epicenter.MapId != epicenter.MapId) + continue; + + var dst2 = queued.Proto.MaxCombineDistance * queued.Proto.MaxCombineDistance; + var direction = queued.Epicenter.Position - epicenter.Position; + if (direction.LengthSquared() > dst2) + continue; + + // they are close enough to combine so just add total intensity and prevent queuing another one + queued.TotalIntensity += totalIntensity; + return; + } + + var boom = new QueuedExplosion() + { + Epicenter = epicenter, + Proto = type, + TotalIntensity = totalIntensity, + Slope = slope, + MaxTileIntensity = maxTileIntensity, + TileBreakScale = tileBreakScale, + MaxTileBreak = maxTileBreak, + CanCreateVacuum = canCreateVacuum + }; + _explosionQueue.Enqueue(boom); + _queuedExplosions.Add(boom); } /// @@ -306,32 +335,26 @@ public sealed partial class ExplosionSystem : EntitySystem /// information about the affected tiles for the explosion system to process. It will also trigger the /// camera shake and sound effect. /// - private Explosion? SpawnExplosion(MapCoordinates epicenter, - ExplosionPrototype type, - float totalIntensity, - float slope, - float maxTileIntensity, - float tileBreakScale, - int maxTileBreak, - bool canCreateVacuum) + private Explosion? SpawnExplosion(QueuedExplosion queued) { - if (!_mapManager.MapExists(epicenter.MapId)) + var pos = queued.Epicenter; + if (!_mapManager.MapExists(pos.MapId)) return null; - var results = GetExplosionTiles(epicenter, type.ID, totalIntensity, slope, maxTileIntensity); + var results = GetExplosionTiles(pos, queued.Proto.ID, queued.TotalIntensity, queued.Slope, queued.MaxTileIntensity); if (results == null) return null; var (area, iterationIntensity, spaceData, gridData, spaceMatrix) = results.Value; - var visualEnt = CreateExplosionVisualEntity(epicenter, type.ID, spaceMatrix, spaceData, gridData.Values, iterationIntensity); + var visualEnt = CreateExplosionVisualEntity(pos, queued.Proto.ID, spaceMatrix, spaceData, gridData.Values, iterationIntensity); // camera shake - CameraShake(iterationIntensity.Count * 4f, epicenter, totalIntensity); + CameraShake(iterationIntensity.Count * 4f, pos, queued.TotalIntensity); //For whatever bloody reason, sound system requires ENTITY coordinates. - var mapEntityCoords = EntityCoordinates.FromMap(_mapManager.GetMapEntityId(epicenter.MapId), epicenter, _transformSystem, EntityManager); + var mapEntityCoords = EntityCoordinates.FromMap(_mapManager.GetMapEntityId(pos.MapId), pos, _transformSystem, EntityManager); // play sound. // for the normal audio, we want everyone in pvs range @@ -339,34 +362,35 @@ public sealed partial class ExplosionSystem : EntitySystem // this is capped to 30 because otherwise really huge bombs // will attempt to play regular audio for people who can't hear it anyway because the epicenter is so far away var audioRange = Math.Min(iterationIntensity.Count * 2, MaxExplosionAudioRange); - var filter = Filter.Pvs(epicenter).AddInRange(epicenter, audioRange); - var sound = iterationIntensity.Count < type.SmallSoundIterationThreshold - ? type.SmallSound - : type.Sound; + var filter = Filter.Pvs(pos).AddInRange(pos, audioRange); + var sound = iterationIntensity.Count < queued.Proto.SmallSoundIterationThreshold + ? queued.Proto.SmallSound + : queued.Proto.Sound; _audio.PlayStatic(sound, filter, mapEntityCoords, true, sound.Params); // play far sound // far sound should play for anyone who wasn't in range of any of the effects of the bomb var farAudioRange = iterationIntensity.Count * 5; - var farFilter = Filter.Empty().AddInRange(epicenter, farAudioRange).RemoveInRange(epicenter, audioRange); - var farSound = iterationIntensity.Count < type.SmallSoundIterationThreshold - ? type.SmallSoundFar - : type.SoundFar; + var farFilter = Filter.Empty().AddInRange(pos, farAudioRange).RemoveInRange(pos, audioRange); + var farSound = iterationIntensity.Count < queued.Proto.SmallSoundIterationThreshold + ? queued.Proto.SmallSoundFar + : queued.Proto.SoundFar; _audio.PlayGlobal(farSound, farFilter, true, farSound.Params); return new Explosion(this, - type, + queued.Proto, spaceData, gridData.Values.ToList(), iterationIntensity, - epicenter, + pos, spaceMatrix, area, - tileBreakScale, - maxTileBreak, - canCreateVacuum, + // TODO: instead of le copy paste fields refactor so it has QueuedExplosion as a field? + queued.TileBreakScale, + queued.MaxTileBreak, + queued.CanCreateVacuum, EntityManager, _mapManager, visualEnt); diff --git a/Content.Shared/Explosion/ExplosionPrototype.cs b/Content.Shared/Explosion/ExplosionPrototype.cs index ec9f2efa1e..df2fb18360 100644 --- a/Content.Shared/Explosion/ExplosionPrototype.cs +++ b/Content.Shared/Explosion/ExplosionPrototype.cs @@ -77,6 +77,13 @@ public sealed partial class ExplosionPrototype : IPrototype [DataField("smallSoundIterationThreshold")] public int SmallSoundIterationThreshold = 6; + /// + /// How far away another explosion in the same tick can be and be combined. + /// Total intensity is added to the original queued explosion. + /// + [DataField] + public float MaxCombineDistance = 1f; + [DataField("sound")] public SoundSpecifier Sound = new SoundCollectionSpecifier("Explosion");