Fix turrets not shooting in space (#12820)

* Fix turrets not shooting in space

* Faster target acquisition
This commit is contained in:
metalgearsloth
2022-12-02 02:02:01 +11:00
committed by GitHub
parent 85cdf4d797
commit cc90f68f0f
2 changed files with 60 additions and 26 deletions

View File

@@ -30,7 +30,8 @@ public abstract class NPCCombatOperator : HTNOperator
/// Regardless of pathfinding or LOS these are the max we'll check /// Regardless of pathfinding or LOS these are the max we'll check
/// </summary> /// </summary>
private const int MaxConsideredTargets = 10; private const int MaxConsideredTargets = 10;
private const int MaxTargetCount = 5;
protected virtual bool IsRanged => false;
public override void Initialize(IEntitySystemManager sysManager) public override void Initialize(IEntitySystemManager sysManager)
{ {
@@ -66,6 +67,7 @@ public abstract class NPCCombatOperator : HTNOperator
private async Task<List<(EntityUid Entity, float Rating, float Distance)>> GetTargets(NPCBlackboard blackboard) private async Task<List<(EntityUid Entity, float Rating, float Distance)>> GetTargets(NPCBlackboard blackboard)
{ {
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner); var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
var ownerCoordinates = blackboard.GetValueOrDefault<EntityCoordinates>(NPCBlackboard.OwnerCoordinates, EntManager);
var radius = blackboard.GetValueOrDefault<float>(NPCBlackboard.VisionRadius, EntManager); var radius = blackboard.GetValueOrDefault<float>(NPCBlackboard.VisionRadius, EntManager);
var targets = new List<(EntityUid Entity, float Rating, float Distance)>(); var targets = new List<(EntityUid Entity, float Rating, float Distance)>();
@@ -73,18 +75,14 @@ public abstract class NPCCombatOperator : HTNOperator
var xformQuery = EntManager.GetEntityQuery<TransformComponent>(); var xformQuery = EntManager.GetEntityQuery<TransformComponent>();
var mobQuery = EntManager.GetEntityQuery<MobStateComponent>(); var mobQuery = EntManager.GetEntityQuery<MobStateComponent>();
var canMove = blackboard.GetValueOrDefault<bool>(NPCBlackboard.CanMove, EntManager); var canMove = blackboard.GetValueOrDefault<bool>(NPCBlackboard.CanMove, EntManager);
var cancelToken = new CancellationTokenSource();
var count = 0; var count = 0;
var paths = new List<Task>();
// TODO: Really this should be a part of perception so we don't have to constantly re-plan targets.
if (xformQuery.TryGetComponent(existingTarget, out var targetXform)) // Special-case existing target.
if (EntManager.EntityExists(existingTarget))
{ {
var distance = await _pathfinding.GetPathDistance(owner, targetXform.Coordinates, paths.Add(UpdateTarget(owner, existingTarget, existingTarget, ownerCoordinates, blackboard, radius, canMove, xformQuery, targets));
SharedInteractionSystem.InteractionRange, cancelToken.Token, _pathfinding.GetFlags(blackboard));
if (distance != null)
{
targets.Add((existingTarget, GetRating(blackboard, existingTarget, existingTarget, distance.Value, canMove, xformQuery), distance.Value));
}
} }
// TODO: Need a perception system instead // TODO: Need a perception system instead
@@ -94,7 +92,7 @@ public abstract class NPCCombatOperator : HTNOperator
{ {
if (mobQuery.TryGetComponent(target, out var mobState) && if (mobQuery.TryGetComponent(target, out var mobState) &&
mobState.CurrentState > DamageState.Alive || mobState.CurrentState > DamageState.Alive ||
!xformQuery.TryGetComponent(target, out targetXform)) target == existingTarget)
{ {
continue; continue;
} }
@@ -104,27 +102,61 @@ public abstract class NPCCombatOperator : HTNOperator
if (count >= MaxConsideredTargets) if (count >= MaxConsideredTargets)
break; break;
if (!ExamineSystemShared.InRangeUnOccluded(owner, target, radius, null)) paths.Add(UpdateTarget(owner, target, existingTarget, ownerCoordinates, blackboard, radius, canMove, xformQuery, targets));
{
continue;
}
var distance = await _pathfinding.GetPathDistance(owner, targetXform.Coordinates,
SharedInteractionSystem.InteractionRange, cancelToken.Token, _pathfinding.GetFlags(blackboard));
if (distance == null)
continue;
targets.Add((target, GetRating(blackboard, target, existingTarget, distance.Value, canMove, xformQuery), distance.Value));
if (targets.Count >= MaxTargetCount)
break;
} }
await Task.WhenAll(paths);
targets.Sort((x, y) => y.Rating.CompareTo(x.Rating)); targets.Sort((x, y) => y.Rating.CompareTo(x.Rating));
return targets; return targets;
} }
private async Task UpdateTarget(
EntityUid owner,
EntityUid target,
EntityUid existingTarget,
EntityCoordinates ownerCoordinates,
NPCBlackboard blackboard,
float radius,
bool canMove,
EntityQuery<TransformComponent> xformQuery,
List<(EntityUid Entity, float Rating, float Distance)> targets)
{
if (!xformQuery.TryGetComponent(target, out var targetXform))
return;
var inLos = false;
// If it's not an existing target then check LOS.
if (target != existingTarget)
{
inLos = ExamineSystemShared.InRangeUnOccluded(owner, target, radius, null);
if (!inLos)
return;
}
// Turret or the likes, check LOS only.
if (IsRanged && !canMove)
{
inLos = inLos || ExamineSystemShared.InRangeUnOccluded(owner, target, radius, null);
if (!inLos || !targetXform.Coordinates.TryDistance(EntManager, ownerCoordinates, out var distance))
return;
targets.Add((target, GetRating(blackboard, target, existingTarget, distance, canMove, xformQuery), distance));
return;
}
var nDistance = await _pathfinding.GetPathDistance(owner, targetXform.Coordinates,
SharedInteractionSystem.InteractionRange, default, _pathfinding.GetFlags(blackboard));
if (nDistance == null)
return;
targets.Add((target, GetRating(blackboard, target, existingTarget, nDistance.Value, canMove, xformQuery), nDistance.Value));
}
protected abstract float GetRating(NPCBlackboard blackboard, EntityUid uid, EntityUid existingTarget, float distance, bool canMove, protected abstract float GetRating(NPCBlackboard blackboard, EntityUid uid, EntityUid existingTarget, float distance, bool canMove,
EntityQuery<TransformComponent> xformQuery); EntityQuery<TransformComponent> xformQuery);
} }

View File

@@ -8,6 +8,8 @@ namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Ranged;
[UsedImplicitly] [UsedImplicitly]
public sealed class PickRangedTargetOperator : NPCCombatOperator public sealed class PickRangedTargetOperator : NPCCombatOperator
{ {
protected override bool IsRanged => true;
protected override float GetRating(NPCBlackboard blackboard, EntityUid uid, EntityUid existingTarget, float distance, bool canMove, EntityQuery<TransformComponent> xformQuery) protected override float GetRating(NPCBlackboard blackboard, EntityUid uid, EntityUid existingTarget, float distance, bool canMove, EntityQuery<TransformComponent> xformQuery)
{ {
// Yeah look I just came up with values that seemed okay but they will need a lot of tweaking. // Yeah look I just came up with values that seemed okay but they will need a lot of tweaking.