Class TargetSelector
Abstract base class for selecting targets in an ability or event context. Implementations consume the current EventData (its Target or Initiator serve as the spatial / contextual reference) and yield one or more UnityEngine.GameObjects for triggers, conditions or actions to operate on.
Asset safety: selectors are serialized inline on Trigger ScriptableObjects via
[SerializeReference]. Unity cannot serialize references to scene GameObjects from
asset files, so selectors intentionally hold no direct scene references. To "pick a
specific scene object" from an asset-based Trigger, use
NamedSceneObjectTargetSelector or TaggedSceneObjectTargetSelector
— they resolve scene objects at runtime by name or tag. For inline (MonoBehaviour-hosted)
triggers in a scene, prefer setting Target at the invocation
site so the trigger receives the picked GameObject through standard event flow.
[Serializable]
public abstract class TargetSelector
- Inheritance
-
TargetSelector
- Derived
- Inherited Members
Fields
Conditions
Conditions that must be met for a target to be valid. Evaluated per-candidate inside AreConditionsMet(GameObject, EventData). Honors the ambient ConditionFilter via AreConditionsMet(List<BaseCondition>, EventData, Func<BaseCondition, bool>).
[Tooltip("Conditions that must be met for a target to be valid.")]
[SerializeReference]
public List<BaseCondition> Conditions
Field Value
Methods
AreConditionsMet(GameObject, EventData)
Evaluates this selector's per-target Conditions against the candidate target. Builds a forked EventData scoped to the candidate so conditions see the right Target / TargetCharacter, then delegates to AreConditionsMet(List<BaseCondition>, EventData, Func<BaseCondition, bool>) so nested conditions' own TargetSelector and Combine settings are honored uniformly with top-level Trigger conditions.
protected bool AreConditionsMet(GameObject target, EventData eventData)
Parameters
targetGameObjectThe candidate target GameObject.
eventDataEventDataThe parent event data, or null.
Returns
- bool
True when no conditions exist, or all conditions pass.
GatherRewound(EventData, GameObject, List<GameObject>, GatherTargets)
Collects candidates inside a single rewind scope and returns them once it has closed.
protected static void GatherRewound(EventData eventData, GameObject context, List<GameObject> results, TargetSelector.GatherTargets gather)
Parameters
eventDataEventDataThe event driving the selection.
contextGameObjectThe spatial origin object; its scene is the one rewound.
resultsList<GameObject>Receives the selected objects, in the gather's order.
gatherTargetSelector.GatherTargetsThe query and ranking to run under the scope.
Remarks
This is ChainTargetSelector's pattern, generalised, and it exists for two reasons the chain learned first.
Ranking must read the same world the query did. LagCompensatedQuery closes its rewind before returning, so a selector that queried through it and then measured distances was selecting from the rewound world and ranking by live positions — the nearest candidate by one measure and a different one by the other, differing by the peer's speed times its latency. Conditions are evaluated inside the scope for the same reason: a range condition that disagrees with the query that produced the candidate is not a filter, it is a coin toss.
Nothing is yielded while the world is displaced. Selectors are iterators and the consumer between two yields is the damage and ECA pipeline. Materialising the whole result first means the scope has closed before any of that runs.
GetContext(EventData)
protected static GameObject GetContext(EventData eventData)
Parameters
eventDataEventData
Returns
- GameObject
GetTooltipContribution()
Returns a short, designer-facing tooltip line describing this selector's targeting
(e.g. "Nearest enemy within 10m"), or null when the selector has nothing
to contribute. Override on selectors that have player-visible targeting semantics.
public virtual string GetTooltipContribution()
Returns
IsAuthoritativePeer(EventData)
Returns the spatial origin for this selector — preferring Target, falling back to Initiator's GameObject.
protected static bool IsAuthoritativePeer(EventData eventData)
Parameters
eventDataEventDataThe current event data.
Returns
- bool
A GameObject to use as a spatial reference, or null.
Remarks
Server only, and not "not a replicate tick". Every physics selector used to open
with if (tickData.IsReplicateTick) yield break;, on the theory that a replicate tick
means a client replay. It does not. AbilityObject's self-target dispatch and its
OnPreSpawn/OnSpawn dispatches, and AbilityController's activation triggers, all
attach a TickEventData built from the replicate PredictionTick — on the
server as well. So the guard fired on the server too, and a point-blank area ability
selected nothing and dealt no damage on any peer. AbilityApplyAreaAction was
corrected for exactly this and gates on the peer instead; this is the same rule, applied
at the selector.
The tick payload is left on the event untouched. It still carries real information for the tick-domain consumers downstream (buff stamping, cooldowns) — it just never meant what the old guard read it as.
QueryBufferSize(int)
Query buffer size for a selector whose authored cap is maxHits.
protected static int QueryBufferSize(int maxHits)
Parameters
maxHitsint
Returns
Remarks
Deliberately larger than the cap. Sizing the buffer at exactly MaxHits makes the
physics broadphase perform the truncation, in its own order, before the selector ever sees
the candidates — so a cap of 5 in a crowd of 20 picked five arbitrary characters and the
deterministic sort that follows had nothing to work with. Querying wide and capping after
the sort is what makes the cap mean "the first five in a defined order".
A starting size, not a limit. It only moves the truncation point from MaxHits
up to MaxHits * 4; every caller must still grow the buffer through
TryGrowQueryBuffer<T>(ref T[], int) when a query comes back full.
The rule itself lives on TargetOrdering now, because the ability actions
resolve hits without a selector and need the identical arithmetic — it was duplicated
inline in AbilityApplyAreaAction for exactly as long as it lived somewhere only
selectors could reach. This forwarder stays so the selectors read naturally.
SelectTargets(EventData)
Selects targets based on the supplied event context.
public abstract IEnumerable<GameObject> SelectTargets(EventData eventData)
Parameters
eventDataEventDataThe event data driving the selection. Target (when set) or Initiator typically serves as the spatial origin.
Returns
- IEnumerable<GameObject>
The selected GameObjects.