Fix AI singulo shenanigans (#31556)

* weh

* Fix broken tests directly mutating entities from wrong thread.

* fix build

* gundam

* weher

* WHY

---------

Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
This commit is contained in:
metalgearsloth
2024-08-31 18:24:12 +10:00
committed by GitHub
parent 2d43bb6b38
commit 18f5a0dca8
7 changed files with 51 additions and 32 deletions

View File

@@ -11,7 +11,9 @@ using Content.Shared.Tag;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Map.Components; using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Events;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Timing; using Robust.Shared.Timing;
namespace Content.Server.Singularity.EntitySystems; namespace Content.Server.Singularity.EntitySystems;
@@ -28,16 +30,20 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
[Dependency] private readonly IMapManager _mapMan = default!; [Dependency] private readonly IMapManager _mapMan = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedContainerSystem _containerSystem = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedTransformSystem _xformSystem = default!; [Dependency] private readonly SharedTransformSystem _xformSystem = default!;
[Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly TagSystem _tagSystem = default!;
#endregion Dependencies #endregion Dependencies
private EntityQuery<PhysicsComponent> _physicsQuery;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_physicsQuery = GetEntityQuery<PhysicsComponent>();
SubscribeLocalEvent<MapGridComponent, EventHorizonAttemptConsumeEntityEvent>(PreventConsume); SubscribeLocalEvent<MapGridComponent, EventHorizonAttemptConsumeEntityEvent>(PreventConsume);
SubscribeLocalEvent<GhostComponent, EventHorizonAttemptConsumeEntityEvent>(PreventConsume);
SubscribeLocalEvent<StationDataComponent, EventHorizonAttemptConsumeEntityEvent>(PreventConsume); SubscribeLocalEvent<StationDataComponent, EventHorizonAttemptConsumeEntityEvent>(PreventConsume);
SubscribeLocalEvent<EventHorizonComponent, MapInitEvent>(OnHorizonMapInit); SubscribeLocalEvent<EventHorizonComponent, MapInitEvent>(OnHorizonMapInit);
SubscribeLocalEvent<EventHorizonComponent, StartCollideEvent>(OnStartCollide); SubscribeLocalEvent<EventHorizonComponent, StartCollideEvent>(OnStartCollide);
@@ -159,24 +165,19 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
/// Attempts to consume all entities within a given distance of an entity; /// Attempts to consume all entities within a given distance of an entity;
/// Excludes the center entity. /// Excludes the center entity.
/// </summary> /// </summary>
public void ConsumeEntitiesInRange(EntityUid uid, float range, TransformComponent? xform = null, EventHorizonComponent? eventHorizon = null) public void ConsumeEntitiesInRange(EntityUid uid, float range, PhysicsComponent? body = null, EventHorizonComponent? eventHorizon = null)
{ {
if (!Resolve(uid, ref xform, ref eventHorizon)) if (!Resolve(uid, ref body, ref eventHorizon))
return; return;
var range2 = range * range; // TODO: Should be sundries + static-sundries but apparently this is load-bearing for SpawnAndDeleteAllEntitiesInTheSameSpot so go figure.
var xformQuery = EntityManager.GetEntityQuery<TransformComponent>(); foreach (var entity in _lookup.GetEntitiesInRange(uid, range, flags: LookupFlags.Uncontained))
var epicenter = _xformSystem.GetWorldPosition(xform, xformQuery);
foreach (var entity in _lookup.GetEntitiesInRange(_xformSystem.GetMapCoordinates(uid, xform), range, flags: LookupFlags.Uncontained))
{ {
if (entity == uid) if (entity == uid)
continue; continue;
if (!xformQuery.TryGetComponent(entity, out var entityXform))
continue;
// 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. // See TODO above
var displacement = _xformSystem.GetWorldPosition(entityXform, xformQuery) - epicenter; if (_physicsQuery.TryComp(entity, out var otherBody) && !_physics.IsHardCollidable((uid, null, body), (entity, null, otherBody)))
if (displacement.LengthSquared() > range2)
continue; continue;
AttemptConsumeEntity(uid, entity, eventHorizon); AttemptConsumeEntity(uid, entity, eventHorizon);
@@ -318,11 +319,11 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem
/// </summary> /// </summary>
public void ConsumeEverythingInRange(EntityUid uid, float range, TransformComponent? xform = null, EventHorizonComponent? eventHorizon = null) public void ConsumeEverythingInRange(EntityUid uid, float range, TransformComponent? xform = null, EventHorizonComponent? eventHorizon = null)
{ {
if (!Resolve(uid, ref xform, ref eventHorizon)) if (!Resolve(uid, ref eventHorizon))
return; return;
if (eventHorizon.ConsumeEntities) if (eventHorizon.ConsumeEntities)
ConsumeEntitiesInRange(uid, range, xform, eventHorizon); ConsumeEntitiesInRange(uid, range, null, eventHorizon);
if (eventHorizon.ConsumeTiles) if (eventHorizon.ConsumeTiles)
ConsumeTilesInRange(uid, range, xform, eventHorizon); ConsumeTilesInRange(uid, range, xform, eventHorizon);
} }

View File

@@ -2,6 +2,7 @@ using System.Numerics;
using Content.Server.Singularity.Components; using Content.Server.Singularity.Components;
using Content.Shared.Atmos.Components; using Content.Shared.Atmos.Components;
using Content.Shared.Ghost; using Content.Shared.Ghost;
using Content.Shared.Physics;
using Content.Shared.Singularity.EntitySystems; using Content.Shared.Singularity.EntitySystems;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Map.Components; using Robust.Shared.Map.Components;
@@ -33,9 +34,18 @@ public sealed class GravityWellSystem : SharedGravityWellSystem
/// </summary> /// </summary>
public const float MinGravPulseRange = 0.00001f; public const float MinGravPulseRange = 0.00001f;
private EntityQuery<GravityWellComponent> _wellQuery;
private EntityQuery<MapComponent> _mapQuery;
private EntityQuery<MapGridComponent> _gridQuery;
private EntityQuery<PhysicsComponent> _physicsQuery;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_wellQuery = GetEntityQuery<GravityWellComponent>();
_mapQuery = GetEntityQuery<MapComponent>();
_gridQuery = GetEntityQuery<MapGridComponent>();
_physicsQuery = GetEntityQuery<PhysicsComponent>();
SubscribeLocalEvent<GravityWellComponent, ComponentStartup>(OnGravityWellStartup); SubscribeLocalEvent<GravityWellComponent, ComponentStartup>(OnGravityWellStartup);
var vvHandle = _vvManager.GetTypeHandler<GravityWellComponent>(); var vvHandle = _vvManager.GetTypeHandler<GravityWellComponent>();
@@ -111,11 +121,15 @@ public sealed class GravityWellSystem : SharedGravityWellSystem
/// <param name="entity">The entity to check.</param> /// <param name="entity">The entity to check.</param>
private bool CanGravPulseAffect(EntityUid entity) private bool CanGravPulseAffect(EntityUid entity)
{ {
return !( if (_physicsQuery.TryComp(entity, out var physics))
EntityManager.HasComponent<GhostComponent>(entity) || {
EntityManager.HasComponent<MapGridComponent>(entity) || if (physics.CollisionLayer == (int) CollisionGroup.GhostImpassable)
EntityManager.HasComponent<MapComponent>(entity) || return false;
EntityManager.HasComponent<GravityWellComponent>(entity) }
return !(_gridQuery.HasComp(entity) ||
_mapQuery.HasComp(entity) ||
_wellQuery.HasComp(entity)
); );
} }

View File

@@ -22,13 +22,17 @@ public enum CollisionGroup
GhostImpassable = 1 << 5, // 32 Things impassible by ghosts/observers, ie blessed tiles or forcefields GhostImpassable = 1 << 5, // 32 Things impassible by ghosts/observers, ie blessed tiles or forcefields
BulletImpassable = 1 << 6, // 64 Can be hit by bullets BulletImpassable = 1 << 6, // 64 Can be hit by bullets
InteractImpassable = 1 << 7, // 128 Blocks interaction/InRangeUnobstructed InteractImpassable = 1 << 7, // 128 Blocks interaction/InRangeUnobstructed
// Y dis door passable when all the others impassable / collision.
DoorPassable = 1 << 8, // 256 Allows door to close over top, Like blast doors over conveyors for disposals rooms/cargo. DoorPassable = 1 << 8, // 256 Allows door to close over top, Like blast doors over conveyors for disposals rooms/cargo.
MapGrid = MapGridHelpers.CollisionGroup, // Map grids, like shuttles. This is the actual grid itself, not the walls or other entities connected to the grid. MapGrid = MapGridHelpers.CollisionGroup, // Map grids, like shuttles. This is the actual grid itself, not the walls or other entities connected to the grid.
// 32 possible groups // 32 possible groups
// Why dis exist
AllMask = -1, AllMask = -1,
SingularityLayer = Opaque | Impassable | MidImpassable | HighImpassable | LowImpassable | BulletImpassable | InteractImpassable | DoorPassable,
// Humanoids, etc. // Humanoids, etc.
MobMask = Impassable | HighImpassable | MidImpassable | LowImpassable, MobMask = Impassable | HighImpassable | MidImpassable | LowImpassable,
MobLayer = Opaque | BulletImpassable, MobLayer = Opaque | BulletImpassable,

View File

@@ -52,18 +52,18 @@
restitution: 0.8 restitution: 0.8
density: 99999 density: 99999
mask: mask:
- AllMask - SingularityLayer
layer: layer:
- AllMask - SingularityLayer
EventHorizonConsumer: EventHorizonConsumer:
shape: shape:
!type:PhysShapeCircle !type:PhysShapeCircle
radius: 5 radius: 5
hard: false hard: false
mask: mask:
- AllMask - SingularityLayer
layer: layer:
- AllMask - SingularityLayer
- type: Input - type: Input
context: "ghost" context: "ghost"
- type: MovementIgnoreGravity - type: MovementIgnoreGravity

View File

@@ -24,7 +24,7 @@
!type:PhysShapeCircle !type:PhysShapeCircle
radius: 0.35 radius: 0.35
density: 15 density: 15
mask: layer:
- GhostImpassable - GhostImpassable
- type: entity - type: entity

View File

@@ -49,18 +49,18 @@
restitution: 0.8 restitution: 0.8
density: 1 density: 1
mask: mask:
- AllMask - SingularityLayer
layer: layer:
- AllMask - SingularityLayer
EventHorizonConsumer: EventHorizonConsumer:
shape: shape:
!type:PhysShapeCircle !type:PhysShapeCircle
radius: 5 radius: 5
hard: false hard: false
mask: mask:
- AllMask - SingularityLayer
layer: layer:
- AllMask - SingularityLayer
- type: Input - type: Input
context: "ghost" context: "ghost"
- type: MovementIgnoreGravity - type: MovementIgnoreGravity

View File

@@ -31,18 +31,18 @@
restitution: 0.8 restitution: 0.8
density: 99999 density: 99999
mask: mask:
- AllMask - SingularityLayer
layer: layer:
- AllMask - SingularityLayer
EventHorizonConsumer: EventHorizonConsumer:
shape: shape:
!type:PhysShapeCircle !type:PhysShapeCircle
radius: 0.35 radius: 0.35
hard: false hard: false
mask: mask:
- AllMask - SingularityLayer
layer: layer:
- AllMask - SingularityLayer
- type: Singularity - type: Singularity
energy: 180 energy: 180
level: 1 level: 1