Skip to content

fix: set TargetType on DynamicCast nodes via targetClass param#478

Merged
ChiR24 merged 8 commits into
ChiR24:devfrom
mhsm555:fix/dynamiccast-target-class
Jul 6, 2026
Merged

fix: set TargetType on DynamicCast nodes via targetClass param#478
ChiR24 merged 8 commits into
ChiR24:devfrom
mhsm555:fix/dynamiccast-target-class

Conversation

@mhsm555

@mhsm555 mhsm555 commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Creating a K2Node_DynamicCast ("Cast To ...") over MCP fell through to a generic node-instantiation path that never set TargetType, producing an unusable "Bad cast node" with only a wildcard Object pin and no typed As <Class> output. This made every cast created over MCP non-functional. This PR resolves the target class and assigns it so casts are created correctly.

Changes

  • Added a dedicated DynamicCast branch in CreateBlueprintGraphNode that reads a targetClass parameter (Blueprint asset path like /Game/Blueprints/BP_Cole, or a native class name), resolves it via ResolveClassByName, and assigns UK2Node_DynamicCast::TargetType.
  • Plumbed targetClass from the add_node/create_node payload through to the node factory.
  • Updated the CreateBlueprintGraphNode declaration signature accordingly.
  • Added the K2Node_DynamicCast.h include (with path fallbacks).
  • Returns clear INVALID_ARGUMENT / CLASS_NOT_FOUND errors when the target is missing or unresolvable.

Related Issues

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Testing

  • Tested with Unreal Engine (version: 5.5)
  • Tested MCP client integration (client: Claude)
  • Added/updated tests

Pre-Merge Checklist

  • Code follows project style guidelines
  • Self-reviewed the code
  • Updated relevant documentation
  • Added/updated tests
  • CI passes

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

CreateBlueprintGraphNode and CreateDynamicNode gain a new TargetClass parameter to support dynamic cast and create-widget nodes. The implementation adds conditional include logic for K2Node_DynamicCast.h, introduces specialized branches in both paths that instantiate the correct node type, resolve TargetClass to a UClass, assign type properties (TargetType for dynamic cast; WidgetType for create widget), and return structured errors on failure. Shared helper functions perform class resolution and payload extraction with legacy fallbacks. The handler extracts targetClass from the payload and forwards it through the updated function signature. The changelog documents both this feature and an unrelated add_variable default-value fix.

Changes

TargetClass support for cast and widget nodes

Layer / File(s) Summary
Function signature contract and conditional includes
McpAutomationBridge_BlueprintHandlersDeclarations.h, McpAutomationBridge_BlueprintHandlersAddNodeGraph.cpp
CreateBlueprintGraphNode declaration gains const FString &TargetClass parameter after NodeName. Implementation adds __has_include-guarded conditional inclusion of K2Node_DynamicCast.h to support multiple header locations across editor builds.
CreateBlueprintGraphNode cast node implementation
McpAutomationBridge_BlueprintHandlersAddNodeGraph.cpp
CreateBlueprintGraphNode signature updated with new cast-node branch that detects node types containing "dynamiccast", "castto", or "cast"; validates TargetClass is non-empty, resolves it to UClass, assigns CastNode->TargetType, and returns INVALID_ARGUMENT or CLASS_NOT_FOUND errors on missing or unresolvable targets.
CreateDynamicNode alternative cast node implementation
McpAutomationBridge_BlueprintGraphHandlersNodeCreation.cpp
Adds shared helper functions (ResolveTargetClassFromString and ReadTargetClassPayload) for class resolution and payload extraction with legacy field fallbacks and CastTo* prefix derivation. Introduces dedicated UK2Node_DynamicCast and UK2Node_CreateWidget branches in CreateDynamicNode that validate targetClass, resolve it to UClass, emit detailed errors on missing or unresolvable input, instantiate the correct node type, configure required type properties (TargetType for cast; WidgetType pre-pin for widget), and return early.
HandleBlueprintAddNode targetClass extraction and forwarding
McpAutomationBridge_BlueprintHandlersAddNode.cpp
HandleBlueprintAddNode reads targetClass from LocalPayload and falls back to legacy memberClass/nodeClass fields or derives it from nodeType when it starts with CastTo; forwards the resolved value as TargetClass in the updated CreateBlueprintGraphNode call.
Changelog documentation
CHANGELOG.md
Adds UnreleasedFixed section documenting create_node/add_node for K2Node_CreateWidget and K2Node_DynamicCast with TargetClass resolution, type property assignment, shared class-resolution helpers, and INVALID_ARGUMENT/CLASS_NOT_FOUND error codes; also documents add_variable default-value propagation with type-aware formatting.

