diff --git a/Content.Server/Singularity/EntitySystems/ContainmentFieldGeneratorSystem.cs b/Content.Server/Singularity/EntitySystems/ContainmentFieldGeneratorSystem.cs
index 8e89fda9ec..ac21342376 100644
--- a/Content.Server/Singularity/EntitySystems/ContainmentFieldGeneratorSystem.cs
+++ b/Content.Server/Singularity/EntitySystems/ContainmentFieldGeneratorSystem.cs
@@ -390,11 +390,11 @@ public sealed class ContainmentFieldGeneratorSystem : EntitySystem
/// The entity the singularity is trying to eat.
/// The containment field generator the singularity is trying to eat.
/// The event arguments.
- private void PreventBreach(EntityUid uid, ContainmentFieldGeneratorComponent comp, EventHorizonAttemptConsumeEntityEvent args)
+ private void PreventBreach(EntityUid uid, ContainmentFieldGeneratorComponent comp, ref EventHorizonAttemptConsumeEntityEvent args)
{
if (args.Cancelled)
return;
if (comp.IsConnected && !args.EventHorizon.CanBreachContainment)
- args.Cancel();
+ args.Cancelled = true;
}
}
diff --git a/Content.Server/Singularity/EntitySystems/ContainmentFieldSystem.cs b/Content.Server/Singularity/EntitySystems/ContainmentFieldSystem.cs
index c03ea25b7c..70cc992dc3 100644
--- a/Content.Server/Singularity/EntitySystems/ContainmentFieldSystem.cs
+++ b/Content.Server/Singularity/EntitySystems/ContainmentFieldSystem.cs
@@ -41,9 +41,9 @@ public sealed class ContainmentFieldSystem : EntitySystem
}
}
- private void HandleEventHorizon(EntityUid uid, ContainmentFieldComponent component, EventHorizonAttemptConsumeEntityEvent args)
+ private void HandleEventHorizon(EntityUid uid, ContainmentFieldComponent component, ref EventHorizonAttemptConsumeEntityEvent args)
{
if(!args.Cancelled && !args.EventHorizon.CanBreachContainment)
- args.Cancel();
+ args.Cancelled = true;
}
}
diff --git a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs
index ceaf6acaae..312ac5739d 100644
--- a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs
+++ b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs
@@ -1,21 +1,19 @@
-using System.Numerics;
using Content.Server.Administration.Logs;
+using Content.Server.Ghost.Components;
+using Content.Server.Mind.Components;
+using Content.Server.Station.Components;
+using Content.Server.Singularity.Events;
+using Content.Shared.Database;
+using Content.Shared.Singularity.Components;
+using Content.Shared.Singularity.EntitySystems;
+using Content.Shared.Tag;
using Robust.Shared.Containers;
using Robust.Shared.Timing;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Events;
+using System.Numerics;
-using Content.Shared.Singularity.Components;
-using Content.Shared.Singularity.EntitySystems;
-
-using Content.Server.Ghost.Components;
-using Content.Server.Mind.Components;
-using Content.Server.Station.Components;
-using Content.Server.Singularity.Components;
-using Content.Server.Singularity.Events;
-using Content.Shared.Database;
-using Content.Shared.Tag;
namespace Content.Server.Singularity.EntitySystems;
@@ -25,24 +23,15 @@ namespace Content.Server.Singularity.EntitySystems;
///
public sealed class EventHorizonSystem : SharedEventHorizonSystem
{
-#region Dependencies
+ #region Dependencies
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IMapManager _mapMan = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
+ [Dependency] private readonly SharedTransformSystem _xformSystem = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
-#endregion Dependencies
-
- ///
- /// The maximum number of nested containers an event horizon is allowed to eat through in an attempt to get to the map.
- ///
- private const int MaxEventHorizonUnnestingIterations = 100;
-
- ///
- /// The maximum number of nested containers an immune entity in a container being consumed by an event horizon is allowed to search through before it gives up and just jumps to the map.
- ///
- private const int MaxEventHorizonDumpSearchIterations = 100;
+ #endregion Dependencies
public override void Initialize()
{
@@ -74,99 +63,88 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
/// Updates the cooldowns of all event horizons.
/// If an event horizon are off cooldown this makes it consume everything within range and resets their cooldown.
///
- /// The amount of time that has elapsed since the last cooldown update.
public override void Update(float frameTime)
{
- if(!_timing.IsFirstTimePredicted)
- return;
-
- foreach(var (eventHorizon, xform) in EntityManager.EntityQuery())
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var eventHorizon, out var xform))
{
var curTime = _timing.CurTime;
if (eventHorizon.NextConsumeWaveTime <= curTime)
- Update(eventHorizon.Owner, eventHorizon, xform);
+ Update(uid, eventHorizon, xform);
}
}
///
/// Makes an event horizon consume everything nearby and resets the cooldown it for the next automated wave.
///
- /// The uid of the event horizon consuming everything nearby.
- /// The event horizon we want to consume nearby things.
- /// The transform of the event horizon.
public void Update(EntityUid uid, EventHorizonComponent? eventHorizon = null, TransformComponent? xform = null)
{
- if(!Resolve(uid, ref eventHorizon))
+ if (!Resolve(uid, ref eventHorizon))
return;
eventHorizon.LastConsumeWaveTime = _timing.CurTime;
eventHorizon.NextConsumeWaveTime = eventHorizon.LastConsumeWaveTime + eventHorizon.TargetConsumePeriod;
if (eventHorizon.BeingConsumedByAnotherEventHorizon)
return;
- if(!Resolve(uid, ref xform))
+ if (!Resolve(uid, ref xform))
return;
// Handle singularities some admin smited into a locker.
if (_containerSystem.TryGetContainingContainer(uid, out var container, transform: xform)
- && !AttemptConsumeEntity(container.Owner, eventHorizon))
+ && !AttemptConsumeEntity(uid, container.Owner, eventHorizon))
{
+ // Locker is indestructible. Consume everything else in the locker instead of magically teleporting out.
ConsumeEntitiesInContainer(uid, container, eventHorizon, container);
return;
}
if (eventHorizon.Radius > 0.0f)
- ConsumeEverythingInRange(xform.Owner, eventHorizon.Radius, xform, eventHorizon);
+ ConsumeEverythingInRange(uid, eventHorizon.Radius, xform, eventHorizon);
}
-#region Consume
+ #region Consume
-#region Consume Entities
+ #region Consume Entities
///
/// Makes an event horizon consume a given entity.
///
- /// The entity to consume.
- /// The event horizon consuming the given entity.
- /// The innermost container of the entity to consume that isn't also being consumed by the event horizon.
- public void ConsumeEntity(EntityUid uid, EventHorizonComponent eventHorizon, IContainer? outerContainer = null)
+ public void ConsumeEntity(EntityUid hungry, EntityUid morsel, EventHorizonComponent eventHorizon, IContainer? outerContainer = null)
{
- var eventHorizonOwner = eventHorizon.Owner;
+ if (!EntityManager.IsQueuedForDeletion(morsel) // I saw it log twice a few times for some reason?
+ && (HasComp(morsel)
+ || _tagSystem.HasTag(morsel, "HighRiskItem")
+ || HasComp(morsel)))
+ {
+ _adminLogger.Add(LogType.EntityDelete, LogImpact.Extreme, $"{ToPrettyString(morsel)} entered the event horizon of {ToPrettyString(hungry)} and was deleted");
+ }
- if (!EntityManager.IsQueuedForDeletion(uid) && // I saw it log twice a few times for some reason?
- (HasComp(uid) ||
- _tagSystem.HasTag(uid, "HighRiskItem") ||
- HasComp(uid)))
- _adminLogger.Add(LogType.EntityDelete, LogImpact.Extreme, $"{ToPrettyString(uid)} entered the event horizon of {ToPrettyString(eventHorizonOwner)} and was deleted");
-
- EntityManager.QueueDeleteEntity(uid);
- RaiseLocalEvent(eventHorizonOwner, new EntityConsumedByEventHorizonEvent(uid, eventHorizon, outerContainer));
- RaiseLocalEvent(uid, new EventHorizonConsumedEntityEvent(uid, eventHorizon, outerContainer));
+ EntityManager.QueueDeleteEntity(morsel);
+ var evSelf = new EntityConsumedByEventHorizonEvent(morsel, hungry, eventHorizon, outerContainer);
+ var evEaten = new EventHorizonConsumedEntityEvent(morsel, hungry, eventHorizon, outerContainer);
+ RaiseLocalEvent(hungry, ref evSelf);
+ RaiseLocalEvent(morsel, ref evEaten);
}
///
/// Makes an event horizon attempt to consume a given entity.
///
- /// The entity to attempt to consume.
- /// The event horizon attempting to consume the given entity.
- /// The innermost container of the entity to consume that isn't also being consumed by the event horizon.
- public bool AttemptConsumeEntity(EntityUid uid, EventHorizonComponent eventHorizon, IContainer? outerContainer = null)
+ public bool AttemptConsumeEntity(EntityUid hungry, EntityUid morsel, EventHorizonComponent eventHorizon, IContainer? outerContainer = null)
{
- if(!CanConsumeEntity(uid, eventHorizon))
+ if (!CanConsumeEntity(hungry, morsel, eventHorizon))
return false;
- ConsumeEntity(uid, eventHorizon, outerContainer);
+ ConsumeEntity(hungry, morsel, eventHorizon, outerContainer);
return true;
}
///
/// Checks whether an event horizon can consume a given entity.
///
- /// The entity to check for consumability.
- /// The event horizon checking whether it can consume the entity.
- public bool CanConsumeEntity(EntityUid uid, EventHorizonComponent eventHorizon)
+ public bool CanConsumeEntity(EntityUid hungry, EntityUid uid, EventHorizonComponent eventHorizon)
{
- var ev = new EventHorizonAttemptConsumeEntityEvent(uid, eventHorizon);
- RaiseLocalEvent(uid, ev);
+ var ev = new EventHorizonAttemptConsumeEntityEvent(uid, hungry, eventHorizon);
+ RaiseLocalEvent(uid, ref ev);
return !ev.Cancelled;
}
@@ -174,21 +152,27 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
/// Attempts to consume all entities within a given distance of an entity;
/// Excludes the center entity.
///
- /// The entity uid in the center of the region to consume all entities within.
- /// The distance of the center entity within which to consume all entities.
- /// The transform component attached to the center entity.
- /// The event horizon component attached to the center entity.
public void ConsumeEntitiesInRange(EntityUid uid, float range, TransformComponent? xform = null, EventHorizonComponent? eventHorizon = null)
{
- if(!Resolve(uid, ref xform, ref eventHorizon))
+ if (!Resolve(uid, ref xform, ref eventHorizon))
return;
- foreach(var entity in _lookup.GetEntitiesInRange(xform.MapPosition, range, flags: LookupFlags.Uncontained))
+ var range2 = range * range;
+ var xformQuery = EntityManager.GetEntityQuery();
+ var epicenter = _xformSystem.GetWorldPosition(xform, xformQuery);
+ foreach (var entity in _lookup.GetEntitiesInRange(xform.MapPosition, range, flags: LookupFlags.Uncontained))
{
if (entity == uid)
continue;
+ if (!xformQuery.TryGetComponent(entity, out var entityXform))
+ continue;
- AttemptConsumeEntity(entity, eventHorizon);
+ // GetEntitiesInRange gets everything in a _square_ centered on the given position, but we are a _circle_. If we don't have this check and the station is rotated it is possible for the singularity to reach _outside of the containment field_ and eat the emitters.
+ var displacement = _xformSystem.GetWorldPosition(entityXform, xformQuery) - epicenter;
+ if (displacement.LengthSquared() > range2)
+ continue;
+
+ AttemptConsumeEntity(uid, entity, eventHorizon);
}
}
@@ -197,31 +181,28 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
/// Excludes the event horizon itself.
/// All immune entities within the container will be dumped to a given container or the map/grid if that is impossible.
///
- /// The uid of the event horizon. The single entity that is immune-by-default.
- /// The container within which to consume all entities.
- /// The state of the event horizon.
- /// The location any immune entities within the container should be dumped to.
- public void ConsumeEntitiesInContainer(EntityUid uid, IContainer container, EventHorizonComponent eventHorizon, IContainer? outerContainer = null) {
+ public void ConsumeEntitiesInContainer(EntityUid hungry, IContainer container, EventHorizonComponent eventHorizon, IContainer? outerContainer = null)
+ {
// Removing the immune entities from the container needs to be deferred until after iteration or the iterator raises an error.
List immune = new();
- foreach(var entity in container.ContainedEntities)
+ foreach (var entity in container.ContainedEntities)
{
- if (entity == uid || !AttemptConsumeEntity(entity, eventHorizon, outerContainer))
+ if (entity == hungry || !AttemptConsumeEntity(hungry, entity, eventHorizon, outerContainer))
immune.Add(entity); // The first check keeps singularities an admin smited into a locker from consuming themselves.
// The second check keeps things that have been rendered immune to singularities from being deleted by a singularity eating their container.
}
- if (outerContainer == container)
+ if (outerContainer == container || immune.Count <= 0)
return; // The container we are intended to drop immune things to is the same container we are consuming everything in
// it's a safe bet that we aren't consuming the container entity so there's no reason to eject anything from this container.
// We need to get the immune things out of the container because the chances are we are about to eat the container and we don't want them to get deleted despite their immunity.
- foreach(var entity in immune)
+ foreach (var entity in immune)
{
// Attempt to insert immune entities into innermost container at least as outer as outerContainer.
var target_container = outerContainer;
- while(target_container != null)
+ while (target_container != null)
{
if (target_container.Insert(entity))
break;
@@ -231,62 +212,58 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
// If we couldn't or there was no container to insert into just dump them to the map/grid.
if (target_container == null)
- Transform(entity).AttachToGridOrMap();
+ _xformSystem.AttachToGridOrMap(entity);
}
}
-#endregion Consume Entities
+ #endregion Consume Entities
-#region Consume Tiles
+ #region Consume Tiles
///
/// Makes an event horizon consume a specific tile on a grid.
///
- /// The tile to consume.
- /// The event horizon which is consuming the tile on the grid.
- public void ConsumeTile(TileRef tile, EventHorizonComponent eventHorizon)
- => ConsumeTiles(new List<(Vector2i, Tile)>(new []{(tile.GridIndices, Tile.Empty)}), _mapMan.GetGrid(tile.GridUid), eventHorizon);
+ public void ConsumeTile(EntityUid hungry, TileRef tile, EventHorizonComponent eventHorizon)
+ {
+ ConsumeTiles(hungry, new List<(Vector2i, Tile)>(new[] { (tile.GridIndices, Tile.Empty) }), tile.GridUid, _mapMan.GetGrid(tile.GridUid), eventHorizon);
+ }
///
/// Makes an event horizon attempt to consume a specific tile on a grid.
///
- /// The tile to attempt to consume.
- /// The event horizon which is attempting to consume the tile on the grid.
- public void AttemptConsumeTile(TileRef tile, EventHorizonComponent eventHorizon)
- => AttemptConsumeTiles(new TileRef[1]{tile}, _mapMan.GetGrid(tile.GridUid), eventHorizon);
+ public void AttemptConsumeTile(EntityUid hungry, TileRef tile, EventHorizonComponent eventHorizon)
+ {
+ AttemptConsumeTiles(hungry, new TileRef[1] { tile }, tile.GridUid, _mapMan.GetGrid(tile.GridUid), eventHorizon);
+ }
///
/// Makes an event horizon consume a set of tiles on a grid.
///
- /// The tiles to consume.
- /// The grid hosting the tiles to consume.
- /// The event horizon which is consuming the tiles on the grid.
- public void ConsumeTiles(List<(Vector2i, Tile)> tiles, MapGridComponent grid, EventHorizonComponent eventHorizon)
+ public void ConsumeTiles(EntityUid hungry, List<(Vector2i, Tile)> tiles, EntityUid gridId, MapGridComponent grid, EventHorizonComponent eventHorizon)
{
if (tiles.Count <= 0)
return;
- RaiseLocalEvent(eventHorizon.Owner, new TilesConsumedByEventHorizonEvent(tiles, grid, eventHorizon));
+ var ev = new TilesConsumedByEventHorizonEvent(tiles, gridId, grid, hungry, eventHorizon);
+ RaiseLocalEvent(hungry, ref ev);
grid.SetTiles(tiles);
}
///
/// Makes an event horizon attempt to consume a set of tiles on a grid.
///
- /// The tiles to attempt to consume.
- /// The grid hosting the tiles to attempt to consume.
- /// The event horizon which is attempting to consume the tiles on the grid.
- public int AttemptConsumeTiles(IEnumerable tiles, MapGridComponent grid, EventHorizonComponent eventHorizon)
+ public int AttemptConsumeTiles(EntityUid hungry, IEnumerable tiles, EntityUid gridId, MapGridComponent grid, EventHorizonComponent eventHorizon)
{
var toConsume = new List<(Vector2i, Tile)>();
- foreach(var tile in tiles) {
- if (CanConsumeTile(tile, grid, eventHorizon))
+ foreach (var tile in tiles)
+ {
+ if (CanConsumeTile(hungry, tile, grid, eventHorizon))
toConsume.Add((tile.GridIndices, Tile.Empty));
}
var result = toConsume.Count;
if (toConsume.Count > 0)
- ConsumeTiles(toConsume, grid, eventHorizon);
+ ConsumeTiles(hungry, toConsume, gridId, grid, eventHorizon);
return result;
}
@@ -294,14 +271,11 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
/// Checks whether an event horizon can consume a given tile.
/// This is only possible if it can also consume all entities anchored to the tile.
///
- /// The tile to check for consumability.
- /// The grid hosting the tile to check.
- /// The event horizon which is checking to see if it can consume the tile on the grid.
- public bool CanConsumeTile(TileRef tile, MapGridComponent grid, EventHorizonComponent eventHorizon)
+ public bool CanConsumeTile(EntityUid hungry, TileRef tile, MapGridComponent grid, EventHorizonComponent eventHorizon)
{
- foreach(var blockingEntity in grid.GetAnchoredEntities(tile.GridIndices))
+ foreach (var blockingEntity in grid.GetAnchoredEntities(tile.GridIndices))
{
- if(!CanConsumeEntity(blockingEntity, eventHorizon))
+ if (!CanConsumeEntity(hungry, blockingEntity, eventHorizon))
return false;
}
return true;
@@ -311,44 +285,36 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
/// Consumes all tiles within a given distance of an entity.
/// Some entities are immune to consumption.
///
- /// The entity uid in the center of the region to consume all tiles within.
- /// The distance of the center entity within which to consume all tiles.
- /// The transform component attached to the center entity.
- /// The event horizon component attached to the center entity.
public void ConsumeTilesInRange(EntityUid uid, float range, TransformComponent? xform, EventHorizonComponent? eventHorizon)
{
- if(!Resolve(uid, ref xform) || !Resolve(uid, ref eventHorizon))
+ if (!Resolve(uid, ref xform) || !Resolve(uid, ref eventHorizon))
return;
var mapPos = xform.MapPosition;
var box = Box2.CenteredAround(mapPos.Position, new Vector2(range, range));
var circle = new Circle(mapPos.Position, range);
- foreach(var grid in _mapMan.FindGridsIntersecting(mapPos.MapId, box))
- {
- AttemptConsumeTiles(grid.GetTilesIntersecting(circle), grid, eventHorizon);
+ foreach (var grid in _mapMan.FindGridsIntersecting(mapPos.MapId, box))
+ { // TODO: Remover grid.Owner when this iterator returns entityuids as well.
+ AttemptConsumeTiles(uid, grid.GetTilesIntersecting(circle), grid.Owner, grid, eventHorizon);
}
}
-#endregion Consume Tiles
+ #endregion Consume Tiles
///
/// Consumes most entities and tiles within a given distance of an entity.
/// Some entities are immune to consumption.
///
- /// The entity uid in the center of the region to consume everything within.
- /// The distance of the center entity within which to consume everything.
- /// The transform component attached to the center entity.
- /// The event horizon component attached to the center entity.
public void ConsumeEverythingInRange(EntityUid uid, float range, TransformComponent? xform = null, EventHorizonComponent? eventHorizon = null)
{
- if(!Resolve(uid, ref xform, ref eventHorizon))
+ if (!Resolve(uid, ref xform, ref eventHorizon))
return;
ConsumeEntitiesInRange(uid, range, xform, eventHorizon);
ConsumeTilesInRange(uid, range, xform, eventHorizon);
}
-#endregion Consume
+ #endregion Consume
#region Getters/Setters
@@ -357,12 +323,9 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
/// The value is specifically how long the subsystem should wait between scans.
/// If the new scanning period would have already prompted a scan given the previous scan time one is prompted immediately.
///
- /// The uid of the event horizon to set the consume wave period for.
- /// The amount of time that this subsystem should wait between scans.
- /// The state of the event horizon to set the consume wave period for.
public void SetConsumePeriod(EntityUid uid, TimeSpan value, EventHorizonComponent? eventHorizon = null)
{
- if(!Resolve(uid, ref eventHorizon))
+ if (!Resolve(uid, ref eventHorizon))
return;
if (MathHelper.CloseTo(eventHorizon.TargetConsumePeriod.TotalSeconds, value.TotalSeconds))
@@ -378,65 +341,54 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
#endregion Getters/Setters
-#region Event Handlers
+ #region Event Handlers
///
/// Prevents a singularity from colliding with anything it is incapable of consuming.
///
- /// The event horizon entity that is trying to collide with something.
- /// The event horizon that is trying to collide with something.
- /// The event arguments.
protected override bool PreventCollide(EntityUid uid, EventHorizonComponent comp, ref PreventCollideEvent args)
{
if (base.PreventCollide(uid, comp, ref args) || args.Cancelled)
return true;
- args.Cancelled = !CanConsumeEntity(args.OtherEntity, comp);
+ // If we can eat it we don't want to bounce off of it. If we can't eat it we want to bounce off of it (containment fields).
+ args.Cancelled = args.OurFixture.Hard && CanConsumeEntity(uid, args.OtherEntity, comp);
return false;
}
///
/// A generic event handler that prevents singularities from consuming entities with a component of a given type if registered.
///
- /// The entity the singularity is trying to eat.
- /// The component the singularity is trying to eat.
- /// The event arguments.
- public void PreventConsume(EntityUid uid, TComp comp, EventHorizonAttemptConsumeEntityEvent args)
+ public static void PreventConsume(EntityUid uid, TComp comp, ref EventHorizonAttemptConsumeEntityEvent args)
{
- if(!args.Cancelled)
- args.Cancel();
+ if (!args.Cancelled)
+ args.Cancelled = true;
}
///
/// A generic event handler that prevents singularities from breaching containment.
/// In this case 'breaching containment' means consuming an entity with a component of the given type unless the event horizon is set to breach containment anyway.
///
- /// The entity the singularity is trying to eat.
- /// The component the singularity is trying to eat.
- /// The event arguments.
- public void PreventBreach(EntityUid uid, TComp comp, EventHorizonAttemptConsumeEntityEvent args)
+ public static void PreventBreach(EntityUid uid, TComp comp, ref EventHorizonAttemptConsumeEntityEvent args)
{
if (args.Cancelled)
return;
- if(!args.EventHorizon.CanBreachContainment)
- PreventConsume(uid, comp, args);
+ if (!args.EventHorizon.CanBreachContainment)
+ PreventConsume(uid, comp, ref args);
}
///
/// Handles event horizons consuming any entities they bump into.
/// The event horizon will not consume any entities if it itself has been consumed by an event horizon.
///
- /// The event horizon entity.
- /// The event horizon.
- /// The event arguments.
private void OnStartCollide(EntityUid uid, EventHorizonComponent comp, ref StartCollideEvent args)
{
if (comp.BeingConsumedByAnotherEventHorizon)
return;
- if (args.OurFixture.ID != comp.HorizonFixtureId)
+ if (args.OurFixture.ID != comp.ConsumerFixtureId)
return;
- AttemptConsumeEntity(args.OtherEntity, comp);
+ AttemptConsumeEntity(uid, args.OtherEntity, comp);
}
///
@@ -444,40 +396,31 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
/// Specifically prevents event horizons from consuming themselves.
/// Also ensures that if this event horizon has already been consumed by another event horizon it cannot be consumed again.
///
- /// The event horizon entity.
- /// The event horizon.
- /// The event arguments.
- private void OnAnotherEventHorizonAttemptConsumeThisEventHorizon(EntityUid uid, EventHorizonComponent comp, EventHorizonAttemptConsumeEntityEvent args)
+ private void OnAnotherEventHorizonAttemptConsumeThisEventHorizon(EntityUid uid, EventHorizonComponent comp, ref EventHorizonAttemptConsumeEntityEvent args)
{
- if(!args.Cancelled && (args.EventHorizon == comp || comp.BeingConsumedByAnotherEventHorizon))
- args.Cancel();
+ if (!args.Cancelled && (args.EventHorizon == comp || comp.BeingConsumedByAnotherEventHorizon))
+ args.Cancelled = true;
}
///
/// Prevents two singularities from annihilating one another.
/// Specifically ensures if this event horizon is consumed by another event horizon it knows that it has been consumed.
///
- /// The event horizon entity.
- /// The event horizon.
- /// The event arguments.
- private void OnAnotherEventHorizonConsumedThisEventHorizon(EntityUid uid, EventHorizonComponent comp, EventHorizonConsumedEntityEvent args)
+ private void OnAnotherEventHorizonConsumedThisEventHorizon(EntityUid uid, EventHorizonComponent comp, ref EventHorizonConsumedEntityEvent args)
{
comp.BeingConsumedByAnotherEventHorizon = true;
}
///
/// Handles event horizons deciding to escape containers they are inserted into.
- /// Delegates the actual escape to on a delay.
+ /// Delegates the actual escape to on a delay.
/// This ensures that the escape is handled after all other handlers for the insertion event and satisfies the assertion that
/// the inserted entity SHALL be inside of the specified container after all handles to the entity event
/// are processed.
///
- /// The uid of the event horizon.]
- /// The state of the event horizon.]
- /// The arguments of the insertion.]
- private void OnEventHorizonContained(EntityUid uid, EventHorizonComponent comp, EntGotInsertedIntoContainerMessage args) {
+ private void OnEventHorizonContained(EntityUid uid, EventHorizonComponent comp, EntGotInsertedIntoContainerMessage args)
+ {
// Delegates processing an event until all queued events have been processed.
- // As of 1:44 AM, Sunday, Dec. 4, 2022 this is the one use for this in the codebase.
QueueLocalEvent(new EventHorizonContainedEvent(uid, comp, args));
}
@@ -487,38 +430,38 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
/// container and drop the the next innermost contaning container.
/// This loops until the event horizon has escaped to the map or wound up in an indestructible container.
///
- /// The arguments for this event.]
- private void OnEventHorizonContained(EventHorizonContainedEvent args) {
+ private void OnEventHorizonContained(EventHorizonContainedEvent args)
+ {
var uid = args.Entity;
- var comp = args.EventHorizon;
if (!EntityManager.EntityExists(uid))
return;
+ var comp = args.EventHorizon;
if (comp.BeingConsumedByAnotherEventHorizon)
return;
var containerEntity = args.Args.Container.Owner;
- if(!(EntityManager.EntityExists(containerEntity) && AttemptConsumeEntity(containerEntity, comp))) {
- ConsumeEntitiesInContainer(uid, args.Args.Container, comp, args.Args.Container);
- }
+ if (!EntityManager.EntityExists(containerEntity))
+ return;
+ if (AttemptConsumeEntity(uid, containerEntity, comp))
+ return; // If we consume the entity we also consume everything in the containers it has.
+
+ ConsumeEntitiesInContainer(uid, args.Args.Container, comp, args.Args.Container);
}
///
/// Recursively consumes all entities within a container that is consumed by the singularity.
/// If an entity within a consumed container cannot be consumed itself it is removed from the container.
///
- /// The uid of the container being consumed.
- /// The state of the container being consumed.
- /// The event arguments.
- private void OnContainerConsumed(EntityUid uid, ContainerManagerComponent comp, EventHorizonConsumedEntityEvent args)
+ private void OnContainerConsumed(EntityUid uid, ContainerManagerComponent comp, ref EventHorizonConsumedEntityEvent args)
{
var drop_container = args.Container;
if (drop_container is null)
_containerSystem.TryGetContainingContainer(uid, out drop_container);
- foreach(var container in comp.GetAllContainers())
+ foreach (var container in comp.GetAllContainers())
{
- ConsumeEntitiesInContainer(args.EventHorizon.Owner, container, args.EventHorizon, drop_container);
+ ConsumeEntitiesInContainer(args.EventHorizonUid, container, args.EventHorizon, drop_container);
}
}
-#endregion Event Handlers
+ #endregion Event Handlers
}
diff --git a/Content.Server/Singularity/EntitySystems/SingularitySystem.cs b/Content.Server/Singularity/EntitySystems/SingularitySystem.cs
index a30d8bb02b..e4416b21e1 100644
--- a/Content.Server/Singularity/EntitySystems/SingularitySystem.cs
+++ b/Content.Server/Singularity/EntitySystems/SingularitySystem.cs
@@ -256,7 +256,7 @@ public sealed class SingularitySystem : SharedSingularitySystem
/// The entity UID of the singularity that is consuming the entity.
/// The component of the singularity that is consuming the entity.
/// The event arguments.
- public void OnConsumedEntity(EntityUid uid, SingularityComponent comp, EntityConsumedByEventHorizonEvent args)
+ public void OnConsumedEntity(EntityUid uid, SingularityComponent comp, ref EntityConsumedByEventHorizonEvent args)
{
AdjustEnergy(uid, BaseEntityEnergy, singularity: comp);
}
@@ -267,21 +267,21 @@ public sealed class SingularitySystem : SharedSingularitySystem
/// The entity UID of the singularity that is consuming the tiles.
/// The component of the singularity that is consuming the tiles.
/// The event arguments.
- public void OnConsumedTiles(EntityUid uid, SingularityComponent comp, TilesConsumedByEventHorizonEvent args)
+ public void OnConsumedTiles(EntityUid uid, SingularityComponent comp, ref TilesConsumedByEventHorizonEvent args)
{
AdjustEnergy(uid, args.Tiles.Count * BaseTileEnergy, singularity: comp);
}
///
- /// Adds the energy of this singularity to singularities consume it.
+ /// Adds the energy of this singularity to singularities that consume it.
///
/// The entity UID of the singularity that is being consumed.
/// The component of the singularity that is being consumed.
/// The event arguments.
- private void OnConsumed(EntityUid uid, SingularityComponent comp, EventHorizonConsumedEntityEvent args)
+ private void OnConsumed(EntityUid uid, SingularityComponent comp, ref EventHorizonConsumedEntityEvent args)
{
// Should be slightly more efficient than checking literally everything we consume for a singularity component and doing the reverse.
- if (EntityManager.TryGetComponent(args.EventHorizon.Owner, out var singulo))
+ if (EntityManager.TryGetComponent(args.EventHorizonUid, out var singulo))
{
AdjustEnergy(singulo.Owner, comp.Energy, singularity: singulo);
SetEnergy(uid, 0.0f, comp);
@@ -294,10 +294,10 @@ public sealed class SingularitySystem : SharedSingularitySystem
/// The entity UID of the singularity food that is being consumed.
/// The component of the singularity food that is being consumed.
/// The event arguments.
- public void OnConsumed(EntityUid uid, SinguloFoodComponent comp, EventHorizonConsumedEntityEvent args)
+ public void OnConsumed(EntityUid uid, SinguloFoodComponent comp, ref EventHorizonConsumedEntityEvent args)
{
- if (EntityManager.TryGetComponent(args.EventHorizon.Owner, out var singulo))
- AdjustEnergy(args.EventHorizon.Owner, comp.Energy, singularity: singulo);
+ if (EntityManager.TryGetComponent(args.EventHorizonUid, out var singulo))
+ AdjustEnergy(args.EventHorizonUid, comp.Energy, singularity: singulo);
}
///
diff --git a/Content.Server/Singularity/Events/EntityConsumedByEventHorizonEvent.cs b/Content.Server/Singularity/Events/EntityConsumedByEventHorizonEvent.cs
index 116131d8b1..84e8a8ff2b 100644
--- a/Content.Server/Singularity/Events/EntityConsumedByEventHorizonEvent.cs
+++ b/Content.Server/Singularity/Events/EntityConsumedByEventHorizonEvent.cs
@@ -6,28 +6,28 @@ namespace Content.Server.Singularity.Events;
///
/// Event raised on the event horizon entity whenever an event horizon consumes an entity.
///
-public sealed class EntityConsumedByEventHorizonEvent : EntityEventArgs
+[ByRefEvent]
+public readonly record struct EntityConsumedByEventHorizonEvent
+(EntityUid entity, EntityUid eventHorizonUid, EventHorizonComponent eventHorizon, IContainer? container)
{
///
/// The entity being consumed by the event horizon.
///
- public readonly EntityUid Entity;
+ public readonly EntityUid Entity = entity;
+
+ ///
+ /// The uid of the event horizon consuming the entity.
+ ///
+ public readonly EntityUid EventHorizonUid = eventHorizonUid;
///
/// The event horizon consuming the entity.
///
- public readonly EventHorizonComponent EventHorizon;
+ public readonly EventHorizonComponent EventHorizon = eventHorizon;
///
/// The innermost container of the entity being consumed by the event horizon that is not also in the process of being consumed by the event horizon.
/// Used to correctly dump out the contents containers that are consumed by the event horizon.
///
- public readonly IContainer? Container;
-
- public EntityConsumedByEventHorizonEvent(EntityUid entity, EventHorizonComponent eventHorizon, IContainer? container = null)
- {
- Entity = entity;
- EventHorizon = eventHorizon;
- Container = container;
- }
+ public readonly IContainer? Container = container;
}
diff --git a/Content.Server/Singularity/Events/EventHorizonAttemptConsumeEntityEvent.cs b/Content.Server/Singularity/Events/EventHorizonAttemptConsumeEntityEvent.cs
index 26119019f9..257e66981a 100644
--- a/Content.Server/Singularity/Events/EventHorizonAttemptConsumeEntityEvent.cs
+++ b/Content.Server/Singularity/Events/EventHorizonAttemptConsumeEntityEvent.cs
@@ -6,21 +6,27 @@ namespace Content.Server.Singularity.Events;
/// Event raised on the target entity whenever an event horizon attempts to consume an entity.
/// Can be cancelled to prevent the target entity from being consumed.
///
-public sealed class EventHorizonAttemptConsumeEntityEvent : CancellableEntityEventArgs
+[ByRefEvent]
+public record struct EventHorizonAttemptConsumeEntityEvent
+(EntityUid entity, EntityUid eventHorizonUid, EventHorizonComponent eventHorizon)
{
///
/// The entity that the event horizon is attempting to consume.
///
- public readonly EntityUid Entity;
+ public readonly EntityUid Entity = entity;
+
+ ///
+ /// The uid of the event horizon consuming the entity.
+ ///
+ public readonly EntityUid EventHorizonUid = eventHorizonUid;
///
/// The event horizon consuming the target entity.
///
- public readonly EventHorizonComponent EventHorizon;
+ public readonly EventHorizonComponent EventHorizon = eventHorizon;
- public EventHorizonAttemptConsumeEntityEvent(EntityUid entity, EventHorizonComponent eventHorizon)
- {
- Entity = entity;
- EventHorizon = eventHorizon;
- }
+ ///
+ /// Whether the event horizon has been prevented from consuming the target entity.
+ ///
+ public bool Cancelled = false;
}
diff --git a/Content.Server/Singularity/Events/EventHorizonConsumedEntityEvent.cs b/Content.Server/Singularity/Events/EventHorizonConsumedEntityEvent.cs
index eaf1ca2a9a..1934219517 100644
--- a/Content.Server/Singularity/Events/EventHorizonConsumedEntityEvent.cs
+++ b/Content.Server/Singularity/Events/EventHorizonConsumedEntityEvent.cs
@@ -4,30 +4,30 @@ using Robust.Shared.Containers;
namespace Content.Server.Singularity.Events;
///
-/// Event raised on the event horizon entity whenever an event horizon consumes an entity.
+/// Event raised on the entity being consumed whenever an event horizon consumes an entity.
///
-public sealed class EventHorizonConsumedEntityEvent : EntityEventArgs
+[ByRefEvent]
+public readonly record struct EventHorizonConsumedEntityEvent
+(EntityUid entity, EntityUid eventHorizonUid, EventHorizonComponent eventHorizon, IContainer? container)
{
///
/// The entity being consumed by the event horizon.
///
- public readonly EntityUid Entity;
+ public readonly EntityUid Entity = entity;
+
+ ///
+ /// The uid of the event horizon consuming the entity.
+ ///
+ public readonly EntityUid EventHorizonUid = eventHorizonUid;
///
/// The event horizon consuming the target entity.
///
- public readonly EventHorizonComponent EventHorizon;
+ public readonly EventHorizonComponent EventHorizon = eventHorizon;
///
/// The innermost container of the entity being consumed by the event horizon that is not also in the process of being consumed by the event horizon.
/// Used to correctly dump out the contents containers that are consumed by the event horizon.
///
- public readonly IContainer? Container;
-
- public EventHorizonConsumedEntityEvent(EntityUid entity, EventHorizonComponent eventHorizon, IContainer? container = null)
- {
- Entity = entity;
- EventHorizon = eventHorizon;
- Container = container;
- }
+ public readonly IContainer? Container = container;
}
diff --git a/Content.Server/Singularity/Events/EventHorizonContainedEvent.cs b/Content.Server/Singularity/Events/EventHorizonContainedEvent.cs
index 3c908efd41..b22c49800a 100644
--- a/Content.Server/Singularity/Events/EventHorizonContainedEvent.cs
+++ b/Content.Server/Singularity/Events/EventHorizonContainedEvent.cs
@@ -6,8 +6,10 @@ namespace Content.Shared.Singularity.EntitySystems;
///
/// An event queued when an event horizon is contained (put into a container).
/// Exists to delay the event horizon eating its way out of the container until events relating to the insertion have been processed.
+/// Needs to be a class because ref structs can't be put into the queue.
///
-public sealed class EventHorizonContainedEvent : EntityEventArgs {
+public sealed class EventHorizonContainedEvent : EntityEventArgs
+{
///
/// The uid of the event horizon that has been contained.
///
@@ -23,7 +25,8 @@ public sealed class EventHorizonContainedEvent : EntityEventArgs {
///
public readonly EntGotInsertedIntoContainerMessage Args;
- public EventHorizonContainedEvent(EntityUid entity, EventHorizonComponent eventHorizon, EntGotInsertedIntoContainerMessage args) {
+ public EventHorizonContainedEvent(EntityUid entity, EventHorizonComponent eventHorizon, EntGotInsertedIntoContainerMessage args)
+ {
Entity = entity;
EventHorizon = eventHorizon;
Args = args;
diff --git a/Content.Server/Singularity/Events/TilesConsumedByEventHorizonEvent.cs b/Content.Server/Singularity/Events/TilesConsumedByEventHorizonEvent.cs
index 79261302ba..dc669dc796 100644
--- a/Content.Server/Singularity/Events/TilesConsumedByEventHorizonEvent.cs
+++ b/Content.Server/Singularity/Events/TilesConsumedByEventHorizonEvent.cs
@@ -8,28 +8,33 @@ namespace Content.Server.Singularity.Events;
///
/// Event raised on the event horizon entity whenever an event horizon consumes an entity.
///
-public sealed class TilesConsumedByEventHorizonEvent : EntityEventArgs
+[ByRefEvent]
+public readonly record struct TilesConsumedByEventHorizonEvent
+(IReadOnlyList<(Vector2i, Tile)> tiles, EntityUid mapGridUid, MapGridComponent mapGrid, EntityUid eventHorizonUid, EventHorizonComponent eventHorizon)
{
///
/// The tiles that the event horizon is consuming.
/// Ripped directly from the relevant proc so the second element of each element will be what the tiles are going to be after the grid is updated; usually .
///
- public readonly IReadOnlyList<(Vector2i, Tile)> Tiles;
+ public readonly IReadOnlyList<(Vector2i, Tile)> Tiles = tiles;
+
+ ///
+ /// The uid of the map grid the event horizon is consuming part of.
+ ///
+ public readonly EntityUid MapGridUid = mapGridUid;
///
/// The mapgrid that the event horizon is consuming tiles of.
///
- public readonly MapGridComponent MapGrid;
+ public readonly MapGridComponent MapGrid = mapGrid;
+
+ ///
+ /// The uid of the event horizon consuming the entity.
+ ///
+ public readonly EntityUid EventHorizonUid = eventHorizonUid;
///
/// The event horizon consuming the tiles.
///
- public readonly EventHorizonComponent EventHorizon;
-
- public TilesConsumedByEventHorizonEvent(IReadOnlyList<(Vector2i, Tile)> tiles, MapGridComponent mapGrid, EventHorizonComponent eventHorizon)
- {
- Tiles = tiles;
- MapGrid = mapGrid;
- EventHorizon = eventHorizon;
- }
+ public readonly EventHorizonComponent EventHorizon = eventHorizon;
}
diff --git a/Content.Shared/Singularity/Components/EventHorizonComponent.cs b/Content.Shared/Singularity/Components/EventHorizonComponent.cs
index a25f78c8ca..ce4f263077 100644
--- a/Content.Shared/Singularity/Components/EventHorizonComponent.cs
+++ b/Content.Shared/Singularity/Components/EventHorizonComponent.cs
@@ -8,6 +8,7 @@ namespace Content.Shared.Singularity.Components;
/// Also makes the associated entity destroy other entities upon contact.
/// Primarily managed by and its server/client versions.
///
+[Access(friends: typeof(SharedEventHorizonSystem))]
[RegisterComponent, NetworkedComponent]
public sealed class EventHorizonComponent : Component
{
@@ -17,7 +18,6 @@ public sealed class EventHorizonComponent : Component
/// If you want to set this go through .
///
[DataField("radius")]
- [Access(friends:typeof(SharedEventHorizonSystem))]
public float Radius;
///
@@ -25,7 +25,7 @@ public sealed class EventHorizonComponent : Component
/// If you want to set this go through .
///
[DataField("canBreachContainment")]
- [Access(friends:typeof(SharedEventHorizonSystem))]
+ [ViewVariables(VVAccess.ReadWrite)]
public bool CanBreachContainment = false;
///
@@ -33,9 +33,18 @@ public sealed class EventHorizonComponent : Component
/// Can be set to null, in which case no such fixture is used.
/// If you want to set this go through .
///
- [DataField("horizonFixtureId")]
- [Access(friends:typeof(SharedEventHorizonSystem))]
- public string? HorizonFixtureId = "EventHorizon";
+ [DataField("consumerFixtureId")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public string? ConsumerFixtureId = "EventHorizonConsumer";
+
+ ///
+ /// The ID of the fixture used to detect if the event horizon has collided with any physics objects.
+ /// Can be set to null, in which case no such fixture is used.
+ /// If you want to set this go through .
+ ///
+ [DataField("colliderFixtureId")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public string? ColliderFixtureId = "EventHorizonCollider";
///
/// Whether the entity this event horizon is attached to is being consumed by another event horizon.
@@ -49,22 +58,19 @@ public sealed class EventHorizonComponent : Component
/// The amount of time that should elapse between this event horizon consuming everything it overlaps with.
///
[DataField("consumePeriod")]
- [ViewVariables(VVAccess.ReadOnly)]
- [Access(typeof(SharedEventHorizonSystem))]
+ [ViewVariables(VVAccess.ReadWrite)]
public TimeSpan TargetConsumePeriod { get; set; } = TimeSpan.FromSeconds(0.5);
///
/// The last time at which this consumed everything it overlapped with.
///
[ViewVariables(VVAccess.ReadOnly)]
- [Access(typeof(SharedEventHorizonSystem))]
public TimeSpan LastConsumeWaveTime { get; set; } = default!;
///
/// The next time at which this consumed everything it overlapped with.
///
[ViewVariables(VVAccess.ReadOnly)]
- [Access(typeof(SharedEventHorizonSystem))]
public TimeSpan NextConsumeWaveTime { get; set; } = default!;
#endregion Update Timing
diff --git a/Content.Shared/Singularity/Components/SingularityComponent.cs b/Content.Shared/Singularity/Components/SingularityComponent.cs
index fbe1c69b96..bef848b7d8 100644
--- a/Content.Shared/Singularity/Components/SingularityComponent.cs
+++ b/Content.Shared/Singularity/Components/SingularityComponent.cs
@@ -18,8 +18,8 @@ public sealed class SingularityComponent : Component
/// Used as a scaling factor for things like visual size, event horizon radius, gravity well radius, radiation output, etc.
/// If you want to set this use ().
///
+ [Access(friends: typeof(SharedSingularitySystem), Other = AccessPermissions.Read, Self = AccessPermissions.Read)]
[DataField("level")]
- [Access(friends:typeof(SharedSingularitySystem), Other=AccessPermissions.Read, Self=AccessPermissions.Read)]
public byte Level = 1;
///
@@ -27,8 +27,8 @@ public sealed class SingularityComponent : Component
/// Has to be on shared in case someone attaches a RadiationPulseComponent to the singularity.
/// If you want to set this use ().
///
+ [Access(friends: typeof(SharedSingularitySystem), Other = AccessPermissions.Read, Self = AccessPermissions.Read)]
[DataField("radsPerLevel")]
- [Access(friends:typeof(SharedSingularitySystem), Other=AccessPermissions.Read, Self=AccessPermissions.Read)]
[ViewVariables(VVAccess.ReadWrite)]
public float RadsPerLevel = 2f;
@@ -88,7 +88,7 @@ public sealed class SingularityComponent : Component
/// The amount of time that should elapse between automated updates to this singularity.
///
[DataField("updatePeriod")]
- [ViewVariables(VVAccess.ReadOnly)]
+ [ViewVariables(VVAccess.ReadWrite)]
public TimeSpan TargetUpdatePeriod = TimeSpan.FromSeconds(1.0);
///
diff --git a/Content.Shared/Singularity/EntitySystems/SharedEventHorizonSystem.cs b/Content.Shared/Singularity/EntitySystems/SharedEventHorizonSystem.cs
index 01f6f586ff..dcc83946a2 100644
--- a/Content.Shared/Singularity/EntitySystems/SharedEventHorizonSystem.cs
+++ b/Content.Shared/Singularity/EntitySystems/SharedEventHorizonSystem.cs
@@ -31,7 +31,8 @@ public abstract class SharedEventHorizonSystem : EntitySystem
var vvHandle = Vvm.GetTypeHandler();
vvHandle.AddPath(nameof(EventHorizonComponent.Radius), (_, comp) => comp.Radius, (uid, value, comp) => SetRadius(uid, value, eventHorizon: comp));
vvHandle.AddPath(nameof(EventHorizonComponent.CanBreachContainment), (_, comp) => comp.CanBreachContainment, (uid, value, comp) => SetCanBreachContainment(uid, value, eventHorizon: comp));
- vvHandle.AddPath(nameof(EventHorizonComponent.HorizonFixtureId), (_, comp) => comp.HorizonFixtureId, (uid, value, comp) => SetHorizonFixtureId(uid, value, eventHorizon: comp));
+ vvHandle.AddPath(nameof(EventHorizonComponent.ColliderFixtureId), (_, comp) => comp.ColliderFixtureId, (uid, value, comp) => SetColliderFixtureId(uid, value, eventHorizon: comp));
+ vvHandle.AddPath(nameof(EventHorizonComponent.ConsumerFixtureId), (_, comp) => comp.ConsumerFixtureId, (uid, value, comp) => SetConsumerFixtureId(uid, value, eventHorizon: comp));
}
public override void Shutdown()
@@ -39,12 +40,13 @@ public abstract class SharedEventHorizonSystem : EntitySystem
var vvHandle = Vvm.GetTypeHandler();
vvHandle.RemovePath(nameof(EventHorizonComponent.Radius));
vvHandle.RemovePath(nameof(EventHorizonComponent.CanBreachContainment));
- vvHandle.RemovePath(nameof(EventHorizonComponent.HorizonFixtureId));
+ vvHandle.RemovePath(nameof(EventHorizonComponent.ColliderFixtureId));
+ vvHandle.RemovePath(nameof(EventHorizonComponent.ConsumerFixtureId));
base.Shutdown();
}
-#region Getters/Setters
+ #region Getters/Setters
///
/// Setter for
@@ -56,7 +58,7 @@ public abstract class SharedEventHorizonSystem : EntitySystem
/// The state of the event horizon to change the radius of.
public void SetRadius(EntityUid uid, float value, bool updateFixture = true, EventHorizonComponent? eventHorizon = null)
{
- if(!Resolve(uid, ref eventHorizon))
+ if (!Resolve(uid, ref eventHorizon))
return;
var oldValue = eventHorizon.Radius;
@@ -79,7 +81,7 @@ public abstract class SharedEventHorizonSystem : EntitySystem
/// The state of the event horizon to make (in)capable of breaching containment.
public void SetCanBreachContainment(EntityUid uid, bool value, bool updateFixture = true, EventHorizonComponent? eventHorizon = null)
{
- if(!Resolve(uid, ref eventHorizon))
+ if (!Resolve(uid, ref eventHorizon))
return;
var oldValue = eventHorizon.CanBreachContainment;
@@ -100,16 +102,39 @@ public abstract class SharedEventHorizonSystem : EntitySystem
/// The new fixture ID to associate the event horizon with.
/// Whether to update the associated fixture upon changing whether the event horizon can breach containment.
/// The state of the event horizon with the fixture ID to change.
- public void SetHorizonFixtureId(EntityUid uid, string? value, bool updateFixture = true, EventHorizonComponent? eventHorizon = null)
+ public void SetColliderFixtureId(EntityUid uid, string? value, bool updateFixture = true, EventHorizonComponent? eventHorizon = null)
{
- if(!Resolve(uid, ref eventHorizon))
+ if (!Resolve(uid, ref eventHorizon))
return;
- var oldValue = eventHorizon.HorizonFixtureId;
+ var oldValue = eventHorizon.ColliderFixtureId;
if (value == oldValue)
return;
- eventHorizon.HorizonFixtureId = value;
+ eventHorizon.ColliderFixtureId = value;
+ Dirty(eventHorizon);
+ if (updateFixture)
+ UpdateEventHorizonFixture(uid, eventHorizon: eventHorizon);
+ }
+
+ ///
+ /// Setter for
+ /// May also update the fixture associated with the event horizon.
+ ///
+ /// The uid of the event horizon with the fixture ID to change.
+ /// The new fixture ID to associate the event horizon with.
+ /// Whether to update the associated fixture upon changing whether the event horizon can breach containment.
+ /// The state of the event horizon with the fixture ID to change.
+ public void SetConsumerFixtureId(EntityUid uid, string? value, bool updateFixture = true, EventHorizonComponent? eventHorizon = null)
+ {
+ if (!Resolve(uid, ref eventHorizon))
+ return;
+
+ var oldValue = eventHorizon.ConsumerFixtureId;
+ if (value == oldValue)
+ return;
+
+ eventHorizon.ConsumerFixtureId = value;
Dirty(eventHorizon);
if (updateFixture)
UpdateEventHorizonFixture(uid, eventHorizon: eventHorizon);
@@ -118,33 +143,48 @@ public abstract class SharedEventHorizonSystem : EntitySystem
///
/// Updates the state of the fixture associated with the event horizon.
///
- /// The uid of the event horizon associated with the fixture to update.
- /// The physics component containing the fixture to update.
+ /// The uid of the event horizon associated with the fixture to update.
+ /// The fixture manager component containing the fixture to update.
/// The state of the event horizon associated with the fixture to update.
- public void UpdateEventHorizonFixture(EntityUid uid, PhysicsComponent? physics = null, EventHorizonComponent? eventHorizon = null)
+ public void UpdateEventHorizonFixture(EntityUid uid, FixturesComponent? fixtures = null, EventHorizonComponent? eventHorizon = null)
{
- if(!Resolve(uid, ref eventHorizon))
+ if (!Resolve(uid, ref eventHorizon))
return;
- var fixtureId = eventHorizon.HorizonFixtureId;
- FixturesComponent? manager = null;
-
- if (fixtureId == null || !Resolve(uid, ref manager, ref physics, logMissing: false))
+ var consumerId = eventHorizon.ConsumerFixtureId;
+ var colliderId = eventHorizon.ColliderFixtureId;
+ if (consumerId == null || colliderId == null
+ || !Resolve(uid, ref fixtures, logMissing: false))
return;
- var fixture = _fixtures.GetFixtureOrNull(uid, fixtureId, manager);
- if (fixture == null)
- return;
+ // Update both fixtures the event horizon is associated with:
+ if (consumerId != null)
+ {
+ var consumer = _fixtures.GetFixtureOrNull(uid, consumerId, fixtures);
+ if (consumer != null)
+ {
+ _physics.SetRadius(uid, consumer, consumer.Shape, eventHorizon.Radius, fixtures);
+ _physics.SetHard(uid, consumer, false, fixtures);
+ }
+ }
- var shape = (PhysShapeCircle)fixture.Shape;
- _physics.SetRadius(uid, fixture, shape, eventHorizon.Radius, manager: manager, body: physics);
- _physics.SetHard(uid, fixture, true, manager);
+ if (colliderId != null)
+ {
+ var collider = _fixtures.GetFixtureOrNull(uid, colliderId, fixtures);
+ if (collider != null)
+ {
+ _physics.SetRadius(uid, collider, collider.Shape, eventHorizon.Radius, fixtures);
+ _physics.SetHard(uid, collider, true, fixtures);
+ }
+ }
+
+ EntityManager.Dirty(uid, fixtures);
}
-#endregion Getters/Setters
+ #endregion Getters/Setters
-#region EventHandlers
+ #region EventHandlers
///
/// Syncs the state of the fixture associated with the event horizon upon startup.
@@ -167,7 +207,7 @@ public abstract class SharedEventHorizonSystem : EntitySystem
/// The event arguments.
private void OnPreventCollide(EntityUid uid, EventHorizonComponent comp, ref PreventCollideEvent args)
{
- if(!args.Cancelled)
+ if (!args.Cancelled)
PreventCollide(uid, comp, ref args);
}
@@ -205,5 +245,5 @@ public abstract class SharedEventHorizonSystem : EntitySystem
return false;
}
-#endregion EventHandlers
+ #endregion EventHandlers
}
diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml
index d02d2cd383..ad38290c37 100644
--- a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml
+++ b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/singularity.yml
@@ -14,20 +14,31 @@
- type: EventHorizon # To make the singularity consume things.
radius: 0.5
canBreachContainment: false
- horizonFixtureId: EventHorizon
+ colliderFixtureId: EventHorizonCollider
+ consumerFixtureId: EventHorizonConsumer
- type: GravityWell # To make the singularity attract things.
- type: Fixtures
fixtures:
- EventHorizon:
+ EventHorizonCollider:
shape:
!type:PhysShapeCircle
radius: 0.35
+ hard: true
restitution: 0.8
density: 99999
mask:
- AllMask
layer:
- AllMask
+ EventHorizonConsumer:
+ shape:
+ !type:PhysShapeCircle
+ radius: 0.35
+ hard: false
+ mask:
+ - AllMask
+ layer:
+ - AllMask
- type: Singularity
energy: 180
level: 1
@@ -80,4 +91,3 @@
sprite: Structures/Power/Generation/Singularity/singularity_6.rsi
state: singularity_6
scale: .9,.9
-