Agent skill

Ue Game Features

by quodsoler in quodsoler/unreal-engine-skills

A skill your agent uses when building, activating or debugging Game Feature plugins and modular gameplay.

MITAuto-check passedDevelopment

Install Ue Game Features

skills CLI
$ npx skills add quodsoler/unreal-engine-skills --skill ue-game-features -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install quodsoler/unreal-engine-skills ue-game-features --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/quodsoler/unreal-engine-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/ue-game-features .claude/skills/ue-game-features && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
ue-game-features
GitHub stars
362
Token cost
~8k tokens
SKILL.md length
2,292 words
Files
3 (incl. references)
Skills in repo
31
Repo updated
First seen
Licence
MIT

At a glance

A skill your agent uses when building, activating or debugging Game Feature plugins and modular gameplay.

  • Debugging Game Feature plugins and modular gameplay
  • SKILL.md covers Context, Plugin Layout and Descriptor, Plugin States and the Subsystem and Writing a UGameFeatureAction, plus 8 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md
  • The user mentions GameFeatureAction

What it does

Ue Game Features is an agent skill from quodsoler/unreal-engine-skills. Use when building, activating or debugging Game Feature plugins and modular gameplay. Also use when the user mentions 'GameFeatureAction', 'UGameFeatureData', 'GameFeaturesSubsystem', 'LoadAndActivateGameFeaturePlugin', 'BuiltInInitialFeatureState', 'ExplicitlyLoaded', '.uplugin', 'GameFrameworkComponentManager', 'AddReceiver', 'AddComponentRequest', 'AddExtensionHandler', 'NAMEGameActorReady', 'init state', 'UPawnComponent', 'ModularGameplay', 'experience system' or 'Lyra-style modular architecture'. For plugin…

Its SKILL.md is about 8k tokens, which your agent loads only when the skill is triggered. The skill folder holds 3 other files, including reference files (for example `references/experience-system.md` and `references/game-feature-patterns.md`).

It sits in Development. The repository describes itself as: Unreal Engine C++ skills for AI coding agents. 27 skills covering gameplay, rendering, networking, animation, and more. Works with Claude Code, Cursor, Windsurf, and any agent… The licence is MIT.

When your agent uses it

  • Debugging Game Feature plugins and modular gameplay
  • The user mentions GameFeatureAction
  • UGameFeatureData
  • GameFeaturesSubsystem

Example prompts

  • “GameFeatureAction”
  • “UGameFeatureData”
  • “GameFeaturesSubsystem”
  • “/ue-game-features”

What it can do on your machine

Read from SKILL.md and the folder at commit f3742d7. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are cpp, json and ini).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Ue Game Features loads about 8k tokens when it runs, and up to ~16k if it reads all its reference files. Until then it costs about 164 tokens; SKILL.md has 2,292 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~164
When it runs · the whole SKILL.md, loaded when a task matches
~8k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~16k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from quodsoler/unreal-engine-skills at commit f3742d7, republished under its MIT licence (© quodsoler). 2,292 words, ~8,011 tokens.