Sequence Diagram(s)

sequenceDiagram
  participant Client as MCP Client
  participant Handler as HandleBlueprintAddNode
  participant Factory as CreateBlueprintGraphNode
  participant UE as UObject / StaticFindObject
  participant DynCastNode as UK2Node_DynamicCast

  Client->>Handler: add_node payload (nodeType, targetClass, ...)
  Handler->>Handler: Extract targetClass from LocalPayload
  Handler->>Handler: Fallback: memberClass, nodeClass, or derive from nodeType
  Handler->>Factory: CreateBlueprintGraphNode(..., TargetClass, ...)
  Factory->>Factory: NodeType matches cast keywords?
  alt TargetClass is empty
    Factory-->>Handler: OutErrorCode = INVALID_ARGUMENT
    Handler-->>Client: error response
  else TargetClass provided
    Factory->>UE: StaticFindObject(TargetClass)
    alt Class not found
      Factory-->>Handler: OutErrorCode = CLASS_NOT_FOUND
      Handler-->>Client: error response
    else Class resolved
      Factory->>DynCastNode: NewObject<UK2Node_DynamicCast>
      Factory->>DynCastNode: TargetType = ResolvedUClass
      Factory-->>Handler: UEdGraphNode*
      Handler-->>Client: success response
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • ChiR24/Unreal_mcp#471: Both PRs modify Blueprint node creation flow in CreateDynamicNode (main PR adds DynamicCast/CreateWidget class-resolution and pin setup paths; retrieved PR guards AllocateDefaultPins() to prevent duplicate pins), so they affect the same node instantiation/pin-allocation path.

Suggested labels

size/m

Poem

🐰 A cast to the right class, no more guessing games,
TargetType and WidgetType resolve all claims!
__has_include guards the header door,
Helpers peel fallbacks, no fields left to explore.
The rabbit hops forth with INVALID_ARGUMENT in hand —
Dynamic nodes wired just as planned! 🎯

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the primary change: fixing DynamicCast node creation by setting TargetType via a targetClass parameter, which directly addresses the main issue described in the PR objectives.
Description check ✅ Passed The description includes all key required sections: a clear summary of the problem and solution, detailed changes list, type of change checkbox, testing information, and pre-merge checklist completion. All critical information is present and well-documented.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added the bug Something isn't working label Jun 14, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.md`:
- Around line 10-24: The CHANGELOG.md contains transient merge/stash markers
("Updated upstream" and "Stashed changes") that are workspace metadata and
should not appear in published release notes. Remove both of these lines from
the changelog to keep only the actual release note content describing the bug
fixes and features.

