diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs index 7142eda037..abae513dbe 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs @@ -46,7 +46,6 @@ public sealed partial class NPCSteeringSystem Angle offsetRot, float moveSpeed, float[] interest, - EntityQuery 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 dangerPoints, - EntityQuery bodyQuery, - EntityQuery 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 bodyQuery, - EntityQuery 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) diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs index 0a49846bce..318cc978ea 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs @@ -33,7 +33,7 @@ public sealed partial class NPCSteeringSystem */ - private SteeringObstacleStatus TryHandleFlags(EntityUid uid, NPCSteeringComponent component, PathPoly poly, EntityQuery 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(); - 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 bodyQuery, - List ents) + private void GetObstacleEntities(PathPoly poly, int mask, int layer, List 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) diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.cs index 5cdfe9799f..4c7984226d 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.cs @@ -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 _fixturesQuery; + private EntityQuery _physicsQuery; + private EntityQuery _modifierQuery; + private EntityQuery _xformQuery; + /// /// Enabled antistuck detection so if an NPC is in the same spot for a while it will re-path. /// @@ -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(); + _physicsQuery = GetEntityQuery(); + _modifierQuery = GetEntityQuery(); + _xformQuery = GetEntityQuery(); + #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(); - var modifierQuery = GetEntityQuery(); - var xformQuery = GetEntityQuery(); - var npcs = EntityQuery() .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 modifierQuery, - EntityQuery bodyQuery, - EntityQuery 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;