Download SKILL.mdSave it as .claude/skills/ue-game-features/SKILL.md (or your agent's skills folder). This skill also uses 2 other files; get the full folder from GitHub.
name
ue-game-features
description
Use when building, activating or debugging Game Feature plugins and modular gameplay. Also use when the user mentions 'GameFeatureAction', 'UGameFeatureData', 'GameFeaturesSubsystem', 'LoadAndActivateGameFeaturePlugin', 'BuiltInInitialFeatureState', 'ExplicitlyLoaded', '.uplugin', 'GameFrameworkComponentManager', 'AddReceiver', 'AddComponentRequest', 'AddExtensionHandler', 'NAME_GameActorReady', 'init state', 'UPawnComponent', 'ModularGameplay', 'experience system' or 'Lyra-style modular architecture'. For plugin modules and Build.cs wiring, see ue-module-build-system; for component fundamentals, see ue-actor-component-architecture.
metadata.version
2.0.0
metadata.engine
5.8

UE Game Features and Modular Gameplay

Target engine: UE 5.8. APIs below are verified against the 5.8 headers; older forms are listed under "Deprecated — do not use".

Game Features (Beta in 5.8) packages gameplay as self-contained plugins under Plugins/GameFeatures/. UGameFeaturesSubsystem (a UEngineSubsystem) drives each plugin through a state machine; a UGameFeatureData primary data asset inside the plugin holds an instanced list of UGameFeatureAction objects that run at registration, load, activation and deactivation. Modular Gameplay (Beta in 5.8) supplies UGameFrameworkComponentManager (a UGameInstanceSubsystem) that injects components into opted-in actors, plus the UGameFrameworkComponent bases and the init-state system that orders initialization across independently loaded features. Build.cs modules: GameFeatures and ModularGameplay. The GameFeatures module already depends publicly on ModularGameplay and DataRegistry, so code that only consumes actions needs GameFeatures alone.

Context

Read .agents/ue-project-context.md if it exists (module names, conventions, enabled plugins, GAS/networking setup). Do not stop if it is missing.

Identify the area from the request and the codebase. Ask only when two plausible readings would produce different code.

Request is about…Go to
Creating a feature plugin, .uplugin keys, folder layout, UGameFeatureDataPlugin Layout and Descriptor
Activating or unloading a feature at runtime, plugin URLs, plugin statesPlugin States and the Subsystem
Writing an action that runs when a feature turns on or offWriting a UGameFeatureAction
Picking a ready-made action instead of writing oneEngine-Provided Actions
Adding components to actors from a feature, extension eventsComponent Injection
Ordering initialization between components that load separatelyInit State System
Choosing a base class for a Pawn/Controller/PlayerState/GameState componentModular Component Bases
Filtering which plugins load, client/server data, state observersProject Policies and Observers
Lyra-style experience composition (sample code, not engine API)references/experience-system.md
Full templates: custom action, receiver setup, policies subclassreferences/game-feature-patterns.md

Plugin Layout and Descriptor

A Game Feature plugin is an ordinary plugin that lives under <Project>/Plugins/GameFeatures/ or under <AdditionalPluginDirectory>/GameFeatures/. That location is what makes it a Game Feature plugin — UGameFeaturesSubsystemSettings::IsValidGameFeaturePlugin matches the descriptor path against those folders. There is no plugin-level "Type" key in the .uplugin schema.

Plugins/GameFeatures/
├── MyFeature/
│   ├── MyFeature.uplugin
│   ├── Content/MyFeature.uasset        (UGameFeatureData, named after the plugin)
│   └── Source/MyFeatureRuntime/
└── MyFeatureRules/
    ├── MyFeatureRules.uplugin
    └── Content/MyFeatureRules.uasset
json
{
	"FileVersion": 3,
	"Version": 1,
	"VersionName": "1.0",
	"FriendlyName": "My Feature",
	"Description": "Adds my gameplay feature",
	"Category": "Game Features",
	"CreatedBy": "",
	"CanContainContent": true,
	"ExplicitlyLoaded": true,
	"BuiltInInitialFeatureState": "Active",
	"Modules": [
		{ "Name": "MyFeatureRuntime", "Type": "Runtime", "LoadingPhase": "Default" }
	],
	"Plugins": [
		{ "Name": "GameFeatures", "Enabled": true },
		{ "Name": "ModularGameplay", "Enabled": true }
	]
}
KeyMeaning
ExplicitlyLoadedThe plugin manager does not mount the plugin at startup; the feature's state machine mounts and unmounts it. Always true for a feature plugin.
CanContainContentPlugin ships a Content/ directory (needed for the UGameFeatureData asset).
BuiltInInitialFeatureStateHow far a built-in plugin advances at startup: "Installed", "Registered", "Loaded" or "Active". Unknown values log an error and fall back to Active.
EnabledByDefaultPlugin is enabled without a .uproject entry.
Modules[].TypeModuleHostType name: Runtime, RuntimeNoCommandlet, Editor, Developer, Program, …
Modules[].LoadingPhaseModuleLoadingPhase name: Default, PreDefault, PostConfigInit, PostEngineInit, …

A content-only feature plugin omits Modules entirely. Adding a module means adding a Build.cs; see ue-module-build-system.

UGameFeatureData

UGameFeatureData : UPrimaryDataAsset is the asset the subsystem loads for the plugin. Its two authored properties are protected; read them through accessors:

cpp
const TArray<UGameFeatureAction*>& FeatureActions = FeatureData->GetActions();
const TArray<FPrimaryAssetTypeInfo>& ScanTypes = FeatureData->GetPrimaryAssetTypesToScan();

Actions is an Instanced array of UGameFeatureAction subclasses created inline in the asset. PrimaryAssetTypesToScan tells the Asset Manager which primary asset types inside the plugin to scan when the feature registers; see ue-data-assets-tables.

Subclass UGameFeatureData only to change GetPrimaryAssetTypesToScan or, in the editor, GetDisallowedActions.

Plugin States and the Subsystem

Destination states are fully ordered; transition and error states sit between them. EGameFeaturePluginState is a plain enum generated from the GAME_FEATURE_PLUGIN_STATE_LIST macro.

Destination stateMeaning
TerminalFinal state before the state machine is removed.
UnknownStatusOnly the URL is known.
StatusKnownAvailability confirmed (on disk or in a bundle).
UninstalledLocal data for the plugin has been removed.
InstalledFiles are in local storage, not registered.
RegisteredAssets discovered and registered; actions received OnGameFeatureRegistering.
LoadedPlugin code and content are in memory, not yet affecting the game.
ActiveActions applied; the feature affects the game.

Transition states that show up in logs and in GetPluginState results include CheckingStatus, Downloading, Mounting, Registering, Loading, ActivatingDependencies, Activating, Deactivating, Unloading, Unregistering, Unmounting, Releasing, Uninstalling, plus the matching Error* states.

Two other enums: EGameFeatureTargetState (Installed, Registered, Loaded, Active) is what you pass to ChangeGameFeatureTargetState; EBuiltInAutoState (Invalid, Installed, Registered, Loaded, Active) is what BuiltInInitialFeatureState parses into.

Driving a plugin from code
cpp
#include "GameFeaturesSubsystem.h"

void UMyFeatureManager::EnableMyFeature()
{
    UGameFeaturesSubsystem& GFS = UGameFeaturesSubsystem::Get();

    FString PluginURL;
    if (!GFS.GetPluginURLByName(TEXT("MyFeature"), PluginURL))
    {
        UE_LOG(LogMyGame, Error, TEXT("MyFeature is not a discovered game feature plugin"));
        return;
    }

    GFS.LoadAndActivateGameFeaturePlugin(PluginURL,
        FGameFeaturePluginLoadComplete::CreateUObject(this, &UMyFeatureManager::HandleFeatureLoaded));
}

void UMyFeatureManager::HandleFeatureLoaded(const UE::GameFeatures::FResult& Result)
{
    if (Result.HasError())
    {
        UE_LOG(LogMyGame, Error, TEXT("MyFeature failed: %s"), *Result.GetError());
    }
}

GetPluginURLByName(FStringView PluginName, FString& OutPluginURL) is the safe way to build a URL for a built-in plugin. The static builders UGameFeaturesSubsystem::GetPluginURL_FileProtocol(PluginDescriptorPath) and GetPluginURL_InstallBundleProtocol(PluginName, BundleName) produce file: and installbundle: URLs (EGameFeaturePluginProtocol::File, ::InstallBundle).

CallEffect
LoadGameFeaturePlugin(URL, CompleteDelegate)Advance to Loaded.
LoadAndActivateGameFeaturePlugin(URL, CompleteDelegate)Advance to Active.
RegisterGameFeaturePlugin(URL, CompleteDelegate)Advance to Registered.
ChangeGameFeatureTargetState(URL, EGameFeatureTargetState::Registered, CompleteDelegate)Move to any destination state.
DeactivateGameFeaturePlugin(URL)Back down to Loaded.
UnloadGameFeaturePlugin(URL, /*bKeepRegistered=*/ false)Back down to Registered or Installed.
TerminateGameFeaturePlugin(URL)Tear the state machine down.
CancelGameFeatureStateChange(URL)Abort an in-flight transition.

Every completion delegate above is an alias of FGameFeaturePluginChangeStateComplete, i.e. DECLARE_DELEGATE_OneParam(..., const UE::GameFeatures::FResult&). Overloads taking TConstArrayView<FString> PluginURLs report through FMultipleGameFeaturePluginsLoaded, a TDelegate<void(const TMap<FString, UE::GameFeatures::FResult>&)>.

Queries: GetPluginState(URL), IsGameFeaturePluginActive(URL, bCheckForActivating), IsGameFeaturePluginActiveByName(PluginName, bCheckForActivating), IsGameFeaturePluginRegistered(URL, bCheckForRegistering), IsGameFeaturePluginLoaded(URL), IsGameFeaturePluginInErrorState(URL), GetActivePluginNames().

Console commands for testing (GameFeaturesSubsystem.cpp:583-661, take a plugin name or URL): ListGameFeaturePlugins [-activeonly] [-csv], LoadGameFeaturePlugin, DeactivateGameFeaturePlugin, UnloadGameFeaturePlugin, ReleaseGameFeaturePlugin, CancelGameFeaturePlugin, TerminateGameFeaturePlugin. The LoadGameFeaturePlugin console command calls LoadAndActivateGameFeaturePlugin and is ECVF_Cheat, unlike the C++ function of the same name, which only reaches Loaded.

Writing a UGameFeatureAction

UGameFeatureAction is UCLASS(MinimalAPI, DefaultToInstanced, EditInlineNew, Abstract) deriving from UObject. DefaultToInstanced and EditInlineNew are what let instances be created inline in the Actions array. The overridable virtuals, verbatim:

cpp
virtual void OnGameFeatureRegistering() {}
virtual void OnGameFeatureUnregistering() {}
virtual void OnGameFeatureLoading() {}
virtual void OnGameFeatureUnloading() {}
virtual void OnGameFeatureActivating(FGameFeatureActivatingContext& Context);
virtual void OnGameFeatureActivating() {}
virtual void OnGameFeatureActivated() {}
virtual void OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context) {}

