Interaction Integration
CrimsonCore is where the abstract CrimsonInteraction system becomes a working interaction loop. The integration ships:
UCrimsonCoreGameplayAbility_Interact— concrete persistent scan + dispatch ability. Picks between top-down and forward-line-trace strategies, binds two input tags (quick-press + context-menu), broadcastsMessage.Interaction.OptionsChangedfor HUD widgets. Prompt presentation is switchable viaPromptMode(on-actor world indicators by default).UCrimsonCoreGameplayAbility_InteractionDuration— thin subclass that defaults the UIExtension slot + success tag and forwardsNotifyInteractionSuccessto the target on completion. Not abstract: assign it directly as an option'sInteractionActionAbilityfor a working default channel. Channels are press-and-forget; opt-in cancels:MaxDistanceFromTarget(walk-away, default 600) andbCancelWhenInputReleased(hold-to-mine).UCrimsonCoreGameplayAbility_InteractionHandler— fire-and-forget handler ability; defaultPickupHandlerAbilityon pickups.FCrimsonInteractionOptionsChangedMessage— broadcast struct so the prompt widget can listen without coupling to the ability.- Collision channel
Crimson_TraceChannel_Interaction+ profilesInteractable_OverlapDynamic/Interactable_BlockDynamic(host project's DefaultEngine.ini). - Native tags
InputTag.Interact,InputTag.Interact.OpenMenu,HUD.Interaction.Prompt,HUD.Interaction.Progress,Ability.Interaction.SuccessEvent.Default,Message.Interaction.OptionsChanged.
Quick-press vs context menu
Two input bindings on the same persistent ability: quick-press fires Options[0] immediately (Diablo / PoE pickup feel); OpenMenu opens a world-anchored context menu listing every available option via UCrimsonCoreContextMenuSubsystem::ShowContextMenuForActor. If only one option exists, OpenMenu falls through to the quick-press path so single-option pickups don't show a useless one-row menu.
// BP defaults on BP_GA_Interact:InputTag = InputTag.Interact; // quick-press -> Options[0]ContextMenuInputTag = InputTag.Interact.OpenMenu; // right-click / F -> context menuContextMenuWidgetClass = WBP_ContextMenu_World; // optional: unset falls back to// UCrimsonUISettings::DefaultWorldContextMenuClass
Multi-action pickups
ACrimsonCorePickupActor::SecondaryActions is a TArray<FCrimsonPickupSecondaryAction> exposed in Blueprint defaults. Each entry produces an extra FCrimsonInteractionOption in GatherInteractionOptions, so designers can add Split Stack, Drop Here, Inspect, etc. without C++. The primary pickup action stays as Options[0]; secondaries are Options[1..N] and reachable only through the OpenMenu input.
USTRUCT(BlueprintType)struct FCrimsonPickupSecondaryAction{UPROPERTY(EditDefaultsOnly) FText Label;UPROPERTY(EditDefaultsOnly) FText SubText;UPROPERTY(EditDefaultsOnly) TSubclassOf<UGameplayAbility> HandlerAbility;};
Each HandlerAbility should be a subclass of UCrimsonCoreGameplayAbility_InteractionHandler (or any ability that triggers on Ability.Interaction.Activate and reads TriggerEventData->Target).
Prompt widget — more-options hint
UCrimsonCoreInteractionPromptWidget has two optional BindWidgetOptional slots: MoreOptionsContainer (a UWidget wrapper — usually a horizontal box with a label + action widget) and MoreOptionsActionWidget (a UCrimsonActionWidget). Set OpenMenuInputAction in Class Defaults to your IA_Interact_OpenMenu. The container auto-shows only when more than one option is available, so simple pickups stay uncluttered.
Prompt widget - progress ring around the input key
No extra widget is needed: UCommonActionWidget already ships a progress layer behind the key icon. On the prompt widget's bound ActionWidget, set Progress Material Brush to a radial-fill material and Progress Material Param to its 0..1 scalar parameter - hold and duration-channel progress then renders as a ring around the input key, with no separate progress HUD element. The prompt widget drives the layer via OnActionProgress / OnActionComplete from Message.Interaction.Progress, filtered to the owning pawn (so it is multiplayer-safe on listen servers). For fully custom display, implement the On Interaction Progress event (or read CurrentProgress01).
UCrimsonActionWidget also shows it whenever a progress material is authored, since Crimson holds are ability-timer driven on trigger-less actions.Setup steps
- Create a Blueprint subclass of
UCrimsonCoreGameplayAbility_Interact. SetScanStrategy(TopDown or SingleLineTrace), trace profiles, scan rate/range, and theInputTag(defaults toInputTag.Interact). - Add the ability to a
UCrimsonAbilitySetgranted on pawn spawn — auto-activates viaOnAvatarSet/OnGiveAbility(Lyra passive pattern). - In your
UCrimsonInputConfig, mapInputTag.Interactto anIA_InteractEnhanced Input action. - On each interactable object (pickup, door, NPC), implement
ICrimsonInteractableTarget::GatherInteractionOptions. SetInputType = Instantfor press, orHold+InputHoldDuration, or setInteractionActionAbility(yourUCrimsonCoreGameplayAbility_InteractionDurationsubclass) for a channeled interaction. - Configure the interactable's overlap component on the
Interactable_OverlapDynamicprofile so the scan trace finds it.
Collision channel + profiles
UCollisionProfile before plugin configs mount, so the channel + profiles must live in the host project's Config/DefaultEngine.ini — not the plugin's. Copy the block from the CrimsonCore README. The plugin logs LogCrimsonCore warnings on startup if the profiles aren't found.Interactable_OverlapDynamic is set on ACrimsonCorePickupActor::InteractionSphere; Interactable_BlockDynamic is for blocking surfaces that still let the interaction trace through. The custom trace channel Crimson_TraceChannel_Interaction claims ECC_GameTraceChannel18 (highest slot, picked so it rarely collides with project-defined channels — override in the project's ini if you already use slot 18).
Prompt presentation (PromptMode)
PromptMode on the interact ability picks how "you can interact" is shown to the local player:
| Mode | Behavior |
|---|---|
| World Indicator (default) | Floats a widget over each interactable actor in range. Zero setup: the required UCrimsonIndicatorManagerComponent is added to the local player controller on demand, and the widget class resolves per option - InteractionWidgetClass on the option, else DefaultIndicatorWidgetClass, else DefaultInteractionWidgetClass. |
| HUD Slot | Pins the single prompt widget at the HUD.Interaction.Prompt extension slot (the previous default). Needs a CrimsonUIExtensionPoint at that tag in your HUD layout. |
| Both | World indicators plus the HUD prompt. |
| Custom | No built-in prompt. Override the PresentInteractionPrompt (activation), UpdateInteractionPrompt (options changed), and DismissInteractionPrompt (ability end) events - Blueprint or C++ - to supply your own UI. |
DismissInteractionPrompt.HUD widgets
Extension-point slots are only needed for the paths you opt into: HUD.Interaction.Prompt when PromptMode is HUD Slot or Both (the pinned prompt widget listens on Message.Interaction.OptionsChanged to show/hide itself), and HUD.Interaction.Progress only when a duration ability sets ActionWidgetClass (it then auto-registers its progress widget there via UCrimsonUIExtensionSubsystem). The progress ring on the prompt widget's ActionWidget covers hold/channel progress with no extension slot at all.
Plugins/CrimsonCore/Source/CrimsonCore/Public/Abilities/Interaction/. Message struct: Public/Abilities/Interaction/CrimsonInteractionOptionsChangedMessage.h. Tags: Public/CrimsonCoreTags.h. Abstract bases + scan tasks: Plugins/CrimsonInteraction/Source/CrimsonInteraction/Public/.