Agent skill

Unreal Engine C++ Foundations

by quodsoler in quodsoler/unreal-engine-skills

Reference for Unreal Engine C++ on the reflection system and core types: UCLASS macros, containers, delegates, strings, object lifetime, subsystems and logging.

MITAuto-check passedGame Development

Install Unreal Engine C++ Foundations

skills CLI
$ npx skills add quodsoler/unreal-engine-skills --skill ue-cpp-foundations -a claude-code

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

GitHub CLI
$ gh skill install quodsoler/unreal-engine-skills ue-cpp-foundations --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-cpp-foundations .claude/skills/ue-cpp-foundations && 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-cpp-foundations
GitHub stars
359
Token cost
~6.8k tokens
SKILL.md length
1,315 words
Files
4 (incl. references)
Skills in repo
31
Repo updated
First seen
Licence
MIT

At a glance

Reference for Unreal Engine C++ on the reflection system and core types: UCLASS macros, containers, delegates, strings, object lifetime, subsystems and logging.

  • Declaring UCLASS, USTRUCT or UENUM types with the right specifiers
  • SKILL.md covers Context, Reflection Macros, Containers and Delegates, plus 10 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md
  • Choosing between TObjectPtr, TWeakObjectPtr and TSharedPtr for references

What it does

The skill covers the C++ layer that every Unreal module sits on, written against UE 5.8 headers with older forms listed under a deprecated section. Topics are the reflection macros (UCLASS, UPROPERTY, UFUNCTION, USTRUCT, UENUM, UINTERFACE), containers, delegates, string types, object lifetime and garbage collection, class default object access and the subsystem family.

A routing table sends the agent to the section that matches a request, and the file also covers replicated properties, UE_LOG logging and WITH_EDITOR or shipping build guards. It reads `.agents/ue-project-context.md` for module names and conventions when that file exists but carries on without it, and it asks questions only when two readings would give different code. Reference files cover container patterns, delegate patterns and property specifiers. Actor and component lifecycle, Build.cs modules and Blueprint interop are left to sibling skills.

When your agent uses it

  • Declaring UCLASS, USTRUCT or UENUM types with the right specifiers
  • Choosing between TObjectPtr, TWeakObjectPtr and TSharedPtr for references
  • Declaring and binding dynamic multicast delegates
  • Writing a game instance or world subsystem
  • Setting up replicated properties with GetLifetimeReplicatedProps

Example prompts

  • “Create a UCLASS for an inventory item with editable properties and a Blueprint-callable Use function.”
  • “Our UObject pointer keeps getting garbage collected, so fix the ownership with the right pointer type.”
  • “Add a world subsystem that tracks active quests and broadcasts a delegate when one completes.”

Requirements

  • An Unreal Engine C++ project (the skill targets UE 5.8)

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).

    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

Unreal Engine C++ Foundations loads about 6.8k tokens when it runs, and up to ~19k if it reads all its reference files. Until then it costs about 176 tokens; SKILL.md has 1,315 words of instructions outside code blocks.

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

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). 1,315 words, ~6,788 tokens.

