UE Blueprint / C++ Interop
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.
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 |
|---|---|
| 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 |
UFUNCTION Exposure
| 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();.
Parameters and pins
| 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.
UPROPERTY Exposure
| 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.
Function Libraries
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").
Latent Nodes
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.
Async Action Nodes
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.
Blueprint Interfaces
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_.
Enums and Structs in Blueprint
// 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)requiresenum class : uint8; UHT rejects any other base ("Invalid BlueprintType enum base - currently only uint8 supported").UMETA(DisplayName="โฆ")renames an enumerator andUMETA(Hidden)hides it from pickers.USTRUCT(BlueprintType)gives Make and Break nodes. Structs cannot holdUFUNCTIONs โ put struct helpers in a function library.- No nested containers.
TArray,TSetandTMapclear their own "can be a container key/value" capability in UHT, soTArray<TArray<int32>>andTMap<FName, TArray<int32>>do not compile. Wrap the inner container in aUSTRUCT. - A container is Blueprint-exposable only when its element type โ and for
TMapits key type โ is itself Blueprint-supported. FTableRowBase(Engine/DataTable.h) isUSTRUCT(BlueprintInternalUseOnly); derive row structs from it and mark the derived structBlueprintType. Table loading and row lookup:ue-data-assets-tables.FInstancedStruct(StructUtils/InstancedStruct.h) isUSTRUCT(BlueprintType)and gives Blueprint a single pin whose concrete struct type is chosen in the editor;TInstancedStruct<FMyBase>is the typed C++ wrapper.
Delegates and Events
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; addingBlueprintCallablealso gives it a Broadcast node. Both are legal only on multicast dynamic delegates.- Delegate parameters need names โ they become the pin names on the event node.
- Any C++ handler bound with
AddDynamicmust be aUFUNCTION(); otherwise the name lookup fails at runtime and the handler never runs. - A single dynamic delegate (
DECLARE_DYNAMIC_DELEGATE,DECLARE_DYNAMIC_DELEGATE_OneParam, โฆ) works as aUFUNCTIONparameter, which is how async nodes take a one-shot callback:UPARAM(DisplayName="Event") FMyReadySignature Callback. - Native (non-dynamic) delegates cannot be exposed at all; wrap them in a dynamic delegate or an async action.
Calling Blueprint from Native Code
| 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.
Subsystems and Settings in Blueprint
- Every
UGameInstanceSubsystem,UWorldSubsystem,ULocalPlayerSubsystemandUEngineSubsystemsubclass automatically gets aGet <Subsystem>node (UK2Node_GetSubsystem); itsBlueprintCallablemembers then appear on that object. No extra specifier is needed. Subsystem lifetimes and native accessors:ue-cpp-foundations. UDeveloperSettings(Engine/DeveloperSettings.h, moduleDeveloperSettings) auto-registers a Project Settings page. Declare itUCLASS(Config=Game, DefaultConfig, meta=(DisplayName="My Game")), mark fieldsUPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category=โฆ), and add aUFUNCTION(BlueprintPure)static accessor returningGetDefault<UMyGameSettings>()โ Blueprint has no node forGetDefault.GetContainerName(),GetCategoryName()andGetSectionName()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 aBlueprintCallableout of Shipping, asUKismetSystemLibrary::PrintStringdoes.
Editor-Callable Functions
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.
Deprecated โ do not use
| 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 |
Common Mistakes
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.
Related Skills
ue-cpp-foundationsโUCLASS/UPROPERTY/UFUNCTIONfundamentals, 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โUUserWidgetC++ bases,BindWidget, exposing widget data to Blueprint