In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Blueprint/Graph/McpAutomationBridge_BlueprintHandlersAddNode.cpp`:
- Around line 54-55: The code currently only reads the `targetClass` field from
the payload before forwarding it at lines 119-122, but existing request paths
still use legacy field names `memberClass` or `nodeClass`. Add fallback logic
after the initial TryGetStringField call for `targetClass` to also attempt
reading from `memberClass` and `nodeClass` fields if `targetClass` is empty.
This ensures the `TargetClass` variable gets properly populated regardless of
which legacy or current field name is present in the payload, preventing
DynamicCast creation failures with INVALID_ARGUMENT errors.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 58814abc-a279-4e16-946a-84348ca3bcc6

📥 Commits

Reviewing files that changed from the base of the PR and between 558adb3 and b091aa4.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Blueprint/Graph/McpAutomationBridge_BlueprintHandlersAddNode.cpp
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Blueprint/Graph/McpAutomationBridge_BlueprintHandlersAddNodeGraph.cpp
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/Blueprint/McpAutomationBridge_BlueprintHandlersDeclarations.h

Comment thread CHANGELOG.md Outdated
@mhsm555 mhsm555 changed the title Fix/dynamiccast target class fix: set TargetType on DynamicCast nodes via targetClass param Jun 14, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/BlueprintGraph/McpAutomationBridge_BlueprintGraphHandlersNodeCreation.cpp (1)

6-6: ⚡ Quick win

Add __has_include guards for cross-version compatibility.

The parallel implementation in McpAutomationBridge_BlueprintHandlersAddNodeGraph.cpp (Context snippet 1) wraps the K2Node_DynamicCast.h include with __has_include fallbacks to handle different header locations across Unreal Engine versions. This file should use the same defensive pattern to ensure compilation succeeds regardless of UE version.

🔀 Suggested include guards
-#include "K2Node_DynamicCast.h"
+#if defined(__has_include)
+#if __has_include("BlueprintGraph/K2Node_DynamicCast.h")
+#include "BlueprintGraph/K2Node_DynamicCast.h"
+#elif __has_include("BlueprintGraph/Classes/K2Node_DynamicCast.h")
+#include "BlueprintGraph/Classes/K2Node_DynamicCast.h"
+#elif __has_include("K2Node_DynamicCast.h")
+#include "K2Node_DynamicCast.h"
+#endif
+#else
+#include "K2Node_DynamicCast.h"
+#endif
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/BlueprintGraph/McpAutomationBridge_BlueprintGraphHandlersNodeCreation.cpp`
at line 6, The include statement for K2Node_DynamicCast.h needs defensive
preprocessing directives for cross-version compatibility. Replace the direct
`#include` "K2Node_DynamicCast.h" with __has_include guards that check for the
header availability and provide fallback alternatives for different Unreal
Engine versions, following the same pattern already implemented in
McpAutomationBridge_BlueprintHandlersAddNodeGraph.cpp. This ensures the
compilation succeeds regardless of which UE version is being used.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/BlueprintGraph/McpAutomationBridge_BlueprintGraphHandlersNodeCreation.cpp`:
- Around line 150-223: The DynamicCast node resolution block contains inline
class-resolution logic (the section starting with checking if TargetClass starts
with "/" and progressing through LoadObject, FindNodeClassByName, and
UClass::TryFindTypeSlow) that duplicates the ResolveClassByName helper function.
Replace this entire inline resolution block with a single call to
ResolveClassByName(TargetClass), assigning the result to ResolvedTarget. This
eliminates the bug where a dot in the path prevents PackageName from being
updated correctly (causing malformed paths like
"/Game/Blueprints/BP_Cole.BP_Cole.BP_Cole_C"), and ensures consistency with
other code paths in the file that already use ResolveClassByName for class
resolution.
- Line 227: The CastNode SetPurity call is hardcoded to false instead of being
configurable like other payload-based settings in the BlueprintGraph handlers.
Extract an optional "pure" field from the payload object (defaulting to false if
not present) and pass that extracted value to the SetPurity method on the
CastNode instead of the hardcoded false value, making the cast purity
configurable by callers through the payload.

---

Nitpick comments:
In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/BlueprintGraph/McpAutomationBridge_BlueprintGraphHandlersNodeCreation.cpp`:
- Line 6: The include statement for K2Node_DynamicCast.h needs defensive
preprocessing directives for cross-version compatibility. Replace the direct
`#include` "K2Node_DynamicCast.h" with __has_include guards that check for the
header availability and provide fallback alternatives for different Unreal
Engine versions, following the same pattern already implemented in
McpAutomationBridge_BlueprintHandlersAddNodeGraph.cpp. This ensures the
compilation succeeds regardless of which UE version is being used.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cfcfbc86-bde8-44e0-9d22-02d921137ddd

📥 Commits

Reviewing files that changed from the base of the PR and between c3cc57e and 77e26dd.

📒 Files selected for processing (1)
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/BlueprintGraph/McpAutomationBridge_BlueprintGraphHandlersNodeCreation.cpp

@mhsm555

mhsm555 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions github-actions Bot added size/l and removed size/m labels Jun 17, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/BlueprintGraph/McpAutomationBridge_BlueprintGraphHandlersNodeCreation.cpp (1)

27-44: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

PackageName is never updated when dot is found, producing malformed paths.

When InClassString contains a dot (e.g., "/Game/Blueprints/BP_Cole.BP_Cole"), PackageName remains the full path while only ObjectName is updated. Line 44 then produces "/Game/Blueprints/BP_Cole.BP_Cole.BP_Cole_C" instead of the correct "/Game/Blueprints/BP_Cole.BP_Cole_C".