Download SKILL.mdSave it as .claude/skills/ue-cpp-foundations/SKILL.md (or your agent's skills folder). This skill also uses 3 other files; get the full folder from GitHub.
name
ue-cpp-foundations
description
Use when writing Unreal Engine C++ that touches the reflection system or core types: UCLASS, UPROPERTY, UFUNCTION, USTRUCT, UENUM, GENERATED_BODY, TObjectPtr, TWeakObjectPtr, TSharedPtr, FGCObject, TArray, TMap, TSet, TOptional, TVariant, DECLARE_DYNAMIC_MULTICAST_DELEGATE, AddDynamic, FName, FString, FText, UGameInstanceSubsystem, UWorldSubsystem, GetDefault, TNotNull. Also use when the user mentions 'UE C++', 'garbage collection', 'CDO', 'smart pointers' or 'specifiers'. For Actor and component lifecycle, see ue-actor-component-architecture; for Build.cs and modules, see ue-module-build-system; for Blueprint-facing functions and latent actions, see ue-blueprint-cpp-interop.
metadata.version
2.0.0
metadata.engine
5.8

UE C++ Foundations

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 C++ layer every Unreal module is built on: reflection macros (UCLASS, UPROPERTY, UFUNCTION, USTRUCT, UENUM, UINTERFACE), containers, delegates, string types, object lifetime and garbage collection, CDO access, and the subsystem family. All of it lives in the Core, CoreUObject and Engine modules (PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine" });). Editor subsystems additionally need EditorSubsystem and UnrealEd in an editor-only module.

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
UCLASS, UPROPERTY, UFUNCTION, USTRUCT, UENUM specifiersReflection Macros
TArray, TMap, TSet, TOptional, TVariantContainers
Delegates, events, AddDynamic, BroadcastDelegates
FName, FString, FText, LOCTEXTString Types
TObjectPtr, TWeakObjectPtr, TSharedPtr, GC roots, FGCObjectObject Lifetime and Pointers
Class default objects, GetDefault, TNotNull parametersCDO Access and Non-Null Parameters
Game instance / world / local player / engine / editor subsystemsSubsystems
Replicated, ReplicatedUsing, GetLifetimeReplicatedPropsReplicated Properties
UE_LOG, log categoriesLogging
WITH_EDITOR, UE_BUILD_SHIPPING guardsConditional Compilation Guards

Reflection Macros

Every reflected type has GENERATED_BODY() as the first line of its body and #include "TypeName.generated.h" as the last include of its header. Every UCLASS in a game module carries the module API macro (MYGAME_API). Specifier parsing is case-insensitive (engine headers use both config=Game and Config=Game). Complete specifier and meta= tables: references/property-specifiers.md.

UCLASS
SpecifierEffect
Blueprintable / BlueprintTypeAllow Blueprint subclasses / use as a Blueprint variable type (Not… forms block them)
AbstractCannot be instantiated; subclasses can
Config=Game, DefaultConfigUPROPERTY(Config) members load from DefaultGame.ini; DefaultConfig also saves there
TransientInstances are never saved
ClassGroup=Name + meta=(BlueprintSpawnableComponent)Component appears in the Add Component menu
UPROPERTY
GroupSpecifiers
Editor visibilityEditAnywhere, EditDefaultsOnly, EditInstanceOnly, VisibleAnywhere, VisibleDefaultsOnly, VisibleInstanceOnly, AdvancedDisplay
Blueprint accessBlueprintReadWrite, BlueprintReadOnly, BlueprintGetter=Fn, BlueprintSetter=Fn, BlueprintAssignable (multicast delegates only)
SerializationTransient, DuplicateTransient, SaveGame, Config, GlobalConfig, Instanced, SkipSerialization, NonTransactional
ReplicationReplicated, ReplicatedUsing=OnRep_Fn, NotReplicated
Frequent meta= keysClampMin/ClampMax, UIMin/UIMax, EditCondition, EditConditionHides, AllowPrivateAccess, DisplayName, ToolTip, Units, AllowedClasses, MustImplement, ExposeOnSpawn, TitleProperty
cpp
// MyCharacter.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyCharacter.generated.h"

class UStaticMeshComponent;
class UStaticMesh;

UCLASS(Blueprintable)
class MYGAME_API AMyCharacter : public ACharacter
{
    GENERATED_BODY()
public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats", meta=(ClampMin="1.0"))
    float MaxHealth = 100.f;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Stats")
    float CurrentHealth = 100.f;

    UPROPERTY(Transient)
    TObjectPtr<UStaticMeshComponent> CachedMesh;     // not serialized, still GC-tracked

    UPROPERTY(EditDefaultsOnly, Category="Config")
    TSubclassOf<AActor> ProjectileClass;             // class reference restricted to AActor subclasses
    UPROPERTY(EditDefaultsOnly, Category="Config")
    TSoftObjectPtr<UStaticMesh> LazyMesh;            // path reference; load on demand

    UFUNCTION(BlueprintNativeEvent, Category="Combat")
    void OnDamageTaken(float Amount);
    virtual void OnDamageTaken_Implementation(float Amount);
};
UFUNCTION
SpecifierEffect
BlueprintCallable / BlueprintPureNode with / without execution pins; BlueprintPure must not mutate state
BlueprintNativeEventBlueprint may override; the C++ default body is Name_Implementation
BlueprintImplementableEventBlueprint implements; no C++ body at all
BlueprintAuthorityOnly / BlueprintCosmeticBlueprint calls run only with network authority / never on a dedicated server (direct C++ calls are not filtered)
Server, Client, NetMulticast with Reliable or Unreliable, WithValidationRPCs — rules and examples in ue-networking-replication
ExecConsole command; the console routes to PlayerInput, PlayerController, Pawn, HUD, GameMode, CheatManager, GameState, PlayerCameraManager and GameInstance
CallInEditorAdds a button to the Details panel
cpp
// MyCharacter.cpp — the only body a BlueprintNativeEvent gets in C++
void AMyCharacter::OnDamageTaken_Implementation(float Amount) { CurrentHealth = FMath::Max(0.f, CurrentHealth - Amount); }

Function libraries, latent and async nodes, WorldContext/DefaultToSelf/ExpandEnumAsExecs and the rest of the Blueprint-facing meta= keys: ue-blueprint-cpp-interop.

USTRUCT, UENUM, UINTERFACE
cpp
// MyTypes.h
#pragma once
#include "CoreMinimal.h"
#include "MyTypes.generated.h"

USTRUCT(BlueprintType)
struct MYGAME_API FMyWeaponStats
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
    float BaseDamage = 10.f;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
    float FireRate = 0.5f;
};

UENUM(BlueprintType)
enum class EMyWeaponState : uint8      // Blueprint-visible enums are enum class : uint8
{
    Idle,
    Firing    UMETA(DisplayName="Firing Weapon"),
    MAX       UMETA(Hidden)
};
  • A UDataTable row type is a USTRUCT deriving from FTableRowBase (Engine/DataTable.h); see ue-data-assets-tables.
  • Initialize every USTRUCT member in-class; reflected structs are value types copied freely by the engine.
  • A polymorphic struct value (any USTRUCT derived from a base) is stored as FInstancedStruct or typed TInstancedStruct<FMyBase> (StructUtils/InstancedStruct.h, module CoreUObject).
  • UINTERFACE pairs a UMyThing : UInterface stub with an IMyThing class; specifier table and a native example are in references/property-specifiers.md. Blueprint-implementable interfaces belong to ue-blueprint-cpp-interop.

Containers

Full API, iteration and performance notes: references/container-patterns.md. Containers of UObject pointers are GC-tracked only as UPROPERTY() TArray<TObjectPtr<T>> (likewise TMap/TSet).

cpp
TArray<FString> Names;
Names.Add(TEXT("Alpha"));
Names.Emplace(TEXT("Beta"));                       // construct in place
Names.Reserve(100);                                // pre-size before a known number of Adds
int32 Idx = Names.Find(TEXT("Beta"));              // INDEX_NONE if absent
FString* Ptr = Names.FindByPredicate([](const FString& S) { return S.StartsWith(TEXT("A")); });
Names.Sort([](const FString& A, const FString& B) { return A.Len() < B.Len(); });
Names.Remove(TEXT("Alpha"));                       // order-preserving, O(n)
Names.RemoveAtSwap(0);                             // O(1), reorders
for (int32 i = Names.Num() - 1; i >= 0; --i) { if (Names[i].IsEmpty()) { Names.RemoveAt(i); } }  // never mutate inside ranged-for

TMap<FName, int32> ItemCounts;
int32& Count = ItemCounts.FindOrAdd(FName("Sword"));  // inserts default if absent
int32* Found = ItemCounts.Find(FName("Axe"));         // nullptr if absent
for (const TPair<FName, int32>& Pair : ItemCounts) { UE_LOG(LogMyGame, Log, TEXT("%s x%d"), *Pair.Key.ToString(), Pair.Value); }

TSet<FName> Tags;
Tags.Add(FName("Flying"));
bool bFlying = Tags.Contains(FName("Flying"));     // hashed, no duplicates

TOptional<float> MaybeHP;
float Safe = MaybeHP.Get(0.f);                     // default when unset
TVariant
cpp
#include "Misc/TVariant.h"
#include <type_traits>

TVariant<int32, float, FString> Value;             // first type must be default-constructible (or use FEmptyVariantState)
Value.Set<FString>(TEXT("Hello"));
if (const FString* Str = Value.TryGet<FString>()) { UE_LOG(LogMyGame, Log, TEXT("%s"), **Str); }

Visit([](auto& Held)                               // one generic lambda; branch with if constexpr
{
    using HeldType = std::decay_t<decltype(Held)>;
    if constexpr (std::is_same_v<HeldType, FString>) { UE_LOG(LogMyGame, Log, TEXT("%s"), *Held); }
}, Value);

Delegates

All declaration macros, binding methods and payload rules: references/delegate-patterns.md.

Macro familyBindingsBlueprintUse for
DECLARE_DELEGATE (_RetVal, _OneParam …)1NoSingle-owner callbacks, may return a value
DECLARE_MULTICAST_DELEGATENNoC++ events (DECLARE_TS_… for other threads)
DECLARE_DYNAMIC_DELEGATE1YesBlueprint-assignable callback (UFUNCTION targets only)
DECLARE_DYNAMIC_MULTICAST_DELEGATENYesUPROPERTY(BlueprintAssignable) events
cpp
// MyHealthComponent.h — delegate types are declared at file scope, above the UCLASS
DECLARE_MULTICAST_DELEGATE_TwoParams(FOnMyHealthChangedNative, float /*Current*/, float /*Max*/);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnMyHealthChanged, float, CurrentHealth, float, MaxHealth);