Override the context version of OnGameFeatureActivating; the base implementation of that one calls the no-arg version, so overriding both runs your code twice. IsDataValid is a UObject override, not a UGameFeatureAction member, and is editor-only.

cpp
// MyGameFeatureAction_GrantTag.h
#pragma once

#include "GameFeatureAction.h"
#include "GameplayTagContainer.h"
#include "MyGameFeatureAction_GrantTag.generated.h"

struct FGameFeatureActivatingContext;
struct FGameFeatureDeactivatingContext;
struct FWorldContext;

UCLASS(meta = (DisplayName = "My Grant Tag"))
class MYGAME_API UMyGameFeatureAction_GrantTag : public UGameFeatureAction
{
    GENERATED_BODY()

public:
    virtual void OnGameFeatureActivating(FGameFeatureActivatingContext& Context) override;
    virtual void OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context) override;

#if WITH_EDITOR
    virtual EDataValidationResult IsDataValid(class FDataValidationContext& Context) const override;
#endif

    UPROPERTY(EditAnywhere, Category = "Tags")
    FGameplayTag TagToGrant;

private:
    void ApplyToWorld(const FWorldContext& WorldContext);
};

An action instance is shared by every world the feature applies to, so never keep per-world state in a bare member. Filter worlds with the context and key state by FObjectKey:

