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:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user