// in UMyHealthComponent : public UActorComponent
UPROPERTY(BlueprintAssignable, Category="Health")
FOnMyHealthChanged OnHealthChanged;               // dynamic: needs UPROPERTY, params need names
FOnMyHealthChangedNative OnHealthChangedNative;   // native: no reflection, cheaper to broadcast

// in AMyListenerActor : public AActor
UFUNCTION()                                       // AddDynamic targets must be UFUNCTIONs
void HandleHealthChanged(float CurrentHealth, float MaxHealth);
void HandleHealthChangedNative(float Current, float Max);
UPROPERTY() TObjectPtr<UMyHealthComponent> Health;
FDelegateHandle NativeHandle;
cpp
// AMyListenerActor.cpp — bind in BeginPlay (after Super::), unbind in EndPlay (before Super::)
Health->OnHealthChanged.AddDynamic(this, &AMyListenerActor::HandleHealthChanged);
NativeHandle = Health->OnHealthChangedNative.AddUObject(this, &AMyListenerActor::HandleHealthChangedNative);
// EndPlay: guard with IsValid(Health) first
Health->OnHealthChanged.RemoveDynamic(this, &AMyListenerActor::HandleHealthChanged);
Health->OnHealthChangedNative.Remove(NativeHandle);

The owner broadcasts with OnHealthChanged.Broadcast(CurrentHealth, MaxHealth);. Both classes in full: references/delegate-patterns.md.

