$npx -y skills add quodsoler/unreal-engine-skills --skill ue-procedural-generationUse this skill when working with procedural generation in Unreal Engine: PCG framework, ProceduralMesh, instanced mesh, HISM, spline, runtime mesh, noise, terrain generation, or dungeon generation. See references/pcg-node-reference.md for PCG node types and references/procedural-
| 1 | # ue-procedural-generation |
| 2 | |
| 3 | You are an expert in Unreal Engine's procedural generation systems, including the PCG framework, ProceduralMeshComponent, instanced static meshes, noise functions, and spline-based generation. |
| 4 | |
| 5 | ## Context Check |
| 6 | |
| 7 | Before advising, read `.agents/ue-project-context.md` to determine: |
| 8 | - Whether the PCG plugin is enabled (plugins list) |
| 9 | - Target generation type: world layout, terrain, dungeon, vegetation, runtime mesh |
| 10 | - Performance constraints (mobile, console, Nanite enabled) |
| 11 | - Multiplayer requirements (server authority vs. deterministic seeding) |
| 12 | |
| 13 | ## Information Gathering |
| 14 | |
| 15 | Ask for clarification on: |
| 16 | 1. **Generation type**: world population (PCG), runtime mesh (ProceduralMeshComponent), instanced geometry (ISM/HISM), or spline-driven? |
| 17 | 2. **Timing**: editor-time baked result or runtime dynamic generation? |
| 18 | 3. **Instance count**: hundreds (ISM) or tens of thousands (HISM)? |
| 19 | 4. **Collision**: does generated geometry need physics collision? |
| 20 | 5. **Determinism**: same seed must produce same result across sessions or network clients? |
| 21 | |
| 22 | --- |
| 23 | |
| 24 | ## 1. PCG Framework (UE 5.2+) |
| 25 | |
| 26 | Node-based rule-driven world generation. Operates on point clouds with transform, density, color, seed, and metadata attributes. |
| 27 | |
| 28 | ### Plugin Setup |
| 29 | |
| 30 | ```csharp |
| 31 | // Build.cs |
| 32 | PublicDependencyModuleNames.Add("PCG"); |
| 33 | ``` |
| 34 | ```json |
| 35 | // .uproject Plugins array |
| 36 | { "Name": "PCG", "Enabled": true } |
| 37 | ``` |
| 38 | |
| 39 | ### Core Classes |
| 40 | |
| 41 | | Class | Header | Purpose | |
| 42 | |---|---|---| |
| 43 | | `UPCGComponent` | `PCGComponent.h` | Actor component driving generation | |
| 44 | | `UPCGGraph` | `PCGGraph.h` | Asset: nodes + edges | |
| 45 | | `UPCGGraphInstance` | `PCGGraph.h` | Graph instance with parameter overrides | |
| 46 | | `UPCGPointData` | `Data/PCGPointData.h` | Point cloud between nodes | |
| 47 | | `UPCGSettings` | `PCGSettings.h` | Node settings base class | |
| 48 | | `UPCGBlueprintBaseElement` | `Elements/Blueprint/PCGBlueprintBaseElement.h` | Custom Blueprint node base | |
| 49 | |
| 50 | ### UPCGComponent Key API (from `PCGComponent.h`) |
| 51 | |
| 52 | ```cpp |
| 53 | // Assign graph (NetMulticast) |
| 54 | void SetGraph(UPCGGraphInterface* InGraph); |
| 55 | |
| 56 | // Trigger generation (NetMulticast, Reliable) — use for multiplayer |
| 57 | void Generate(bool bForce); |
| 58 | |
| 59 | // Local non-replicated generation |
| 60 | void GenerateLocal(bool bForce); |
| 61 | |
| 62 | // Cleanup |
| 63 | void Cleanup(bool bRemoveComponents); |
| 64 | void CleanupLocal(bool bRemoveComponents); |
| 65 | |
| 66 | // Notify to re-evaluate after Blueprint property change |
| 67 | void NotifyPropertiesChangedFromBlueprint(); |
| 68 | |
| 69 | // Read generated output |
| 70 | const FPCGDataCollection& GetGeneratedGraphOutput() const; |
| 71 | ``` |
| 72 | |
| 73 | Generation triggers (`EPCGComponentGenerationTrigger`): |
| 74 | - `GenerateOnLoad` — one-shot on BeginPlay |
| 75 | - `GenerateOnDemand` — explicit `Generate()` call only |
| 76 | - `GenerateAtRuntime` — budget-scheduled by `UPCGSubsystem` |
| 77 | |
| 78 | ### UPCGGraph Node API (from `PCGGraph.h`) |
| 79 | |
| 80 | ```cpp |
| 81 | // Add node by settings class |
| 82 | UPCGNode* AddNodeOfType(TSubclassOf<UPCGSettings> InSettingsClass, UPCGSettings*& DefaultNodeSettings); |
| 83 | |
| 84 | // Connect two nodes |
| 85 | UPCGNode* AddEdge(UPCGNode* From, const FName& FromPinLabel, UPCGNode* To, const FName& ToPinLabel); |
| 86 | |
| 87 | // Graph parameters (typed template) |
| 88 | template<typename T> |
| 89 | TValueOrError<T, EPropertyBagResult> GetGraphParameter(const FName PropertyName) const; |
| 90 | |
| 91 | template<typename T> |
| 92 | EPropertyBagResult SetGraphParameter(const FName PropertyName, const T& Value); |
| 93 | ``` |
| 94 | |
| 95 | ### Custom Blueprint PCG Node |
| 96 | |
| 97 | Derive from `UPCGBlueprintBaseElement`: |
| 98 | |
| 99 | ```cpp |
| 100 | UCLASS(BlueprintType, Blueprintable) |
| 101 | class UMyPCGNode : public UPCGBlueprintBaseElement |
| 102 | { |
| 103 | GENERATED_BODY() |
| 104 | public: |
| 105 | UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PCG|Execution") |
| 106 | void Execute(const FPCGDataCollection& Input, FPCGDataCollection& Output); |
| 107 | }; |
| 108 | |
| 109 | // In Execute: |
| 110 | FRandomStream Stream = GetRandomStreamWithContext(GetContextHandle()); // deterministic seed |
| 111 | |
| 112 | for (const FPCGTaggedData& In : Input.GetInputsByPin(PCGPinConstants::DefaultInputLabel)) |
| 113 | { |
| 114 | const UPCGPointData* InPts = Cast<UPCGPointData>(In.Data); |
| 115 | if (!InPts) continue; |
| 116 | |
| 117 | UPCGPointData* OutPts = NewObject<UPCGPointData>(); |
| 118 | for (const FPCGPoint& Pt : InPts->GetPoints()) |
| 119 | { |
| 120 | FPCGPoint NewPt = Pt; |
| 121 | NewPt.Density = Stream.FRandRange(0.5f, 1.0f); |
| 122 | OutPts->GetMutablePoints().Add(NewPt); |
| 123 | } |
| 124 | Output.TaggedData.Emplace_GetRef().Data = OutPts; |
| 125 | } |
| 126 | ``` |
| 127 | |
| 128 | Key `UPCGBlueprintBaseElement` properties: |
| 129 | - `bIsCacheable = false` — when node spawns actors or components |
| 130 | - `bRequiresGameThread = true` — for actor spawn, component add |
| 131 | - `CustomInputPins` / `CustomOutputPins` — extra typed pins |
| 132 | |
| 133 | ### PCG Determinism |
| 134 | |
| 135 | PCG graphs are deterministic by default — |