Concept: Scan, Gather, Filter, Broadcast
Your persistent interact ability runs two of this plugin's tasks: a client-side scan that decides what to show, and a server-side granter that makes the options activatable.
- Scan - every scan-rate seconds the scan task traces (cursor or forward) and collects every
ICrimsonInteractableTargetit finds, in priority order (closest / first hit). - Gather - each target's
GatherInteractionOptionsfills the builder with itsFCrimsonInteractionOptions. - Filter -
UpdateInteractableOptionsresolves each option's ability spec and keeps only those whoseCanActivateAbilitypasses, so unavailable options never show. - Broadcast - if the option set changed, the task fires its
InteractableObjectsChangeddelegate with the surviving options in priority order. What happens next is your ability's job: store them and update your prompt. - Grant - in parallel, the server-only
GrantNearbyInteractiontask overlaps the avatar and grants each option'sInteractionAbilityToGrantandInteractionActionAbility, revoking grants for interactables that leave range.
Priority order is preserved
The delegate's array keeps the scan task's priority order, so index 0 is reliably the focused target. Change-detection sorts a separate snapshot, so a pure reorder does not re-fire the broadcast (no prompt flicker).
The filter is why the grant task is mandatory
An option whose granted/target ability cannot currently activate is silently dropped in the Filter step. If your prompt never appears, the usual cause is the grant task not running (it must be spawned on the server instance of the ability) or the handler ability failing
CanActivateAbility (cost/cooldown/tag blocks).