cpp
void UMyGameFeatureAction_GrantTag::OnGameFeatureActivating(FGameFeatureActivatingContext& Context)
{
    for (const FWorldContext& WorldContext : GEngine->GetWorldContexts())
    {
        if (Context.ShouldApplyToWorldContext(WorldContext))
        {
            ApplyToWorld(WorldContext);
        }
    }
}

FGameFeatureActivatingContext and FGameFeatureDeactivatingContext both derive from FGameFeatureStateChangeContext, which supplies ShouldApplyToWorldContext(const FWorldContext&), ShouldApplyUsingOtherContext(const FGameFeatureStateChangeContext&) and SetRequiredWorldContextHandle(FName).

Deactivation that needs async work must hold the state machine open. FGameFeatureDeactivatingContext::PauseDeactivationUntilComplete(FString InPauserTag) returns an FSimpleDelegate you must execute on the game thread, on every path:

cpp
void UMyGameFeatureAction_GrantTag::OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context)
{
    FSimpleDelegate Resume = Context.PauseDeactivationUntilComplete(TEXT("MyGrantTag_Cleanup"));
    StartAsyncCleanup(Resume);   // must call Resume.ExecuteIfBound() when finished
}

Full templates, including world tracking and the RAII handle patterns, are in references/game-feature-patterns.md.

Engine-Provided Actions

ActionPurpose
UGameFeatureAction_AddComponentsAdds actor↔component spawn requests to UGameFrameworkComponentManager.
UGameFeatureAction_AddCheatsAdds cheat manager extensions for each player.
UGameFeatureAction_AddActorFactoryRegisters an actor factory when the plugin registers.
UGameFeatureAction_AddChunkOverrideCooks the plugin's assets into a specified chunk id.
UGameFeatureAction_AddWPContentAdds World Partition content as a content bundle.
UGameFeatureAction_AddWorldPartitionContentAdds World Partition content for the plugin.
UGameFeatureAction_DataRegistryLoads and initializes a list of Data Registries.
UGameFeatureAction_DataRegistrySourceAdds source assets to existing Data Registries.
UGameFeatureAction_AudioActionBaseAbstract base for actions that affect the audio engine.
UIrisFilterGameFeatureActionCreates an Iris network filter.

UGameFeatureAction_AddComponents is the one most features need. It holds TArray<FGameFeatureComponentEntry> ComponentList, and each FGameFeatureComponentEntry carries TSoftClassPtr<AActor> ActorClass (meta=(AllowAbstract="True")), TSoftClassPtr<UActorComponent> ComponentClass, the bitfields uint8 bClientComponent:1 and uint8 bServerComponent:1, and uint8 AdditionFlags (meta=(Bitmask, BitmaskEnum="/Script/ModularGameplay.EGameFrameworkAddComponentFlags")).

Set both bClientComponent and bServerComponent for components needed everywhere, server-only for authoritative gameplay logic, client-only for cosmetics. The action keeps a TSharedPtr<FComponentRequestHandle> per game instance and drops them on deactivation, which removes the injected components.

Component Injection

UGameFrameworkComponentManager is a UGameInstanceSubsystem. Get it from an actor:

cpp
#include "Components/GameFrameworkComponentManager.h"

UGameFrameworkComponentManager* CompMgr = UGameFrameworkComponentManager::GetForActor(MyActor);

GetForActor(const AActor* Actor, bool bOnlyGameWorlds = true) returns null outside game worlds. GetGameInstance()->GetSubsystem<UGameFrameworkComponentManager>() also works where a game instance is in hand.

Receivers

An actor receives injected components only after it registers itself:

cpp
void AMyCharacter::BeginPlay()
{
    Super::BeginPlay();
    UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this);
}

void AMyCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
    UGameFrameworkComponentManager::RemoveGameFrameworkComponentReceiver(this);
    Super::EndPlay(EndPlayReason);
}

The static helpers resolve the manager for the actor and forward to AddReceiver(AActor* Receiver, bool bAddOnlyInGameWorlds = true) and RemoveReceiver(AActor* Receiver), which you can also call directly on the manager.

Requests and extension handlers
cpp
TSharedPtr<FComponentRequestHandle> RequestHandle = CompMgr->AddComponentRequest(
    TSoftClassPtr<AActor>(AMyCharacter::StaticClass()),
    UMyHealthComponent::StaticClass(),
    EGameFrameworkAddComponentFlags::AddUnique);

FComponentRequestHandle is RAII: keep it alive for as long as the injection should last, and destroy it to remove the request and the components it created. It also exposes IsValid(), which returns false once the owning manager is gone.

EGameFrameworkAddComponentFlagsValueBehavior
None0Always create the component on the receiver.
AddUnique0b00000001Skip if the receiver already has a component of that class.
AddIfNotChild0b00000010Skip if the requested class is a child of an existing component's class.
UseAutoGeneratedName0b00000100Generate a new name instead of reusing the class name.

Extension handlers observe receivers instead of adding components. The delegate is declared inside the manager as DECLARE_DELEGATE_TwoParams(FExtensionHandlerDelegate, AActor*, FName):

