Ue Cpp Foundations
Use when writing Unreal Engine C++ code involving UPROPERTY, UFUNCTION, UCLASS, TArray, TMap, delegates, FString, garbage collection, or smart pointers. Also use when the user asks about "UE C++", USTRUCT, UENUM, FName, FText, TObjectPtr, TWeakObjectPtr, UObject lifetime, UE_LOG, or UE subsystems. For module build configuration, see ue-module-build-system. For Actor/Component architecture, see ue-actor-component-architecture.
- Skill ID
- quodsoler/unreal-engine-skills/ue-cpp-foundations
- Publisher
- quodsoler
- Repository
- unreal-engine-skills
- Installs
- 0
- Files
- 4
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
quodsoler/unreal-engine-skills/ue-cpp-foundationsInstalls these files- SKILL.md
- references/container-patterns.md
- references/delegate-patterns.md
- references/property-specifiers.md
What this skill tells the agent
UE C++ Foundations
You are an expert in Unreal Engine's C++ extensions and property system.
Context
Read .agents/ue-project-context.md for engine version, coding conventions, and project-specific rules. Engine version matters: UE5 uses TObjectPtr<> where UE4 used raw UObject*, and GENERATED_BODY() replaces GENERATED_USTRUCT_BODY() in structs.
Before You Start
Ask which area the user needs help with if unclear:
- Macros & Reflection — UCLASS, UPROPERTY, UFUNCTION, USTRUCT, UENUM
- Containers — TArray, TMap, TSet, TOptional
- Delegates — static, dynamic, multicast, binding patterns
- Strings — FName, FString, FText conversion and formatting
- Memory & GC — TObjectPtr, TWeakObjectPtr, TSharedPtr, GC roots
- Logging — UE_LOG, log categories, verbosity
- Subsystems — GameInstance, World, LocalPlayer subsystems
UObject Macros & Reflection
All UE reflection macros require GENERATED_BODY() inside the class/struct and the corresponding .generated.h include.
UCLASS()
| Specifier | Effect |
|---|---|
Blueprintable | Blueprint subclassing allowed |
BlueprintType | Usable as Blueprint variable |
Abstract | Cannot be instantiated |
NotBlueprintable | Blocks Blueprint subclassing |
Config=<Name> | Loads UPROPERTY(Config) from <Name>.ini |
Transient | Not saved/serialized |
Within=<OuterClass> | Outer must be of given type |
UCLASS(Blueprintable, BlueprintType)
class MYGAME_API UMyDataObject : public UObject
{
GENERATED_BODY()
public:
UMyDataObject();
};Full specifier list: references/property-specifiers.md.
UPROPERTY()
UCLASS(Blueprintable)
class MYGAME_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats")
float MaxHealth = 100.f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Stats")
float CurrentHealth;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Config")
int32 MaxLevel = 50;
UPROPERTY(ReplicatedUsing=OnRep_Health, Category="Replication")
float ReplicatedHealth;
UPROPERTY(Transient) // Not serialized; GC still tracks
TObjectPtr<UParticleSystemComponent> CachedFX;
UPROPERTY(SaveGame, BlueprintReadWrite, Category="Persistence")
int32 PlayerScore;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats",
meta=(ClampMin="0.0", ClampMax="1.0"))
float DamageMultiplier = 1.f;
UFUNCTION()
void OnRep_Health();
virtual void GetLifetimeReplicatedProps(
TArray<FLifetimeProperty>& OutLifetimeProps) const override;
};UFUNCTION()
UFUNCTION(BlueprintCallable, Category="Actions")
void PerformAttack(float Damage);
UFUNCTION(BlueprintPure, Category="Queries")
float GetHealthPercent() const;
UFUNCTION(BlueprintNativeEvent, Category="Events") // C++ provides _Implementation
void OnDamageTaken(float Amount);
virtual void OnDamageTaken_Implementation(float Amount);
UFUNCTION(BlueprintImplementableEvent, Category="Events") // Blueprint must implement
void OnLevelUp(int32 NewLevel);
UFUNCTION(Server, Reliable, WithValidation) // RPC: runs on server
void ServerFireWeapon(FVector Origin, FVector Direction);
void ServerFireWeapon_Implementation(FVector Origin, FVector Direction);
bool ServerFireWeapon_Validate(FVector Origin, FVector Direction);
UFUNCTION(Client, Reliable) // RPC: runs on owning client
void ClientShowDamageNumber(float Amount);
void ClientShowDamageNumber_Implementation(float Amount);
UFUNCTION(NetMulticast, Reliable) // RPC: runs on all
void MulticastPlayEffect(FVector Location);
void MulticastPlayEffect_Implementation(FVector Location);
UFUNCTION(Exec) // Console command (~ in-game)
void DebugResetStats(); // Works on PC, Pawn, HUD, GM, GI, CheatManagerUSTRUCT() and UENUM()
// UE5: always GENERATED_BODY() — never GENERATED_USTRUCT_BODY()
USTRUCT(BlueprintType)
struct MYGAME_API FWeaponStats
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite) float BaseDamage = 10.f;
UPROPERTY(EditAnywhere, BlueprintReadWrite) float FireRate = 0.5f;
};
// DataTable row
USTRUCT(BlueprintType)
struct MYGAME_API FEnemyTableRow : public FTableRowBase
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite) FName EnemyID;
UPROPERTY(EditAnywhere, BlueprintReadWrite) TSoftClassPtr<AActor> SpawnClass;
};
UENUM(BlueprintType)
enum class EWeaponState : uint8
{
Idle UMETA(DisplayName="Idle"),
Firing UMETA(DisplayName="Firing"),
Reloading UMETA(DisplayName="Reloading"),
};UE Containers
See references/container-patterns.md for full API and performance guide.
TArray — Ordered Dynamic Array
TArray<FString> Names;
Names.Add(TEXT("Alpha"));
Names.Emplace(TEXT("Beta")); // Construct in-place (avoids copy)
Names.Reserve(100); // Pre-allocate
FString First = Names[0];
bool bHas = Names.Contains(TEXT("Alpha"));
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); // Fast O(1), destroys order
for (const FString& N : Names) { /* do NOT add/remove during ranged-for */ }
for (int32 i = Names.Num()-1; i >= 0; --i) { if (Names[i].IsEmpty()) Names.RemoveAt(i); }TMap — Hash Map
TMap<FName, int32> ItemCounts;
ItemCounts.Add(FName("Sword"), 3);
int32& Ref = ItemCounts.FindOrAdd(FName("Sword")); // Insert default if absent
int32* Ptr = ItemCounts.Find(FName("Axe")); // nullptr if absent
bool bHas = ItemCounts.Contains(FName("Shield"));
ItemCounts.Remove(FName("Shield"));
for (const TPair<FName, int32>& Pair : ItemCounts) { /* ... */ }TSet — Hash Set
TSet<FName> Tags;
Tags.Add(FName("Flying"));
bool bFlying = Tags.Contains(FName("Flying"));
TSet<FName> Intersect = Tags.Intersect(OtherTags);
TSet<FName> Union = Tags.Union(OtherTags);TOptional
TOptional<float> MaybeHP;
if (MaybeHP.IsSet()) { float H = MaybeHP.GetValue(); }
float Safe = MaybeHP.Get(0.f); // Default if not set
MaybeHP = 75.f;
MaybeHP.Reset();TVariant
// Type-safe tagged union — avoids unsafe casts
TVariant<int32, float, FString> Value;
Value.Set<FString>(TEXT("Hello"));
if (Value.IsType<FString>())
{
const FString& Str = Value.Get<FString>();
}
// Visit — use explicit overloads; LexToString(V) fails when V is FString.
Visit(TOverloaded{
[](int32 V) { UE_LOG(LogTemp, Log, TEXT("%d"), V); },
[](float V) { UE_LOG(LogTemp, Log, TEXT("%f"), V); },
[](const FString& V) { UE_LOG(LogTemp, Log, TEXT("%s"), *V); },
}, Value);Delegates
See references/delegate-patterns.md for all declaration macros and binding methods.
Choosing the Right Type
| Type | Bindings | Blueprint | When to Use |
|---|---|---|---|
DECLARE_DELEGATE | 1 | No | Internal single-owner callback |
DECLARE_MULTICAST_DELEGATE | N | No | Internal multi-listener events |
DECLARE_DYNAMIC_DELEGATE | 1 | Yes | Blueprint-assignable single callback |
DECLARE_DYNAMIC_MULTICAST_DELEGATE | N | Yes | Blueprint-bindable events (most common) |
Declaration, Binding, Invocation
// File scope (before UCLASS)
DECLARE_DELEGATE_OneParam(FOnItemPickedUp, AActor*);
DECLARE_MULTICAST_DELEGATE_TwoParams(FOnHealthChanged, float, float);More from quodsoler
Use this skill in a project
Open any RiverX project, search the Skills panel for quodsoler/unreal-engine-skills/ue-cpp-foundations, and install it in one click.
