Claude
Skills
Sign in
Back

ue-game-features

Included with Lifetime
$97 forever

Use this skill when working with Game Feature plugins, modular gameplay, GameFeatureAction, GameFeatureData, GameFrameworkComponentManager, init state system, experience system, modular components, UPawnComponent, UControllerComponent, UGameStateComponent, UPlayerStateComponent, or Lyra-style modular architecture. See references/ for code templates and experience system patterns.

General

What this skill does


# UE Game Features and Modular Gameplay

You are an expert in Unreal Engine's Game Features plugin system and modular gameplay architecture.

## Context Check

Read `.agents/ue-project-context.md` before proceeding. Determine:
- Whether the `GameFeatures` and `ModularGameplay` plugins are enabled
- Which actors register as component receivers (`AddReceiver`)
- Whether the project uses an init state system or experience-based loading
- Existing `UGameFeatureAction` subclasses or modular component base classes

## Information Gathering

Ask the developer:
1. Are you creating a new Game Feature plugin or extending an existing one?
2. What components or abilities should the feature inject into gameplay actors?
3. Does the feature need async loading or runtime activation/deactivation?
4. Is there an experience/game mode composition system (Lyra-style)?
5. Do components need ordered initialization across features?

---

## Game Feature Plugin Structure

A Game Feature plugin is a standard UE plugin with `Type` set to `"GameFeature"` in its `.uplugin` descriptor. This tells the engine to manage its lifecycle through the Game Features subsystem rather than loading it as a regular plugin.

### .uplugin Descriptor

```cpp
{
    "Type": "GameFeature",
    "BuiltInInitialFeatureState": "Active",  // or "Registered", "Installed"
    "Plugins": [
        { "Name": "GameFeatures", "Enabled": true },
        { "Name": "ModularGameplay", "Enabled": true }
    ]
}
```

`BuiltInInitialFeatureState` controls how far the plugin advances on startup. Use `"Active"` for always-on features, `"Registered"` for features activated by gameplay code, or `"Installed"` for downloadable content loaded on demand.

### UGameFeatureData

Each Game Feature plugin contains a `UGameFeatureData` primary data asset (extends `UPrimaryDataAsset`) that defines what the feature does:

```cpp
// From GameFeatureData.h
UPROPERTY(EditDefaultsOnly, Instanced, Category = "Game Feature | Actions")
TArray<TObjectPtr<UGameFeatureAction>> Actions;

UPROPERTY(EditAnywhere, Category = "Game Feature | Asset Manager")
TArray<FPrimaryAssetTypeInfo> PrimaryAssetTypesToScan;
```

`Actions` is the core — an instanced array of `UGameFeatureAction` subclasses that execute when the feature activates.

### Directory Convention

```
Plugins/GameFeatures/
├── ShooterCore/
│   ├── ShooterCore.uplugin          (Type: GameFeature)
│   ├── Content/
│   │   └── ShooterCore.uasset       (UGameFeatureData)
│   └── Source/ShooterCoreRuntime/
└── DeathmatchRules/
    ├── DeathmatchRules.uplugin
    └── Content/DeathmatchRules.uasset
```

---

## Plugin State Machine

Game Feature plugins transition through a well-defined state machine. Actions fire at specific transitions and runtime activation must target valid destination states.

### EGameFeaturePluginState Lifecycle

```
Uninitialized → Terminal → UnknownStatus → StatusKnown
    → Installed → Registered → Loaded → Active
```

Each major state has transition states between them (e.g., `Registering`, `Loading`, `Activating`). You target a destination state and the subsystem walks the chain.

### Destination States

| State | Description |
|-------|-------------|
| `Terminal` | Plugin removed from tracking entirely |
| `StatusKnown` | Availability confirmed (exists on disk or bundle) |
| `Installed` | Files on local storage, not yet registered |
| `Registered` | Assets registered with Asset Manager, actions notified |
| `Loaded` | Assets loaded into memory |
| `Active` | Actions fully activated, components injected |

URL protocols: `file:` for built-in disk plugins, `installbundle:` for downloadable features. Convert descriptor path to URL with `UGameFeaturesSubsystem::GetPluginURL_FileProtocol(Path)`.

---

## UGameFeatureAction

`UGameFeatureAction` (`UCLASS(MinimalAPI, DefaultToInstanced, EditInlineNew, Abstract)`) is the base class for all actions. `DefaultToInstanced` + `EditInlineNew` allow instances to be created inline within `UGameFeatureData`'s `Actions` array.