cpp
ExtensionHandle = CompMgr->AddExtensionHandler(
    TSoftClassPtr<AActor>(AMyCharacter::StaticClass()),
    UGameFrameworkComponentManager::FExtensionHandlerDelegate::CreateUObject(
        this, &UMyFeatureManager::HandleActorExtension));
cpp
void UMyFeatureManager::HandleActorExtension(AActor* Actor, FName EventName)
{
    if (EventName == UGameFrameworkComponentManager::NAME_GameActorReady)
    {
        // Actor has finished its default initialization
    }
}

The five static FName event constants are NAME_ReceiverAdded, NAME_ReceiverRemoved, NAME_ExtensionAdded, NAME_ExtensionRemoved and NAME_GameActorReady. Send your own with CompMgr->SendExtensionEvent(Receiver, EventName, bOnlyInGameWorlds) or the static UGameFrameworkComponentManager::SendGameFrameworkComponentExtensionEvent(Receiver, EventName, bOnlyInGameWorlds).

Show full SKILL.md (959 more words)Show less

Init State System

Init states solve ordered initialization when components arrive from different plugins. States are FGameplayTag values registered in order on the manager; for how to declare the tags themselves see ue-gameplay-tags-messaging.

cpp
CompMgr->RegisterInitState(TAG_InitState_Spawned, false, FGameplayTag());
CompMgr->RegisterInitState(TAG_InitState_DataAvailable, false, TAG_InitState_Spawned);
CompMgr->RegisterInitState(TAG_InitState_DataInitialized, false, TAG_InitState_DataAvailable);
CompMgr->RegisterInitState(TAG_InitState_GameplayReady, false, TAG_InitState_DataInitialized);

RegisterInitState(FGameplayTag NewState, bool bAddBefore, FGameplayTag ExistingState) inserts relative to an existing state, so the engine ships no fixed state list — the project owns it. Register the states once, for example from a UGameInstanceSubsystem or from the project's policies class.

Manager callUse
ChangeFeatureInitState(Actor, FeatureName, Implementer, FeatureState)Advance one feature; returns bool.
GetInitStateForFeature(Actor, FeatureName)Current state tag.
HasFeatureReachedInitState(Actor, FeatureName, FeatureState)Test one feature.
HaveAllFeaturesReachedInitState(Actor, RequiredState, ExcludingFeature)Test the whole actor.
IsInitStateAfterOrEqual(FeatureState, RelativeState)Compare two tags in registration order.
GetImplementerForFeature(Actor, FeatureName, RequiredState)Find the object implementing a feature.
RegisterAndCallForActorInitState(Actor, FeatureName, RequiredState, Delegate, bCallImmediately)Wait on one actor; returns FDelegateHandle.
RegisterAndCallForClassInitState(ActorClass, FeatureName, RequiredState, Delegate, bCallImmediately)Wait on every actor of a class; returns FDelegateHandle.
UnregisterActorInitStateDelegate(Actor, Handle) / UnregisterClassInitStateDelegate(ActorClass, Handle)Remove a native binding (takes FDelegateHandle&).

The native delegate is DECLARE_DELEGATE_OneParam(FActorInitStateChangedDelegate, const FActorInitStateChangedParams&). FActorInitStateChangedParams is a USTRUCT with OwningActor, FeatureName, Implementer and FeatureState.

IGameFrameworkInitStateInterface

Implement IGameFrameworkInitStateInterface (UINTERFACE UGameFrameworkInitStateInterface, NotBlueprintable) on a component to get the standard progression. The virtuals worth overriding, verbatim from the header:

cpp
virtual FName GetFeatureName() const { return NAME_None; }
virtual bool CanChangeInitState(UGameFrameworkComponentManager* Manager, FGameplayTag CurrentState, FGameplayTag DesiredState) const { return true; }
virtual void HandleChangeInitState(UGameFrameworkComponentManager* Manager, FGameplayTag CurrentState, FGameplayTag DesiredState) {}
virtual void CheckDefaultInitialization() {}
virtual void OnActorInitStateChanged(const FActorInitStateChangedParams& Params) {}

The rest you call rather than override:

CallEffect
RegisterInitStateFeature()Registers this implementer with the manager (call from OnRegister).
UnregisterInitStateFeature()Removes the registration and the bound delegate (call from EndPlay).
BindOnActorInitStateChanged(FeatureName, RequiredState, bCallIfReached)Binds OnActorInitStateChanged, storing the handle in ActorInitStateChangedHandle.
TryToChangeInitState(DesiredState)Runs CanChangeInitState, then HandleChangeInitState, then notifies the manager.
ContinueInitStateChain(const TArray<FGameplayTag>& InitStateChain)Walks the chain from the current state, running CanChangeInitState and HandleChangeInitState for each step and notifying the manager; returns the furthest state reached.
CheckDefaultInitializationForImplementers()Calls CheckDefaultInitialization on every other feature of the same actor.
HasReachedInitState(DesiredState) / GetInitState()Query this feature's state through the manager.

A CheckDefaultInitialization override normally calls CheckDefaultInitializationForImplementers() and then ContinueInitStateChain with the project's ordered tag list; a full component implementation is in references/game-feature-patterns.md.

Modular Component Bases

