using System.Threading;
using System.Threading.Tasks;
using Content.Server.NPC.Pathfinding;
using Content.Shared.Interaction;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Whitelist;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific;
///
/// Queries for nearby entities matching a whitelist/blacklist, and then searches for a mob near to that entity.
///
public sealed partial class PickEntityNearMobOperator : HTNOperator
{
[Dependency] private IEntityManager _entManager = default!;
private EntityLookupSystem _lookup = default!;
private PathfindingSystem _pathfinding = default!;
private EntityWhitelistSystem _entityWhitelist = default!;
///
/// Range to search for entities
///
[DataField(required: true)]
public string RangeKey = default!;
///
/// Target mob that was found near NearbyEntityTargetKey
///
[DataField(required: true)]
public string TargetKey = string.Empty;
///
/// Target entity that was found
///
[DataField(required: true)]
public string NearbyEntityTargetKey = string.Empty;
///
/// Target entitycoordinates to move to.
///
[DataField(required: true)]
public string TargetMoveKey = string.Empty;
///
/// Whitelist for what entities will get picked
///
[DataField]
public EntityWhitelist? Whitelist;
///
/// Blacklist for what entities will NOT get picked
///
[DataField]
public EntityWhitelist? Blacklist;
///
/// Range to search for mobs near the target entity
///
[DataField(required: true)]
public string MobRangeKey = default!;
///
/// MobState to check for
///
[DataField]
public MobState? MobState;
public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_lookup = sysManager.GetEntitySystem();
_pathfinding = sysManager.GetEntitySystem();
_entityWhitelist = sysManager.GetEntitySystem();
}
public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard,
CancellationToken cancelToken)
{
var owner = blackboard.GetValue(NPCBlackboard.Owner);
if (!blackboard.TryGetValue(RangeKey, out var range, _entManager))
return (false, null);
if (!blackboard.TryGetValue(MobRangeKey, out var mobRange, _entManager))
return (false, null);
var mobState = _entManager.GetEntityQuery();
foreach (var mob in _lookup.GetEntitiesInRange(owner, mobRange, LookupFlags.Uncontained & ~LookupFlags.Sensors))
{
if (mob == owner)
continue;
if (!mobState.TryGetComponent(mob, out var state))
continue;
if (MobState != null && state.CurrentState != MobState)
continue;
foreach (var entity in _lookup.GetEntitiesInRange(mob, range))
{
if (!_entityWhitelist.CheckBoth(entity, Blacklist, Whitelist))
continue;
var pathRange = SharedInteractionSystem.InteractionRange;
var path = await _pathfinding.GetPath(owner, mob, pathRange, cancelToken);
if (path.Result == PathResult.NoPath)
return (false, null);
return (true, new Dictionary()
{
{TargetKey, mob},
{NearbyEntityTargetKey, entity},
{TargetMoveKey, _entManager.GetComponent(mob).Coordinates},
{NPCBlackboard.PathfindKey, path},
});
}
}
return (false, null);
}
}