$npx -y skills add quodsoler/unreal-engine-skills --skill ue-cpp-foundationsUse 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,
| 1 | # UE C++ Foundations |
| 2 | |
| 3 | You are an expert in Unreal Engine's C++ extensions and property system. |
| 4 | |
| 5 | ## Context |
| 6 | |
| 7 | 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. |
| 8 | |
| 9 | ## Before You Start |
| 10 | |
| 11 | Ask which area the user needs help with if unclear: |
| 12 | - **Macros & Reflection** — UCLASS, UPROPERTY, UFUNCTION, USTRUCT, UENUM |
| 13 | - **Containers** — TArray, TMap, TSet, TOptional |
| 14 | - **Delegates** — static, dynamic, multicast, binding patterns |
| 15 | - **Strings** — FName, FString, FText conversion and formatting |
| 16 | - **Memory & GC** — TObjectPtr, TWeakObjectPtr, TSharedPtr, GC roots |
| 17 | - **Logging** — UE_LOG, log categories, verbosity |
| 18 | - **Subsystems** — GameInstance, World, LocalPlayer subsystems |
| 19 | |
| 20 | --- |
| 21 | |
| 22 | ## UObject Macros & Reflection |
| 23 | |
| 24 | All UE reflection macros require `GENERATED_BODY()` inside the class/struct and the corresponding `.generated.h` include. |
| 25 | |
| 26 | ### UCLASS() |
| 27 | |
| 28 | | Specifier | Effect | |
| 29 | |-----------|--------| |
| 30 | | `Blueprintable` | Blueprint subclassing allowed | |
| 31 | | `BlueprintType` | Usable as Blueprint variable | |
| 32 | | `Abstract` | Cannot be instantiated | |
| 33 | | `NotBlueprintable` | Blocks Blueprint subclassing | |
| 34 | | `Config=<Name>` | Loads UPROPERTY(Config) from `<Name>.ini` | |
| 35 | | `Transient` | Not saved/serialized | |
| 36 | | `Within=<OuterClass>` | Outer must be of given type | |
| 37 | |
| 38 | ```cpp |
| 39 | UCLASS(Blueprintable, BlueprintType) |
| 40 | class MYGAME_API UMyDataObject : public UObject |
| 41 | { |
| 42 | GENERATED_BODY() |
| 43 | public: |
| 44 | UMyDataObject(); |
| 45 | }; |
| 46 | ``` |
| 47 | |
| 48 | Full specifier list: [references/property-specifiers.md](references/property-specifiers.md). |
| 49 | |
| 50 | ### UPROPERTY() |
| 51 | |
| 52 | ```cpp |
| 53 | UCLASS(Blueprintable) |
| 54 | class MYGAME_API AMyCharacter : public ACharacter |
| 55 | { |
| 56 | GENERATED_BODY() |
| 57 | public: |
| 58 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats") |
| 59 | float MaxHealth = 100.f; |
| 60 | |
| 61 | UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Stats") |
| 62 | float CurrentHealth; |
| 63 | |
| 64 | UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Config") |
| 65 | int32 MaxLevel = 50; |
| 66 | |
| 67 | UPROPERTY(ReplicatedUsing=OnRep_Health, Category="Replication") |
| 68 | float ReplicatedHealth; |
| 69 | |
| 70 | UPROPERTY(Transient) // Not serialized; GC still tracks |
| 71 | TObjectPtr<UParticleSystemComponent> CachedFX; |
| 72 | |
| 73 | UPROPERTY(SaveGame, BlueprintReadWrite, Category="Persistence") |
| 74 | int32 PlayerScore; |
| 75 | |
| 76 | UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats", |
| 77 | meta=(ClampMin="0.0", ClampMax="1.0")) |
| 78 | float DamageMultiplier = 1.f; |
| 79 | |
| 80 | UFUNCTION() |
| 81 | void OnRep_Health(); |
| 82 | |
| 83 | virtual void GetLifetimeReplicatedProps( |
| 84 | TArray<FLifetimeProperty>& OutLifetimeProps) const override; |
| 85 | }; |
| 86 | ``` |
| 87 | |
| 88 | ### UFUNCTION() |
| 89 | |
| 90 | ```cpp |
| 91 | UFUNCTION(BlueprintCallable, Category="Actions") |
| 92 | void PerformAttack(float Damage); |
| 93 | |
| 94 | UFUNCTION(BlueprintPure, Category="Queries") |
| 95 | float GetHealthPercent() const; |
| 96 | |
| 97 | UFUNCTION(BlueprintNativeEvent, Category="Events") // C++ provides _Implementation |
| 98 | void OnDamageTaken(float Amount); |
| 99 | virtual void OnDamageTaken_Implementation(float Amount); |
| 100 | |
| 101 | UFUNCTION(BlueprintImplementableEvent, Category="Events") // Blueprint must implement |
| 102 | void OnLevelUp(int32 NewLevel); |
| 103 | |
| 104 | UFUNCTION(Server, Reliable, WithValidation) // RPC: runs on server |
| 105 | void ServerFireWeapon(FVector Origin, FVector Direction); |
| 106 | void ServerFireWeapon_Implementation(FVector Origin, FVector Direction); |
| 107 | bool ServerFireWeapon_Validate(FVector Origin, FVector Direction); |
| 108 | |
| 109 | UFUNCTION(Client, Reliable) // RPC: runs on owning client |
| 110 | void ClientShowDamageNumber(float Amount); |
| 111 | void ClientShowDamageNumber_Implementation(float Amount); |
| 112 | |
| 113 | UFUNCTION(NetMulticast, Reliable) // RPC: runs on all |
| 114 | void MulticastPlayEffect(FVector Location); |
| 115 | void MulticastPlayEffect_Implementation(FVector Location); |
| 116 | |
| 117 | UFUNCTION(Exec) // Console command (~ in-game) |
| 118 | void DebugResetStats(); // Works on PC, Pawn, HUD, GM, GI, CheatManager |
| 119 | ``` |
| 120 | |
| 121 | ### USTRUCT() and UENUM() |
| 122 | |
| 123 | ```cpp |
| 124 | // UE5: always GENERATED_BODY() — never GENERATED_USTRUCT_BODY() |
| 125 | USTRUCT(BlueprintType) |
| 126 | struct MYGAME_API FWeaponStats |
| 127 | { |
| 128 | GENERATED_BODY() |
| 129 | UPROPERTY(EditAnywhere, BlueprintReadWrite) float BaseDamage = 10.f; |
| 130 | UPROPERTY(EditAnywhere, BlueprintReadWrite) float FireRate = 0.5f; |
| 131 | }; |
| 132 | |
| 133 | // DataTable row |
| 134 | USTRUCT(BlueprintType) |
| 135 | struct MYGAME_API FEnemyTableRow : public FTableRowBase |
| 136 | { |
| 137 | GENERATED_BODY( |