Single delegates bind with BindUObject, BindSP, BindRaw, BindStatic, BindLambda, BindWeakLambda(this, ...) and fire with ExecuteIfBound(...). For a lambda that captures this, prefer AddWeakLambda/BindWeakLambda so the binding dies with the object.

String Types

TypeUse forCompareNotes
FNameIdentifiers, asset and bone names, tagsO(1) integer, case-insensitiveInterned in a global table; immutable
FStringPaths, parsing, runtime-built textO(n)Mutable heap string; *Str yields const TCHAR*
FTextAnything a player reads—Localizable; build with LOCTEXT/NSLOCTEXT/FText::Format
cpp
float Health = 42.f; int32 Current = 3; int32 Max = 5;

FName   Tag(TEXT("Weapon.Rifle"));
FString S    = Tag.ToString();
FName   Back = FName(*S);
FString Msg  = FString::Printf(TEXT("HP: %.1f (%d/%d)"), Health, Current, Max);
int32 Parsed = FCString::Atoi(TEXT("42"));

#define LOCTEXT_NAMESPACE "MyGame"
FText Label = LOCTEXT("RifleName", "Assault Rifle");
FText Fmt   = FText::Format(LOCTEXT("HPFmt", "HP: {0}/{1}"), FText::AsNumber(Current), FText::AsNumber(Max));
#undef LOCTEXT_NAMESPACE
FText Other = NSLOCTEXT("MyGame", "Key", "Text");   // no #define needed
FText Raw   = FText::FromString(S);                 // not localized; runtime-generated text only

Object Lifetime and Pointers

The garbage collector keeps alive every UObject reachable from a root through reflected (UPROPERTY) references, FGCObject referencers, TStrongObjectPtr and rooted objects. A pointer the GC cannot see may dangle.

cpp
// Reflected members: TObjectPtr — GC-tracked, access-tracked in the editor, used like a raw pointer
UPROPERTY() TObjectPtr<UStaticMeshComponent> MeshComp;

// Legacy APIs that want raw pointers
void FillObjects(TArray<UObject*>& Out);
TArray<TObjectPtr<UObject>> Objects;
FillObjects(MutableView(Objects));                       // temporary TArray<UObject*>& view; ToRawPtr(Ptr) for a single read-only copy

// Non-owning reference: TWeakObjectPtr becomes null once the object is destroyed or collected
TWeakObjectPtr<AMyCharacter> WeakTarget;
if (AMyCharacter* Target = WeakTarget.Get()) { Target->OnDamageTaken(5.f); }

