Radial Slot Bindings
CrimsonActionBar owns the binding store, the provider contract and the generic ability and object providers; CrimsonUI's player-editable wheel has its own binding model. CrimsonCore contributes what has to know about several plugins at once: the ability/object adapters and the inventory resolver, UCrimsonCoreRadialBindingProvider_SlotBinding (action-bar providers on a wheel), the equipment provider, and the save wiring (UCrimsonCoreSlotBindingComponent, UCrimsonCoreRadialBindingComponent).
The providers
| Provider | Binding payload | Identity, and why that one |
|---|---|---|
UCrimsonSlotBindingProvider_Ability (CrimsonActionBar) | FCrimsonSlotBindingData_Ability { Identity } | A Crimson ability's identity is its gameplay-event trigger tag (via ICrimsonSlotBindingPresentable) - the same key UCrimsonCoreRadialAction_GameplayAbility settled on. Asset tags matched several abilities at once; a class reference breaks the moment the ability is granted by a different set. |
UCrimsonSlotBindingProvider_Object (CrimsonActionBar) | FCrimsonSlotBindingData_Object { Identity } | For an item, the item definition class path, which is exactly what FCrimsonInventorySaveEntry already persists. Not a stack: bind a potion, drink the last one, buy more an hour later, and the slot still works. |
UCrimsonCoreSlotBindingProvider_Equipment (CrimsonCore) | FCrimsonBinding_Equipment { SlotTag, AssignedSlotIndex } | The identity triple FCrimsonEquipmentSaveEntry persists. Not the instance - those are re-created on load and on replication. Not the definition either: the player is binding 'my off-hand', so swapping the axe for a sword should follow the slot. |
The equipment provider (and, by default, the Object provider) dispatches through a gameplay event rather than acting directly - a configurable tag carrying the instance as OptionalObject. The ability provider routes press/release edges through the ASC (ICrimsonAbilityInputRouter), exactly like a bound key. Drinking a potion, wielding a weapon and quick-firing are different games' answers to the same gesture, so the provider raises the intent and an ability decides what it means.
UserInterface/Bindings/CrimsonCoreAbilityTriggerUtils.h. (UCrimsonCoreRadialAction_GameplayAbility calls it; the bindable ability provider now lives in CrimsonActionBar and uses the same trigger-tag identity, so the two cannot drift apart.Setting one up
On your CrimsonRadialLayoutDefinition, add a Providers entry and pick Gameplay Abilities / Objects (CrimsonActionBar) or Equipment Slots (CrimsonCore). Set Provider Id to a tag unique to that provider.
For items and equipment, also set the Use Event Tag / Select Event Tag that your ability listens for. Leaving it unset makes the wheel purely informational, which is a legitimate read-only setup.
DA_RadialLayout_Test (/CrimsonCore/UserInterface/Radial/) - two pages of eight slots, an ability provider and the CrimsonUI tag provider authored inline, a locked slot pre-bound to an ability, an ability-filtered slot, and one editable slot that starts pre-bound. W_CrimsonCoreRadialMenu_BindableTest in the same folder is the wheel pointed at it, and exercises every branch without any game code.Where the display comes from
| Provider | Name and icon | Note |
|---|---|---|
| Ability | UCrimsonAbilityDisplayData on the granted ability | An ability with no display data is not offered. Authoring it is how an ability opts in to being bindable. |
| Inventory item | DisplayName plus the UCrimsonInventoryItemFragment_Visuals icon | The count badge sums every stack the player holds, not just one. |
| Equipment | The source object, when that is an inventory item | Equipment definitions carry no display data of their own; the fallback is the slot tag's leaf name. |
Reading from the ability's own display data is what makes renaming a spell or changing its icon update every wheel that offers it, with nothing re-typed anywhere.
ResolveBinding on the equipment provider and supply it there. The fallback exists so a slice is never nameless, not because it is the right answer for every game.Availability
| Provider | Grays out when | Binding kept? |
|---|---|---|
| Ability | On cooldown, or no longer granted | Yes |
| Inventory item | Stack count reaches zero | Yes |
| Equipment | The bound slot is empty | Yes |
Ability cooldown is read off the ability system's own effect state, never by asking the ability. Spec.Ability is the class default object, and CanActivateAbility on a CDO walks into GetOwningActorFromActorInfo() and ensure-fails. The ability system already knows exactly what is active - the same answer, with no instance required.
An out-of-stock item and an unequipped slot are not stale bindings. The player will restock and re-equip, so they resolve normally and are grayed out instead. Only an ability that is no longer granted reports stale, and even then the layout's ECrimsonStaleBindingPolicy has the final say.
Persistence
UCrimsonCoreSlotBindingComponent is UCrimsonSlotBindingComponent plus ICrimsonSaveableSystem. Use it in place of the CrimsonUI component and bindings persist with no code from you.
// There is no fragment class and no gather code. The save manager always serializes a// system's UPROPERTY(SaveGame) fields whether or not it returns a custom fragment, and the// base component marks its layout container and presets SaveGame at every nesting level.FString GetFragmentName_Implementation() const; // -> SaveFragmentNameECrimsonSaveScope GetSaveScope_Implementation() const; // -> PlayerFGuid GetProfileId_Implementation() const; // -> ResolveProfileIdForActor(owner)
| Detail | Behavior |
|---|---|
| Where to add it | PlayerController, PlayerState or Pawn - whichever your project persists. |
GetSaveScope / GetProfileId | Resolves the controller from any of the three, so moving the component later does not orphan existing saves. |
SaveFragmentName | Editable, so two independent stores (wheels and a hotbar, say) do not overwrite each other. |
| Registration | Server only. A client registering would race its own replicated copy against the restore. |
See also
- CrimsonUI -> How-To: Build a Player-Editable Wheel
- CrimsonUI -> Concept: Slot Bindings
- Radial Menu - the authored CrimsonCore wheel and its hold-to-open ability