Expertise·Gaming & Entertainment·v1.0.0

Unreal C++ Foundations

Write Unreal Engine C++ involving UPROPERTY, UFUNCTION, UCLASS, TArray, TMap, delegates, FString, garbage collection and smart pointers.

You say
Buy it · $69 Read it before you buy $69 Written by quodsoler · unverified publisher
Context cost
14.2k tokensestimated from the bundle, loaded when it triggers
Bundle
4 files · 56.6 kBtext throughout, nothing executable
Licence
MITpaid listing
Last change
v1.0.0
Servers it uses
Noneruns standalone

What it does

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.

Installed, it changes the agent in these ways.

What this skill changes about the agent is not written down here yet. The listing was collected from its source, and the description is in its own SKILL.md.

Expertise

Domain judgement the base model does not have.

unrealcppgame-enginegamedev

The skill itself

This is the whole product. A skill is instructions the model reads, so there is nothing behind the listing you cannot see first — the front matter loads with every session, and the body below it loads when the skill triggers.

SKILL.md16.4 kB · 501 lines
--- name: ue-cpp-foundations description: 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. metadata: version: 1.0.0 ---
8# UE C++ Foundations
9
10You are an expert in Unreal Engine's C++ extensions and property system.
11
12## Context
13
14Read .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.
15
16## Before You Start
17
18Ask which area the user needs help with if unclear:
19- **Macros & Reflection** — UCLASS, UPROPERTY, UFUNCTION, USTRUCT, UENUM
20- **Containers** — TArray, TMap, TSet, TOptional
21- **Delegates** — static, dynamic, multicast, binding patterns
22- **Strings** — FName, FString, FText conversion and formatting
23- **Memory & GC** — TObjectPtr, TWeakObjectPtr, TSharedPtr, GC roots
24- **Logging** — UE_LOG, log categories, verbosity
25- **Subsystems** — GameInstance, World, LocalPlayer subsystems
26
27---
28
29## UObject Macros & Reflection
30
31All UE reflection macros require GENERATED_BODY() inside the class/struct and the corresponding .generated.h include.
32
33### UCLASS()
34
35| Specifier | Effect |
36|-----------|--------|
37| Blueprintable | Blueprint subclassing allowed |
38| BlueprintType | Usable as Blueprint variable |
39| Abstract | Cannot be instantiated |
40| NotBlueprintable | Blocks Blueprint subclassing |
41| Config=<Name> | Loads UPROPERTY(Config) from <Name>.ini |
42| Transient | Not saved/serialized |
43| Within=<OuterClass> | Outer must be of given type |
44
45```cpp
46UCLASS(Blueprintable, BlueprintType)
47class MYGAME_API UMyDataObject : public UObject
48{
49 GENERATED_BODY()
50public:
51 UMyDataObject();
52};
53```
54
55Full specifier list: [references/property-specifiers.md](references/property-specifiers.md).
56
57### UPROPERTY()
58
59```cpp
60UCLASS(Blueprintable)
61class MYGAME_API AMyCharacter : public ACharacter
62{
63 GENERATED_BODY()
64public:
65 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats")
66 float MaxHealth = 100.f;
67
68 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Stats")
69 float CurrentHealth;
70
71 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Config")
72 int32 MaxLevel = 50;
73
74 UPROPERTY(ReplicatedUsing=OnRep_Health, Category="Replication")
75 float ReplicatedHealth;
76
77 UPROPERTY(Transient) // Not serialized; GC still tracks
78 TObjectPtr<UParticleSystemComponent> CachedFX;
79
80 UPROPERTY(SaveGame, BlueprintReadWrite, Category="Persistence")
81 int32 PlayerScore;
82
83 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats",
84 meta=(ClampMin="0.0", ClampMax="1.0"))
85 float DamageMultiplier = 1.f;
86
87 UFUNCTION()
88 void OnRep_Health();
89
90 virtual void GetLifetimeReplicatedProps(
91 TArray<FLifetimeProperty>& OutLifetimeProps) const override;
92};
93```
94
95### UFUNCTION()
96
97```cpp
98UFUNCTION(BlueprintCallable, Category="Actions")
99void PerformAttack(float Damage);
100
101UFUNCTION(BlueprintPure, Category="Queries")
102float GetHealthPercent() const;
103
104UFUNCTION(BlueprintNativeEvent, Category="Events") // C++ provides _Implementation
105void OnDamageTaken(float Amount);
106virtual void OnDamageTaken_Implementation(float Amount);
107
108UFUNCTION(BlueprintImplementableEvent, Category="Events") // Blueprint must implement
109void OnLevelUp(int32 NewLevel);
110
111UFUNCTION(Server, Reliable, WithValidation) // RPC: runs on server
112void ServerFireWeapon(FVector Origin, FVector Direction);
113void ServerFireWeapon_Implementation(FVector Origin, FVector Direction);
114bool ServerFireWeapon_Validate(FVector Origin, FVector Direction);
115
116UFUNCTION(Client, Reliable) // RPC: runs on owning client
117void ClientShowDamageNumber(float Amount);
118void ClientShowDamageNumber_Implementation(float Amount);
119
120UFUNCTION(NetMulticast, Reliable) // RPC: runs on all
121void MulticastPlayEffect(FVector Location);
122void MulticastPlayEffect_Implementation(FVector Location);
123
124UFUNCTION(Exec) // Console command (~ in-game)
125void DebugResetStats(); // Works on PC, Pawn, HUD, GM, GI, CheatManager
126```
127
128### USTRUCT() and UENUM()
129
130```cpp
131// UE5: always GENERATED_BODY() — never GENERATED_USTRUCT_BODY()
132USTRUCT(BlueprintType)
133struct MYGAME_API FWeaponStats
134{
135 GENERATED_BODY()
136 UPROPERTY(EditAnywhere, BlueprintReadWrite) float BaseDamage = 10.f;
137 UPROPERTY(EditAnywhere, BlueprintReadWrite) float FireRate = 0.5f;
138};
139
140// DataTable row
141USTRUCT(BlueprintType)
142struct MYGAME_API FEnemyTableRow : public FTableRowBase
143{
144 GENERATED_BODY()
145 UPROPERTY(EditAnywhere, BlueprintReadWrite) FName EnemyID;
146 UPROPERTY(EditAnywhere, BlueprintReadWrite) TSoftClassPtr<AActor> SpawnClass;
147};
148
149UENUM(BlueprintType)
150enum class EWeaponState : uint8
151{
152 Idle UMETA(DisplayName="Idle"),
153 Firing UMETA(DisplayName="Firing"),
154 Reloading UMETA(DisplayName="Reloading"),
155};
156```
157
158---
159
160## UE Containers
161
162See [references/container-patterns.md](references/container-patterns.md) for full API and performance guide.
163
164### TArray — Ordered Dynamic Array
165
166```cpp
167TArray<FString> Names;
168Names.Add(TEXT("Alpha"));
169Names.Emplace(TEXT("Beta")); // Construct in-place (avoids copy)
170Names.Reserve(100); // Pre-allocate
171
172FString First = Names[0];
173bool bHas = Names.Contains(TEXT("Alpha"));
174int32 Idx = Names.Find(TEXT("Beta")); // INDEX_NONE if absent
175FString* Ptr = Names.FindByPredicate([](const FString& S){ return S.StartsWith(TEXT("A")); });
176
177Names.Sort([](const FString& A, const FString& B){ return A.Len() < B.Len(); });
178Names.Remove(TEXT("Alpha")); // Order-preserving O(n)
179Names.RemoveAtSwap(0); // Fast O(1), destroys order
180
181for (const FString& N : Names) { /* do NOT add/remove during ranged-for */ }
182for (int32 i = Names.Num()-1; i >= 0; --i) { if (Names[i].IsEmpty()) Names.RemoveAt(i); }
183```
184
185### TMap — Hash Map
186
187```cpp
188TMap<FName, int32> ItemCounts;
189ItemCounts.Add(FName("Sword"), 3);
190
191int32& Ref = ItemCounts.FindOrAdd(FName("Sword")); // Insert default if absent
192int32* Ptr = ItemCounts.Find(FName("Axe")); // nullptr if absent
193bool bHas = ItemCounts.Contains(FName("Shield"));
194ItemCounts.Remove(FName("Shield"));
195
196for (const TPair<FName, int32>& Pair : ItemCounts) { /* ... */ }
197```
198
199### TSet — Hash Set
200
201```cpp
202TSet<FName> Tags;
203Tags.Add(FName("Flying"));
204bool bFlying = Tags.Contains(FName("Flying"));
205TSet<FName> Intersect = Tags.Intersect(OtherTags);
206TSet<FName> Union = Tags.Union(OtherTags);
207```
208
209### TOptional
210
211```cpp
212TOptional<float> MaybeHP;
213if (MaybeHP.IsSet()) { float H = MaybeHP.GetValue(); }
214float Safe = MaybeHP.Get(0.f); // Default if not set
215MaybeHP = 75.f;
216MaybeHP.Reset();
217```
218
219### TVariant
220
221```cpp
222// Type-safe tagged union — avoids unsafe casts
223TVariant<int32, float, FString> Value;
224Value.Set<FString>(TEXT("Hello"));
225
226if (Value.IsType<FString>())
227{
228 const FString& Str = Value.Get<FString>();
229}
230
231// Visit — use explicit overloads; LexToString(V) fails when V is FString.
232Visit(TOverloaded{
233 [](int32 V) { UE_LOG(LogTemp, Log, TEXT("%d"), V); },
234 [](float V) { UE_LOG(LogTemp, Log, TEXT("%f"), V); },
235 [](const FString& V) { UE_LOG(LogTemp, Log, TEXT("%s"), *V); },
236}, Value);
237```
238
239---
240
241## Delegates
242
243See [references/delegate-patterns.md](references/delegate-patterns.md) for all declaration macros and binding methods.
244
245### Choosing the Right Type
246
247| Type | Bindings | Blueprint | When to Use |
248|------|----------|-----------|-------------|
249| DECLARE_DELEGATE | 1 | No | Internal single-owner callback |
250| DECLARE_MULTICAST_DELEGATE | N | No | Internal multi-listener events |
251| DECLARE_DYNAMIC_DELEGATE | 1 | Yes | Blueprint-assignable single callback |
252| DECLARE_DYNAMIC_MULTICAST_DELEGATE | N | Yes | Blueprint-bindable events (most common) |
253
254### Declaration, Binding, Invocation
255
256```cpp
257// File scope (before UCLASS)
258DECLARE_DELEGATE_OneParam(FOnItemPickedUp, AActor*);
259DECLARE_MULTICAST_DELEGATE_TwoParams(FOnHealthChanged, float, float);
260DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnHealthChangedDynamic, float, CurrentHealth, float, MaxHealth);
261
262UCLASS()
263class AMyActor : public AActor
264{
265 GENERATED_BODY()
266public:
267 UPROPERTY(BlueprintAssignable, Category="Events")
268 FOnHealthChangedDynamic OnHealthChanged; // Dynamic multicast in UPROPERTY
269};
270
271// Static single delegate
272FOnItemPickedUp D;
273D.BindUObject(this, &AMyCharacter::HandlePickup);
274D.BindLambda([this](AActor* Item){ UE_LOG(LogTemp, Log, TEXT("%s"), *Item->GetName()); });
275D.ExecuteIfBound(SomeActor);
276// Multicast: add/broadcast/remove
277FDelegateHandle H = HealthDelegate.AddUObject(this, &AMyHUD::OnHealthChanged);
278HealthDelegate.Broadcast(75.f, 100.f);
279HealthDelegate.Remove(H);
280// Dynamic multicast
281OnHealthChanged.AddDynamic(this, &AMyCharacter::HandleHealthChange);
282OnHealthChanged.RemoveDynamic(this, &AMyCharacter::HandleHealthChange);
283OnHealthChanged.Broadcast(75.f, 100.f);
284```
285
286---
287
288## String Types
289
290| Type | Use For | Comparison | Mutable |
291|------|---------|-----------|---------|
292| FName | Identifiers, asset names, tags | O(1) integer | No |
293| FString | General-purpose strings, file paths | O(n) | Yes |
294| FText | Player-visible display strings | — | No |
295
296```cpp
297// FName — global name table, case-insensitive O(1) compare
298FName Tag("WeaponTag_Rifle");
299FString S = Tag.ToString();
300FName N = FName(*S);
301
302// FString — heap string, Printf for formatting
303FString Msg = FString::Printf(TEXT("HP: %.1f"), Health);
304UE_LOG(LogTemp, Log, TEXT("%s"), *Msg); // * dereferences to TCHAR*
305int32 Num = FCString::Atoi(*FString("42"));
306
307// FText — localized display text
308// LOCTEXT requires a namespace defined in the same translation unit:
309#define LOCTEXT_NAMESPACE "MyGame"
310FText Label = LOCTEXT("Key", "Assault Rifle");
311FText Fmt = FText::Format(LOCTEXT("HP", "HP: {0}/{1}"),
312 FText::AsNumber(Cur), FText::AsNumber(Max));
313#undef LOCTEXT_NAMESPACE // Or: NSLOCTEXT("MyGame", "Key", "...") without a define
314```
315
316**Conversion:** Name.ToString() → FString, FName(*Str) ← FString, FText::FromString(Str), Text.ToString().
317
318---
319
320## Memory & Garbage Collection
321
322UE's GC tracks every UObject* reachable from a root. Unreachable objects are destroyed.
323
324```cpp
325// UE5: TObjectPtr<> for UPROPERTY member UObject pointers
326UPROPERTY()
327TObjectPtr<UStaticMeshComponent> MeshComp; // GC-tracked, lazy-load aware
328// Without UPROPERTY — invisible to GC, pointer may dangle
329UMyObject* UnsafePtr; // BAD
330// TWeakObjectPtr — non-owning, safe (becomes null after GC)
331TWeakObjectPtr<AMyActor> WeakRef;
332if (WeakRef.IsValid()) { WeakRef->DoSomething(); }
333// TSharedPtr/TWeakPtr — for non-UObject plain C++ types ONLY
334TSharedPtr<FMyData> Data = MakeShared<FMyData>();
335TWeakPtr<FMyData> Weak = Data;
336if (TSharedPtr<FMyData> Pinned = Weak.Pin()) { Pinned->Process(); }
337// NEVER use TSharedPtr for UObject-derived types
338// GC root: AddToRoot (use sparingly)
339UMyObject* Obj = NewObject<UMyObject>();
340Obj->AddToRoot();
341// ...
342Obj->RemoveFromRoot();
343// FGCObject: preferred for non-UObject C++ classes holding UObject refs
344// UE 5.3+: use TObjectPtr<> — raw UObject* crashes with incremental GC.
345class FMyManager : public FGCObject
346{
347public:
348 virtual void AddReferencedObjects(FReferenceCollector& Collector) override
349 {
350 Collector.AddReferencedObject(ManagedObject);
351 }
352 virtual FString GetReferencerName() const override { return TEXT("FMyManager"); }
353private:
354 TObjectPtr<UMyObject> ManagedObject = nullptr;
355};
356```
357
358---
359
360## Logging
361
362```cpp
363// MyGameLog.h / .cpp
364DECLARE_LOG_CATEGORY_EXTERN(LogMyGame, Log, All);
365DEFINE_LOG_CATEGORY(LogMyGame);
366
367// Single-file: DEFINE_LOG_CATEGORY_STATIC(LogLocal, Log, All);
368
369UE_LOG(LogMyGame, Log, TEXT("Loaded: %s"), *LevelName);
370UE_LOG(LogMyGame, Warning, TEXT("HP low: %.1f"), Health);
371UE_LOG(LogMyGame, Error, TEXT("Spawn failed: %s"), *ClassName);
372UE_CLOG(Health < 0.f, LogMyGame, Error, TEXT("Negative HP: %.1f"), Health);
373```
374
375| Verbosity | Visible | When |
376|-----------|---------|------|
377| Fatal | Always | Crash-level |
378| Error | Always | Operation failed |
379| Warning | Always | Unexpected but recoverable |
380| Log | Non-shipping | Standard trace |
381| Verbose | -LogCmds | Fine-grained trace |
382
383---
384
385## Subsystems
386
387Auto-registered singletons — no manual AddToRoot needed.
388
389| Subsystem | Owner | Persists Level Load | Per Player |
390|-----------|-------|---------------------|------------|
391| UGameInstanceSubsystem | UGameInstance | Yes | No |
392| UWorldSubsystem | UWorld | No | No |
393| ULocalPlayerSubsystem | ULocalPlayer | Yes | Yes |
394| UEngineSubsystem | UEngine | Yes (whole session) | No |
395
396```cpp
397UCLASS()
398class MYGAME_API UInventorySubsystem : public UGameInstanceSubsystem
399{
400 GENERATED_BODY()
401public:
402 virtual void Initialize(FSubsystemCollectionBase& Collection) override;
403 virtual void Deinitialize() override;
404
405 UFUNCTION(BlueprintCallable) void AddItem(FName ItemID, int32 Count);
406private:
407 TMap<FName, int32> Inventory;
408};
409
410// Access — each subsystem type has a different accessor
411UInventorySubsystem* Inv = GetGameInstance()->GetSubsystem<UInventorySubsystem>();
412USpawnSubsystem* Sp = GetWorld()->GetSubsystem<USpawnSubsystem>();
413UUIStateSubsystem* UI = GetLocalPlayer()->GetSubsystem<UUIStateSubsystem>();
414UMyEngineSubsystem* ES = GEngine->GetEngineSubsystem<UMyEngineSubsystem>();
415```
416
417Subsystems have Initialize() and Deinitialize() -- override for setup/teardown. UGameInstanceSubsystem persists across map changes; UWorldSubsystem reinitializes per world. Call GetSubsystem<T>() via the owning context (GetGameInstance(), GetWorld(), GetLocalPlayer()).
418
419---
420
421## Replicated Properties
422
423Both UPROPERTY specifier AND GetLifetimeReplicatedProps are required:
424
425```cpp
426UPROPERTY(ReplicatedUsing = OnRep_Health)
427float Health;
428
429UFUNCTION()
430void OnRep_Health(); // Called on clients when server updates Health
431
432void AMyActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutProps) const
433{
434 Super::GetLifetimeReplicatedProps(OutProps);
435 DOREPLIFETIME_CONDITION(AMyActor, Health, COND_OwnerOnly);
436 // COND_None, COND_OwnerOnly, COND_SkipOwner, COND_SimulatedOnly, COND_InitialOnly
437}
438```
439
440---
441
442## Conditional Compilation Guards
443
444```cpp
445#if WITH_EDITOR
446// Editor-only properties — stripped from shipping builds
447UPROPERTY(EditAnywhere, Category="Debug")
448bool bShowDebugSpheres = false;
449
450virtual void PostEditChangeProperty(FPropertyChangedEvent& E) override;
451#endif
452
453#if !UE_BUILD_SHIPPING
454// Available in Development + Debug, stripped from Shipping
455void DrawDebugInfo();
456#endif
457```
458
459---
460
461## Common Mistakes
462
463**Raw UObject* member without UPROPERTY — dangling pointer:**
464```cpp
465UMyObject* Obj; // BAD — GC invisible
466UPROPERTY() TObjectPtr<UMyObject> Obj; // GOOD
467```
468
469**Modify TArray during ranged-for — undefined behavior:**
470```cpp
471for (const AActor* A : Actors) { Actors.Remove(A); } // CRASH
472for (int32 i = Actors.Num()-1; i >= 0; --i) { if (ShouldRemove(Actors[i])) Actors.RemoveAt(i); }
473```
474
475**TSharedPtr on a UObject — GC + refcount conflict:**
476```cpp
477TSharedPtr<UMyObject> P = MakeShared<UMyObject>(); // BAD — leaks or double-free
478UPROPERTY() TObjectPtr<UMyObject> P; // GOOD
479```
480
481**Missing GetLifetimeReplicatedProps:**
482```cpp
483void AMyActor::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
484{
485 Super::GetLifetimeReplicatedProps(OutLifetimeProps);
486 DOREPLIFETIME(AMyActor, ReplicatedHealth);
487 DOREPLIFETIME_CONDITION(AMyActor, TeamScore, COND_OwnerOnly);
488}
489```
490
491**GENERATED_USTRUCT_BODY() in UE5 structs — use GENERATED_BODY() instead.**
492
493**AddDynamic with a non-UFUNCTION — compile error or crash at runtime.**
494
495---
496
497## Related Skills
498
499- **ue-module-build-system** — Build.cs, module dependencies, include paths, PCH configuration
500- **ue-actor-component-architecture** — AActor/UActorComponent lifecycle, spawning, tick groups, component setup
501
In the file
SKILL.md1,723 words
Files4
LicenceMIT
Why you can read it

