Concept: The Integration Layer
Every Crimson Fab plugin compiles and ships alone: it depends on no other Crimson plugin, not even CrimsonCommon. Each type has exactly one owning plugin. When a feature needs two plugins at once - an inventory item in a UI context menu, an ability set granted by equipment, the camera lock-on driving motion warping - the code that joins them lives in CrimsonCore, under Source/CrimsonCore/{Public,Private}/Integration/<Plugin>/.
How the plugins expose themselves
| Mechanism | What a plugin offers | Example |
|---|---|---|
| Delegates | A native ...Native multicast (FGameplayTag Channel, const Payload&) plus a BlueprintAssignable twin on the object that owns the event | UCrimsonInventoryManagerComponent::OnStackChangedNative, UCrimsonAbilitySystemComponent::OnAbilityProgress |
| Feature states | A ModularGameplay feature announced with ChangeFeatureInitState when a system is ready on an actor | CrimsonInventory::SystemReadyFeatureName, GameState feature Crimson.Experience.Loaded |
| Interfaces and extension points | An interface or instanced extension class outsiders implement | ICrimsonWarpTargetProvider, UCrimsonGameplayAbilityExtension, ICrimsonPoolableAdapter |
| Static hooks | A static delegate the plugin calls and CrimsonCore binds; unbound = standalone behavior | FCrimsonActionBarIntegrationHooks, UCrimsonCombatTextFilter::TagLabelResolver() |
| Settings | A class setting that lets outsiders substitute a subclass | UCrimsonInventorySettings::ItemInstanceClass, UCrimsonSettingRegistry::KeybindingSettingClass |
What CrimsonCore installs
| Folder | Integration | Joins | Installed by |
|---|---|---|---|
AbilitySystem/ | UCrimsonCoreAbilityExtension_FixedSlotUI, UCrimsonFixedAbilitySlotContext | AbilitySystem + UI | Ability Extensions |
AbilitySystem/ | UCrimsonCoreAbilityExtension_PawnFacing, UCrimsonCoreAbilityCameraStatics | AbilitySystem + Camera | Ability Extensions; static calls |
AbilitySystem/ | UCrimsonCoreComboModifierBridge | AbilitySystem + Input | Engine subsystem, automatic |
AbilitySystem/ | UCrimsonGameplayAbility_UseObject (the shared use-item ability) | AbilitySystem + Inventory | Grant once |
AbilitySystem/ | UCrimsonInteractionCondition_AttributeCompare | AbilitySystem + Interaction | Instanced condition |
AbilitySystemUI/ | UCrimsonContextAction_GrantAbility | AbilitySystem + UI | Context action in action sets |
ActionBar/ | UCrimsonCoreActionBarIntegrationSubsystem, UCrimsonCoreActionBarAbilityAdapter, UCrimsonCoreActionBarObjectAdapter, UCrimsonActionBarWidgetPayload | ActionBar + AbilitySystem + Inventory + Input + UI | Engine subsystem, automatic |
CombatText/ | UCrimsonCoreCombatTextTagLabelBridge | CombatText + UI | Engine subsystem, automatic |
Equipment/ | UCrimsonCoreEquipmentAbilitySetSubsystem | Equipment + AbilitySystem | World subsystem, automatic |
Experience/ | UCrimsonCoreExperienceLoadingScreenBridge, UCrimsonCoreExperienceStatics | Experience + LoadingScreen (+ CrimsonCommon sessions) | Engine subsystem, automatic; static calls |
Input/ | CrimsonCoreInputSensitivity::ToInputSensitivity | Settings + Input | Used by UCrimsonCoreLocalPlayer |
Interaction/ | UCrimsonCoreInteractionStatics, UCrimsonCoreInteractionDurationPayload | Interaction + UI | Static calls; Core duration ability |
InteractionUI/ | UCrimsonInteractionContextActionContributor, UCrimsonContextAction_FromInteractionOption | Interaction + UI | World subsystem, automatic |
Inventory/ | Context actions (UCrimsonInventoryContextAction_Use / _Drop / _Equip / _Unequip / _Buy, base UCrimsonInventoryQuantityContextAction), UCrimsonInventoryItemTypeActionSet, UCrimsonInventoryItemFragment_ContextActions, UCrimsonInventoryContextActionSettings, UCrimsonInventoryContextActionStatics | Inventory + UI (+ Equipment) | Action sets and item fragments; settings |
Inventory/ | UCrimsonCoreInventoryItemInstance | Inventory + UI + ActionBar | ItemInstanceClass setting |
Inventory/ | ACrimsonInteractableContainerActor, UCrimsonInteractionCondition_HasItem | Inventory + Interaction | Container base class; instanced condition |
Inventory/ | UCrimsonInventoryEquipmentStatics, UCrimsonInventoryIntegrationSubsystem, UCrimsonInventorySlotBindingResolverComponent | Inventory + Equipment + ActionBar | Static calls; world subsystem, automatic (it adds the resolver to player controllers) |
Inventory/ | UCrimsonCoreInventoryCheats | Inventory + UI + Interaction | Cheat manager extension |
MotionWarping/ | UCrimsonCoreLockOnWarpTargetProvider, UCrimsonCoreLockOnWarpTargetSubsystem | Camera + MotionWarping | GameInstance subsystem adds the provider to receiver pawns |
ObjectPool/ | UCrimsonCoreProjectilePoolingSubsystem | HitDetection + ObjectPool | Engine subsystem, automatic |
QuestSystem/ | UCrimsonCoreQuestMessageBridge, UCrimsonCoreQuestEvent_MessageReceived | QuestSystem + CrimsonCommon bus | GameInstance subsystem, automatic; instanced event |
Settings/ | UCrimsonCoreSettingKeyboardInput, UCrimsonCoreSettingsListEntry_KeyboardInput, UCrimsonPressAnyKeyWithModifiers | Settings + Input + UI | Registry KeybindingSettingClass; keybind row parent |
Settings/ | UCrimsonCorePerfStatSettings, UCrimsonCorePerfStatUserSettings, UCrimsonCorePerfStatSettingsLibrary, UCrimsonSettingValueDiscrete_PerfStat | Settings + UI | AddPerformanceStatsPage |
Teams/ | UCrimsonInteractionCondition_TeamAttitude | Teams + Interaction | Instanced condition |
Teams/ | UCrimsonCorePartyMessageForwarder | Teams + CrimsonCommon bus | GameInstance subsystem, automatic |
UI/ | UCrimsonCoreActionWidgetChordBridge | UI + Input | Engine subsystem, automatic |
UI/ | UCrimsonCoreRadialBindingProvider_SlotBinding, UCrimsonCoreRadialBindingBridge, UCrimsonSlotBindingDragDropOperation | UI + ActionBar | Wheel provider; engine subsystem |
UI/ | UCrimsonCoreRadialBindingComponent | UI + SaveSystem | Component on the player controller |
Forwarding events onto the message bus
Plugins no longer broadcast on CrimsonCommon's UCrimsonMessageSubsystem. For projects that want one global channel tree, bind the plugin's native delegate and re-broadcast; UCrimsonCorePartyMessageForwarder is the worked example.
#include "Messaging/CrimsonMessageSubsystem.h" // CrimsonCommon#include "Party/CrimsonPartySubsystem.h" // CrimsonTeamsPartySubsystem->OnPartyMessageNative.AddUObject(this, &ThisClass::HandlePartyMessage);void UMyForwarder::HandlePartyMessage(FGameplayTag Channel, const FCrimsonPartyMessage& Message){UCrimsonMessageSubsystem::Get(this).BroadcastMessage(Channel, Message);}
Waiting for a plugin to be ready
Components added by Game Feature actions arrive after their owner. Wait on the owning plugin's feature state rather than binding in BeginPlay; CrimsonCore may also use UCrimsonExperienceManagerComponent::CallOrRegister_OnExperienceLoaded* directly.
#include "Components/GameFrameworkComponentManager.h"#include "CrimsonInventoryTags.h"if (UGameFrameworkComponentManager* GFCM = UGameFrameworkComponentManager::GetForActor(Owner)){Handle = GFCM->RegisterAndCallForActorInitState(Owner, CrimsonInventory::SystemReadyFeatureName, FGameplayTag(),FActorInitStateChangedDelegate::CreateUObject(this, &ThisClass::HandleInventoryReady), /*bCallImmediately*/ true);}// Params.Implementer is the inventory manager. Unregister with UnregisterActorInitStateDelegate(Owner, Handle).
| Feature name | Actor | Implementer |
|---|---|---|
CrimsonInventory::SystemReadyFeatureName / RoutingSystemReadyFeatureName | Inventory owner / player controller | Manager / routing component |
CrimsonAbilitySystem::SystemReadyFeatureName | Player state | ASC |
CrimsonEquipment::SystemReadyFeatureName | Pawn | Slots component |
CrimsonTeams::SystemReadyFeatureName / PartySystemReadyFeatureName | Team agent owner / player state | Agent / party member component |
CrimsonSkillTreeTags::SystemReadyFeatureName | Skill tree owner | Skill tree manager |
Crimson.Experience.Loaded (CrimsonExperience::ExperienceLoadedFeatureName) | GameState | Experience manager component |
FGameplayTag() as the required state.