// Keep-alive from non-reflected code: scoped root instead of AddToRoot()/RemoveFromRoot()
TStrongObjectPtr<UMyDataObject> Pinned(NewObject<UMyDataObject>());

// Plain C++ types only: never wrap a UObject in TSharedPtr/TUniquePtr
struct FMyData { int32 Score = 0; };
TSharedPtr<FMyData> Data = MakeShared<FMyData>();
TWeakPtr<FMyData>   WeakData = Data;                     // Pin() returns a TSharedPtr if still alive

Non-UObject classes that hold UObjects derive from FGCObject and report them through TObjectPtr members; the raw UObject* overloads of AddReferencedObject(s) are deprecated and unsafe with incremental GC.

cpp
#include "UObject/GCObject.h"

class FMyManager : public FGCObject
{
public:
    virtual void AddReferencedObjects(FReferenceCollector& Collector) override { Collector.AddReferencedObject(ManagedObject); }
    virtual FString GetReferencerName() const override { return TEXT("FMyManager"); }
private:
    TObjectPtr<UMyDataObject> ManagedObject;   // TObjectPtr<T>& overload; raw UObject* is deprecated
};

CDO Access and Non-Null Parameters

cpp
#include "Misc/NotNull.h"

const UMyDataObject* Defaults = GetDefault<UMyDataObject>();        // class default object, read-only
UMyDataObject*       Settings = GetMutableDefault<UMyDataObject>(); // settings-style objects
UClass* SomeClass = AMyCharacter::StaticClass();
const AMyCharacter* ClassCDO = SomeClass->GetDefaultObject<AMyCharacter>();  // CDO of a runtime UClass

// TNotNull<T*>: caller cannot pass null; checked at the call site in Debug/Development, a plain pointer in Test and Shipping
void RegisterOwner(TNotNull<AActor*> Owner);
void RegisterOwner(TNotNull<AActor*> Owner)
{
    Owner->SetActorHiddenInGame(false);   // no null check needed inside
}

UClass::ClassDefaultObject is deprecated for direct access. TNotNull<T*> converts implicitly to T*; keep T* where null is a meaningful value.

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

Subsystems

Auto-instanced singletons owned by an engine object; no manual rooting. Override Initialize(FSubsystemCollectionBase&)/Deinitialize(); call Collection.InitializeDependency<UMyOtherSubsystem>() inside Initialize when ordering matters; return false from ShouldCreateSubsystem(UObject* Outer) const to opt out.

ClassHeaderOwner / lifetimeAccessor
UEngineSubsystemSubsystems/EngineSubsystem.hUEngine; whole processGEngine->GetEngineSubsystem<T>()
UGameInstanceSubsystemSubsystems/GameInstanceSubsystem.hUGameInstance; survives map changesGetGameInstance()->GetSubsystem<T>()
UWorldSubsystemSubsystems/WorldSubsystem.hUWorld; recreated per world; filter with DoesSupportWorldTypeGetWorld()->GetSubsystem<T>()
UTickableWorldSubsystemSubsystems/WorldSubsystem.hAs above, plus Tick(); must implement GetStatId()GetWorld()->GetSubsystem<T>()
ULocalPlayerSubsystemSubsystems/LocalPlayerSubsystem.hULocalPlayer; one per local playerLocalPlayer->GetSubsystem<T>(), ULocalPlayer::GetSubsystemFromController<T>(PC)
UEditorSubsystemEditorSubsystem.h (module EditorSubsystem)UEditorEngine; editor session onlyGEditor->GetEditorSubsystem<T>()
cpp
// MyInventorySubsystem.h
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "MyInventorySubsystem.generated.h"

UCLASS()
class MYGAME_API UMyInventorySubsystem : public UGameInstanceSubsystem
{
    GENERATED_BODY()
public:
    virtual void Initialize(FSubsystemCollectionBase& Collection) override;
    virtual void Deinitialize() override;

    UFUNCTION(BlueprintCallable, Category="Inventory")
    void AddItem(FName ItemID, int32 Count);
private:
    TMap<FName, int32> Inventory;
};