Nothing in a skill executes. The client loads the text and the model follows it, so a skill can be audited the way a runbook is — by reading it.

What it costs in context

Skills are not billed by the call. They are paid for in context: every token the instructions occupy is a token your code, your diff and your conversation cannot use. Here is what this one takes and when it takes it.

≈130
always loaded
The name and description, so the model knows the skill exists and when to reach for it.
14,020
on trigger
The instruction body and 3 supporting files, read only when the skill fires.
7.1%
of a 200k window
Ten skills this size would take about 71% of the window before you open a file.
050k100k150k200k context window

14.2k tokens, estimated from the bundle at four bytes to the token, held for the rest of the session once it triggers. Heavy. Teams tend to install this one per project rather than globally, and load it only when the job comes up.

Servers bill, skills cost

A server charges by the month. A skill charges once per session, in context, and then keeps charging it for as long as the session lives.

Before and after

The same question, put to the same model twice: once as it comes, and once with these instructions loaded.

No worked example has been published for this skill yet.

Adoption
Installsnone yet
Ratingno reviews yet

The procedure it runs

The procedure has not been published here. It is in the skill’s own SKILL.md, which its author has not sent to the marketplace yet.

Prose, not code

These steps are written for a model to follow, not executed by a runtime. It can still be told to skip one, and it will say so when it does.