Base classOwner it expectsTyped accessors
UGameFrameworkComponentany AActorGetGameInstance<T>(), GetGameInstanceChecked<T>(), HasAuthority()
UPawnComponentAPawnGetPawn<T>(), GetPawnChecked<T>(), GetPlayerState<T>(), GetController<T>()
UControllerComponentAControllerGetController<T>(), GetControllerChecked<T>(), GetPawn<T>(), GetViewTarget<T>(), GetPawnOrViewTarget<T>(), GetPlayerState<T>(), GetPlayer<T>()
UPlayerStateComponentAPlayerStateGetPlayerState<T>(), GetPlayerStateChecked<T>()
UGameStateComponentAGameStateBaseGetGameState<T>(), GetGameStateChecked<T>(), GetGameMode<T>()

All five live in ModularGameplay under #include "Components/<Name>.h". UGameFrameworkComponent derives from UActorComponent and is Blueprintable, BlueprintType. Prefer these over raw UActorComponent for injected components: the accessors are static_assert-checked against the owner type and the init-state interface is designed around them.

Project Policies and Observers

UGameFeaturesProjectPolicies decides which plugins may load and what data each build type loads. Select the subclass in project settings, which writes:

ini
[/Script/GameFeatures.GameFeaturesSubsystemSettings]
GameFeaturesManagerClassName=/Script/MyGame.MyGameFeaturesProjectPolicies

Useful virtuals: InitGameFeatureManager(), ShutdownGameFeatureManager(), IsPluginAllowed(const FString& PluginURL, FString* OutReason) const, GetGameFeatureLoadingMode(bool& bLoadClientData, bool& bLoadServerData) const, ShouldReadPluginDetails(const FString& PluginDescriptorFilename) const, GetPreloadBundleStateForPlugin(const FString& PluginName) const, IsLoadingStartupPlugins() const. UDefaultGameFeaturesProjectPolicies is the fallback implementation. A subclass template is in references/game-feature-patterns.md.

UGameFeaturesSubsystemSettings::LoadStateClient and ::LoadStateServer are the FName bundle states used for client/server asset filtering; the settings class also carries EnabledPlugins, DisabledPlugins and AdditionalPluginMetadataKeys.

For cross-cutting reactions that are not tied to one feature's data asset, implement IGameFeatureStateChangeObserver and register it:

cpp
UGameFeaturesSubsystem::Get().AddObserver(MyObserver,
    UGameFeaturesSubsystem::EObserverPluginStateUpdateMode::CurrentAndFuture);

EObserverPluginStateUpdateMode is FutureOnly or CurrentAndFuture; the latter replays current plugin states at add time and is expensive when a project has many plugins. Remove with RemoveObserver(MyObserver). Observer hooks include OnGameFeatureRegistering(const UGameFeatureData*, const FString& PluginName, const FString& PluginURL), OnGameFeatureLoading(const UGameFeatureData*, const FString& PluginURL), OnGameFeatureActivating(const UGameFeatureData*, const FString& PluginURL), OnGameFeatureDeactivating(const UGameFeatureData*, FGameFeatureDeactivatingContext& Context, const FString& PluginURL) and the download and mounting hooks. Prefer a UGameFeatureAction on the feature's data asset whenever data is involved.

Deprecated — do not use

Do not emitUse in 5.8Source
"Type": "GameFeature" in a .upluginPlace the plugin under Plugins/GameFeatures/ and set "ExplicitlyLoaded": trueNo plugin-level Type key in PluginDescriptor.cs
"BuiltInAutoRegister" / "BuiltInAutoLoad" / "BuiltInAutoActivate""BuiltInInitialFeatureState"Legacy fallback in GameFeaturesSubsystem.cpp:5079-5090
AddObserver(Observer)AddObserver(Observer, EObserverPluginStateUpdateMode::CurrentAndFuture)UE_DEPRECATED(5.7) in GameFeaturesSubsystem.h:488
IsPluginAllowed(PluginURL)IsPluginAllowed(PluginURL, OutReason)UE_DEPRECATED(5.6) in GameFeaturesProjectPolicies.h:102
GetStreamingAssetInstallBundles(PluginURL)GetStreamingAssetInstallModes(PluginURL, InstallBundleNames)UE_DEPRECATED(5.6) in GameFeaturesProjectPolicies.h:154
FInstallBundlePluginProtocolOptions::ReleaseInstallBundleFlagsNothing — release flags are applied internallyUE_DEPRECATED(5.6) in GameFeaturesSubsystem.h:409
FString-based plugin details (FPluginString)Set UE_GAME_FEATURE_PLUGIN_DETAILS_USE_UTF8_STRING=1 and use the UTF8 formsUE_DEPRECATED(5.8) in GameFeaturesSubsystem.h:258
Overriding OnGameFeatureActivating() with no argumentOverride OnGameFeatureActivating(FGameFeatureActivatingContext& Context)"Older-style activation function" in GameFeatureAction.h:38-39
GetGameFeaturePluginState(URL)GetPluginState(URL)Not an engine function; the real call is at GameFeaturesSubsystem.h:731
UGameFeatureData::Actions touched directlyGetActions()Actions is protected in GameFeatureData.h:120; getter :102
ULyraExperienceDefinition, ULyraExperienceManagerComponent, UGameFeatureAction_AddInputContextMappingLyra sample code, not engine API — write your own equivalents, see references/experience-system.mdNot in any 5.8 engine header

