Files
tbd-station-14/Content.Server/Atmos/EntitySystems/AirtightSystem.cs
Leon Friedrich 56168e592e Explosion refactor (#5230)
* Explosions

* fix yaml typo

and prevent silly UI inputs

* oop

* Use modified contains() checks

And remove IEnumerable

* Buff nuke, nerf meteors

* optimize the entity lookup stuff a bit

* fix tile (0,0) error

forgot to do an initial Enumerator.MoveNext(), so the first tile was always the "null" tile.

* remove celebration

* byte -> int

* remove diag edge tile dict

* fix one bug

but there is another

* fix the other bug

turns out dividing a ushort leads to rounding errors.  Why TF is the grid tile size even a ushort in the first place.

* improve edge map

* fix minor bug

If the initial-explosion tile had an airtight entity on it, the tile was processed twice.

* some reviews (transform queries, eye.mapid, and tilesizes in overlays)

* Apply suggestions from code review

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>

* is map paused

* GetAllTiles ignores space by default

* WriteLine -> WriteError

* First -> FirstOrDefault()

* default prototype const string

* entity query

* misc review changes

* grid edge max distance

* fix fire texture defn

bad use of type serializer and ioc-resolves

* Remove ExplosionLaunched

And allow nukes to throw items towards the outer part of an explosion

* no hot-reload disclaimer

* replace prototype id string with int index

* optimise damage a tiiiiny bit.

* entity queries

* comments

* misc mirror comments

* cvars

* admin logs

* move intensity-per-state to prototype

* update tile event to ECS event

* git mv

* Tweak rpg & minibomb

also fix merge bug

* you don't exist anymore go away

* Fix build

Co-authored-by: moonheart08 <moonheart08@users.noreply.github.com>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
2022-03-31 21:39:26 -05:00

150 lines
5.6 KiB
C#

using Content.Server.Atmos.Components;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Kudzu;
using Content.Shared.Atmos;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
namespace Content.Server.Atmos.EntitySystems
{
[UsedImplicitly]
public sealed class AirtightSystem : EntitySystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly ExplosionSystem _explosionSystem = default!;
public override void Initialize()
{
SubscribeLocalEvent<AirtightComponent, ComponentInit>(OnAirtightInit);
SubscribeLocalEvent<AirtightComponent, ComponentShutdown>(OnAirtightShutdown);
SubscribeLocalEvent<AirtightComponent, AnchorStateChangedEvent>(OnAirtightPositionChanged);
SubscribeLocalEvent<AirtightComponent, RotateEvent>(OnAirtightRotated);
}
private void OnAirtightInit(EntityUid uid, AirtightComponent airtight, ComponentInit args)
{
var xform = EntityManager.GetComponent<TransformComponent>(uid);
if (airtight.FixAirBlockedDirectionInitialize)
{
var rotateEvent = new RotateEvent(airtight.Owner, Angle.Zero, xform.WorldRotation, xform);
OnAirtightRotated(uid, airtight, ref rotateEvent);
}
// Adding this component will immediately anchor the entity, because the atmos system
// requires airtight entities to be anchored for performance.
xform.Anchored = true;
UpdatePosition(airtight);
}
private void OnAirtightShutdown(EntityUid uid, AirtightComponent airtight, ComponentShutdown args)
{
var xform = Transform(uid);
// If the grid is deleting no point updating atmos.
if (_mapManager.TryGetGrid(xform.GridID, out var grid))
{
if (MetaData(grid.GridEntityId).EntityLifeStage > EntityLifeStage.MapInitialized) return;
}
SetAirblocked(airtight, false, xform);
}
private void OnAirtightPositionChanged(EntityUid uid, AirtightComponent airtight, ref AnchorStateChangedEvent args)
{
var xform = EntityManager.GetComponent<TransformComponent>(uid);
var gridId = xform.GridID;
var coords = xform.Coordinates;
var grid = _mapManager.GetGrid(gridId);
var tilePos = grid.TileIndicesFor(coords);
// Update and invalidate new position.
airtight.LastPosition = (gridId, tilePos);
InvalidatePosition(gridId, tilePos);
}
private void OnAirtightRotated(EntityUid uid, AirtightComponent airtight, ref RotateEvent ev)
{
if (!airtight.RotateAirBlocked || airtight.InitialAirBlockedDirection == (int)AtmosDirection.Invalid)
return;
airtight.CurrentAirBlockedDirection = (int) Rotate((AtmosDirection)airtight.InitialAirBlockedDirection, ev.NewRotation);
UpdatePosition(airtight);
RaiseLocalEvent(uid, new AirtightChanged(airtight));
}
public void SetAirblocked(AirtightComponent airtight, bool airblocked, TransformComponent? xform = null)
{
if (!Resolve(airtight.Owner, ref xform)) return;
airtight.AirBlocked = airblocked;
UpdatePosition(airtight, xform);
RaiseLocalEvent(airtight.Owner, new AirtightChanged(airtight));
}
public void UpdatePosition(AirtightComponent airtight, TransformComponent? xform = null)
{
if (!Resolve(airtight.Owner, ref xform)) return;
if (!xform.Anchored || !xform.GridID.IsValid())
return;
var grid = _mapManager.GetGrid(xform.GridID);
airtight.LastPosition = (xform.GridID, grid.TileIndicesFor(xform.Coordinates));
InvalidatePosition(airtight.LastPosition.Item1, airtight.LastPosition.Item2, airtight.FixVacuum && !airtight.AirBlocked);
}
public void InvalidatePosition(GridId gridId, Vector2i pos, bool fixVacuum = false)
{
if (!gridId.IsValid())
return;
var query = EntityManager.GetEntityQuery<AirtightComponent>();
_explosionSystem.UpdateAirtightMap(gridId, pos, query);
// TODO make atmos system use query
_atmosphereSystem.UpdateAdjacent(gridId, pos);
_atmosphereSystem.InvalidateTile(gridId, pos);
if(fixVacuum)
_atmosphereSystem.FixVacuum(gridId, pos);
}
private AtmosDirection Rotate(AtmosDirection myDirection, Angle myAngle)
{
var newAirBlockedDirs = AtmosDirection.Invalid;
if (myAngle == Angle.Zero)
return myDirection;
// TODO ATMOS MULTIZ: When we make multiZ atmos, special case this.
for (var i = 0; i < Atmospherics.Directions; i++)
{
var direction = (AtmosDirection) (1 << i);
if (!myDirection.IsFlagSet(direction)) continue;
var angle = direction.ToAngle();
angle += myAngle;
newAirBlockedDirs |= angle.ToAtmosDirectionCardinal();
}
return newAirBlockedDirs;
}
}
public sealed class AirtightChanged : EntityEventArgs
{
public AirtightComponent Airtight;
public AirtightChanged(AirtightComponent airtight)
{
Airtight = airtight;
}
}
}