### Lifecycle Methods

```cpp
// Registration phase
virtual void OnGameFeatureRegistering();
virtual void OnGameFeatureUnregistering();

// Loading phase
virtual void OnGameFeatureLoading();
virtual void OnGameFeatureUnloading();

// Activation — primary override point
virtual void OnGameFeatureActivating(FGameFeatureActivatingContext& Context);
virtual void OnGameFeatureActivating();  // legacy no-arg fallback

// Post-activation confirmation
virtual void OnGameFeatureActivated();

// Deactivation — supports async via context
virtual void OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context);
```

`OnGameFeatureActivating(Context)` is the primary override. The base calls the legacy no-arg version for backward compatibility.

### Async Deactivation

When deactivation requires async work, pause it via the context:

```cpp
void UMyAction::OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context)
{
    FSimpleDelegate ResumeDelegate = Context.PauseDeactivationUntilComplete(
        TEXT("MyAction_AsyncCleanup"));
    // Start async work — MUST invoke ResumeDelegate when done or deactivation hangs
    AsyncTask(ENamedThreads::GameThread, [ResumeDelegate]()
    {
        // ... cleanup ...
        ResumeDelegate.ExecuteIfBound();
    });
}
```

See `references/game-feature-patterns.md` for complete custom action subclass templates.

---

## Built-in Actions

### UGameFeatureAction_AddComponents

`UCLASS(MinimalAPI, meta=(DisplayName="Add Components"), final)`. The most commonly used action — injects components into actors via `UGameFrameworkComponentManager`.

Configuration uses `FGameFeatureComponentEntry`:

```cpp
UPROPERTY(EditAnywhere) TSoftClassPtr<AActor> ActorClass;
UPROPERTY(EditAnywhere) TSoftClassPtr<UActorComponent> ComponentClass;
UPROPERTY(EditAnywhere) uint8 bClientComponent : 1;
UPROPERTY(EditAnywhere) uint8 bServerComponent : 1;
```

Internally stores `TSharedPtr<FComponentRequestHandle>` — RAII removes components when the handle drops (feature deactivates). Set both `bClientComponent` and `bServerComponent` for components needed everywhere, server-only for gameplay logic, client-only for cosmetic.

### Other Built-in Actions

| Action | Purpose |
|--------|---------|
| `UGameFeatureAction_AddCheats` | Register cheat manager extensions |
| `UGameFeatureAction_DataRegistry` | Register data registry sources |

---

## UGameFeaturesSubsystem

`UGameFeaturesSubsystem` (`UEngineSubsystem`) manages all Game Feature plugin lifecycles:

```cpp
UGameFeaturesSubsystem& GFS = UGameFeaturesSubsystem::Get();
```

### Runtime Activation and Deactivation

```cpp
FString PluginURL = UGameFeaturesSubsystem::GetPluginURL_FileProtocol(
    TEXT("/MyProject/Plugins/GameFeatures/MyFeature/MyFeature.uplugin"));

// Activate — callback receives const UE::GameFeatures::FResult&
GFS.LoadAndActivateGameFeaturePlugin(PluginURL,
    FGameFeaturePluginLoadComplete::CreateUObject(this, &UMyMgr::OnLoaded));

// Deactivate and unload
GFS.DeactivateGameFeaturePlugin(PluginURL);
GFS.UnloadGameFeaturePlugin(PluginURL, /*bKeepRegistered=*/ false);

// Or target a specific state:
GFS.ChangeGameFeatureTargetState(PluginURL, EGameFeatureTargetState::Registered,
    FGameFeaturePluginChangeStateComplete());
```

### Query and Observe

```cpp
bool bActive = GFS.IsGameFeaturePluginActive(PluginURL, /*bCheckForActivating=*/ false);
EGameFeaturePluginState State = GFS.GetPluginState(PluginURL);

// Global observer — implement IGameFeatureStateChangeObserver
GFS.AddObserver(MyObserver, UGameFeaturesSubsystem::EObserverPluginStateUpdateMode::CurrentAndFuture);
GFS.RemoveObserver(MyObserver);
```

`IGameFeatureStateChangeObserver` provides: `OnGameFeatureRegistering(Data, PluginName, URL)`, `OnGameFeatureActivating(Data, URL)`, `OnGameFeatureDeactivating(Data, Context, URL)`.

---

## Component Injection System

`UGameFrameworkComponentManager` (`UGameInstanceSubsystem`) is the runtime engine that injects component

Related in General