🐛 Proposed fix
             int32 DotIdx;
             if (ClassPath.FindChar('.', DotIdx))
             {
+                PackageName = ClassPath.Left(DotIdx);
                 ObjectName = ClassPath.RightChop(DotIdx + 1);
             }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/BlueprintGraph/McpAutomationBridge_BlueprintGraphHandlersNodeCreation.cpp`
around lines 27 - 44, The issue is that PackageName is initialized to the full
ClassPath value but never updated when a dot is found in the path. When
ClassPath contains a dot (e.g., "/Game/Blueprints/BP_Cole.BP_Cole"), the code
correctly extracts ObjectName using RightChop after finding the dot position
with FindChar, but PackageName remains unchanged as the full path. This causes
line 44 to construct an incorrect path by concatenating the unmodified
PackageName with the ObjectName. Fix this by updating PackageName to contain
only the portion before the dot using Left(DotIdx) when a dot is found, so that
both PackageName and ObjectName are properly extracted from the input ClassPath.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/BlueprintGraph/McpAutomationBridge_BlueprintGraphHandlersNodeCreation.cpp`:
- Around line 27-44: The issue is that PackageName is initialized to the full
ClassPath value but never updated when a dot is found in the path. When
ClassPath contains a dot (e.g., "/Game/Blueprints/BP_Cole.BP_Cole"), the code
correctly extracts ObjectName using RightChop after finding the dot position
with FindChar, but PackageName remains unchanged as the full path. This causes
line 44 to construct an incorrect path by concatenating the unmodified
PackageName with the ObjectName. Fix this by updating PackageName to contain
only the portion before the dot using Left(DotIdx) when a dot is found, so that
both PackageName and ObjectName are properly extracted from the input ClassPath.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 743c148b-28fb-4e6e-a8b6-55ee45df620d

📥 Commits

Reviewing files that changed from the base of the PR and between 77e26dd and f2c92f4.

📒 Files selected for processing (2)
  • CHANGELOG.md
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/BlueprintGraph/McpAutomationBridge_BlueprintGraphHandlersNodeCreation.cpp
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md

@mhsm555

mhsm555 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot added the size/m label Jun 17, 2026
@ChiR24

ChiR24 commented Jun 20, 2026

Copy link
Copy Markdown
Owner

Thanks for the fix! I think this needs one small follow-up before merging.

The DynamicCast part looks good, but the CreateWidget fix seems to only cover the newer create_node path. The older add_node path still doesn’t appear to set WidgetType or handle the legacy widgetType field, so CreateWidget can still be created untyped there.

Could you also mirror the CreateWidget handling in the add_node path? Minor cleanup: the changelog also has a couple leftover branch-label lines that should be removed.

Mirror the create_node CreateWidget handling in the older add_node path
so CreateWidget nodes are no longer created untyped there:
- add_node payload now backfills targetClass from the legacy widgetType
  field, matching ReadTargetClassPayload on the create_node path
- CreateBlueprintGraphNode resolves the requested widget class and sets
  the node's WidgetType UClass property via reflection before pin
  allocation, so the typed Return Value is built; returns
  INVALID_ARGUMENT / CLASS_NOT_FOUND on missing/unresolvable class
- changelog: drop leftover branch-label lines from the Unreleased block
@github-actions github-actions Bot removed the size/m label Jun 29, 2026
@mhsm555

mhsm555 commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the fix! I think this needs one small follow-up before merging.

The DynamicCast part looks good, but the CreateWidget fix seems to only cover the newer create_node path. The older add_node path still doesn’t appear to set WidgetType or handle the legacy widgetType field, so CreateWidget can still be created untyped there.

Could you also mirror the CreateWidget handling in the add_node path? Minor cleanup: the changelog also has a couple leftover branch-label lines that should be removed.

Thanks for the review — both addressed in the latest push:

CreateWidget in the add_node path: mirrored the create_node handling. CreateBlueprintGraphNode now has a dedicated CreateWidget branch that resolves targetClass and sets the node's WidgetType via reflection before pin allocation, so the typed Return Value gets built. The add_node payload also now backfills targetClass from the legacy widgetType field, matching ReadTargetClassPayload. Missing/unresolvable class returns INVALID_ARGUMENT / CLASS_NOT_FOUND, consistent with the create_node path.
Changelog: dropped the leftover fix/dynamiccast-target-class and dev branch-label lines from the Unreleased block.

@ChiR24 ChiR24 merged commit 6e3893f into ChiR24:dev Jul 6, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants