Skip to content

fix(umg): bind_on_hovered and bind_on_value_changed author real bound-event nodes#482

Open
SoloGorilla wants to merge 1 commit into
ChiR24:devfrom
SoloGorilla:fix/umg-event-bindings-real-nodes
Open

fix(umg): bind_on_hovered and bind_on_value_changed author real bound-event nodes#482
SoloGorilla wants to merge 1 commit into
ChiR24:devfrom
SoloGorilla:fix/umg-event-bindings-real-nodes

Conversation

@SoloGorilla

Copy link
Copy Markdown
Contributor

Problem

bind_on_hovered and bind_on_value_changed returned a plain instruction string (e.g. "Bind 'OnButtonHovered' to BtnStart's OnHovered event.") instead of authoring anything — no node, no nodeId. Only bind_on_clicked created a real UK2Node_ComponentBoundEvent.

Fix (EventBindings.cpp)

Extracted the working bind_on_clicked implementation into a shared BindComponentDelegateEvent helper and routed the other two through it:

  • bind_on_hovered → Button OnHovered.
  • bind_on_value_changed → per widget type: Slider/SpinBox OnValueChanged, CheckBox OnCheckStateChanged, ComboBoxString OnSelectionChanged; unsupported widgets return UNSUPPORTED_WIDGET rather than a misleading success.

Both now author a real UK2Node_ComponentBoundEvent (returns nodeId + compileSucceeded), are idempotent (reuse an existing bound event via FindBoundEventForComponent), and only dirty/recompile when something actually changed — matching bind_on_clicked exactly. create_property_binding is intentionally left unchanged (separate follow-up).

Validation (UE 5.8, live)

bind_on_hovered (Button) and bind_on_value_changed (Slider) both produce real K2Node_ComponentBoundEvent nodes (OnButtonHoverEvent / OnFloatValueChangedEvent) with compileSucceeded:true.

🤖 Generated with Claude Code

…-event nodes

