Fix NPC assert (#17770)
This commit is contained in:
@@ -46,7 +46,6 @@ public sealed partial class NPCSteeringSystem
|
||||
Angle offsetRot,
|
||||
float moveSpeed,
|
||||
float[] interest,
|
||||
EntityQuery<PhysicsComponent> bodyQuery,
|
||||
float frameTime,
|
||||
ref bool forceSteer)
|
||||
{
|
||||
@@ -132,7 +131,7 @@ public sealed partial class NPCSteeringSystem
|
||||
return true;
|
||||
}
|
||||
|
||||
status = TryHandleFlags(uid, steering, node, bodyQuery);
|
||||
status = TryHandleFlags(uid, steering, node);
|
||||
}
|
||||
|
||||
// TODO: Need to handle re-pathing in case the target moves around.
|
||||
@@ -202,7 +201,7 @@ public sealed partial class NPCSteeringSystem
|
||||
// A) NPCs get stuck on non-anchored static bodies still (e.g. closets)
|
||||
// B) NPCs still try to move in locked containers (e.g. cow, hamster)
|
||||
// and I don't want to spam grafana even harder than it gets spammed rn.
|
||||
_sawmill.Debug($"NPC {ToPrettyString(uid)} found stuck at {ourCoordinates}");
|
||||
Log.Debug($"NPC {ToPrettyString(uid)} found stuck at {ourCoordinates}");
|
||||
steering.Status = SteeringStatus.NoPath;
|
||||
return false;
|
||||
}
|
||||
@@ -380,10 +379,7 @@ public sealed partial class NPCSteeringSystem
|
||||
int layer,
|
||||
int mask,
|
||||
TransformComponent xform,
|
||||
float[] danger,
|
||||
List<Vector2> dangerPoints,
|
||||
EntityQuery<PhysicsComponent> bodyQuery,
|
||||
EntityQuery<TransformComponent> xformQuery)
|
||||
float[] danger)
|
||||
{
|
||||
var objectRadius = 0.15f;
|
||||
var detectionRadius = MathF.Max(0.35f, agentRadius + objectRadius);
|
||||
@@ -392,7 +388,7 @@ public sealed partial class NPCSteeringSystem
|
||||
{
|
||||
// TODO: If we can access the door or smth.
|
||||
if (ent == uid ||
|
||||
!bodyQuery.TryGetComponent(ent, out var otherBody) ||
|
||||
!_physicsQuery.TryGetComponent(ent, out var otherBody) ||
|
||||
!otherBody.Hard ||
|
||||
!otherBody.CanCollide ||
|
||||
(mask & otherBody.CollisionLayer) == 0x0 &&
|
||||
@@ -401,7 +397,7 @@ public sealed partial class NPCSteeringSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
var xformB = xformQuery.GetComponent(ent);
|
||||
var xformB = _xformQuery.GetComponent(ent);
|
||||
|
||||
if (!_physics.TryGetNearest(uid, ent, out var pointA, out var pointB, out var distance, xform, xformB))
|
||||
{
|
||||
@@ -417,19 +413,16 @@ public sealed partial class NPCSteeringSystem
|
||||
// Inside each other so just use worldPos
|
||||
if (distance == 0f)
|
||||
{
|
||||
obstacleDirection = _transform.GetWorldPosition(xformB, xformQuery) - worldPos;
|
||||
|
||||
// Welp
|
||||
if (obstacleDirection == Vector2.Zero)
|
||||
{
|
||||
obstacleDirection = Vector2.One.Normalized;
|
||||
}
|
||||
obstacleDirection = _transform.GetWorldPosition(xformB) - worldPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
weight = distance / detectionRadius;
|
||||
}
|
||||
|
||||
if (obstacleDirection == Vector2.Zero)
|
||||
continue;
|
||||
|
||||
obstacleDirection = offsetRot.RotateVec(obstacleDirection);
|
||||
var norm = obstacleDirection.Normalized;
|
||||
|
||||
@@ -458,9 +451,7 @@ public sealed partial class NPCSteeringSystem
|
||||
int mask,
|
||||
PhysicsComponent body,
|
||||
TransformComponent xform,
|
||||
float[] danger,
|
||||
EntityQuery<PhysicsComponent> bodyQuery,
|
||||
EntityQuery<TransformComponent> xformQuery)
|
||||
float[] danger)
|
||||
{
|
||||
var objectRadius = 0.25f;
|
||||
var detectionRadius = MathF.Max(0.35f, agentRadius + objectRadius);
|
||||
@@ -472,7 +463,7 @@ public sealed partial class NPCSteeringSystem
|
||||
{
|
||||
// TODO: If we can access the door or smth.
|
||||
if (ent == uid ||
|
||||
!bodyQuery.TryGetComponent(ent, out var otherBody) ||
|
||||
!_physicsQuery.TryGetComponent(ent, out var otherBody) ||
|
||||
!otherBody.Hard ||
|
||||
!otherBody.CanCollide ||
|
||||
(mask & otherBody.CollisionLayer) == 0x0 &&
|
||||
@@ -485,7 +476,7 @@ public sealed partial class NPCSteeringSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
var xformB = xformQuery.GetComponent(ent);
|
||||
var xformB = _xformQuery.GetComponent(ent);
|
||||
|
||||
if (!_physics.TryGetNearest(uid, ent, out var pointA, out var pointB, out var distance, xform, xformB))
|
||||
{
|
||||
@@ -501,7 +492,7 @@ public sealed partial class NPCSteeringSystem
|
||||
// Inside each other so just use worldPos
|
||||
if (distance == 0f)
|
||||
{
|
||||
obstacleDirection = _transform.GetWorldPosition(xformB, xformQuery) - worldPos;
|
||||
obstacleDirection = _transform.GetWorldPosition(xformB) - worldPos;
|
||||
|
||||
// Welp
|
||||
if (obstacleDirection == Vector2.Zero)
|
||||
|
||||
@@ -33,7 +33,7 @@ public sealed partial class NPCSteeringSystem
|
||||
*/
|
||||
|
||||
|
||||
private SteeringObstacleStatus TryHandleFlags(EntityUid uid, NPCSteeringComponent component, PathPoly poly, EntityQuery<PhysicsComponent> bodyQuery)
|
||||
private SteeringObstacleStatus TryHandleFlags(EntityUid uid, NPCSteeringComponent component, PathPoly poly)
|
||||
{
|
||||
DebugTools.Assert(!poly.Data.IsFreeSpace);
|
||||
// TODO: Store PathFlags on the steering comp
|
||||
@@ -71,7 +71,7 @@ public sealed partial class NPCSteeringSystem
|
||||
|
||||
var obstacleEnts = new List<EntityUid>();
|
||||
|
||||
GetObstacleEntities(poly, mask, layer, bodyQuery, obstacleEnts);
|
||||
GetObstacleEntities(poly, mask, layer, obstacleEnts);
|
||||
var isDoor = (poly.Data.Flags & PathfindingBreadcrumbFlag.Door) != 0x0;
|
||||
var isAccessRequired = (poly.Data.Flags & PathfindingBreadcrumbFlag.Access) != 0x0;
|
||||
|
||||
@@ -157,8 +157,7 @@ public sealed partial class NPCSteeringSystem
|
||||
return SteeringObstacleStatus.Completed;
|
||||
}
|
||||
|
||||
private void GetObstacleEntities(PathPoly poly, int mask, int layer, EntityQuery<PhysicsComponent> bodyQuery,
|
||||
List<EntityUid> ents)
|
||||
private void GetObstacleEntities(PathPoly poly, int mask, int layer, List<EntityUid> ents)
|
||||
{
|
||||
// TODO: Can probably re-use this from pathfinding or something
|
||||
if (!_mapManager.TryGetGrid(poly.GraphUid, out var grid))
|
||||
@@ -168,7 +167,7 @@ public sealed partial class NPCSteeringSystem
|
||||
|
||||
foreach (var ent in grid.GetLocalAnchoredEntities(poly.Box))
|
||||
{
|
||||
if (!bodyQuery.TryGetComponent(ent, out var body) ||
|
||||
if (!_physicsQuery.TryGetComponent(ent, out var body) ||
|
||||
!body.Hard ||
|
||||
!body.CanCollide ||
|
||||
(body.CollisionMask & layer) == 0x0 && (body.CollisionLayer & mask) == 0x0)
|
||||
|
||||
@@ -19,6 +19,7 @@ using Content.Shared.Weapons.Melee;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Player;
|
||||
@@ -60,6 +61,11 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedCombatModeSystem _combat = default!;
|
||||
|
||||
private EntityQuery<FixturesComponent> _fixturesQuery;
|
||||
private EntityQuery<PhysicsComponent> _physicsQuery;
|
||||
private EntityQuery<MovementSpeedModifierComponent> _modifierQuery;
|
||||
private EntityQuery<TransformComponent> _xformQuery;
|
||||
|
||||
/// <summary>
|
||||
/// Enabled antistuck detection so if an NPC is in the same spot for a while it will re-path.
|
||||
/// </summary>
|
||||
@@ -75,16 +81,19 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
|
||||
|
||||
private object _obstacles = new();
|
||||
|
||||
private ISawmill _sawmill = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_sawmill = Logger.GetSawmill("npc.steering");
|
||||
|
||||
_fixturesQuery = GetEntityQuery<FixturesComponent>();
|
||||
_physicsQuery = GetEntityQuery<PhysicsComponent>();
|
||||
_modifierQuery = GetEntityQuery<MovementSpeedModifierComponent>();
|
||||
_xformQuery = GetEntityQuery<TransformComponent>();
|
||||
|
||||
#if DEBUG
|
||||
_sawmill.Level = LogLevel.Warning;
|
||||
Log.Level = LogLevel.Warning;
|
||||
#else
|
||||
_sawmill.Level = LogLevel.Debug;
|
||||
Log.Level = LogLevel.Debug;
|
||||
#endif
|
||||
|
||||
for (var i = 0; i < InterestDirections; i++)
|
||||
@@ -226,10 +235,6 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
|
||||
return;
|
||||
|
||||
// Not every mob has the modifier component so do it as a separate query.
|
||||
var bodyQuery = GetEntityQuery<PhysicsComponent>();
|
||||
var modifierQuery = GetEntityQuery<MovementSpeedModifierComponent>();
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
|
||||
var npcs = EntityQuery<ActiveNPCComponent, NPCSteeringComponent, InputMoverComponent, TransformComponent>()
|
||||
.Select(o => (o.Item1.Owner, o.Item2, o.Item3, o.Item4)).ToArray();
|
||||
|
||||
@@ -243,7 +248,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
|
||||
Parallel.For(0, npcs.Length, options, i =>
|
||||
{
|
||||
var (uid, steering, mover, xform) = npcs[i];
|
||||
Steer(uid, steering, mover, xform, modifierQuery, bodyQuery, xformQuery, frameTime, curTime);
|
||||
Steer(uid, steering, mover, xform, frameTime, curTime);
|
||||
});
|
||||
|
||||
|
||||
@@ -288,9 +293,6 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
|
||||
NPCSteeringComponent steering,
|
||||
InputMoverComponent mover,
|
||||
TransformComponent xform,
|
||||
EntityQuery<MovementSpeedModifierComponent> modifierQuery,
|
||||
EntityQuery<PhysicsComponent> bodyQuery,
|
||||
EntityQuery<TransformComponent> xformQuery,
|
||||
float frameTime,
|
||||
TimeSpan curTime)
|
||||
{
|
||||
@@ -319,14 +321,14 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
|
||||
var interest = steering.Interest;
|
||||
var danger = steering.Danger;
|
||||
var agentRadius = steering.Radius;
|
||||
var worldPos = _transform.GetWorldPosition(xform, xformQuery);
|
||||
var worldPos = _transform.GetWorldPosition(xform);
|
||||
var (layer, mask) = _physics.GetHardCollision(uid);
|
||||
|
||||
// Use rotation relative to parent to rotate our context vectors by.
|
||||
var offsetRot = -_mover.GetParentGridAngle(mover);
|
||||
modifierQuery.TryGetComponent(uid, out var modifier);
|
||||
_modifierQuery.TryGetComponent(uid, out var modifier);
|
||||
var moveSpeed = GetSprintSpeed(uid, modifier);
|
||||
var body = bodyQuery.GetComponent(uid);
|
||||
var body = _physicsQuery.GetComponent(uid);
|
||||
var dangerPoints = steering.DangerPoints;
|
||||
dangerPoints.Clear();
|
||||
|
||||
@@ -341,7 +343,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
|
||||
// If seek has arrived at the target node for example then immediately re-steer.
|
||||
var forceSteer = true;
|
||||
|
||||
if (steering.CanSeek && !TrySeek(uid, mover, steering, body, xform, offsetRot, moveSpeed, interest, bodyQuery, frameTime, ref forceSteer))
|
||||
if (steering.CanSeek && !TrySeek(uid, mover, steering, body, xform, offsetRot, moveSpeed, interest, frameTime, ref forceSteer))
|
||||
{
|
||||
SetDirection(mover, steering, Vector2.Zero);
|
||||
return;
|
||||
@@ -360,10 +362,10 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem
|
||||
}
|
||||
|
||||
// Avoid static objects like walls
|
||||
CollisionAvoidance(uid, offsetRot, worldPos, agentRadius, layer, mask, xform, danger, dangerPoints, bodyQuery, xformQuery);
|
||||
CollisionAvoidance(uid, offsetRot, worldPos, agentRadius, layer, mask, xform, danger);
|
||||
DebugTools.Assert(!float.IsNaN(danger[0]));
|
||||
|
||||
Separation(uid, offsetRot, worldPos, agentRadius, layer, mask, body, xform, danger, bodyQuery, xformQuery);
|
||||
Separation(uid, offsetRot, worldPos, agentRadius, layer, mask, body, xform, danger);
|
||||
|
||||
// Remove the danger map from the interest map.
|
||||
var desiredDirection = -1;
|
||||
|
||||
Reference in New Issue
Block a user