Servers it uses

None. This skill calls no MCP servers at all.

Everything it needs is in the instructions, so it works in a project with nothing connected — the model reads the file and changes how it works with what it can already reach.

It writes no files and reaches no network. All it changes is how the model reasons and writes.

What it asks for
Writes filesno
Network accessno

Read from the allowed-tools line of this skill’s own SKILL.md. A skill grants no permissions of its own — it can only ask for tools your client already has.

What it will not do

Every skill is narrow, and the useful ones say where they stop. These are the jobs this one is the wrong tool for.

What this skill is not for has not been published here. Nothing is implied by that: it is a section the author has not filled in.

What is in the bundle

4 files, 56.6 kB on disk. A bundle is text throughout: the instructions the model reads, plus the templates it fills in.

  • SKILL.md16.4 kB
  • references/container-patterns.md14.0 kB
  • references/delegate-patterns.md14.9 kB
  • references/property-specifiers.md11.3 kB
What is not in it

No dependencies and nothing executable: a skill is text the agent reads, so the bundle is 4 files you can review in full before installing. The MIT licence covers the templates and examples as well as the instructions.

Install

Installing copies the bundle into your project. Nothing runs at install time — the files sit on disk until the model reads them.

$69 once
Unreal C++ Foundations · MIT · quodsoler
one-time
Price$69 once
LicenceMIT — the author’s, unchanged by this purchase
Paid throughStripe, once, on the card you add at the checkout
Keeps workingfor good — the files are yours once they are on disk
Updatesevery release of 1.x through this account