bind_on_hovered and bind_on_value_changed returned an instruction string ("Bind '...' to ...'s
... event.") instead of authoring a node, unlike bind_on_clicked which creates a real
UK2Node_ComponentBoundEvent.

Extracted the working bind_on_clicked path into a shared BindComponentDelegateEvent helper and
routed both actions through it:
- bind_on_hovered -> Button OnHovered.
- bind_on_value_changed -> per widget type: Slider/SpinBox OnValueChanged, CheckBox
  OnCheckStateChanged, ComboBoxString OnSelectionChanged; unsupported widgets return
  UNSUPPORTED_WIDGET instead of a misleading success.

Both now return a real node (nodeId + compileSucceeded), are idempotent (reuse an existing bound
event), and only dirty/recompile when something changed. create_property_binding is left unchanged.

Verified live in UE 5.8: bind_on_hovered and bind_on_value_changed (Slider) both produce real
K2Node_ComponentBoundEvent nodes with compileSucceeded:true.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Enhanced support for binding value change events to additional widget types (sliders, spin boxes, checkboxes, combo boxes)
    • Provides more detailed response information when creating event bindings
  • Bug Fixes

    • Improved error handling for widget event binding operations with structured error messages
    • Optimized blueprint recompilation to occur only when structural changes are necessary

Walkthrough

A new internal helper BindComponentDelegateEvent is introduced to idempotently create or reuse a UK2Node_ComponentBoundEvent for a widget component and multicast delegate, handling blueprint mutation and recompilation conditionally. Both bind_on_hovered and bind_on_value_changed are refactored to delegate to this helper instead of their previous ad-hoc instruction/markup flows.

Changes

Widget Event Binding Refactor

Layer / File(s) Summary
BindComponentDelegateEvent core helper
plugins/.../McpAutomationBridge_WidgetAuthoringEventBindings.cpp
Adds a shared helper that resolves the delegate property and component variable, finds or creates a UK2Node_ComponentBoundEvent idempotently, marks the blueprint structurally modified and recompiles only on new node/component changes, and returns structured JSON (bound, createdNew, compileSucceeded, nodeId, eventFunctionName); missing resource cases emit automation errors.
Updated bind_on_hovered and bind_on_value_changed callers
plugins/.../McpAutomationBridge_WidgetAuthoringEventBindings.cpp
Replaces bind_on_hovered's inline instruction/markup logic with a call to BindComponentDelegateEvent for UButton::OnHovered; replaces bind_on_value_changed's binding-info construction with per-widget-type delegate name resolution (Slider/SpinBox → OnValueChanged, CheckBox → OnCheckStateChanged, ComboBoxString → OnSelectionChanged) and a call to the helper; unsupported widget types now emit a structured automation error.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • ChiR24/Unreal_mcp#454: Modifies the same WidgetAuthoring event bindings file to author real UK2Node_ComponentBoundEvent nodes for OnClicked; the current PR generalizes that pattern into a shared helper and extends it to OnHovered and OnValueChanged.

Suggested reviewers

  • ChiR24

Poem

🐇 Hop, hop! No more copy-paste,
One helper now sets delegate pace,
OnHovered, OnValueChanged too,
A tidy node for me and you,
Compile once, then skip the rest —
This rabbit thinks refactors best! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.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 clearly and concisely summarizes the main change: fixing bind_on_hovered and bind_on_value_changed to author real bound-event nodes instead of returning instruction strings.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering the problem, the fix, implementation details, and validation results, though it lacks formal alignment with the repository's template structure and missing explicit checkbox selections.
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 and usage tips.

@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: 1

🧹 Nitpick comments (1)
plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/WidgetAuthoring/Bindings/McpAutomationBridge_WidgetAuthoringEventBindings.cpp (1)

25-116: ⚡ Quick win

Route bind_on_clicked through the helper as well.

The new helper duplicates the full OnClicked binding path, but bind_on_clicked still keeps its own copy. That means fixes like the structural-dirtying issue above must be patched twice. The helper signature already supports ButtonWidget, UButton::StaticClass(), and OnClicked, so the clicked handler can delegate after validation.

Also applies to: 159-237

🤖 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/WidgetAuthoring/Bindings/McpAutomationBridge_WidgetAuthoringEventBindings.cpp`
around lines 25 - 116, The bind_on_clicked handler is duplicating the full
binding logic instead of using the new BindComponentDelegateEvent helper
function that was created. Locate the bind_on_clicked handler implementation and
refactor it to call BindComponentDelegateEvent with the appropriate parameters
(TargetWidget as ButtonWidget, DelegateOwnerClass as UButton::StaticClass(),
DelegateName as OnClicked, and other metadata) instead of implementing the same
logic directly. This eliminates code duplication and ensures that any future
fixes to the binding process only need to be applied once in the helper
function.
🤖 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/WidgetAuthoring/Bindings/McpAutomationBridge_WidgetAuthoringEventBindings.cpp`:
- Around line 85-100: When creating a new UK2Node_ComponentBoundEvent node in
the EventGraph, the code marks the Blueprint as modified via
MarkBlueprintAsModified but fails to mark it as structurally modified. Graph
node creation is a structural change to the Blueprint, so you need to add a call
to MarkBlueprintAsStructurallyModified in addition to MarkBlueprintAsModified.
Specifically, when bCreatedNew is true (indicating a new BoundNode was created),
call FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified on the WidgetBP
before or after the MarkBlueprintAsModified call to properly notify the
Blueprint system of the structural change.

---

Nitpick comments:
In
`@plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/WidgetAuthoring/Bindings/McpAutomationBridge_WidgetAuthoringEventBindings.cpp`:
- Around line 25-116: The bind_on_clicked handler is duplicating the full
binding logic instead of using the new BindComponentDelegateEvent helper
function that was created. Locate the bind_on_clicked handler implementation and
refactor it to call BindComponentDelegateEvent with the appropriate parameters
(TargetWidget as ButtonWidget, DelegateOwnerClass as UButton::StaticClass(),
DelegateName as OnClicked, and other metadata) instead of implementing the same
logic directly. This eliminates code duplication and ensures that any future
fixes to the binding process only need to be applied once in the helper
function.
🪄 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: 7deb5908-9bba-4d14-95af-530dde7d3ab7

📥 Commits

Reviewing files that changed from the base of the PR and between e1ceb64 and 3cae682.

📒 Files selected for processing (1)
  • plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/WidgetAuthoring/Bindings/McpAutomationBridge_WidgetAuthoringEventBindings.cpp

Comment on lines +85 to +100
if (!BoundNode)
{
EventGraph->Modify();
FGraphNodeCreator<UK2Node_ComponentBoundEvent> Creator(*EventGraph);
BoundNode = Creator.CreateNode(false);
BoundNode->InitializeComponentBoundEventParams(CompProp, DelegateProp);
Creator.Finalize();
bCreatedNew = true;
bBlueprintChanged = true;
}

bool bCompiled = true;
if (bBlueprintChanged)
{
FBlueprintEditorUtils::MarkBlueprintAsModified(WidgetBP);
bCompiled = McpSafeCompileBlueprint(WidgetBP);

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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the actual code file at the specified lines
cat -n plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/WidgetAuthoring/Bindings/McpAutomationBridge_WidgetAuthoringEventBindings.cpp | sed -n '80,110p'

Repository: ChiR24/Unreal_mcp

Length of output: 1628


🏁 Script executed:

# Get full context of the BindComponentDelegateEvent function
cat -n plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/WidgetAuthoring/Bindings/McpAutomationBridge_WidgetAuthoringEventBindings.cpp | sed -n '25,120p'

Repository: ChiR24/Unreal_mcp

Length of output: 4763


🏁 Script executed:

# Check for any other uses of MarkBlueprintAsStructurallyModified in this file or related files
rg "MarkBlueprintAsStructurallyModified" plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/Domains/WidgetAuthoring/

Repository: ChiR24/Unreal_mcp

Length of output: 18120


🏁 Script executed:

# Search for UK2Node_ComponentBoundEvent usage in the codebase
rg "UK2Node_ComponentBoundEvent" plugins/McpAutomationBridge/

Repository: ChiR24/Unreal_mcp

Length of output: 2127


🏁 Script executed:

# Check for other instances of MarkBlueprintAsModified vs MarkBlueprintAsStructurallyModified usage patterns in the codebase
rg "MarkBlueprintAsModified|MarkBlueprintAsStructurallyModified" plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/ -A 2 -B 2 | head -100

Repository: ChiR24/Unreal_mcp

Length of output: 15813


Add MarkBlueprintAsStructurallyModified when creating bound-event nodes.

Creating UK2Node_ComponentBoundEvent is a structural Blueprint change. When TargetWidget->bIsVariable is already true, the code path skips the structural modification call at line 48 and proceeds to create the node at line 89. However, line 99 only calls MarkBlueprintAsModified, which is insufficient for graph node creation. The Blueprint's structural state must be marked dirty when the new event node is added.

Fix
         Creator.Finalize();
         bCreatedNew = true;
         bBlueprintChanged = true;
+        FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(WidgetBP);
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!BoundNode)
{
EventGraph->Modify();
FGraphNodeCreator<UK2Node_ComponentBoundEvent> Creator(*EventGraph);
BoundNode = Creator.CreateNode(false);
BoundNode->InitializeComponentBoundEventParams(CompProp, DelegateProp);
Creator.Finalize();
bCreatedNew = true;
bBlueprintChanged = true;
}
bool bCompiled = true;
if (bBlueprintChanged)
{
FBlueprintEditorUtils::MarkBlueprintAsModified(WidgetBP);
bCompiled = McpSafeCompileBlueprint(WidgetBP);
if (!BoundNode)
{
EventGraph->Modify();
FGraphNodeCreator<UK2Node_ComponentBoundEvent> Creator(*EventGraph);
BoundNode = Creator.CreateNode(false);
BoundNode->InitializeComponentBoundEventParams(CompProp, DelegateProp);
Creator.Finalize();
bCreatedNew = true;
bBlueprintChanged = true;
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(WidgetBP);
}
bool bCompiled = true;
if (bBlueprintChanged)
{
FBlueprintEditorUtils::MarkBlueprintAsModified(WidgetBP);
bCompiled = McpSafeCompileBlueprint(WidgetBP);
🤖 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/WidgetAuthoring/Bindings/McpAutomationBridge_WidgetAuthoringEventBindings.cpp`
around lines 85 - 100, When creating a new UK2Node_ComponentBoundEvent node in
the EventGraph, the code marks the Blueprint as modified via
MarkBlueprintAsModified but fails to mark it as structurally modified. Graph
node creation is a structural change to the Blueprint, so you need to add a call
to MarkBlueprintAsStructurallyModified in addition to MarkBlueprintAsModified.
Specifically, when bCreatedNew is true (indicating a new BoundNode was created),
call FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified on the WidgetBP
before or after the MarkBlueprintAsModified call to properly notify the
Blueprint system of the structural change.

@SoloGorilla

Copy link
Copy Markdown
Contributor Author

On adding MarkBlueprintAsStructurallyModified to the node-creation path: this helper (BindComponentDelegateEvent) is a faithful extraction of the existing bind_on_clicked, which uses the same pattern — structural-modify only when toggling bIsVariable, then MarkBlueprintAsModified + recompile on node creation — and produces working, compiled bound-event nodes. Both bind_on_hovered (Button) and bind_on_value_changed (Slider) were live-validated in UE 5.8 with compileSucceeded:true and real K2Node_ComponentBoundEvent nodes. I kept it consistent with bind_on_clicked rather than diverging one path; happy to add the structural mark to all three (incl. bind_on_clicked) if you'd prefer it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant