# Bpproject2cpp

> Primary use: Converting pure Blueprint UE projects to C++ projects. Generates Source/, Build.cs, Target.cs, .h/.cpp, .sln/.vcxproj via UnrealBuildTool command line, without opening the editor. Also supports adding new C++ classes, adding plugin modules, compiling, and updating project files.

- Skill: `cc8887/bpproject2cpp` (Agent Skill)
- Install (CLI): `npx skillmds@latest add cc8887/bpproject2cpp`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cc8887/bpproject2cpp/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: cc8887 (https://skillmd.com/u/cc8887)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/cc8887/bpproject2cpp

---


**bpproject2cpp** converts pure Blueprint UE projects to C++ projects entirely from the command line.

- Pure Blueprint projects have no `Source/` directory and no `.sln` file
- This skill automates the full workflow: create Source structure → update `.uproject` → generate `.sln` → compile
- No editor required — all operations are command-line via UnrealBuildTool
- **Verified on UE 5.5** with real compilation

## Use Cases

| Scenario | Trigger |
|----------|---------|
| Pure BP project needs C++ module | "Add C++ support to this blueprint project" |
| Generate/regenerate .sln | "Generate solution file" / "Regenerate project files" |
| Add a new C++ class | "Create a new Actor class called MyCharacter" |
| Add a plugin module reference | "Add a C++ module for MyPlugin" |
| Check project C++ setup | "Does this project have C++ support?" |
| Compile C++ module | "Build the project" |

---

## Mandatory Constraints

1. **Always backup** `.uproject` before modifying it. Restore on failure.
2. **Verify engine path** — check `EngineAssociation` in `.uproject` and resolve the engine root via registry or known paths.
3. **Never open the editor** — all operations via command line only.
4. **Use forward slashes** in all path arguments passed to UnrealBuildTool.
5. **Read `.uproject`** before any operation to check current state (existing modules, plugins, etc.).
6. **Do NOT delete** existing `Source/` directories or `.sln` files without explicit user confirmation.
7. **Target.cs must be in `Source/` (top-level), NOT in `Source/{ModuleName}/`** — UBT uses `TopDirectoryOnly` search for `*.Target.cs`.
8. **Match engine settings** — Read `Build.version` and inspect the engine's target-setting enums; use only values it supports.
9. **Confirm upgrades** — Compare `EngineAssociation` with the resolved engine version; explain the impact and obtain confirmation before changing it.

---

## Critical: Correct Directory Structure

UE projects have a specific directory layout that UBT expects. Getting this wrong causes compilation failures.

```
{ProjectDir}/
├── Source/                          ← UBT scans this dir for *.Target.cs (TopDirectoryOnly!)
│   ├── {ProjectName}.Target.cs      ← MUST be here, NOT in Source/{ModuleName}/
│   ├── {ProjectName}Editor.Target.cs ← MUST be here
│   └── {ModuleName}/                ← Module source files
│       ├── {ModuleName}.Build.cs
│       ├── {ModuleName}.h           ← Module header (REQUIRED for compilation)
│       └── {ModuleName}.cpp         ← Module source (REQUIRED for compilation)
├── {ProjectName}.sln                ← Generated by GenerateProjectFiles.bat
├── {ProjectName}.vcxproj            ← Generated by GenerateProjectFiles.bat
└── {ProjectName}.uproject
```

### Why Target.cs must be in Source/ (not Source/ModuleName/)

UBT's `ProjectHasCode()` function (in `UnrealBuildTool/System/NativeProjects.cs`) checks for `*.Target.cs` using `SearchOption.TopDirectoryOnly` on the `Source/` directory. If Target.cs is in a subdirectory like `Source/ModuleName/`, UBT won't find it, will treat the project as "has no code", and will auto-generate temporary Target.cs files in `Intermediate/Source/` — causing duplicate definition errors.

### Why .h and .cpp are required

Without at least one C++ source file (`.h` + `.cpp`) in the module directory, UBT may still treat the project as "no code" or fail to compile. A valid UE module must have an `IMPLEMENT_MODULE` macro in a `.cpp` file.

---

## Core Workflow

### Step 1: Resolve Engine Path

Read the `.uproject` file's `EngineAssociation` field:

- If it's a GUID like `{B1861105-...}`: query Windows registry `HKCU\Software\Epic Games\Unreal Engine\Builds\{GUID}` to get the engine root path.
- If it's a version string like `"5.5"`: check default install location or registry.
- If it starts with `/`: it's a relative path from the project.

### Step 2: Detect Current State

```python
import os, json

uproject_path = "<PROJECT_ROOT>/MyProject.uproject"
project_dir = os.path.dirname(uproject_path)
project_name = os.path.splitext(os.path.basename(uproject_path))[0]

has_source = os.path.isdir(os.path.join(project_dir, "Source"))
has_sln = os.path.exists(os.path.join(project_dir, f"{project_name}.sln"))

with open(uproject_path, 'r', encoding='utf-8') as f:
    uproject = json.load(f)

existing_modules = [m["Name"] for m in uproject.get("Modules", [])]
```

### Step 3: Create Source Structure

Create files in **two locations**: Target.cs files in `Source/`, module files in `Source/{ModuleName}/`.

**File: `{ProjectDir}/Source/{ModuleName}/{ModuleName}.Build.cs`**
```csharp
using UnrealBuildTool;

public class {ModuleName} : ModuleRules
{
    public {ModuleName}(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
        PublicDependencyModuleNames.AddRange(new string[] {
            "Core",
            "CoreUObject",
            "Engine",
            "InputCore"
        });
    }
}
```

**File: `{ProjectDir}/Source/{ProjectName}.Target.cs`** (top-level Source/)
```csharp
using UnrealBuildTool;
using System.Collections.Generic;

public class {ProjectName}Target : TargetRules
{
    public {ProjectName}Target(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Game;
		// Set versioned build options only after checking this engine's supported values.
        ExtraModuleNames.AddRange(new string[] { "{ModuleName}" });
    }
}
```

**File: `{ProjectDir}/Source/{ProjectName}Editor.Target.cs`** (top-level Source/)
```csharp
using UnrealBuildTool;
using System.Collections.Generic;

public class {ProjectName}EditorTarget : TargetRules
{
    public {ProjectName}EditorTarget(TargetInfo Target) : base(Target)
    {
        Type = TargetType.Editor;
		// Set versioned build options only after checking this engine's supported values.
        ExtraModuleNames.AddRange(new string[] { "{ModuleName}" });
    }
}
```

**File: `{ProjectDir}/Source/{ModuleName}/{ModuleName}.h`** — Module header (REQUIRED)
```cpp
// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"

class F{ModuleName}Module : public IModuleInterface
{
public:

	/** IModuleInterface implementation */
	virtual void StartupModule() override;
	virtual void ShutdownModule() override;
};
```

**File: `{ProjectDir}/Source/{ModuleName}/{ModuleName}.cpp`** — Module source (REQUIRED)
```cpp
// Copyright Epic Games, Inc. All Rights Reserved.

#include "{ModuleName}.h"
#include "Modules/ModuleManager.h"

#define LOCTEXT_NAMESPACE "F{ModuleName}Module"

void F{ModuleName}Module::StartupModule()
{
	// Module startup logic
}

void F{ModuleName}Module::ShutdownModule()
{
	// Module shutdown logic
}

#undef LOCTEXT_NAMESPACE

IMPLEMENT_MODULE(F{ModuleName}Module, {ModuleName})
```

### Step 4: Update .uproject

Add the module entry to the `Modules` array:
```python
import json

with open(uproject_path, 'r', encoding='utf-8') as f:
    uproject = json.load(f)

modules = uproject.setdefault("Modules", [])
if module_name not in [m["Name"] for m in modules]:
    modules.append({
        "Name": module_name,
        "Type": "Runtime",
        "LoadingPhase": "Default"
    })

with open(uproject_path, 'w', encoding='utf-8') as f:
    json.dump(uproject, f, indent='\t', ensure_ascii=False)
    f.write('\n')
```

### Step 5: Clean Intermediate (Important for Existing Projects)

If the project previously had build artifacts, clean `Intermediate/` and `Binaries/` to avoid stale cache conflicts:

```batch
rd /s /q "{ProjectDir}\Intermediate" 2>nul
rd /s /q "{ProjectDir}\Binaries\Win64" 2>nul
```

> **Why**: UBT caches compiled BuildRules assemblies and source copies in `Intermediate/Source/` and `Intermediate/Build/BuildRules/`. Stale files cause duplicate definition errors (CS0101).

### Step 6: Generate .sln

Call UnrealBuildTool:
```batch
{EngineRoot}/Engine/Build/BatchFiles/GenerateProjectFiles.bat -projectfiles -project="{ProjectPath}" -game -progress
```

Alternative using RunUAT:
```batch
{EngineRoot}/Engine/Build/BatchFiles/RunUAT.bat BuildTarget -projectfiles -project="{ProjectPath}" -game
```

### Step 7: Compile

```batch
{EngineRoot}/Engine/Build/BatchFiles/Build.bat {ProjectName}Editor Win64 Development -Project="{ProjectPath}" -WaitMutex
```

### Step 8: Verify Results

Check all expected files exist and compilation succeeded:
- `{ProjectDir}/Source/{ModuleName}/{ModuleName}.Build.cs` ✅
- `{ProjectDir}/Source/{ModuleName}/{ModuleName}.h` ✅
- `{ProjectDir}/Source/{ModuleName}/{ModuleName}.cpp` ✅
- `{ProjectDir}/Source/{ProjectName}.Target.cs` ✅ (top-level)
- `{ProjectDir}/Source/{ProjectName}Editor.Target.cs` ✅ (top-level)
- `{ProjectDir}/{ProjectName}.sln` ✅
- `.uproject` contains the module in `Modules` ✅
- Compilation output: `Result: Succeeded` ✅

---

## File Templates

### Adding a C++ Header (.h)

```cpp
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "{ClassName}.generated.h"

UCLASS()
class {MODULE_API_MACRO} A{ClassName} : public AActor
{
    GENERATED_BODY()

public:
    A{ClassName}();

protected:
    virtual void BeginPlay() override;

public:
    virtual void Tick(float DeltaTime) override;
};
```

### Adding a C++ Source (.cpp)

```cpp
#include "{ClassName}.h"

A{ClassName}::A{ClassName}()
{
    PrimaryActorTick.bCanEverTick = true;
}

void A{ClassName}::BeginPlay()
{
    Super::BeginPlay();
}

void A{ClassName}::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
}
```

> **Note**: The `MODULE_API_MACRO` is `{PROJECTNAME}_API` for game modules (e.g., `CROPOUT_API`).

---

## Common Build.cs Module Dependencies

| Module Name | When to Add |
|-------------|-------------|
| `Core` | Always |
| `CoreUObject` | Always |
| `Engine` | Always |
| `InputCore` | Always (input handling) |
| `EnhancedInput` | Using Enhanced Input system |
| `GameplayTasks` | Using Gameplay Task system |
| `AIModule` | AI / Behavior Trees |
| `Niagara` | Niagara VFX |
| `UMG` | UI widgets |
| `Slate`, `SlateCore` | Editor UI |
| `UnrealEd` | Editor utilities |
| `GameplayTags` | Gameplay tag system |

---

## Error Handling

| Error | Cause | Fix |
|-------|-------|-----|
| `CS0101: already contains a definition` | Stale `Intermediate/Source/*.cs` cache conflicts with new Source files | Delete `Intermediate/Source/` and `Intermediate/Build/BuildRules/` |
| `has no code, but is being treated as a code-based project` | Target.cs in wrong location (e.g., `Source/ModuleName/` instead of `Source/`) | Move Target.cs to `Source/` top-level |
| Target build-setting conflict | Target settings do not match the engine defaults | Inspect the engine's supported target-setting enums |
| `Source/ already exists` | Project already has C++ | Check existing modules, skip or warn |
| `EngineAssociation` not found | Custom/invalid engine path | Ask user for engine root |
| `GenerateProjectFiles.bat` not found | Wrong engine root | Re-resolve engine path |
| UBT fails with missing SDK | Platform SDK not installed | Add `-platform=Win64` or install SDK |
| Compilation fails with no .h/.cpp | Module directory has no C++ source files | Create `{ModuleName}.h` and `{ModuleName}.cpp` with `IMPLEMENT_MODULE` |

---

## Troubleshooting

### "Cannot find GenerateProjectFiles.bat"
The engine path resolution failed. Verify:
1. The GUID in `EngineAssociation` exists in registry
2. The engine root directory actually exists
3. Try: `reg query "HKCU\Software\Epic Games\Unreal Engine\Builds" /s`

### CS0101 Duplicate Definition Errors
Most common issue. UBT caches `.cs` files in `Intermediate/Source/`. When you add new Target.cs files, stale caches cause conflicts.
**Fix**: `rd /s /q {Project}\Intermediate` before generating or building.

### "has no code" Warning
UBT creates temporary Target.cs in `Intermediate/Source/` when it can't find real ones. This conflicts with manually created files.
**Root cause**: Target.cs must be at `Source/*.Target.cs`, not `Source/ModuleName/*.Target.cs`.

### Build-Settings Warnings
Read `Engine/Build/Build.version`, then inspect the engine's target-setting enums and use only supported values.

### Module Name Mismatch
The module name in `Build.cs`, `Target.cs` (ExtraModuleNames), and `.uproject` Modules array must all match exactly (case-sensitive).

