Remove explosion networking jank (#12733)

This commit is contained in:
Leon Friedrich
2022-11-27 23:24:35 +13:00
committed by GitHub
parent 85ce28c0a2
commit 2dc7663d1a
12 changed files with 237 additions and 326 deletions

View File

@@ -1,8 +1,10 @@
using System.Linq;
using Content.Shared.CCVar;
using Content.Shared.Damage;
using Content.Shared.Explosion;
using Content.Shared.Maps;
using Content.Shared.Physics;
using Content.Shared.Spawners.Components;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics;
@@ -15,16 +17,6 @@ namespace Content.Server.Explosion.EntitySystems;
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>
/// Used to limit explosion processing time. See <see cref="MaxProcessingTime"/>.
/// </summary>
@@ -63,6 +55,7 @@ public sealed partial class ExplosionSystem : EntitySystem
if (_activeExplosion?.Epicenter.MapId != ev.Map)
return;
QueueDel(_activeExplosion.VisualEnt);
_activeExplosion = null;
_nodeGroupSystem.PauseUpdating = false;
_pathfindingSystem.PauseUpdating = false;
@@ -103,7 +96,6 @@ public sealed partial class ExplosionSystem : EntitySystem
if (_activeExplosion == null)
continue;
_explosionCounter++;
_previousTileIteration = 0;
// just a lil nap
@@ -131,14 +123,20 @@ public sealed partial class ExplosionSystem : EntitySystem
// has the explosion finished processing?
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
}
catch (Exception e)
{
// Ensure the system does not get stuck in an error-loop.
if (_activeExplosion != null)
QueueDel(_activeExplosion.VisualEnt);
_activeExplosion = null;
RaiseNetworkEvent(new ExplosionOverlayUpdateEvent(_explosionCounter, int.MaxValue));
_nodeGroupSystem.PauseUpdating = false;
_pathfindingSystem.PauseUpdating = false;
throw;
@@ -151,21 +149,13 @@ public sealed partial class ExplosionSystem : EntitySystem
// we have finished processing our tiles. Is there still an ongoing explosion?
if (_activeExplosion != null)
{
// update the client explosion overlays. This ensures that the fire-effects sync up with the entities currently being damaged.
if (_previousTileIteration == _activeExplosion.CurrentIteration)
return;
_previousTileIteration = _activeExplosion.CurrentIteration;
RaiseNetworkEvent(new ExplosionOverlayUpdateEvent(_explosionCounter, _previousTileIteration + 1));
_appearance.SetData(_activeExplosion.VisualEnt, ExplosionAppearanceData.Progress, _activeExplosion.CurrentIteration + 1);
return;
}
if (_explosionQueue.Count > 0)
return;
// We have finished processing all explosions. Clear client explosion overlays
RaiseNetworkEvent(new ExplosionOverlayUpdateEvent(_explosionCounter, int.MaxValue));
//wakey wakey
_nodeGroupSystem.PauseUpdating = false;
_pathfindingSystem.PauseUpdating = false;
@@ -586,6 +576,8 @@ sealed class Explosion
private readonly IEntityManager _entMan;
private readonly ExplosionSystem _system;
public readonly EntityUid VisualEnt;
/// <summary>
/// Initialize a new instance for processing
/// </summary>
@@ -601,8 +593,10 @@ sealed class Explosion
int maxTileBreak,
bool canCreateVacuum,
IEntityManager entMan,
IMapManager mapMan)
IMapManager mapMan,
EntityUid visualEnt)
{
VisualEnt = visualEnt;
_system = system;
ExplosionType = explosionType;
_tileSetIntensity = tileSetIntensity;

View File

@@ -313,7 +313,7 @@ public sealed partial class ExplosionSystem : EntitySystem
return (grids, referenceGrid, radius);
}
public ExplosionEvent? GenerateExplosionPreview(SpawnExplosionEuiMsg.PreviewRequest request)
public ExplosionVisualsState? GenerateExplosionPreview(SpawnExplosionEuiMsg.PreviewRequest request)
{
var stopwatch = new Stopwatch();
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");
// the explosion event that **would** be sent to all clients, if it were a real explosion.
return GetExplosionEvent(request.Epicenter, request.TypeId, spaceMatrix, spaceData, gridData.Values, iterationIntensity);
Dictionary<EntityUid, Dictionary<int, List<Vector2i>>> tileLists = new();
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
);
}
}

View File

@@ -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;
}
}

View File

@@ -11,6 +11,7 @@ using Content.Shared.Explosion;
using Content.Shared.GameTicking;
using Content.Shared.Inventory;
using Content.Shared.Throwing;
using Robust.Server.GameStates;
using Robust.Server.Player;
using Robust.Shared.Audio;
using Robust.Shared.Configuration;
@@ -31,12 +32,14 @@ public sealed partial class ExplosionSystem : EntitySystem
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly NodeGroupSystem _nodeGroupSystem = default!;
[Dependency] private readonly PathfindingSystem _pathfindingSystem = default!;
[Dependency] private readonly SharedCameraRecoilSystem _recoilSystem = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
[Dependency] private readonly PVSOverrideSystem _pvsSys = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
/// <summary>
@@ -81,11 +84,14 @@ public sealed partial class ExplosionSystem : EntitySystem
SubscribeLocalEvent<AirtightComponent, DamageChangedEvent>(OnAirtightDamaged);
SubscribeCvars();
InitAirtightMap();
InitVisuals();
}
private void OnReset(RoundRestartCleanupEvent ev)
{
_explosionQueue.Clear();
if (_activeExplosion !=null)
QueueDel(_activeExplosion.VisualEnt);
_activeExplosion = null;
_nodeGroupSystem.PauseUpdating = false;
_pathfindingSystem.PauseUpdating = false;
@@ -281,7 +287,7 @@ public sealed partial class ExplosionSystem : EntitySystem
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
CameraShake(iterationIntensity.Count * 2.5f, epicenter, totalIntensity);
@@ -306,23 +312,8 @@ public sealed partial class ExplosionSystem : EntitySystem
maxTileBreak,
canCreateVacuum,
EntityManager,
_mapManager);
}
/// <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);
_mapManager,
visualEnt);
}
private void CameraShake(float range, MapCoordinates epicenter, float totalIntensity)