Fix AI avoiding entities they can't collide with (#1331)

Should stop mobs getting trapped at the bar on saltern as they try to avoid light bulbs

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
This commit is contained in:
metalgearsloth
2020-07-09 22:15:48 +10:00
committed by GitHub
parent 9256ff50d0
commit 8938d96402
2 changed files with 16 additions and 13 deletions

View File

@@ -27,8 +27,8 @@ namespace Content.Server.GameObjects.EntitySystems.Pathfinding
public int BlockedCollisionMask { get; private set; } public int BlockedCollisionMask { get; private set; }
private readonly Dictionary<EntityUid, int> _blockedCollidables = new Dictionary<EntityUid, int>(0); private readonly Dictionary<EntityUid, int> _blockedCollidables = new Dictionary<EntityUid, int>(0);
public IReadOnlyCollection<EntityUid> PhysicsUids => _physicsUids; public IReadOnlyDictionary<EntityUid, int> PhysicsLayers => _physicsLayers;
private readonly HashSet<EntityUid> _physicsUids = new HashSet<EntityUid>(0); private readonly Dictionary<EntityUid, int> _physicsLayers = new Dictionary<EntityUid, int>(0);
/// <summary> /// <summary>
/// The entities on this tile that require access to traverse /// The entities on this tile that require access to traverse
@@ -115,11 +115,12 @@ namespace Content.Server.GameObjects.EntitySystems.Pathfinding
return; return;
} }
if (entity.TryGetComponent(out CollidableComponent collidableComponent)) if (entity.TryGetComponent(out CollidableComponent collidableComponent) &&
(PathfindingSystem.TrackedCollisionLayers & collidableComponent.CollisionLayer) != 0)
{ {
if (entity.TryGetComponent(out PhysicsComponent physicsComponent) && !physicsComponent.Anchored) if (entity.TryGetComponent(out PhysicsComponent physicsComponent) && !physicsComponent.Anchored)
{ {
_physicsUids.Add(entity.Uid); _physicsLayers.Add(entity.Uid, collidableComponent.CollisionLayer);
} }
else else
{ {
@@ -139,9 +140,9 @@ namespace Content.Server.GameObjects.EntitySystems.Pathfinding
// There's no guarantee that the entity isn't deleted // There's no guarantee that the entity isn't deleted
// 90% of updates are probably entities moving around // 90% of updates are probably entities moving around
// Entity can't be under multiple categories so just checking each once is fine. // Entity can't be under multiple categories so just checking each once is fine.
if (_physicsUids.Contains(entity.Uid)) if (_physicsLayers.ContainsKey(entity.Uid))
{ {
_physicsUids.Remove(entity.Uid); _physicsLayers.Remove(entity.Uid);
} }
else if (_accessReaders.ContainsKey(entity.Uid)) else if (_accessReaders.ContainsKey(entity.Uid))
{ {

View File

@@ -10,6 +10,7 @@ using Content.Server.GameObjects.EntitySystems.JobQueues;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Server.Interfaces.Timing; using Robust.Server.Interfaces.Timing;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components; using Robust.Shared.GameObjects.Components;
using Robust.Shared.GameObjects.Systems; using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
@@ -319,7 +320,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Steering
return SteeringStatus.Pending; return SteeringStatus.Pending;
} }
var ignoredCollision = new List<IEntity>(); var ignoredCollision = new List<EntityUid>();
// Check if the target entity has moved - If so then re-path // Check if the target entity has moved - If so then re-path
// TODO: Patch the path from the target's position back towards us, stopping if it ever intersects the current path // TODO: Patch the path from the target's position back towards us, stopping if it ever intersects the current path
// Probably need a separate "PatchPath" job // Probably need a separate "PatchPath" job
@@ -338,7 +339,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Steering
RequestPath(entity, steeringRequest); RequestPath(entity, steeringRequest);
} }
ignoredCollision.Add(entitySteer.Target); ignoredCollision.Add(entitySteer.Target.Uid);
} }
HandleStuck(entity); HandleStuck(entity);
@@ -596,9 +597,9 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Steering
/// <param name="direction">entity's travel direction</param> /// <param name="direction">entity's travel direction</param>
/// <param name="ignoredTargets"></param> /// <param name="ignoredTargets"></param>
/// <returns></returns> /// <returns></returns>
private Vector2 CollisionAvoidance(IEntity entity, Vector2 direction, ICollection<IEntity> ignoredTargets) private Vector2 CollisionAvoidance(IEntity entity, Vector2 direction, ICollection<EntityUid> ignoredTargets)
{ {
if (direction == Vector2.Zero || !entity.HasComponent<CollidableComponent>()) if (direction == Vector2.Zero || !entity.TryGetComponent(out CollidableComponent collidableComponent))
{ {
return Vector2.Zero; return Vector2.Zero;
} }
@@ -606,6 +607,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Steering
// We'll check tile-by-tile // We'll check tile-by-tile
// Rewriting this frequently so not many comments as they'll go stale // Rewriting this frequently so not many comments as they'll go stale
// I realise this is bad so please rewrite it ;-; // I realise this is bad so please rewrite it ;-;
var entityCollisionMask = collidableComponent.CollisionMask;
var avoidanceVector = Vector2.Zero; var avoidanceVector = Vector2.Zero;
var checkTiles = new HashSet<TileRef>(); var checkTiles = new HashSet<TileRef>();
var avoidTiles = new HashSet<TileRef>(); var avoidTiles = new HashSet<TileRef>();
@@ -625,10 +627,10 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Steering
{ {
var node = _pathfindingSystem.GetNode(tile); var node = _pathfindingSystem.GetNode(tile);
// Assume the immovables have already been checked // Assume the immovables have already been checked
foreach (var uid in node.PhysicsUids) foreach (var (uid, layer) in node.PhysicsLayers)
{ {
// Ignore myself / my target if applicable // Ignore myself / my target if applicable / if my mask doesn't collide
if (uid == entity.Uid || ignoredTargets.Contains(entity)) continue; if (uid == entity.Uid || ignoredTargets.Contains(uid) || (entityCollisionMask & layer) == 0) continue;
// God there's so many ways to do this // God there's so many ways to do this
// err for now we'll just assume the first entity is the center and just add a vector for it // err for now we'll just assume the first entity is the center and just add a vector for it
var collisionEntity = _entityManager.GetEntity(uid); var collisionEntity = _entityManager.GetEntity(uid);