Unreal Engine MCP
EpicGames/unreal-engine-skills-for-claude-code-plugin
Drives a live Unreal Editor through the unreal-mcp server: spawn actors, edit Blueprints, materials and sequences, change properties and trigger Live Coding.
Reference for exposing Unreal Engine C++ to Blueprint and calling Blueprint from C++, covering UFUNCTION and UPROPERTY specifiers, latent and async nodes, and interfaces.
$ npx skills add quodsoler/unreal-engine-skills --skill ue-blueprint-cpp-interop -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install quodsoler/unreal-engine-skills ue-blueprint-cpp-interop --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/quodsoler/unreal-engine-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/ue-blueprint-cpp-interop .claude/skills/ue-blueprint-cpp-interop && rm -rf skills-srcUse ~/.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/
Install the "ue-blueprint-cpp-interop" agent skill from https://github.com/quodsoler/unreal-engine-skills/tree/main/skills/ue-blueprint-cpp-interop into .claude/skills/ue-blueprint-cpp-interop/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ue-blueprint-cpp-interop", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/quodsoler/unreal-engine-skills/tree/main/skills/ue-blueprint-cpp-interopType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add quodsoler/unreal-engine-skills --skill ue-blueprint-cpp-interop -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install quodsoler/unreal-engine-skills ue-blueprint-cpp-interop --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/quodsoler/unreal-engine-skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/ue-blueprint-cpp-interop .agents/skills/ue-blueprint-cpp-interop && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "ue-blueprint-cpp-interop" agent skill from https://github.com/quodsoler/unreal-engine-skills/tree/main/skills/ue-blueprint-cpp-interop into .agents/skills/ue-blueprint-cpp-interop/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ue-blueprint-cpp-interop", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add quodsoler/unreal-engine-skills --skill ue-blueprint-cpp-interop -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install quodsoler/unreal-engine-skills ue-blueprint-cpp-interop --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/quodsoler/unreal-engine-skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/ue-blueprint-cpp-interop .cursor/skills/ue-blueprint-cpp-interop && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "ue-blueprint-cpp-interop" agent skill from https://github.com/quodsoler/unreal-engine-skills/tree/main/skills/ue-blueprint-cpp-interop into .cursor/skills/ue-blueprint-cpp-interop/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ue-blueprint-cpp-interop", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/quodsoler/unreal-engine-skills.git --path skills/ue-blueprint-cpp-interop--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add quodsoler/unreal-engine-skills --skill ue-blueprint-cpp-interop -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install quodsoler/unreal-engine-skills ue-blueprint-cpp-interop --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/quodsoler/unreal-engine-skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/ue-blueprint-cpp-interop .gemini/skills/ue-blueprint-cpp-interop && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "ue-blueprint-cpp-interop" agent skill from https://github.com/quodsoler/unreal-engine-skills/tree/main/skills/ue-blueprint-cpp-interop into .gemini/skills/ue-blueprint-cpp-interop/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ue-blueprint-cpp-interop", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install quodsoler/unreal-engine-skills ue-blueprint-cpp-interopInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add quodsoler/unreal-engine-skills --skill ue-blueprint-cpp-interop -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/quodsoler/unreal-engine-skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/ue-blueprint-cpp-interop .github/skills/ue-blueprint-cpp-interop && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "ue-blueprint-cpp-interop" agent skill from https://github.com/quodsoler/unreal-engine-skills/tree/main/skills/ue-blueprint-cpp-interop into .github/skills/ue-blueprint-cpp-interop/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ue-blueprint-cpp-interop", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add quodsoler/unreal-engine-skills --skill ue-blueprint-cpp-interop -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install quodsoler/unreal-engine-skills ue-blueprint-cpp-interop --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/quodsoler/unreal-engine-skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/ue-blueprint-cpp-interop .opencode/skills/ue-blueprint-cpp-interop && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "ue-blueprint-cpp-interop" agent skill from https://github.com/quodsoler/unreal-engine-skills/tree/main/skills/ue-blueprint-cpp-interop into .opencode/skills/ue-blueprint-cpp-interop/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ue-blueprint-cpp-interop", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
ue-blueprint-cpp-interopReference for exposing Unreal Engine C++ to Blueprint and calling Blueprint from C++, covering UFUNCTION and UPROPERTY specifiers, latent and async nodes, and interfaces.
Targeting Unreal Engine 5.8, the skill covers the boundary between native code and the Blueprint VM: which UFUNCTION and UPROPERTY specifiers and meta keys produce which node shapes, function libraries, latent and async action nodes, Blueprint-implementable interfaces, delegates, and how C++ calls back into a Blueprint graph. Deprecated forms are listed so they are not used, and ObjectMacros.h is named as the authority for specifiers.
A routing table sends each kind of request to a section, from making a function callable or overridable to subsystems, developer settings and editor-callable buttons. The agent first reads .agents/ue-project-context.md if it exists and asks questions only when two readings would produce different code. The code needs the Core, CoreUObject and Engine modules, plus DeveloperSettings for settings pages. Two reference files cover meta specifiers and node patterns, and related skills handle reflection basics and editor tools.
Read from SKILL.md and the folder at commit f3742d7. It shows what the files ask for, not the result of running them.
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.
No scripts in the folder and no shell commands in SKILL.md (its code samples are cpp).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Unreal Blueprint and C++ Interop loads about 7.8k tokens when it runs, and up to ~15k if it reads all its reference files. Until then it costs about 185 tokens; SKILL.md has 2,206 words of instructions outside code blocks.
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.
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.
The full file from quodsoler/unreal-engine-skills at commit f3742d7, republished under its MIT licence (© quodsoler). 2,206 words, ~7,840 tokens.
.claude/skills/ue-blueprint-cpp-interop/SKILL.md (or your agent's skills folder). This skill also uses 2 other files; get the full folder from GitHub.Target engine: UE 5.8. APIs below are verified against the 5.8 headers; older forms are listed under "Deprecated — do not use".
This skill covers the boundary between native code and the Blueprint VM: which UFUNCTION/UPROPERTY specifiers and meta= keys produce which node shapes, function libraries, latent and async nodes, Blueprint-implementable interfaces, and how C++ calls back into a Blueprint graph. Everything here lives in Core, CoreUObject and Engine (PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine" });); Project Settings pages also need DeveloperSettings. The authority for every specifier is Runtime/CoreUObject/Public/UObject/ObjectMacros.h — anything not declared in its UC, UI, UF, UP, US or UM enumerations is not a specifier.
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 |
|---|---|
| Making a C++ function callable or overridable in Blueprint | UFUNCTION Exposure |
| Making data visible or editable in Blueprint, getters/setters | UPROPERTY Exposure |
Static helpers, WorldContext, DefaultToSelf | Function Libraries |
| A node with an exec pin that finishes later (Delay-style) | Latent Nodes |
| A node with several output exec pins that fire on events | Async Action Nodes |
Interfaces Blueprint can implement, Execute_, TScriptInterface | Blueprint Interfaces |
UENUM, USTRUCT, containers as Blueprint types | Enums and Structs in Blueprint |
BlueprintAssignable events, binding Blueprint to a C++ delegate | Delegates and Events |
| Running Blueprint logic from native code, Blueprint classes | Calling Blueprint from Native Code |
Subsystems, UDeveloperSettings, Exec commands | Subsystems and Settings in Blueprint |
| A button in the Details panel, editor-only actions | Editor-Callable Functions |
| Specifier | Node shape | C++ body |
|---|---|---|
BlueprintCallable | Exec pins in and out | Yours |
BlueprintPure | No exec pins; implies BlueprintCallable | Yours, side-effect free |
BlueprintImplementableEvent | Event the Blueprint implements | None — UHT generates the thunk |
BlueprintNativeEvent | Event the Blueprint may override | Name_Implementation only |
BlueprintGetter / BlueprintSetter | Hidden; reached through the property | Yours |
BlueprintAuthorityOnly | Blueprint calls are skipped without network authority (direct C++ calls still run) | Yours |
BlueprintCosmetic | Blueprint calls are skipped on a dedicated server (direct C++ calls still run) | Yours |
BlueprintInternalUseOnly | Not offered in the palette; only generated nodes call it | Yours |
CallInEditor | Button on the Details panel | Yours |
Exec | Console command | Yours |
Category="A\|B" builds a nested palette category. The node-shaping meta= keys — DisplayName, ToolTip, Keywords, CompactNodeTitle, AdvancedDisplay, ReturnDisplayName, HidePin, DeterminesOutputType, DynamicOutputParam, ArrayParm, ExpandEnumAsExecs, WorldContext, UnsafeDuringActorConstruction, DevelopmentOnly, BlueprintThreadSafe and the rest — are tabled with header citations in references/blueprint-meta-specifiers.md.
// MyActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"
UCLASS(Blueprintable)
class MYGAME_API AMyActor : public AActor
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category="MyGame|Combat", meta=(Keywords="damage hurt"))
void ApplyDamage(float Amount);
UFUNCTION(BlueprintPure, Category="MyGame|Combat", meta=(CompactNodeTitle="HP", ReturnDisplayName="Health"))
float GetHealth() const;
/** Blueprint supplies the whole body; C++ never defines this. */
UFUNCTION(BlueprintImplementableEvent, Category="MyGame|Combat")
void OnDamaged(float Amount);
/** C++ supplies the default in OnDied_Implementation; Blueprint may override it. */
UFUNCTION(BlueprintNativeEvent, Category="MyGame|Combat")
void OnDied();
virtual void OnDied_Implementation();
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category="MyGame|Combat")
void ResetOnServer() { Health = MaxHealth; } // Blueprint calls skipped on clients
UFUNCTION(BlueprintCallable, BlueprintCosmetic, Category="MyGame|FX")
void PlayHitFlash() {} // Blueprint calls skipped on a dedicated server
UFUNCTION(CallInEditor, Category="MyGame|Tools")
void SnapToGround() {} // button in the Details panel
private:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="MyGame|Combat", meta=(AllowPrivateAccess="true", ClampMin="0.0"))
float Health = 100.f;
float MaxHealth = 100.f;
};// MyActor.cpp
#include "MyActor.h"
void AMyActor::ApplyDamage(float Amount)
{
Health = FMath::Max(0.f, Health - Amount);
OnDamaged(Amount); // runs the Blueprint graph
if (Health <= 0.f) { OnDied(); } // runs the BP override if any, else OnDied_Implementation
}
float AMyActor::GetHealth() const { return Health; }
void AMyActor::OnDied_Implementation() {} // the C++ default, overridable in BlueprintRaise an event by its plain name (OnDied()), never OnDied_Implementation() — the plain name is the generated thunk that dispatches to Blueprint. A subclass overrides virtual void OnDied_Implementation() override; and chains with Super::OnDied_Implementation();, never Super::OnDied();.
| C++ parameter | Blueprint pin |
|---|---|
float Amount | Input |
const FVector& Base | Input, passed by reference |
FVector& Out | Output pin, not an input |
UPARAM(ref) FVector& InOut | By-reference input that is also an output |
UPARAM(DisplayName="Event") FMyReadySignature Callback | Input renamed on the node |
A bare T& gets the OutParm flag from UHT; UPARAM(ref) adds ReferenceParm so the pin stays an input. meta=(AutoCreateRefTerm="Offset") gives a reference input an inline literal when nothing is connected.
| Specifier | Effect in Blueprint |
|---|---|
BlueprintReadWrite | Get and Set nodes |
BlueprintReadOnly | Get node only |
BlueprintGetter=Fn | Get routes through UFUNCTION(BlueprintGetter) |
BlueprintSetter=Fn | Set routes through UFUNCTION(BlueprintSetter); implies BlueprintReadWrite |
BlueprintAssignable | Bind Event node (multicast dynamic delegates only) |
BlueprintCallable | Broadcast node (multicast dynamic delegates only) |
BlueprintAuthorityOnly | Delegate accepts only BlueprintAuthorityOnly events |
BlueprintReadWrite/BlueprintReadOnly on a private member is a UHT error ("BlueprintReadWrite should not be used on private members") unless the property carries meta=(AllowPrivateAccess="true"). An editor-only property cannot be a Blueprint-exposed struct member. Editor meta= keys (ClampMin/ClampMax, UIMin/UIMax, EditCondition, EditConditionHides, InlineEditConditionToggle, TitleProperty, ShowOnlyInnerProperties, MultiLine, GetOptions, AllowedClasses, MustImplement, Categories, Bitmask/BitmaskEnum, ExposeOnSpawn): references/blueprint-meta-specifiers.md.
| C++ member type | Blueprint pin |
|---|---|
double / float | Real |
TObjectPtr<UStaticMesh> | Object reference |
TSubclassOf<AActor> | Class (filtered by meta=(MustImplement=…), AllowedClasses, BlueprintBaseOnly) |
TSoftObjectPtr<T> / TSoftClassPtr<T> | Soft reference; Blueprint resolves or loads on demand |
FInstancedStruct | Struct pin whose concrete type is chosen in the editor |
TScriptInterface<IMyInteractable> | Interface reference |
FMyHealthChangedSignature (multicast dynamic) | Bind Event / Broadcast nodes via BlueprintAssignable |
FTimerHandle | USTRUCT(BlueprintType) handle passed straight through |
A worked component showing ExposeOnSpawn, EditCondition/EditConditionHides, InlineEditConditionToggle, MustImplement and a BlueprintGetter/BlueprintSetter pair: references/blueprint-meta-specifiers.md.
Floats and doubles. Both float and double properties show as a Blueprint Real pin (UEdGraphSchema_K2 maps FFloatProperty and FDoubleProperty to PC_Real with sub-category PC_Float/PC_Double), and Blueprint-authored variables are doubles. Declare double for scalars that flow through Blueprint math so no narrowing conversion is inserted; keep float only where the engine type is already float.
UBlueprintFunctionLibrary (Kismet/BlueprintFunctionLibrary.h) is UCLASS(Abstract) and every member is static. GetWorld() returns null on its CDO, so take const UObject* WorldContextObject, tag it meta=(WorldContext="WorldContextObject") and resolve with GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull); meta=(DefaultToSelf="Param") pre-wires a pin to the calling object.
// MyBlueprintLibrary.h
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "Templates/SubclassOf.h"
#include "MyBlueprintLibrary.generated.h"
class AActor;
UENUM(BlueprintType)
enum class EMyConsumeResult : uint8
{
Consumed,
NotEnough
};
UCLASS()
class MYGAME_API UMyBlueprintLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
/** WorldContextObject is hidden on the node and filled in by the graph. */
UFUNCTION(BlueprintCallable, Category="MyGame|Utility", meta=(WorldContext="WorldContextObject"))
static int32 CountPawns(const UObject* WorldContextObject);
/** The return pin takes the type plugged into ActorClass, so Blueprint needs no cast. */
UFUNCTION(BlueprintPure, Category="MyGame|Utility", meta=(DefaultToSelf="Target", DeterminesOutputType="ActorClass"))
static AActor* FindAttachedActorOfClass(AActor* Target, TSubclassOf<AActor> ActorClass);
/** One input enum becomes one output exec pin per enumerator. */
UFUNCTION(BlueprintCallable, Category="MyGame|Utility", meta=(ExpandEnumAsExecs="Result"))
static void TryConsume(int32 Available, int32 Amount, EMyConsumeResult& Result);
};The matching .cpp: references/blueprint-node-patterns.md. ExpandEnumAsExecs accepts exactly one input parameter (UHT errors on a second); name ReturnValue to expand the return value, and use ExpandBoolAsExecs for a bool. Wildcard array nodes use meta=(ArrayParm="Items", ArrayTypeDependentParams="Item").
A latent node holds one exec pin pending across frames. It needs meta=(Latent, LatentInfo="LatentInfo", WorldContext="WorldContextObject") and a trailing FLatentActionInfo parameter, plus an FPendingLatentAction subclass registered with the world's FLatentActionManager. UKismetSystemLibrary::Delay and FDelayAction (Engine/Public/DelayAction.h) are the engine reference.
// MyLatentLibrary.h — declaration
UFUNCTION(BlueprintCallable, Category="MyGame|Flow", meta=(Latent, LatentInfo="LatentInfo", WorldContext="WorldContextObject", Duration="1.0"))
static void WaitSeconds(const UObject* WorldContextObject, float Duration, FLatentActionInfo LatentInfo);// MyLatentLibrary.cpp — the UUID guard is mandatory
void UMyLatentLibrary::WaitSeconds(const UObject* WorldContextObject, float Duration, FLatentActionInfo LatentInfo)
{
if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
{
FLatentActionManager& Manager = World->GetLatentActionManager();
if (Manager.FindExistingAction<FMyWaitAction>(LatentInfo.CallbackTarget, LatentInfo.UUID) == nullptr)
{
Manager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, new FMyWaitAction(Duration, LatentInfo));
}
}
}Without the FindExistingAction guard, re-entering the node stacks a second action on the same UUID and the exec pin fires more than once. The action subclass overrides UpdateOperation(FLatentResponse& Response) and finishes with Response.FinishAndTriggerIf(bDone, ExecutionFunction, OutputLink, CallbackTarget), copying ExecutionFunction, Linkage and CallbackTarget out of the FLatentActionInfo in its constructor; it also overrides NotifyObjectDestroyed(), NotifyActionAborted() and, under WITH_EDITOR, GetDescription() const. FLatentResponse additionally offers DoneIf(bool) and TriggerLink(ExecutionFunction, LinkID, CallbackTarget) for several exit links. Complete subclass and the rest of the FLatentActionManager API: references/blueprint-node-patterns.md.
UBlueprintAsyncActionBase (Kismet/BlueprintAsyncActionBase.h) produces a node with one exec input and one output exec pin per BlueprintAssignable delegate. The static factory must carry meta=(BlueprintInternalUseOnly="true") so only the generated node can call it.
// MyWaitForHealthAction.h
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "MyWaitForHealthAction.generated.h"
class UMyStatsComponent;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMyHealthThresholdSignature, double, Health);
UCLASS()
class MYGAME_API UMyWaitForHealthAction : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category="MyGame|Async", meta=(BlueprintInternalUseOnly="true", WorldContext="WorldContextObject", DisplayName="Wait For Health Below"))
static UMyWaitForHealthAction* WaitForHealthBelow(UObject* WorldContextObject, UMyStatsComponent* Stats, double Threshold);
virtual void Activate() override;
UPROPERTY(BlueprintAssignable)
FMyHealthThresholdSignature OnReached; // one output exec pin
UPROPERTY(BlueprintAssignable)
FMyHealthThresholdSignature OnFailed; // a second output exec pin
private:
UFUNCTION()
void HandleHealthChanged(double NewHealth); // AddDynamic targets must be UFUNCTIONs
UPROPERTY()
TObjectPtr<UMyStatsComponent> TrackedStats;
double ThresholdValue = 0.0;
};The factory does NewObject<UMyWaitForHealthAction>(), stores its inputs, calls RegisterWithGameInstance(WorldContextObject) and returns the action; the node then binds the delegates and calls Activate(), where the work starts. Each completion path broadcasts once and calls SetReadyToDestroy(). An unregistered action lives only for the frame it was created on (RF_StrongRefOnFrame), so a delegate firing later finds it collected. The engine ensures when more than bp.MaxAsyncActionCount (default 10000) actions are alive at once.
UCancellableAsyncAction (Engine/CancellableAsyncAction.h, UCLASS(Abstract, BlueprintType, meta=(ExposedAsyncProxy=AsyncAction))) adds Cancel(), IsActive() const and ShouldBroadcastDelegates() const so the node hands the object back for later cancelling; guard every broadcast with ShouldBroadcastDelegates(). Full Activate/Cancel implementations: references/blueprint-node-patterns.md.
UINTERFACE's own specifiers (UI::) are MinimalAPI, Blueprintable, NotBlueprintable and ConversionRoot plus meta=; UHT's shared BlueprintType is also accepted, and engine interfaces use it so the interface is usable as a Blueprint variable type. Blueprint can implement BlueprintImplementableEvent and BlueprintNativeEvent members; a plain virtual C++ method is invisible to Blueprint.
// MyInteractable.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "MyInteractable.generated.h"
class AActor;
UINTERFACE(Blueprintable, BlueprintType, MinimalAPI)
class UMyInteractable : public UInterface
{
GENERATED_BODY()
};
class MYGAME_API IMyInteractable
{
GENERATED_BODY()
public:
/** Blueprint-only implementations are allowed; C++ implementers write Interact_Implementation. */
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="MyGame|Interaction")
bool Interact(AActor* Interactor);
virtual bool Interact_Implementation(AActor* Interactor);
virtual float GetInteractRange() const { return 200.f; } // native-only: invisible to Blueprint
};// Calling an interface that may be implemented in C++ or in Blueprint
bool MyTryInteract(UObject* Target, AActor* Interactor)
{
return Target && Target->Implements<UMyInteractable>()
&& IMyInteractable::Execute_Interact(Target, Interactor);
}| Form | C++ implementers | Blueprint implementers |
|---|---|---|
IMyInteractable::Execute_Interact(Obj, …) | Yes | Yes — always use this |
Obj->Implements<UMyInteractable>() | Yes | Yes |
Obj->GetClass()->ImplementsInterface(UMyInteractable::StaticClass()) | Yes | Yes |
Cast<IMyInteractable>(Obj) then a direct call | Yes | No — the cast returns null |
TScriptInterface<IMyInteractable> member | Yes | Interface pointer is null; still call through Execute_ |
TScriptInterface<T> (UObject/ScriptInterface.h) stores the object and the interface pointer together and is documented as useful for native interfaces only. Declare UPROPERTY(EditAnywhere, BlueprintReadWrite) TScriptInterface<IMyInteractable> Target; so designers get a filtered picker, and still dispatch with Execute_.
// MyTypes.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataTable.h"
#include "MyTypes.generated.h"
UENUM(BlueprintType)
enum class EMyWeaponState : uint8 // BlueprintType enums must be uint8-based
{
Idle,
Firing UMETA(DisplayName="Firing Weapon"),
Reloading,
MAX UMETA(Hidden)
};
USTRUCT(BlueprintType)
struct MYGAME_API FMyWeaponStats
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
double BaseDamage = 10.0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
TArray<FName> Tags; // container of a Blueprint-supported type
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
TMap<FName, double> Modifiers; // key and value must both be Blueprint-supported
};
USTRUCT(BlueprintType)
struct MYGAME_API FMyWeaponRow : public FTableRowBase // data table row type
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
FMyWeaponStats Stats;
};UENUM(BlueprintType) requires enum class : uint8; UHT rejects any other base ("Invalid BlueprintType enum base - currently only uint8 supported"). UMETA(DisplayName="…") renames an enumerator and UMETA(Hidden) hides it from pickers.USTRUCT(BlueprintType) gives Make and Break nodes. Structs cannot hold UFUNCTIONs — put struct helpers in a function library.TArray, TSet and TMap clear their own "can be a container key/value" capability in UHT, so TArray<TArray<int32>> and TMap<FName, TArray<int32>> do not compile. Wrap the inner container in a USTRUCT.TMap its key type — is itself Blueprint-supported.FTableRowBase (Engine/DataTable.h) is USTRUCT(BlueprintInternalUseOnly); derive row structs from it and mark the derived struct BlueprintType. Table loading and row lookup: ue-data-assets-tables.FInstancedStruct (StructUtils/InstancedStruct.h) is USTRUCT(BlueprintType) and gives Blueprint a single pin whose concrete struct type is chosen in the editor; TInstancedStruct<FMyBase> is the typed C++ wrapper.Only dynamic delegates cross the Blueprint boundary. Declaration macros and native binding rules: ue-cpp-foundations.
UPROPERTY(BlueprintAssignable) on a multicast dynamic delegate gives Blueprint a Bind Event node; adding BlueprintCallable also gives it a Broadcast node. Both are legal only on multicast dynamic delegates.AddDynamic must be a UFUNCTION(); otherwise the name lookup fails at runtime and the handler never runs.DECLARE_DYNAMIC_DELEGATE, DECLARE_DYNAMIC_DELEGATE_OneParam, …) works as a UFUNCTION parameter, which is how async nodes take a one-shot callback: UPARAM(DisplayName="Event") FMyReadySignature Callback.| Need | Use |
|---|---|
| A hook the designer fills in | UFUNCTION(BlueprintImplementableEvent), called by its plain name |
| A hook with a C++ default | UFUNCTION(BlueprintNativeEvent), called by its plain name |
| Fire an event many graphs listen to | UPROPERTY(BlueprintAssignable) multicast, Broadcast(...) |
| Call a function that exists only in a Blueprint asset | FindFunction + ProcessEvent |
| Read defaults off a Blueprint class | TSubclassOf<T>::GetDefaultObject(), UClass::GetDefaultObject<T>() |
// The params struct must match the function's parameter list exactly, in declaration order.
struct FMyOnScoredParams
{
int32 Points;
FString Reason;
};
void MyNotifyScored(UObject* Target, int32 Points)
{
if (!Target) { return; }
if (UFunction* Func = Target->FindFunction(FName(TEXT("OnScored"))))
{
checkf(Func->ParmsSize == sizeof(FMyOnScoredParams), TEXT("OnScored signature changed"));
FMyOnScoredParams Params;
Params.Points = Points;
Params.Reason = TEXT("Kill");
Target->ProcessEvent(Func, &Params);
}
}FindFunction returns null when the Blueprint was renamed or recompiled away, so always branch on it (FindFunctionChecked asserts instead). Prefer a BlueprintImplementableEvent declaration whenever C++ owns the contract — it is type-checked at compile time.
// SpawnClassPath is a UPROPERTY(EditDefaultsOnly) TSoftClassPtr<AMyActor> set to BP_MyThing
void MyInspectSpawnClass(const TSoftClassPtr<AMyActor>& SpawnClassPath)
{
if (UClass* LoadedClass = SpawnClassPath.LoadSynchronous())
{
const AMyActor* Defaults = LoadedClass->GetDefaultObject<AMyActor>();
const bool bIsBlueprintClass = Cast<UBlueprintGeneratedClass>(LoadedClass) != nullptr; // UClass hides IsA (Class.h:4853)
UE_LOG(LogMyGame, Log, TEXT("Default health %.1f, Blueprint class %d"), Defaults->GetHealth(), bIsBlueprintClass ? 1 : 0);
}
}LoadSynchronous blocks the game thread; for streamed loads use the Asset Manager (ue-data-assets-tables). UBlueprintGeneratedClass (Engine/BlueprintGeneratedClass.h) is the runtime UClass a compiled Blueprint produces — test for it when native and Blueprint classes must be handled differently.
UGameInstanceSubsystem, UWorldSubsystem, ULocalPlayerSubsystem and UEngineSubsystem subclass automatically gets a Get <Subsystem> node (UK2Node_GetSubsystem); its BlueprintCallable members then appear on that object. No extra specifier is needed. Subsystem lifetimes and native accessors: ue-cpp-foundations.UDeveloperSettings (Engine/DeveloperSettings.h, module DeveloperSettings) auto-registers a Project Settings page. Declare it UCLASS(Config=Game, DefaultConfig, meta=(DisplayName="My Game")), mark fields UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category=…), and add a UFUNCTION(BlueprintPure) static accessor returning GetDefault<UMyGameSettings>() — Blueprint has no node for GetDefault. GetContainerName(), GetCategoryName() and GetSectionName() are overridable to move the page.UFUNCTION(Exec) declares a console command; the console routes to PlayerInput, PlayerController, Pawn, HUD, GameMode, CheatManager, GameState, PlayerCameraManager and GameInstance. meta=(DevelopmentOnly) compiles a BlueprintCallable out of Shipping, as UKismetSystemLibrary::PrintString does.CallInEditor — see AMyActor::SnapToGround above — is a UFUNCTION specifier, not a meta= key, and the function takes no parameters. It runs against the editor world, so guard anything that assumes PIE. Details customizations, editor utility widgets and asset actions: ue-editor-tools.
| Do not emit | Use in 5.8 | Source |
|---|---|---|
meta=(HideAssetPicker) | meta=(HidePinAssetPicker) | UE_DEPRECATED(5.6) in UObject/ObjectMacros.h:1673 |
Delegate.ProcessMulticastDelegate<UObject>(Params) | Delegate.ProcessDelegate<UObject>(Params) | UE_DEPRECATED(5.8) in UObject/ScriptDelegates.h:1462 |
SomeClass->ClassDefaultObject | GetDefault<T>(), UClass::GetDefaultObject<T>() | UE_DEPRECATED(5.6) in UObject/Class.h:4045 |
GENERATED_UCLASS_BODY(), GENERATED_IINTERFACE_BODY() | GENERATED_BODY() | Legacy aliases in UObject/ObjectMacros.h:802-805 |
Cast<IMyInterface>(Obj)->Foo() on a Blueprint implementer | IMyInterface::Execute_Foo(Obj, …) | Blueprint implementers have no IMyInterface pointer (UObject/ScriptInterface.h:135) |
Obj->Foo_Implementation() to raise a BlueprintNativeEvent | Obj->Foo() | The plain name is the generated dispatch thunk (UObject/ObjectMacros.h:997) |
A C++ body for a BlueprintImplementableEvent | Declare it and stop | UHT generates the body (UObject/ObjectMacros.h:992) |
UPROPERTY(BlueprintReadWrite) on a private member | Add meta=(AllowPrivateAccess="true"), or make it protected | UHT error "BlueprintReadWrite should not be used on private members" |
UENUM(BlueprintType) enum class EMyState : uint32 | enum class EMyState : uint8 | UHT error "Invalid BlueprintType enum base - currently only uint8 supported" |
TArray<TArray<T>> or TMap<K, TArray<V>> in a UPROPERTY | Wrap the inner container in a USTRUCT | TArray/TMap clear CanBeContainerValue/CanBeContainerKey in UHT |
AddNewAction without a FindExistingAction guard | Check LatentInfo.UUID first | Engine/LatentActionManager.h:121,143 |
NewObject<UMyAsyncAction>() returned without registering | RegisterWithGameInstance(WorldContextObject) | Kismet/BlueprintAsyncActionBase.h:37 |
BlueprintNativeEvent without _Implementation, or a C++ body for a BlueprintImplementableEvent: the first is an unresolved external, the second a duplicate symbol (UHT already emitted one). A native event needs virtual void Foo_Implementation(...) defined; an implementable event needs no definition at all.
BlueprintPure with side effects: the compiler prunes unused pure nodes and re-evaluates the rest at each consumer, so the side effect runs an unpredictable number of times. Use BlueprintCallable.
A non-const reference parameter that was meant as an input:
static void Scale(FVector& Value, double Factor); // WRONG: Value becomes an output pin
static void Scale(UPARAM(ref) FVector& Value, double Factor); // RIGHT: by-reference input
static void Scale(const FVector& Value, double Factor); // RIGHT: plain inputA library function that needs the world but declares no WorldContext: GetWorld() returns null on a UBlueprintFunctionLibrary CDO. Take const UObject* WorldContextObject, tag it meta=(WorldContext="WorldContextObject") and resolve with GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull).
BlueprintReadWrite on a private member: a UHT error, not a warning. Add meta=(AllowPrivateAccess="true").
Nested containers in a UPROPERTY: UHT rejects TArray<TArray<T>> and TMap<K, TArray<V>>. Wrap the inner container in a USTRUCT(BlueprintType).
A latent action added without the UUID guard: re-entering the node stacks duplicate actions and the completion pin fires once per copy. Check FindExistingAction<FMyWaitAction>(LatentInfo.CallbackTarget, LatentInfo.UUID) first.
An async action collected mid-flight: an action that never calls RegisterWithGameInstance lives only for the frame it was created on, so a delegate firing later never reaches it. Register in the factory and call SetReadyToDestroy() exactly once when finished.
Cast<IMyInterface>(Obj) on a Blueprint implementer: returns null and the call is silently skipped. Test with Obj->Implements<UMyInterface>() and dispatch with IMyInterface::Execute_Foo(Obj, …).
A static async factory without meta=(BlueprintInternalUseOnly="true"): Blueprint offers both the proxy node and a bare call to the factory, and the bare call returns an object nothing ever activates.
ue-cpp-foundations — UCLASS/UPROPERTY/UFUNCTION fundamentals, containers, delegates, subsystem lifetimes, GCue-actor-component-architecture — Actor and component lifecycle, spawning, BlueprintSpawnableComponentue-gameplay-framework — GameMode, PlayerController, damage, the classes Blueprint most often extendsue-editor-tools — details customization, editor utility widgets, asset actions, editor subsystemsue-async-threading — AsyncTask, UE::Tasks, timers and thread safety behind an async nodeue-data-assets-tables — UDataAsset, DataTable rows, soft references and Asset Manager loadingue-ui-umg-slate — UUserWidget C++ bases, BindWidget, exposing widget data to Blueprint© quodsoler, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 2 other files (references) in skills/ue-blueprint-cpp-interop of quodsoler/unreal-engine-skills.
Open the folder on GitHubat commit f3742d7
Unreal Blueprint and C++ Interop 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.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Unreal Blueprint and C++ Interop this skillquodsoler/unreal-engine-skills | 359 | — | ~7.8k | Automated safety check: Pass | MIT | |
| Unreal Engine MCPEpicGames/unreal-engine-skills-for-claude-code-plugin | 327 | — | ~1.8k | Automated safety check: Pass | MIT | |
| Unreal Live CodingItalink/UnrealClientProtocol | 127 | — | ~1k | Automated safety check: Pass | MIT | |
| Unreal Cpp Gameplayukanwat/overtime | 387 | 1 repos | ~1.5k | Automated safety check: Pass | Apache-2.0 | |
| Unreal Enhanced Inputukanwat/overtime | 387 | 1 repos | ~1.5k | Automated safety check: Pass | Apache-2.0 | |
| Unreal Niagaraukanwat/overtime | 387 | 1 repos | ~1.5k | Automated safety check: Pass | Apache-2.0 |
EpicGames/unreal-engine-skills-for-claude-code-plugin
Drives a live Unreal Editor through the unreal-mcp server: spawn actors, edit Blueprints, materials and sequences, change properties and trigger Live Coding.
Italink/UnrealClientProtocol
Trigger Live Coding compilation via UCP. An agent skill from Italink/UnrealClientProtocol.
ukanwat/overtime
Write Unreal Engine 5 C++ gameplay code: the UCLASS/UPROPERTY/UFUNCTION reflection macros, the Gameplay Framework (GameMode, Pawn, Character, PlayerController, Actor components), and the module…
ukanwat/overtime
Set up player input in Unreal Engine 5 with Enhanced Input: Input Actions, Input Mapping Contexts, modifiers and triggers, adding the mapping context, and binding actions by ETriggerEvent.
ukanwat/overtime
Create and control VFX in Unreal Engine 5 with Niagara: systems and emitters, modules and the spawn/update stages, exposed User parameters, and spawning or driving effects from Blueprints or C++.
scenario-labs/skills
A skill your agent uses when building or debugging UE5 gameplay: a character with double jump or dash, abilities with cooldowns, enemy AI that patrols, chases and attacks, a health bar or HUD…
quodsoler/unreal-engine-skills
Unreal Engine C++ guidance for AActor and UActorComponent: lifecycle hooks, spawning, component creation and attachment, ticking, interfaces and composition.
quodsoler/unreal-engine-skills
Guides Unreal Engine C++ AI work across AI controllers, behavior trees, blackboards, perception, navmesh pathfinding, EQS and Smart Objects.
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.
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.
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.
quodsoler/unreal-engine-skills
Reference for writing and debugging UCharacterMovementComponent code in Unreal Engine C++: custom movement modes, floor detection, root motion, prediction and gravity.
Works with
Categories
Reference for exposing Unreal Engine C++ to Blueprint and calling Blueprint from C++, covering UFUNCTION and UPROPERTY specifiers, latent and async nodes, and interfaces. 8, the skill covers the boundary between native code and the Blueprint VM: which UFUNCTION and UPROPERTY specifiers and meta keys produce which node shapes, function libraries, latent and async action nodes, Blueprint-implementable interfaces, delegates, and how C++ calls back into a Blueprint graph.h is named as the authority for specifiers.
Unreal Blueprint and C++ Interop fits situations like: exposing a C++ function or property to Blueprint; writing a custom or async Blueprint node; calling Blueprint events or interfaces from native code; adding a BlueprintAssignable delegate for Blueprint binding.
Run `npx skills add quodsoler/unreal-engine-skills --skill ue-blueprint-cpp-interop -a claude-code`. Or copy the skill folder (skills/ue-blueprint-cpp-interop in quodsoler/unreal-engine-skills) into .claude/skills/ue-blueprint-cpp-interop in your project. Claude Code loads it when a task matches its description.
Run `npx skills add quodsoler/unreal-engine-skills --skill ue-blueprint-cpp-interop -a codex`. Or copy the skill folder (skills/ue-blueprint-cpp-interop in quodsoler/unreal-engine-skills) into .agents/skills/ue-blueprint-cpp-interop in your project. Codex loads it when a task matches its description.
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-blueprint-cpp-interop -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-blueprint-cpp-interop, .gemini/skills/ue-blueprint-cpp-interop, .github/skills/ue-blueprint-cpp-interop and .opencode/skills/ue-blueprint-cpp-interop in your project.
SKILL.md names no scripts, command-line tools or credentials: Unreal Blueprint and C++ Interop is instructions for the agent only. Our summary lists: An Unreal Engine C++ project; Optionally the project context file at .agents/ue-project-context.md.
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.
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.
Unreal Blueprint and C++ Interop is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 7.8k tokens (SKILL.md is roughly 31k 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.4k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Unreal Blueprint and C++ Interop: Unreal Engine MCP (EpicGames/unreal-engine-skills-for-claude-code-plugin, 327 stars), Unreal Live Coding (Italink/UnrealClientProtocol, 127 stars), Unreal Cpp Gameplay (ukanwat/overtime, 387 stars) and Unreal Enhanced Input (ukanwat/overtime, 387 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
quodsoler (a GitHub user) maintains it in quodsoler/unreal-engine-skills, which has 359 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.