// A ticking world subsystem adds these; Initialize/Deinitialize must call Super:: (the base registers the ticker)
UCLASS()
class MYGAME_API UMyTickableSubsystem : public UTickableWorldSubsystem
{
    GENERATED_BODY()
public:
    virtual void Tick(float DeltaTime) override;
    virtual TStatId GetStatId() const override { RETURN_QUICK_DECLARE_CYCLE_STAT(UMyTickableSubsystem, STATGROUP_Tickables); }
    virtual bool DoesSupportWorldType(const EWorldType::Type WorldType) const override;  // e.g. Game and PIE only
};
cpp
// Access from an AActor member function
UMyInventorySubsystem* Inv = GetGameInstance()->GetSubsystem<UMyInventorySubsystem>();
UMyTickableSubsystem*  Tck = GetWorld()->GetSubsystem<UMyTickableSubsystem>();
APlayerController*     PC  = GetWorld()->GetFirstPlayerController();
UMyUISubsystem*        UI  = ULocalPlayer::GetSubsystemFromController<UMyUISubsystem>(PC);   // null-safe
UMyEngineSubsystem*    Eng = GEngine->GetEngineSubsystem<UMyEngineSubsystem>();

UWorldSubsystem also offers PostInitialize(), OnWorldBeginPlay(UWorld& InWorld), OnWorldEndPlay(UWorld& InWorld) and OnWorldComponentsUpdated(UWorld& World) overrides; ULocalPlayerSubsystem::GetLocalPlayer<T>() and UGameInstanceSubsystem::GetGameInstance() return the owner.

Replicated Properties

Both the specifier and the GetLifetimeReplicatedProps entry are required. Conditions (COND_*), RPC rules, push model and Iris: ue-networking-replication.

cpp
// MyReplicatedActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyReplicatedActor.generated.h"

UCLASS()
class MYGAME_API AMyReplicatedActor : public AActor
{
    GENERATED_BODY()
public:
    AMyReplicatedActor() { bReplicates = true; }
    virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
protected:
    UPROPERTY(ReplicatedUsing=OnRep_Health)
    float Health = 100.f;

    UFUNCTION()
    void OnRep_Health();                 // runs on clients after Health changes
};
cpp
// MyReplicatedActor.cpp
#include "MyReplicatedActor.h"
#include "Net/UnrealNetwork.h"          // required for DOREPLIFETIME

void AMyReplicatedActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);
    DOREPLIFETIME(AMyReplicatedActor, Health);
}

void AMyReplicatedActor::OnRep_Health() {}

Logging

cpp
DECLARE_LOG_CATEGORY_EXTERN(LogMyGame, Log, All);   // MyGame.h (module header)
DEFINE_LOG_CATEGORY(LogMyGame);                     // MyGame.cpp
UE_LOG(LogMyGame, Warning, TEXT("HP low: %.1f"), 12.5f);

Verbosities (Logging/LogVerbosity.h): Fatal, Error, Warning, Display, Log, Verbose, VeryVerbose. Display prints to the console and the log file; Log goes to the log file only. Shipping builds compile UE_LOG out unless the target sets bUseLoggingInShipping = true. Categories, structured logging (UE_LOGFMT), runtime verbosity control and profiling: ue-testing-debugging.

Conditional Compilation Guards

cpp
#if WITH_EDITORONLY_DATA
    UPROPERTY(EditAnywhere, Category="Debug")
    bool bShowDebugSpheres = false;                 // reflected editor-only data
#endif
#if WITH_EDITOR
    virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;   // editor-only code
#endif
#if !UE_BUILD_SHIPPING
    void DrawDebugInfo();                           // Debug, Development and Test only
#endif

Deprecated — do not use

