Skip to content

fix(blueprint): resolve UClass lookups so non-trivial parent_class & component_type work - #26

Open
bwail wants to merge 1 commit into
flopperam:mainfrom
bwail:fix/blueprint-class-resolution
Open

fix(blueprint): resolve UClass lookups so non-trivial parent_class & component_type work#26
bwail wants to merge 1 commit into
flopperam:mainfrom
bwail:fix/blueprint-class-resolution

Conversation

@bwail

@bwail bwail commented May 3, 2026

Copy link
Copy Markdown

Summary

Two longstanding bugs in HandleCreateBlueprint and HandleAddComponentToBlueprint (in EpicUnrealMCPBlueprintCommands.cpp) made the plugin silently incorrect for nearly every input:

Bug 1 — parent_class was effectively limited to Pawn / Actor

The handler prepends an A to the input then looks up /Script/Engine.A<Name>. UE runtime UClass names do not carry the C++ A/U prefix — the actual path is /Script/Engine.Character, not /Script/Engine.ACharacter. So parent_class="Character" (and anything not in the hardcoded short-circuit) silently fell back to AActor, with a warning logged about /Script/Engine.A<Name> not existing.

Bug 2 — component_type rejected every standard engine component

ComponentClass = FindObject<UClass>(nullptr, *ComponentType);

FindObject<UClass>(nullptr, BareName) only searches the transient package. Engine components live in /Script/Engine.*, so StaticMeshComponent, CameraComponent, PointLightComponent, BoxComponent all returned Unknown component type. The existing Component-suffix and U-prefix retries didn't help because the underlying lookup was still scoped wrong.

Fix

  • Parent class: drop the A-prefix logic. Try /Script/Engine.<Bare>, /Script/Engine.A<Bare>, and the /Script/Game.* variants, then fall back to FindFirstObjectSafe<UClass> (UE 5.1+) for plugin/module-defined classes. Validate that the resolved class is Actor-derived.
  • Component type: replace FindObject(nullptr, ...) with FindFirstObjectSafe<UClass> plus a full-path fallback via LoadObject<UClass>. Bare names like Camera, StaticMesh, PointLight, Box, full paths like /Script/Engine.SkeletalMeshComponent, and C++-prefixed UCameraComponent all resolve. Strips a leading U if the caller wrote it C++-style.

Both copies of the file (UnrealMCP/Source/... and FlopperamUnrealMCP/Plugins/UnrealMCP/Source/...) are kept in sync as before.

Verification

Tested on UE 5.7 against a Character-derived blueprint:

  • create_blueprint(name="BP_FPSCharacter", parent_class="Character") → parent now correctly Character (was Actor)
  • add_component_to_blueprint(component_type="CameraComponent", ...) → ✅ (was Unknown component type)
  • add_component_to_blueprint(component_type="StaticMeshComponent", ...) → ✅
  • add_component_to_blueprint(component_type="PointLightComponent", ...) → ✅
  • add_component_to_blueprint(component_type="Box", ...) → ✅ (resolves to BoxComponent)
  • Compile clean, transform/properties applied correctly.

No changes outside the two EpicUnrealMCPBlueprintCommands.cpp copies.

…component_type work

Two longstanding bugs in HandleCreateBlueprint and HandleAddComponentToBlueprint
made the plugin silently incorrect for almost every input:

1. parent_class was effectively limited to Pawn/Actor.
   The handler prepended an 'A' to the input then looked up
   /Script/Engine.A<Name>. UE runtime UClass names do NOT carry the C++
   A/U prefix — the actual path is /Script/Engine.Character, not .ACharacter.
   So 'Character', and anything not in the hardcoded short-circuit, fell
   back to AActor (with a warning logged about /Script/Engine.A<Name>
   not existing).

2. component_type rejected every standard engine component.
   FindObject<UClass>(nullptr, *ComponentType) with a bare name only
   searches the transient package; engine components live in
   /Script/Engine.*, so 'StaticMeshComponent', 'CameraComponent',
   'PointLightComponent', 'BoxComponent' all returned 'Unknown component
   type'. Adding a 'Component' suffix or stripping a 'U' prefix didn't
   help because the underlying lookup was still scoped wrong.

Fix:
  * Drop the A-prefix logic. Try /Script/Engine.<Bare>, /Script/Engine.A<Bare>,
    and /Script/Game.* variants, then fall back to FindFirstObjectSafe<UClass>
    (UE 5.1+) for plugin/module-defined classes. Validate Actor-derived.
  * For components, replace FindObject(nullptr, ...) with FindFirstObjectSafe
    plus a full-path fallback. Now bare names like 'Camera', 'StaticMesh',
    'PointLight', 'Box', and full paths like '/Script/Engine.SkeletalMeshComponent'
    all work. Strip leading C++-style 'U' if present.

Both copies of the file (UnrealMCP/Source and FlopperamUnrealMCP/Plugins/...)
are kept in sync as before.

Verified in UE 5.7 against a Character-derived BP with CameraComponent,
StaticMeshComponent, PointLightComponent — all parented and compiled cleanly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant