Developer Guide (Version 1.12)

Creating System Components

System components are similar to other components in Lumberyard's component entity framework. However, instead of creating game entity behavior, they control the behavior of the engine itself. Currently Lumberyard enables the creation of custom system components through AZ modules and gems. (Gems are a specialization of AZ modules; for more information, see Gems and AZ Modules).

Most games organize their game code in one or more gems that are specific to the game. These gems can contain both components that you can use on game entities and system components that you want to integrate with the engine. The system components that a given gem or module specifies are first-class elements of the game engine and are included at a deep level early in the initialization process. For more information, see System Components in the AZ Modules section.

Like any Lumberyard component, a system component can provide services and can be dependent on or require other system component services. This is an elegant way to control engine initialization order and system dependencies.

When you author system components, follow the best practices for component authoring. For example, your system components should use the following:


Just like game components, system components often provide request and notification buses. However, because system components are global systems, they should not specify IDs for their buses like game components do. Your users should be able to call your system's EBuses without having to deal with or know about the system entity that contains all system components.

The following code example shows a system component EBus.

class AnimationGraphAssetRequests : public AZ::EBusTraits { public: virtual ~AnimationGraphAssetRequests() = default; virtual AZStd::vector<AZ::Uuid> GetGraphNodeTypes(AZ::SerializeContext& serializeContext) = 0; virtual GraphAssetPtr CreateGraphAsset() = 0; virtual NodeId CreateGraphNode(const GraphAssetPtr& asset, const AZ::Uuid& nodeTypeId, AZ::SerializeContext& serializeContext) = 0; virtual bool DeleteGraphNode(const GraphAssetPtr& asset, NodeId nodeId) = 0; virtual NodePtr FindGraphNode(const GraphAssetPtr& asset, NodeId nodeId) = 0; }; using AnimationGraphAssetRequestBus = AZ::EBus<AnimationGraphAssetRequests>;

The following code shows part of the system component itself.

class AnimationGraphSystemComponent : public AZ::Component , private AnimationGraphSystemRequestBus::Handler { public: AZ_COMPONENT(AnimationGraphSystemComponent, "{2D497170-E4C7-40B0-A9D1-2D987CC8932A}"); AnimationGraphSystemComponent(); ~AnimationGraphSystemComponent() override; // AnimationGraphSystemRequestBus::Handler AZStd::intrusive_ptr<PoseBufferStorage> AllocatePoseBufferStorage(AZ::u32 jointCount) override; void FreePoseBufferStorage(PoseBufferStorage* storage) override; AZ::u32 GetActivePoseBufferCount() override; void ExecuteGraph(const AZ::Data::AssetId& assetId, const PlaybackContext& context, PoseBuffer& targetBuffer) override; void UpdateGraph(const AZ::Data::AssetId& assetId, const PlaybackContext& context, float& expectedDuration, float& normalizedTime) override; .... // AZ::Component static void Reflect(AZ::ReflectContext* reflect); static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); private: // AZ::Component void Activate() override; void Deactivate() override;

Defining a System Component

To designate a component as a system component, you must set the AppearsInAddComponentMenu field to System when you reflect to the EditContext, as in the following example.

if (AZ::EditContext* editContext = serializeContext->GetEditContext()) { editContext->Class<AnimationGraphSystemComponent>( "Animation Graph", "Manages animation graph system component and features.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "Engine") ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System")) ; }

This code exposes the component to the editor and other parts of the user interface that are visible to users. The optional Category field determines which submenu contains the component in the Add Component menu in Lumberyard Editor Entity Inspector. In the following example, the Area Light component appears in the submenu Add Component, Rendering, Lights.

... editContext->Class<EditorAreaLightComponent>( "Area Light", "Attach area lighting to an entity.") ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::Category, "Rendering/Lights") ...