Do not emitUse in 5.8Source
SomeClass->ClassDefaultObjectGetDefault<T>(), GetMutableDefault<T>(), SomeClass->GetDefaultObject<T>()UE_DEPRECATED(5.6) in UObject/Class.h:4045
Collector.AddReferencedObject(RawUObjectPtr) with UObject* membersTObjectPtr<T> members passed to AddReferencedObject(s)UE_DEPRECATED(5.3) via UE_REFERENCE_COLLECTOR_REQUIRE_OBJECTPTR_DEPRECATED in UObject/UObjectGlobals.h:109
ToRawPtrArrayUnsafe(Array), ToRawPtrTArrayUnsafe(Array) on mutable arraysMutableView(Array) or keep TArray<TObjectPtr<T>>UE_DEPRECATED(5.6) in UObject/ObjectPtr.h:1112,1156
Visit(<overload-set helper struct>{...}, Variant)One generic lambda with if constexpr (std::is_same_v<...>)Helper is Lyra sample code; absent from 5.8 headers (Misc/TVariant.h)
GENERATED_USTRUCT_BODY(), GENERATED_UCLASS_BODY(), GENERATED_IINTERFACE_BODY()GENERATED_BODY()Legacy aliases in UObject/ObjectMacros.h:802-805
Obj->AddToRoot() / RemoveFromRoot() for temporary keep-aliveTStrongObjectPtr<T> (UObject/StrongObjectPtr.h)Rooting is permanent until removed; scoped pointer cannot leak
TMap::TIterator(Map, /*bRequiresRehashOnRemoval*/ true) (auto-Relax after removal)Map.CreateIterator(); call Compact()/Shrink() yourself if neededUE_DEPRECATED(5.8) in Containers/Map.h.inl:916; TSet::Relax() itself is not yet marked (Containers/SparseSet.h.inl:319)
TIsConst<T>, TIsMemberPointer<T>std::is_const_v<T>, std::is_member_pointer_v<T>UE_DEPRECATED(5.7) Templates/IsConst.h:15; UE_DEPRECATED(5.8) Templates/IsMemberPointer.h:14
FThreadSafeRefCountedObject, FRefCountBaseFRefCountedObject (now thread-safe)UE_DEPRECATED(5.8) in Templates/RefCounting.h:151-153
FCoreDelegates::OnPostEngineInit.AddRaw(...)FCoreDelegates::GetOnPostEngineInit().AddRaw(...)UE_DEPRECATED(5.8) in Misc/CoreDelegates.h:240
Delegate.ProcessMulticastDelegate<UObject>(Params)Delegate.ProcessDelegate<UObject>(Params)UE_DEPRECATED(5.8) in UObject/ScriptDelegates.h:1462
meta=(HideAssetPicker)meta=(HidePinAssetPicker)UE_DEPRECATED(5.6) in UObject/ObjectMacros.h:1673
ObjPtr.IsRemote()ObjPtr.GetResidence()UE_DEPRECATED(5.8) in UObject/ObjectPtr.h:206

Common Mistakes

Raw UObject* member without UPROPERTY — dangling after GC:

cpp
UMyDataObject* Obj;                        // WRONG: invisible to GC
UPROPERTY() TObjectPtr<UMyDataObject> Obj; // RIGHT

Mutating a TArray inside ranged-for — iterator invalidation:

cpp
TArray<AActor*> Actors;
for (AActor* A : Actors) { Actors.Remove(A); }                                                      // WRONG
for (int32 i = Actors.Num() - 1; i >= 0; --i) { if (!IsValid(Actors[i])) { Actors.RemoveAt(i); } }  // RIGHT

TSharedPtr around a UObject — two owners, one crash: UObjects are owned by the GC; use TObjectPtr, TWeakObjectPtr or TStrongObjectPtr.

.generated.h not the last include, or MYGAME_API missing: UnrealHeaderTool rejects the header; the missing API macro surfaces later as LNK2019 from other modules.

AddDynamic bound to a non-UFUNCTION: the reflection lookup fails at runtime and the handler never runs; mark it UFUNCTION().

UPROPERTY/UFUNCTION written above a .cpp definition: UnrealHeaderTool only parses headers; the macro is silently ignored. Put it on the declaration inside the class body.

BlueprintNativeEvent without Name_Implementation: unresolved external at link time. Declare virtual void Name_Implementation(...) and define it.

UTickableWorldSubsystem::Initialize/Deinitialize override without Super::: the tickable registration lives in the base implementation; the subsystem never ticks.

Reading ClassDefaultObject directly: deprecated and about to become private; use GetDefault<T>().

Log verbosity "not showing up": Log is file-only by design; use Display for console output.

  • ue-actor-component-architecture — AActor/UActorComponent lifecycle, spawning, tick groups, component setup
  • ue-module-build-system — Build.cs, module dependencies, API export macros, include paths, PCH
  • ue-testing-debugging — log categories and verbosity, structured logging, automation tests, profiling
  • ue-networking-replication — DOREPLIFETIME conditions, RPC rules, push model, Iris
  • ue-blueprint-cpp-interop — UBlueprintFunctionLibrary, latent and async actions, Blueprint-implementable
  • Also relevant: ue-data-assets-tables, ue-animation-system, ue-async-threading, ue-audio-system, ue-editor-tools, ue-gameplay-abilities, ue-gameplay-framework, ue-gameplay-tags-messaging, ue-input-system, ue-mass-entity, ue-materials-rendering, ue-serialization-savegames, ue-state-trees, ue-ui-umg-slate, ue-world-level-streaming

© 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 3 other files (references) in skills/ue-cpp-foundations of quodsoler/unreal-engine-skills.

  • SKILL.md
  • references/container-patterns.md
  • references/delegate-patterns.md
  • references/property-specifiers.md

