Remove explosion networking jank (#12733)
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Shared.Explosion;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
@@ -10,26 +11,10 @@ namespace Content.Client.Explosion;
|
|||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public sealed class ExplosionOverlay : Overlay
|
public sealed class ExplosionOverlay : Overlay
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The explosion that needs to be drawn. This explosion is currently being processed by the server and
|
|
||||||
/// expanding outwards.
|
|
||||||
/// </summary>
|
|
||||||
internal Explosion? ActiveExplosion;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This index specifies what parts of the currently expanding explosion should be drawn.
|
|
||||||
/// </summary>
|
|
||||||
public int Index;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// These explosions have finished expanding, but we will draw for a few more frames. This is important for
|
|
||||||
/// small explosions, as otherwise they disappear far too quickly.
|
|
||||||
/// </summary>
|
|
||||||
internal List<Explosion> CompletedExplosions = new ();
|
|
||||||
|
|
||||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||||
|
|
||||||
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV;
|
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV;
|
||||||
|
|
||||||
@@ -38,7 +23,7 @@ public sealed class ExplosionOverlay : Overlay
|
|||||||
public ExplosionOverlay()
|
public ExplosionOverlay()
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
_shader = IoCManager.Resolve<IPrototypeManager>().Index<ShaderPrototype>("unshaded").Instance();
|
_shader = _proto.Index<ShaderPrototype>("unshaded").Instance();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Draw(in OverlayDrawArgs args)
|
protected override void Draw(in OverlayDrawArgs args)
|
||||||
@@ -48,22 +33,20 @@ public sealed class ExplosionOverlay : Overlay
|
|||||||
|
|
||||||
var xforms = _entMan.GetEntityQuery<TransformComponent>();
|
var xforms = _entMan.GetEntityQuery<TransformComponent>();
|
||||||
|
|
||||||
if (ActiveExplosion != null && ActiveExplosion.Map == args.Viewport.Eye?.Position.MapId)
|
foreach (var (comp, appearance) in _entMan.EntityQuery<ExplosionVisualsComponent, AppearanceComponent>(true))
|
||||||
{
|
{
|
||||||
DrawExplosion(drawHandle, args.WorldBounds, ActiveExplosion, Index, xforms);
|
if (!appearance.TryGetData(ExplosionAppearanceData.Progress, out int index))
|
||||||
}
|
continue;
|
||||||
|
|
||||||
foreach (var exp in CompletedExplosions)
|
index = Math.Min(index, comp.Intensity.Count - 1);
|
||||||
{
|
DrawExplosion(drawHandle, args.WorldBounds, comp, index, xforms);
|
||||||
if (exp.Map == args.Viewport.Eye?.Position.MapId)
|
|
||||||
DrawExplosion(drawHandle, args.WorldBounds, exp, exp.Intensity.Count, xforms);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
drawHandle.SetTransform(Matrix3.Identity);
|
drawHandle.SetTransform(Matrix3.Identity);
|
||||||
drawHandle.UseShader(null);
|
drawHandle.UseShader(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawExplosion(DrawingHandleWorld drawHandle, Box2Rotated worldBounds, Explosion exp, int index, EntityQuery<TransformComponent> xforms)
|
private void DrawExplosion(DrawingHandleWorld drawHandle, Box2Rotated worldBounds, ExplosionVisualsComponent exp, int index, EntityQuery<TransformComponent> xforms)
|
||||||
{
|
{
|
||||||
Box2 gridBounds;
|
Box2 gridBounds;
|
||||||
foreach (var (gridId, tiles) in exp.Tiles)
|
foreach (var (gridId, tiles) in exp.Tiles)
|
||||||
@@ -94,10 +77,10 @@ public sealed class ExplosionOverlay : Overlay
|
|||||||
Box2 gridBounds,
|
Box2 gridBounds,
|
||||||
int index,
|
int index,
|
||||||
Dictionary<int, List<Vector2i>> tileSets,
|
Dictionary<int, List<Vector2i>> tileSets,
|
||||||
Explosion exp,
|
ExplosionVisualsComponent exp,
|
||||||
ushort tileSize)
|
ushort tileSize)
|
||||||
{
|
{
|
||||||
for (var j = 0; j < index; j++)
|
for (var j = 0; j <= index; j++)
|
||||||
{
|
{
|
||||||
if (!tileSets.TryGetValue(j, out var tiles))
|
if (!tileSets.TryGetValue(j, out var tiles))
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
using Content.Shared.CCVar;
|
|
||||||
using Content.Shared.Explosion;
|
using Content.Shared.Explosion;
|
||||||
using Content.Shared.GameTicking;
|
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.ResourceManagement;
|
using Robust.Client.ResourceManagement;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Client.Explosion;
|
namespace Content.Client.Explosion;
|
||||||
@@ -16,12 +13,9 @@ namespace Content.Client.Explosion;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class ExplosionOverlaySystem : EntitySystem
|
public sealed class ExplosionOverlaySystem : EntitySystem
|
||||||
{
|
{
|
||||||
private ExplosionOverlay _overlay = default!;
|
|
||||||
|
|
||||||
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
||||||
[Dependency] private readonly IMapManager _mapMan = default!;
|
|
||||||
[Dependency] private readonly IResourceCache _resCache = default!;
|
[Dependency] private readonly IResourceCache _resCache = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// For how many seconds should an explosion stay on-screen once it has finished expanding?
|
/// For how many seconds should an explosion stay on-screen once it has finished expanding?
|
||||||
@@ -32,209 +26,57 @@ public sealed class ExplosionOverlaySystem : EntitySystem
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeNetworkEvent<ExplosionEvent>(OnExplosion);
|
SubscribeLocalEvent<ExplosionVisualsComponent, ComponentInit>(OnExplosionInit);
|
||||||
SubscribeNetworkEvent<ExplosionOverlayUpdateEvent>(HandleExplosionUpdate);
|
SubscribeLocalEvent<ExplosionVisualsComponent, ComponentRemove>(OnCompRemove);
|
||||||
SubscribeLocalEvent<MapChangedEvent>(OnMapChanged);
|
SubscribeLocalEvent<ExplosionVisualsComponent, ComponentHandleState>(OnExplosionHandleState);
|
||||||
SubscribeAllEvent<RoundRestartCleanupEvent>(OnReset);
|
_overlayMan.AddOverlay(new ExplosionOverlay());
|
||||||
|
|
||||||
_cfg.OnValueChanged(CCVars.ExplosionPersistence, SetExplosionPersistence, true);
|
|
||||||
|
|
||||||
var overlayManager = IoCManager.Resolve<IOverlayManager>();
|
|
||||||
_overlay = new ExplosionOverlay();
|
|
||||||
if (!overlayManager.HasOverlay<ExplosionOverlay>())
|
|
||||||
overlayManager.AddOverlay(_overlay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnReset(RoundRestartCleanupEvent ev)
|
private void OnExplosionHandleState(EntityUid uid, ExplosionVisualsComponent component, ref ComponentHandleState args)
|
||||||
{
|
{
|
||||||
// Not sure if round restart cleans up client-side entities, but better safe than sorry.
|
if (args.Current is not ExplosionVisualsState state)
|
||||||
foreach (var exp in _overlay.CompletedExplosions)
|
return;
|
||||||
{
|
|
||||||
QueueDel(exp.LightEntity);
|
component.Epicenter = state.Epicenter;
|
||||||
}
|
component.SpaceTiles = state.SpaceTiles;
|
||||||
if (_overlay.ActiveExplosion != null)
|
component.Tiles = state.Tiles;
|
||||||
QueueDel(_overlay.ActiveExplosion.LightEntity);
|
component.Intensity = state.Intensity;
|
||||||
|
component.ExplosionType = state.ExplosionType;
|
||||||
_overlay.CompletedExplosions.Clear();
|
component.SpaceMatrix = state.SpaceMatrix;
|
||||||
_overlay.ActiveExplosion = null;
|
component.SpaceTileSize = state.SpaceTileSize;
|
||||||
_overlay.Index = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMapChanged(MapChangedEvent ev)
|
private void OnCompRemove(EntityUid uid, ExplosionVisualsComponent component, ComponentRemove args)
|
||||||
{
|
{
|
||||||
if (ev.Created)
|
QueueDel(component.LightEntity);
|
||||||
return;
|
|
||||||
|
|
||||||
if (_overlay.ActiveExplosion?.Map == ev.Map)
|
|
||||||
_overlay.ActiveExplosion = null;
|
|
||||||
|
|
||||||
_overlay.CompletedExplosions.RemoveAll(exp => exp.Map == ev.Map);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetExplosionPersistence(float value) => ExplosionPersistence = value;
|
private void OnExplosionInit(EntityUid uid, ExplosionVisualsComponent component, ComponentInit args)
|
||||||
|
|
||||||
public override void FrameUpdate(float frameTime)
|
|
||||||
{
|
{
|
||||||
base.FrameUpdate(frameTime);
|
if (!_protoMan.TryIndex(component.ExplosionType, out ExplosionPrototype? type))
|
||||||
|
|
||||||
// increment the lifetime of completed explosions, and remove them if they have been ons screen for more
|
|
||||||
// than ExplosionPersistence seconds
|
|
||||||
for (int i = _overlay.CompletedExplosions.Count - 1; i>= 0; i--)
|
|
||||||
{
|
|
||||||
var explosion = _overlay.CompletedExplosions[i];
|
|
||||||
|
|
||||||
if (_mapMan.IsMapPaused(explosion.Map))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
explosion.Lifetime += frameTime;
|
|
||||||
|
|
||||||
if (explosion.Lifetime >= ExplosionPersistence)
|
|
||||||
{
|
|
||||||
EntityManager.QueueDeleteEntity(explosion.LightEntity);
|
|
||||||
|
|
||||||
// Remove-swap
|
|
||||||
_overlay.CompletedExplosions[i] = _overlay.CompletedExplosions[^1];
|
|
||||||
_overlay.CompletedExplosions.RemoveAt(_overlay.CompletedExplosions.Count - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The server has processed some explosion. This updates the client-side overlay so that the area covered
|
|
||||||
/// by the fire-visual matches up with the area that the explosion has affected.
|
|
||||||
/// </summary>
|
|
||||||
private void HandleExplosionUpdate(ExplosionOverlayUpdateEvent args)
|
|
||||||
{
|
|
||||||
if (args.ExplosionId != _overlay.ActiveExplosion?.Explosionid && !IsNewer(args.ExplosionId))
|
|
||||||
{
|
|
||||||
// out of order events. Ignore.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_overlay.Index = args.Index;
|
|
||||||
|
|
||||||
if (_overlay.ActiveExplosion == null)
|
|
||||||
{
|
|
||||||
// no active explosion... events out of order?
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.Index != int.MaxValue)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// the explosion has finished expanding
|
// spawn in a client-side light source at the epicenter
|
||||||
_overlay.Index = 0;
|
var lightEntity = Spawn("ExplosionLight", component.Epicenter);
|
||||||
_overlay.CompletedExplosions.Add(_overlay.ActiveExplosion);
|
|
||||||
_overlay.ActiveExplosion = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A new explosion occurred. This prepares the client-side light entity and stores the
|
|
||||||
/// explosion/fire-effect overlay data.
|
|
||||||
/// </summary>
|
|
||||||
private void OnExplosion(ExplosionEvent args)
|
|
||||||
{
|
|
||||||
if (!_protoMan.TryIndex(args.TypeID, out ExplosionPrototype? type))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// spawn in a light source at the epicenter
|
|
||||||
var lightEntity = Spawn("ExplosionLight", args.Epicenter);
|
|
||||||
var light = EnsureComp<PointLightComponent>(lightEntity);
|
var light = EnsureComp<PointLightComponent>(lightEntity);
|
||||||
light.Energy = light.Radius = args.Intensity.Count;
|
light.Energy = light.Radius = component.Intensity.Count;
|
||||||
light.Color = type.LightColor;
|
light.Color = type.LightColor;
|
||||||
|
component.LightEntity = lightEntity;
|
||||||
|
component.FireColor = type.FireColor;
|
||||||
|
component.IntensityPerState = type.IntensityPerState;
|
||||||
|
|
||||||
if (_overlay.ActiveExplosion == null)
|
var fireRsi = _resCache.GetResource<RSIResource>(type.TexturePath).RSI;
|
||||||
|
foreach (var state in fireRsi)
|
||||||
{
|
{
|
||||||
_overlay.ActiveExplosion = new(args, type, lightEntity, _resCache);
|
component.FireFrames.Add(state.GetFrames(RSI.State.Direction.South));
|
||||||
return;
|
if (component.FireFrames.Count == type.FireStates)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we have a currently active explosion. Can happen when events are received out of order. either multiple
|
|
||||||
// explosions are happening in one tick, or a new explosion was received before the event telling us the old one
|
|
||||||
// finished got through.
|
|
||||||
|
|
||||||
if (IsNewer(args.ExplosionId))
|
|
||||||
{
|
|
||||||
// This is a newer explosion. Add the old-currently-active explosions to the completed list
|
|
||||||
_overlay.CompletedExplosions.Add(_overlay.ActiveExplosion);
|
|
||||||
_overlay.ActiveExplosion = new(args, type, lightEntity, _resCache);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// explosions were out of order. keep the active one, and directly add the received one to the completed
|
|
||||||
// list.
|
|
||||||
_overlay.CompletedExplosions.Add(new(args, type, lightEntity, _resCache));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsNewer(int explosionId)
|
|
||||||
{
|
|
||||||
if (_overlay.ActiveExplosion == null)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// If we ever get servers stable enough to live this long, the explosion Id int might overflow.
|
|
||||||
return _overlay.ActiveExplosion.Explosionid < explosionId
|
|
||||||
|| _overlay.ActiveExplosion.Explosionid > int.MaxValue/2 && explosionId < int.MinValue/2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Shutdown()
|
public override void Shutdown()
|
||||||
{
|
{
|
||||||
base.Shutdown();
|
base.Shutdown();
|
||||||
|
_overlayMan.RemoveOverlay<ExplosionOverlay>();
|
||||||
_cfg.UnsubValueChanged(CCVars.ExplosionPersistence, SetExplosionPersistence);
|
|
||||||
|
|
||||||
var overlayManager = IoCManager.Resolve<IOverlayManager>();
|
|
||||||
if (overlayManager.HasOverlay<ExplosionOverlay>())
|
|
||||||
overlayManager.RemoveOverlay<ExplosionOverlay>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class Explosion
|
|
||||||
{
|
|
||||||
public readonly Dictionary<int, List<Vector2i>>? SpaceTiles;
|
|
||||||
public readonly Dictionary<EntityUid, Dictionary<int, List<Vector2i>>> Tiles;
|
|
||||||
public readonly List<float> Intensity;
|
|
||||||
public readonly EntityUid LightEntity;
|
|
||||||
public readonly MapId Map;
|
|
||||||
public readonly int Explosionid;
|
|
||||||
public readonly ushort SpaceTileSize;
|
|
||||||
public readonly float IntensityPerState;
|
|
||||||
|
|
||||||
public readonly Matrix3 SpaceMatrix;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How long have we been drawing this explosion, starting from the time the explosion was fully drawn.
|
|
||||||
/// </summary>
|
|
||||||
public float Lifetime;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The textures used for the explosion fire effect. Each fire-state is associated with an explosion
|
|
||||||
/// intensity range, and each stat itself has several textures.
|
|
||||||
/// </summary>
|
|
||||||
public readonly List<Texture[]> FireFrames = new();
|
|
||||||
|
|
||||||
public readonly Color? FireColor;
|
|
||||||
|
|
||||||
internal Explosion(ExplosionEvent args, ExplosionPrototype type, EntityUid lightEntity, IResourceCache resCache)
|
|
||||||
{
|
|
||||||
Map = args.Epicenter.MapId;
|
|
||||||
SpaceTiles = args.SpaceTiles;
|
|
||||||
Tiles = args.Tiles;
|
|
||||||
Intensity = args.Intensity;
|
|
||||||
SpaceMatrix = args.SpaceMatrix;
|
|
||||||
Explosionid = args.ExplosionId;
|
|
||||||
FireColor = type.FireColor;
|
|
||||||
LightEntity = lightEntity;
|
|
||||||
SpaceTileSize = args.SpaceTileSize;
|
|
||||||
IntensityPerState = type.IntensityPerState;
|
|
||||||
|
|
||||||
var fireRsi = resCache.GetResource<RSIResource>(type.TexturePath).RSI;
|
|
||||||
foreach (var state in fireRsi)
|
|
||||||
{
|
|
||||||
FireFrames.Add(state.GetFrames(RSI.State.Direction.South));
|
|
||||||
if (FireFrames.Count == type.FireStates)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
25
Content.Client/Explosion/ExplosionVisualsComponent.cs
Normal file
25
Content.Client/Explosion/ExplosionVisualsComponent.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using Content.Shared.Explosion;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
|
||||||
|
namespace Content.Client.Explosion;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
[ComponentReference(typeof(SharedExplosionVisualsComponent))]
|
||||||
|
public sealed class ExplosionVisualsComponent : SharedExplosionVisualsComponent
|
||||||
|
{
|
||||||
|
public EntityUid LightEntity;
|
||||||
|
/// <summary>
|
||||||
|
/// How long have we been drawing this explosion, starting from the time the explosion was fully drawn.
|
||||||
|
/// </summary>
|
||||||
|
public float Lifetime;
|
||||||
|
|
||||||
|
public float IntensityPerState;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The textures used for the explosion fire effect. Each fire-state is associated with an explosion
|
||||||
|
/// intensity range, and each stat itself has several textures.
|
||||||
|
/// </summary>
|
||||||
|
public List<Texture[]> FireFrames = new();
|
||||||
|
|
||||||
|
public Color? FireColor;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using Content.Shared.Explosion;
|
||||||
|
|
||||||
|
namespace Content.Server.Explosion;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
[ComponentReference(typeof(SharedExplosionVisualsComponent))]
|
||||||
|
public sealed class ExplosionVisualsComponent : SharedExplosionVisualsComponent
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Explosion;
|
using Content.Shared.Explosion;
|
||||||
using Content.Shared.Maps;
|
using Content.Shared.Maps;
|
||||||
using Content.Shared.Physics;
|
using Content.Shared.Physics;
|
||||||
|
using Content.Shared.Spawners.Components;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Map.Components;
|
using Robust.Shared.Map.Components;
|
||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
@@ -15,16 +17,6 @@ namespace Content.Server.Explosion.EntitySystems;
|
|||||||
|
|
||||||
public sealed partial class ExplosionSystem : EntitySystem
|
public sealed partial class ExplosionSystem : EntitySystem
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Used to identify explosions when communicating with the client. Might be needed if more than one explosion is spawned in a single tick.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Overflowing back to 0 should cause no issue, as long as you don't have more than 256 explosions happening in a single tick.
|
|
||||||
/// </remarks>
|
|
||||||
private int _explosionCounter = 0;
|
|
||||||
// maybe should just use a UID/explosion-entity and a state to convey information?
|
|
||||||
// but then need to ignore PVS? Eeehh this works well enough for now.
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to limit explosion processing time. See <see cref="MaxProcessingTime"/>.
|
/// Used to limit explosion processing time. See <see cref="MaxProcessingTime"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -63,6 +55,7 @@ public sealed partial class ExplosionSystem : EntitySystem
|
|||||||
if (_activeExplosion?.Epicenter.MapId != ev.Map)
|
if (_activeExplosion?.Epicenter.MapId != ev.Map)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
QueueDel(_activeExplosion.VisualEnt);
|
||||||
_activeExplosion = null;
|
_activeExplosion = null;
|
||||||
_nodeGroupSystem.PauseUpdating = false;
|
_nodeGroupSystem.PauseUpdating = false;
|
||||||
_pathfindingSystem.PauseUpdating = false;
|
_pathfindingSystem.PauseUpdating = false;
|
||||||
@@ -103,7 +96,6 @@ public sealed partial class ExplosionSystem : EntitySystem
|
|||||||
if (_activeExplosion == null)
|
if (_activeExplosion == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_explosionCounter++;
|
|
||||||
_previousTileIteration = 0;
|
_previousTileIteration = 0;
|
||||||
|
|
||||||
// just a lil nap
|
// just a lil nap
|
||||||
@@ -131,14 +123,20 @@ public sealed partial class ExplosionSystem : EntitySystem
|
|||||||
|
|
||||||
// has the explosion finished processing?
|
// has the explosion finished processing?
|
||||||
if (_activeExplosion.FinishedProcessing)
|
if (_activeExplosion.FinishedProcessing)
|
||||||
_activeExplosion = null;
|
{
|
||||||
|
var comp = EnsureComp<TimedDespawnComponent>(_activeExplosion.VisualEnt);
|
||||||
|
comp.Lifetime = _cfg.GetCVar(CCVars.ExplosionPersistence);
|
||||||
|
_appearance.SetData(_activeExplosion.VisualEnt, ExplosionAppearanceData.Progress, int.MaxValue);
|
||||||
|
_activeExplosion = null;
|
||||||
|
}
|
||||||
#if EXCEPTION_TOLERANCE
|
#if EXCEPTION_TOLERANCE
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
// Ensure the system does not get stuck in an error-loop.
|
// Ensure the system does not get stuck in an error-loop.
|
||||||
|
if (_activeExplosion != null)
|
||||||
|
QueueDel(_activeExplosion.VisualEnt);
|
||||||
_activeExplosion = null;
|
_activeExplosion = null;
|
||||||
RaiseNetworkEvent(new ExplosionOverlayUpdateEvent(_explosionCounter, int.MaxValue));
|
|
||||||
_nodeGroupSystem.PauseUpdating = false;
|
_nodeGroupSystem.PauseUpdating = false;
|
||||||
_pathfindingSystem.PauseUpdating = false;
|
_pathfindingSystem.PauseUpdating = false;
|
||||||
throw;
|
throw;
|
||||||
@@ -151,21 +149,13 @@ public sealed partial class ExplosionSystem : EntitySystem
|
|||||||
// we have finished processing our tiles. Is there still an ongoing explosion?
|
// we have finished processing our tiles. Is there still an ongoing explosion?
|
||||||
if (_activeExplosion != null)
|
if (_activeExplosion != null)
|
||||||
{
|
{
|
||||||
// update the client explosion overlays. This ensures that the fire-effects sync up with the entities currently being damaged.
|
_appearance.SetData(_activeExplosion.VisualEnt, ExplosionAppearanceData.Progress, _activeExplosion.CurrentIteration + 1);
|
||||||
if (_previousTileIteration == _activeExplosion.CurrentIteration)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_previousTileIteration = _activeExplosion.CurrentIteration;
|
|
||||||
RaiseNetworkEvent(new ExplosionOverlayUpdateEvent(_explosionCounter, _previousTileIteration + 1));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_explosionQueue.Count > 0)
|
if (_explosionQueue.Count > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// We have finished processing all explosions. Clear client explosion overlays
|
|
||||||
RaiseNetworkEvent(new ExplosionOverlayUpdateEvent(_explosionCounter, int.MaxValue));
|
|
||||||
|
|
||||||
//wakey wakey
|
//wakey wakey
|
||||||
_nodeGroupSystem.PauseUpdating = false;
|
_nodeGroupSystem.PauseUpdating = false;
|
||||||
_pathfindingSystem.PauseUpdating = false;
|
_pathfindingSystem.PauseUpdating = false;
|
||||||
@@ -586,6 +576,8 @@ sealed class Explosion
|
|||||||
private readonly IEntityManager _entMan;
|
private readonly IEntityManager _entMan;
|
||||||
private readonly ExplosionSystem _system;
|
private readonly ExplosionSystem _system;
|
||||||
|
|
||||||
|
public readonly EntityUid VisualEnt;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize a new instance for processing
|
/// Initialize a new instance for processing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -601,8 +593,10 @@ sealed class Explosion
|
|||||||
int maxTileBreak,
|
int maxTileBreak,
|
||||||
bool canCreateVacuum,
|
bool canCreateVacuum,
|
||||||
IEntityManager entMan,
|
IEntityManager entMan,
|
||||||
IMapManager mapMan)
|
IMapManager mapMan,
|
||||||
|
EntityUid visualEnt)
|
||||||
{
|
{
|
||||||
|
VisualEnt = visualEnt;
|
||||||
_system = system;
|
_system = system;
|
||||||
ExplosionType = explosionType;
|
ExplosionType = explosionType;
|
||||||
_tileSetIntensity = tileSetIntensity;
|
_tileSetIntensity = tileSetIntensity;
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ public sealed partial class ExplosionSystem : EntitySystem
|
|||||||
return (grids, referenceGrid, radius);
|
return (grids, referenceGrid, radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExplosionEvent? GenerateExplosionPreview(SpawnExplosionEuiMsg.PreviewRequest request)
|
public ExplosionVisualsState? GenerateExplosionPreview(SpawnExplosionEuiMsg.PreviewRequest request)
|
||||||
{
|
{
|
||||||
var stopwatch = new Stopwatch();
|
var stopwatch = new Stopwatch();
|
||||||
stopwatch.Start();
|
stopwatch.Start();
|
||||||
@@ -332,7 +332,19 @@ public sealed partial class ExplosionSystem : EntitySystem
|
|||||||
|
|
||||||
Logger.Info($"Generated explosion preview with {area} tiles in {stopwatch.Elapsed.TotalMilliseconds}ms");
|
Logger.Info($"Generated explosion preview with {area} tiles in {stopwatch.Elapsed.TotalMilliseconds}ms");
|
||||||
|
|
||||||
// the explosion event that **would** be sent to all clients, if it were a real explosion.
|
Dictionary<EntityUid, Dictionary<int, List<Vector2i>>> tileLists = new();
|
||||||
return GetExplosionEvent(request.Epicenter, request.TypeId, spaceMatrix, spaceData, gridData.Values, iterationIntensity);
|
foreach (var (grid, data) in gridData)
|
||||||
|
{
|
||||||
|
tileLists.Add(grid, data.TileLists);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ExplosionVisualsState(
|
||||||
|
request.Epicenter,
|
||||||
|
request.TypeId,
|
||||||
|
iterationIntensity,
|
||||||
|
spaceData?.TileLists,
|
||||||
|
tileLists, spaceMatrix,
|
||||||
|
spaceData?.TileSize ?? DefaultTileSize
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using Content.Shared.Explosion;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
|
namespace Content.Server.Explosion.EntitySystems;
|
||||||
|
|
||||||
|
// This part of the system handled send visual / overlay data to clients.
|
||||||
|
public sealed partial class ExplosionSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public void InitVisuals()
|
||||||
|
{
|
||||||
|
SubscribeLocalEvent<ExplosionVisualsComponent, ComponentGetState>(OnGetState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGetState(EntityUid uid, ExplosionVisualsComponent component, ref ComponentGetState args)
|
||||||
|
{
|
||||||
|
args.State = new ExplosionVisualsState(
|
||||||
|
component.Epicenter,
|
||||||
|
component.ExplosionType,
|
||||||
|
component.Intensity,
|
||||||
|
component.SpaceTiles,
|
||||||
|
component.Tiles,
|
||||||
|
component.SpaceMatrix,
|
||||||
|
component.SpaceTileSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor for the shared <see cref="ExplosionEvent"/> using the server-exclusive explosion classes.
|
||||||
|
/// </summary>
|
||||||
|
private EntityUid CreateExplosionVisualEntity(MapCoordinates epicenter, string prototype, Matrix3 spaceMatrix, ExplosionSpaceTileFlood? spaceData, IEnumerable<ExplosionGridTileFlood> gridData, List<float> iterationIntensity)
|
||||||
|
{
|
||||||
|
var explosionEntity = Spawn(null, MapCoordinates.Nullspace);
|
||||||
|
var comp = AddComp<ExplosionVisualsComponent>(explosionEntity);
|
||||||
|
|
||||||
|
foreach (var grid in gridData)
|
||||||
|
{
|
||||||
|
comp.Tiles.Add(grid.Grid.Owner, grid.TileLists);
|
||||||
|
}
|
||||||
|
|
||||||
|
comp.SpaceTiles = spaceData?.TileLists;
|
||||||
|
comp.Epicenter = epicenter;
|
||||||
|
comp.ExplosionType = prototype;
|
||||||
|
comp.Intensity = iterationIntensity;
|
||||||
|
comp.SpaceMatrix = spaceMatrix;
|
||||||
|
comp.SpaceTileSize = spaceData?.TileSize ?? DefaultTileSize;
|
||||||
|
Dirty(comp);
|
||||||
|
|
||||||
|
// Light, sound & visuals may extend well beyond normal PVS range. In principle, this should probably still be
|
||||||
|
// restricted to something like the same map, but whatever.
|
||||||
|
_pvsSys.AddGlobalOverride(explosionEntity);
|
||||||
|
|
||||||
|
var appearance = AddComp<ServerAppearanceComponent>(explosionEntity);
|
||||||
|
_appearance.SetData(explosionEntity, ExplosionAppearanceData.Progress, 1, appearance);
|
||||||
|
|
||||||
|
return explosionEntity;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ using Content.Shared.Explosion;
|
|||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
|
using Robust.Server.GameStates;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
@@ -31,12 +32,14 @@ public sealed partial class ExplosionSystem : EntitySystem
|
|||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
|
||||||
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||||
[Dependency] private readonly NodeGroupSystem _nodeGroupSystem = default!;
|
[Dependency] private readonly NodeGroupSystem _nodeGroupSystem = default!;
|
||||||
[Dependency] private readonly PathfindingSystem _pathfindingSystem = default!;
|
[Dependency] private readonly PathfindingSystem _pathfindingSystem = default!;
|
||||||
[Dependency] private readonly SharedCameraRecoilSystem _recoilSystem = default!;
|
[Dependency] private readonly SharedCameraRecoilSystem _recoilSystem = default!;
|
||||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||||
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
|
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
|
||||||
|
[Dependency] private readonly PVSOverrideSystem _pvsSys = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -81,11 +84,14 @@ public sealed partial class ExplosionSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<AirtightComponent, DamageChangedEvent>(OnAirtightDamaged);
|
SubscribeLocalEvent<AirtightComponent, DamageChangedEvent>(OnAirtightDamaged);
|
||||||
SubscribeCvars();
|
SubscribeCvars();
|
||||||
InitAirtightMap();
|
InitAirtightMap();
|
||||||
|
InitVisuals();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnReset(RoundRestartCleanupEvent ev)
|
private void OnReset(RoundRestartCleanupEvent ev)
|
||||||
{
|
{
|
||||||
_explosionQueue.Clear();
|
_explosionQueue.Clear();
|
||||||
|
if (_activeExplosion !=null)
|
||||||
|
QueueDel(_activeExplosion.VisualEnt);
|
||||||
_activeExplosion = null;
|
_activeExplosion = null;
|
||||||
_nodeGroupSystem.PauseUpdating = false;
|
_nodeGroupSystem.PauseUpdating = false;
|
||||||
_pathfindingSystem.PauseUpdating = false;
|
_pathfindingSystem.PauseUpdating = false;
|
||||||
@@ -281,7 +287,7 @@ public sealed partial class ExplosionSystem : EntitySystem
|
|||||||
|
|
||||||
var (area, iterationIntensity, spaceData, gridData, spaceMatrix) = results.Value;
|
var (area, iterationIntensity, spaceData, gridData, spaceMatrix) = results.Value;
|
||||||
|
|
||||||
RaiseNetworkEvent(GetExplosionEvent(epicenter, type.ID, spaceMatrix, spaceData, gridData.Values, iterationIntensity));
|
var visualEnt = CreateExplosionVisualEntity(epicenter, type.ID, spaceMatrix, spaceData, gridData.Values, iterationIntensity);
|
||||||
|
|
||||||
// camera shake
|
// camera shake
|
||||||
CameraShake(iterationIntensity.Count * 2.5f, epicenter, totalIntensity);
|
CameraShake(iterationIntensity.Count * 2.5f, epicenter, totalIntensity);
|
||||||
@@ -306,23 +312,8 @@ public sealed partial class ExplosionSystem : EntitySystem
|
|||||||
maxTileBreak,
|
maxTileBreak,
|
||||||
canCreateVacuum,
|
canCreateVacuum,
|
||||||
EntityManager,
|
EntityManager,
|
||||||
_mapManager);
|
_mapManager,
|
||||||
}
|
visualEnt);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructor for the shared <see cref="ExplosionEvent"/> using the server-exclusive explosion classes.
|
|
||||||
/// </summary>
|
|
||||||
internal ExplosionEvent GetExplosionEvent(MapCoordinates epicenter, string id, Matrix3 spaceMatrix, ExplosionSpaceTileFlood? spaceData, IEnumerable<ExplosionGridTileFlood> gridData, List<float> iterationIntensity)
|
|
||||||
{
|
|
||||||
var spaceTiles = spaceData?.TileLists;
|
|
||||||
|
|
||||||
Dictionary<EntityUid, Dictionary<int, List<Vector2i>>> tileLists = new();
|
|
||||||
foreach (var grid in gridData)
|
|
||||||
{
|
|
||||||
tileLists.Add(grid.Grid.Owner, grid.TileLists);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ExplosionEvent(_explosionCounter, epicenter, id, iterationIntensity, spaceTiles, tileLists, spaceMatrix, spaceData?.TileSize ?? DefaultTileSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CameraShake(float range, MapCoordinates epicenter, float totalIntensity)
|
private void CameraShake(float range, MapCoordinates epicenter, float totalIntensity)
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ public static class SpawnExplosionEuiMsg
|
|||||||
{
|
{
|
||||||
public readonly float Slope;
|
public readonly float Slope;
|
||||||
public readonly float TotalIntensity;
|
public readonly float TotalIntensity;
|
||||||
public readonly ExplosionEvent Explosion;
|
public readonly ExplosionVisualsState Explosion;
|
||||||
|
|
||||||
public PreviewData(ExplosionEvent explosion, float slope, float totalIntensity)
|
public PreviewData(ExplosionVisualsState explosion, float slope, float totalIntensity)
|
||||||
{
|
{
|
||||||
Slope = slope;
|
Slope = slope;
|
||||||
TotalIntensity = totalIntensity;
|
TotalIntensity = totalIntensity;
|
||||||
|
|||||||
@@ -630,11 +630,10 @@ namespace Content.Shared.CCVar
|
|||||||
CVarDef.Create("explosion.incremental_tile", false, CVar.SERVERONLY);
|
CVarDef.Create("explosion.incremental_tile", false, CVar.SERVERONLY);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Client-side explosion visuals: for how many seconds should an explosion stay on-screen once it has
|
/// This determines for how many seconds an explosion should stay visible once it has finished expanding.
|
||||||
/// finished expanding?
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly CVarDef<float> ExplosionPersistence =
|
public static readonly CVarDef<float> ExplosionPersistence =
|
||||||
CVarDef.Create("explosion.persistence", 0.3f, CVar.REPLICATED);
|
CVarDef.Create("explosion.persistence", 0.3f, CVar.SERVERONLY);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If an explosion covers a larger area than this number, the damaging/processing will always start during
|
/// If an explosion covers a larger area than this number, the damaging/processing will always start during
|
||||||
|
|||||||
@@ -24,61 +24,3 @@ public sealed class GetExplosionResistanceEvent : EntityEventArgs, IInventoryRel
|
|||||||
ExplotionPrototype = id;
|
ExplotionPrototype = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An explosion event. Used for client side rendering.
|
|
||||||
/// </summary>
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class ExplosionEvent : EntityEventArgs
|
|
||||||
{
|
|
||||||
public MapCoordinates Epicenter;
|
|
||||||
|
|
||||||
public Dictionary<int, List<Vector2i>>? SpaceTiles;
|
|
||||||
public Dictionary<EntityUid, Dictionary<int, List<Vector2i>>> Tiles;
|
|
||||||
|
|
||||||
public List<float> Intensity;
|
|
||||||
|
|
||||||
public string TypeID;
|
|
||||||
|
|
||||||
public Matrix3 SpaceMatrix;
|
|
||||||
|
|
||||||
public int ExplosionId;
|
|
||||||
|
|
||||||
public ushort SpaceTileSize;
|
|
||||||
|
|
||||||
public ExplosionEvent(
|
|
||||||
int explosionId,
|
|
||||||
MapCoordinates epicenter,
|
|
||||||
string typeID,
|
|
||||||
List<float> intensity,
|
|
||||||
Dictionary<int, List<Vector2i>>? spaceTiles,
|
|
||||||
Dictionary<EntityUid, Dictionary<int, List<Vector2i>>> tiles,
|
|
||||||
Matrix3 spaceMatrix,
|
|
||||||
ushort spaceTileSize)
|
|
||||||
{
|
|
||||||
Epicenter = epicenter;
|
|
||||||
SpaceTiles = spaceTiles;
|
|
||||||
Tiles = tiles;
|
|
||||||
Intensity = intensity;
|
|
||||||
TypeID = typeID;
|
|
||||||
SpaceMatrix = spaceMatrix;
|
|
||||||
ExplosionId = explosionId;
|
|
||||||
SpaceTileSize = spaceTileSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update visual rendering of the explosion to correspond to the servers processing of it.
|
|
||||||
/// </summary>
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class ExplosionOverlayUpdateEvent : EntityEventArgs
|
|
||||||
{
|
|
||||||
public int Index;
|
|
||||||
public int ExplosionId;
|
|
||||||
|
|
||||||
public ExplosionOverlayUpdateEvent(int explosionId, int index)
|
|
||||||
{
|
|
||||||
Index = index;
|
|
||||||
ExplosionId = explosionId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
56
Content.Shared/Explosion/SharedExplosionVisualsComponent.cs
Normal file
56
Content.Shared/Explosion/SharedExplosionVisualsComponent.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Explosion;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Component that is used to send explosion overlay/visual data to an abstract explosion entity.
|
||||||
|
/// </summary>
|
||||||
|
[NetworkedComponent]
|
||||||
|
public abstract class SharedExplosionVisualsComponent : Component
|
||||||
|
{
|
||||||
|
public MapCoordinates Epicenter;
|
||||||
|
public Dictionary<int, List<Vector2i>>? SpaceTiles;
|
||||||
|
public Dictionary<EntityUid, Dictionary<int, List<Vector2i>>> Tiles = new();
|
||||||
|
public List<float> Intensity = new();
|
||||||
|
public string ExplosionType = string.Empty;
|
||||||
|
public Matrix3 SpaceMatrix;
|
||||||
|
public ushort SpaceTileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class ExplosionVisualsState : ComponentState
|
||||||
|
{
|
||||||
|
public MapCoordinates Epicenter;
|
||||||
|
public Dictionary<int, List<Vector2i>>? SpaceTiles;
|
||||||
|
public Dictionary<EntityUid, Dictionary<int, List<Vector2i>>> Tiles;
|
||||||
|
public List<float> Intensity;
|
||||||
|
public string ExplosionType = string.Empty;
|
||||||
|
public Matrix3 SpaceMatrix;
|
||||||
|
public ushort SpaceTileSize;
|
||||||
|
|
||||||
|
public ExplosionVisualsState(
|
||||||
|
MapCoordinates epicenter,
|
||||||
|
string typeID,
|
||||||
|
List<float> intensity,
|
||||||
|
Dictionary<int, List<Vector2i>>? spaceTiles,
|
||||||
|
Dictionary<EntityUid, Dictionary<int, List<Vector2i>>> tiles,
|
||||||
|
Matrix3 spaceMatrix,
|
||||||
|
ushort spaceTileSize)
|
||||||
|
{
|
||||||
|
Epicenter = epicenter;
|
||||||
|
SpaceTiles = spaceTiles;
|
||||||
|
Tiles = tiles;
|
||||||
|
Intensity = intensity;
|
||||||
|
ExplosionType = typeID;
|
||||||
|
SpaceMatrix = spaceMatrix;
|
||||||
|
SpaceTileSize = spaceTileSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum ExplosionAppearanceData
|
||||||
|
{
|
||||||
|
Progress, // iteration index tracker for explosions that are still expanding outwards,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user