Common Mistakes

Inventing a plugin Type: a .uplugin has no plugin-level Type key, so "Type": "GameFeature" is silently ignored and the plugin never becomes a feature; put it under Plugins/GameFeatures/ and set "ExplicitlyLoaded": true.

Never registering the receiver: components are injected only into registered actors, and nothing is logged when you forget.

cpp
// WRONG — no components are ever added
void AMyCharacter::BeginPlay() { Super::BeginPlay(); }
// RIGHT
void AMyCharacter::BeginPlay()
{
    Super::BeginPlay();
    UGameFrameworkComponentManager::AddGameFrameworkComponentReceiver(this);
}

Dropping FComponentRequestHandle: the handle is RAII, so discarding it removes the request immediately.

cpp
// WRONG — the temporary destructs at the end of the statement
CompMgr->AddComponentRequest(ActorClass, UMyHealthComponent::StaticClass(), AdditionFlags);
// RIGHT — store it for the lifetime of the injection
RequestHandle = CompMgr->AddComponentRequest(ActorClass, UMyHealthComponent::StaticClass(), AdditionFlags);

Fetching the component manager as an engine subsystem: it is a UGameInstanceSubsystem, so GEngine->GetEngineSubsystem<UGameFrameworkComponentManager>() returns null; use UGameFrameworkComponentManager::GetForActor(MyActor).

Not resuming a paused deactivation: if PauseDeactivationUntilComplete is called and the returned FSimpleDelegate is never executed, the plugin stays in Deactivating forever; execute it on every path, including failures.

Cross-component setup in BeginPlay: a component injected by another feature may not exist yet.

cpp
// WRONG — the other component may be added later
void UMyModularComponent::BeginPlay()
{
    Super::BeginPlay();
    GetOwner()->FindComponentByClass<UMyOtherComponent>()->Configure();
}
// RIGHT — react once the shared state is reached
void UMyModularComponent::HandleChangeInitState(UGameFrameworkComponentManager* Manager, FGameplayTag CurrentState, FGameplayTag DesiredState)
{
    if (DesiredState == TAG_InitState_DataInitialized)
    {
        GetOwner()->FindComponentByClass<UMyOtherComponent>()->Configure();
    }
}

Overriding both OnGameFeatureActivating overloads: the base context version calls the no-arg version, so activation code runs twice; override only the context version.

Treating Lyra classes as engine API: ULyraExperienceDefinition, ULyraExperienceManagerComponent and Lyra's own action subclasses ship with the Lyra sample and are absent from the engine; the engine pieces are UGameFeatureData, UGameFeatureAction and UGameFrameworkComponentManager.

  • ue-gameplay-tags-messaging — declaring the FGameplayTag values used as init states, tag containers and queries
  • ue-module-build-system — plugin and module layout, Build.cs dependencies, loading phases
  • ue-actor-component-architecture — component creation, registration, attachment and tick
  • ue-gameplay-abilities — granting abilities and attribute sets from a feature's components
  • ue-data-assets-tables — primary data assets, Asset Manager scanning and asset bundles
  • ue-input-system — Enhanced Input mapping contexts a feature adds and removes
  • ue-gameplay-framework — GameMode, GameState, PlayerController and PlayerState lifecycle
  • ue-world-level-streaming — World Partition content bundles and data layers added by features

© quodsoler, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 2 other files (references) in skills/ue-game-features of quodsoler/unreal-engine-skills.

  • SKILL.md
  • references/experience-system.md
  • references/game-feature-patterns.md

Open the folder on GitHubat commit f3742d7

Compare with similar skills

Ue Game Features next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Ue Game Features compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Ue Game Features this skillquodsoler/unreal-engine-skills362—~8kAutomated safety check: PassMIT
Vercel Composition Patternssupabase/supabase111k58 repos~726Automated safety check: PassMIT
Finishing a Development Branchobra/superpowers297k5 repos~1.9kAutomated safety check: PassMIT
Typescript Advanced Typesrolling-scopes/rsschool-app10k25 repos~4.2kAutomated safety check: PassMPL-2.0
PR Babysitteropeninterpreter/openinterpreter69k3 repos~4.2kAutomated safety check: PassApache-2.0
Code Review ChecklistshareAI-lab/learn-claude-code78k4 repos~1.1kAutomated safety check: PassMIT

Similar skills

  • Official

    React composition patterns that scale. An agent skill from supabase/supabase.

    111k GitHub starsUsed in 58 repos~726 tokens
    DevelopmentAuto-check passed
  • Walks the last step of a branch: confirm tests pass, detect the git environment, ask how to integrate, carry out your choice and clean up the worktree.

    297k GitHub starsUsed in 5 repos~1.9k tokens
    DevelopmentAuto-check passed
  • Typescript Advanced Types

    rolling-scopes/rsschool-app

    Master TypeScript's advanced type system including generics, conditional types, mapped types, template literals, and utility types for building type-safe applications.

    10k GitHub starsUsed in 25 repos~4.2k tokens
    DevelopmentAuto-check passed
  • PR Babysitter

    openinterpreter/openinterpreter

    Watches an open GitHub pull request until it merges, handling review comments, diagnosing CI failures and retrying flaky checks along the way.

    69k GitHub starsUsed in 3 repos~4.2k tokens
    DevelopmentAuto-check passed
  • Code Review Checklist

    shareAI-lab/learn-claude-code

    Reviews code against a five-part checklist covering security, correctness, performance, maintainability and testing, and reports findings in a fixed format.

    78k GitHub starsUsed in 4 repos~1.1k tokens
    DevelopmentAuto-check passed
  • Greploop

    onyx-dot-app/onyx

    Iteratively improves a PR (GitHub), MR (GitLab), or shelved changelist (Perforce) until Greptile gives it a 5/5 confidence score with zero unresolved comments.

    32k GitHub starsUsed in 4 repos~3.3k tokens
    DevelopmentAuto-check passed