Open the folder on GitHubat commit f3742d7

Compare with similar skills

Unreal Engine C++ Foundations 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.

Unreal Engine C++ Foundations compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Unreal Engine C++ Foundations this skillquodsoler/unreal-engine-skills359—~6.8kAutomated safety check: PassMIT
Unreal Engine MCPEpicGames/unreal-engine-skills-for-claude-code-plugin325—~1.8kAutomated safety check: PassMIT
Unreal Live CodingItalink/UnrealClientProtocol127—~1kAutomated safety check: PassMIT
Unreal Cpp Gameplayukanwat/overtime3871 repos~1.5kAutomated safety check: PassApache-2.0
Unreal Enhanced Inputukanwat/overtime3871 repos~1.5kAutomated safety check: PassApache-2.0
Unreal Niagaraukanwat/overtime3871 repos~1.5kAutomated safety check: PassApache-2.0

Similar skills

  • 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.

    325 GitHub stars~1.8k tokensUpdated 20 days ago
    Game DevelopmentAuto-check passed
  • Unreal Live Coding

    Italink/UnrealClientProtocol

    Trigger Live Coding compilation via UCP. An agent skill from Italink/UnrealClientProtocol.

    127 GitHub stars~1k tokensUpdated 1 mo ago
    Game DevelopmentAuto-check passed
  • Unreal Cpp Gameplay

    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…

    387 GitHub starsUsed in 1 repo~1.5k tokens
    Game DevelopmentAuto-check passed
  • Unreal Enhanced Input

    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.

    387 GitHub starsUsed in 1 repo~1.5k tokens
    Game DevelopmentAuto-check passed
  • Unreal Niagara

    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++.

    387 GitHub starsUsed in 1 repo~1.5k tokens
    Game DevelopmentAuto-check passed
  • Scenario Unreal Gameplay

    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…

    898 GitHub stars~5.2k tokensUpdated today
    Game 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.

    359 GitHub stars~7.5k tokensUpdated 8 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.

    359 GitHub stars~8.9k tokensUpdated 8 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.

    359 GitHub stars~7k tokensUpdated 8 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.

    359 GitHub stars~8k tokensUpdated 8 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.

    359 GitHub stars~7.9k tokensUpdated 8 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.

    359 GitHub stars~7.8k tokensUpdated 8 days ago
    Auto-check passed

Questions about Unreal Engine C++ Foundations

What does Unreal Engine C++ Foundations do?

Reference for Unreal Engine C++ on the reflection system and core types: UCLASS macros, containers, delegates, strings, object lifetime, subsystems and logging. 8 headers with older forms listed under a deprecated section. Topics are the reflection macros (UCLASS, UPROPERTY, UFUNCTION, USTRUCT, UENUM, UINTERFACE), containers, delegates, string types, object lifetime and garbage collection, class default object access and the subsystem family.

When should I use Unreal Engine C++ Foundations?

Unreal Engine C++ Foundations fits situations like: declaring UCLASS, USTRUCT or UENUM types with the right specifiers; choosing between TObjectPtr, TWeakObjectPtr and TSharedPtr for references; declaring and binding dynamic multicast delegates; writing a game instance or world subsystem.

How do I install Unreal Engine C++ Foundations in Claude Code?

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

How do I install Unreal Engine C++ Foundations in Codex?

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

Can I use Unreal Engine C++ Foundations 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-cpp-foundations -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-cpp-foundations, .gemini/skills/ue-cpp-foundations, .github/skills/ue-cpp-foundations and .opencode/skills/ue-cpp-foundations in your project.

What does Unreal Engine C++ Foundations need to run?

SKILL.md names no scripts, command-line tools or credentials: Unreal Engine C++ Foundations is instructions for the agent only. Our summary lists: An Unreal Engine C++ project (the skill targets UE 5.8).

Does Unreal Engine C++ Foundations 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 Unreal Engine C++ Foundations 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 Unreal Engine C++ Foundations use?

Unreal Engine C++ Foundations 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 Unreal Engine C++ Foundations use?

About 6.8k tokens (SKILL.md is roughly 27k 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 12k tokens, read only when the agent opens those files.

What are the alternatives to Unreal Engine C++ Foundations?

Skills that share tags, products or a category with Unreal Engine C++ Foundations: Unreal Engine MCP (EpicGames/unreal-engine-skills-for-claude-code-plugin, 325 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.

Who maintains Unreal Engine C++ Foundations?

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.