You can read the whole bundle before paying — the SKILL.md above is the product, not a preview of it. What the money buys is the delivery: the folder packaged and handed to your machine by key, every update its author ships, and our support if it does not do what this listing says. The terms of use are MIT, set by the author and unchanged by buying it here.

Payment runs through Stripe, on a page like this one rather than a redirect. Once there is an account it joins the same mcprush invoice as everything else you run, so there is never a second card to enter.

Which clients pick it up on their own

A skill is a folder of text. A client with a skills folder reads it without being told; everywhere else the same text works, it is just handed to the model rather than found.

Claude Code.claude/skills/
Claude Desktop
ChatGPT
Cursor.cursor/skills/
VS Code.github/skills/
Codex CLI.agents/skills/
Gemini CLI.gemini/skills/
Grok.grok/skills/
Zed.agents/skills/
Windsurf.windsurf/skills/
Agent SDK.claude/skills/
HTTP / API
This release
Version1.0.0
Publishedno release date on file
Price$69
Referencequodsoler/unreal-c-foundations

Versions

v1.0.0 is what is on the shelf; no release here carries a date. Instructions change more often than APIs do — a skill can be rewritten entirely without anything it depends on moving.

v1.0.0
  • No earlier releases have been published to the marketplace.
Pinning

Put quodsoler/unreal-c-foundations@1.0.0 in the install command to hold this exact version. Without the suffix you get whatever is current the day you install, and nothing moves under you afterwards.

Reviews

no reviews yet · no installs yet

Nobody has reviewed this skill yet. The rating is the mean of the reviews written here, so there is none until somebody writes the first.

Who can post

Only accounts that have had the skill installed for fourteen days, so a review is written after living with it rather than after reading it. Publishers may reply once.

Publisher
Servers0