More from quodsoler/unreal-engine-skills

All 31 skills in this repo
  • Unreal Actor-Component Architecture

    quodsoler/unreal-engine-skills

    Unreal Engine C++ guidance for AActor and UActorComponent: lifecycle hooks, spawning, component creation and attachment, ticking, interfaces and composition.

    362 GitHub stars~7.5k tokensUpdated 12 days ago
    Auto-check passed
  • Unreal Engine AI and Navigation

    quodsoler/unreal-engine-skills

    Guides Unreal Engine C++ AI work across AI controllers, behavior trees, blackboards, perception, navmesh pathfinding, EQS and Smart Objects.

    362 GitHub stars~8.9k tokensUpdated 12 days ago
    Auto-check passed
  • Unreal Engine Animation System

    quodsoler/unreal-engine-skills

    Reference for writing and debugging Unreal Engine 5.8 animation C++: AnimInstance and proxy, montages, notifies, curves, blend spaces, state machines, linked layers and root motion.

    362 GitHub stars~7k tokensUpdated 12 days ago
    Auto-check passed
  • Unreal Engine Async and Threading

    quodsoler/unreal-engine-skills

    Picks and applies the right Unreal Engine C++ concurrency API, from UE::Tasks and FPipe to ParallelFor, FRunnable, locks and timers, with game-thread safety rules.

    362 GitHub stars~8k tokensUpdated 12 days ago
    Auto-check passed
  • Ue Audio System

    quodsoler/unreal-engine-skills

    A skill your agent uses when playing, mixing or debugging sound in Unreal Engine — one-shot SFX, looping ambience, music, dialogue or procedural audio.

    362 GitHub stars~7.9k tokensUpdated 12 days ago
    Auto-check passed
  • Unreal Blueprint and C++ Interop

    quodsoler/unreal-engine-skills

    Reference for exposing Unreal Engine C++ to Blueprint and calling Blueprint from C++, covering UFUNCTION and UPROPERTY specifiers, latent and async nodes, and interfaces.

    362 GitHub stars~7.8k tokensUpdated 12 days ago
    Auto-check passed

Categories

Questions about Ue Game Features

What does Ue Game Features do?

A skill your agent uses when building, activating or debugging Game Feature plugins and modular gameplay. Ue Game Features is an agent skill from quodsoler/unreal-engine-skills. Use when building, activating or debugging Game Feature plugins and modular gameplay.

When should I use Ue Game Features?

Ue Game Features fits situations like: debugging Game Feature plugins and modular gameplay; the user mentions GameFeatureAction; UGameFeatureData; gameFeaturesSubsystem.

How do I install Ue Game Features in Claude Code?

Run `npx skills add quodsoler/unreal-engine-skills --skill ue-game-features -a claude-code`. Or copy the skill folder (skills/ue-game-features in quodsoler/unreal-engine-skills) into .claude/skills/ue-game-features in your project. Claude Code loads it when a task matches its description.

How do I install Ue Game Features in Codex?

Run `npx skills add quodsoler/unreal-engine-skills --skill ue-game-features -a codex`. Or copy the skill folder (skills/ue-game-features in quodsoler/unreal-engine-skills) into .agents/skills/ue-game-features in your project. Codex loads it when a task matches its description.

Can I use Ue Game Features in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add quodsoler/unreal-engine-skills --skill ue-game-features -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/ue-game-features, .gemini/skills/ue-game-features, .github/skills/ue-game-features and .opencode/skills/ue-game-features in your project.

What does Ue Game Features need to run?

SKILL.md names no scripts, command-line tools or credentials: Ue Game Features is instructions for the agent only.

Does Ue Game Features access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Ue Game Features safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Ue Game Features use?

Ue Game Features is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Ue Game Features use?

About 8k tokens (SKILL.md is roughly 32k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 7.8k tokens, read only when the agent opens those files.

What are the alternatives to Ue Game Features?

Skills that share tags, products or a category with Ue Game Features: Vercel Composition Patterns (supabase/supabase, 111k stars), Finishing a Development Branch (obra/superpowers, 297k stars), Typescript Advanced Types (rolling-scopes/rsschool-app, 10k stars) and PR Babysitter (openinterpreter/openinterpreter, 69k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Ue Game Features?

quodsoler (a GitHub user) maintains it in quodsoler/unreal-engine-skills, which has 362 GitHub stars. The repository holds 31 skills in this directory. The repository was last updated on September 28, 2026.

Source: quodsoler/unreal-engine-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.