flockbay 0.10.49 → 0.10.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +60 -60
  2. package/bin/flockbay-mcp.mjs +62 -62
  3. package/bin/flockbay.mjs +95 -95
  4. package/dist/{index-r3VTdgFI.cjs → index-IntvnrmZ.cjs} +71 -14
  5. package/dist/{index-D8AeVbvv.mjs → index-wkeSi0iC.mjs} +70 -13
  6. package/dist/index.cjs +2 -2
  7. package/dist/index.mjs +2 -2
  8. package/dist/lib.cjs +1 -1
  9. package/dist/lib.mjs +1 -1
  10. package/dist/{migratePlugin-CEvGPul8.mjs → migratePlugin-C71hAoc5.mjs} +12 -2
  11. package/dist/{migratePlugin-wFK-k3Wk.cjs → migratePlugin-D1XjjWFq.cjs} +12 -2
  12. package/dist/{runCodex-DuyuYqoB.cjs → runCodex-B7i_ICoQ.cjs} +34 -23
  13. package/dist/{runCodex-ZfUyhHF6.mjs → runCodex-BSx-hCu6.mjs} +34 -23
  14. package/dist/{runGemini-DBU1mMdp.mjs → runGemini-Dwyh7_WI.mjs} +2 -2
  15. package/dist/{runGemini-D7j5Y5TF.cjs → runGemini-gBKR3rdL.cjs} +2 -2
  16. package/dist/{types-DNr0xwSy.cjs → types-5z8UADAi.cjs} +224 -15
  17. package/dist/{types-BRJuZQj_.mjs → types-Bgzap7qR.mjs} +224 -16
  18. package/package.json +131 -131
  19. package/scripts/claude_local_launcher.cjs +72 -72
  20. package/scripts/claude_remote_launcher.cjs +15 -15
  21. package/scripts/claude_version_utils.cjs +445 -445
  22. package/scripts/ripgrep_launcher.cjs +32 -32
  23. package/scripts/run-with-root-env.mjs +37 -32
  24. package/scripts/session_hook_forwarder.cjs +49 -49
  25. package/scripts/test-codex-abort-history.mjs +77 -77
  26. package/scripts/unpack-tools.cjs +244 -244
  27. package/tools/licenses/difftastic-LICENSE +21 -21
  28. package/tools/licenses/ripgrep-LICENSE +3 -3
  29. package/tools/unreal-mcp/UPSTREAM_VERSION.md +8 -8
  30. package/tools/unreal-mcp/upstream/Docs/README.md +8 -8
  31. package/tools/unreal-mcp/upstream/Docs/Tools/README.md +6 -6
  32. package/tools/unreal-mcp/upstream/Docs/Tools/actor_tools.md +183 -183
  33. package/tools/unreal-mcp/upstream/Docs/Tools/blueprint_tools.md +268 -268
  34. package/tools/unreal-mcp/upstream/Docs/Tools/editor_tools.md +104 -104
  35. package/tools/unreal-mcp/upstream/Docs/Tools/node_tools.md +274 -274
  36. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Config/FilterPlugin.ini +8 -8
  37. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/FlockbayMCP.uplugin +36 -36
  38. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/FlockbayMCP.Build.cs +82 -82
  39. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Private/Commands/UnrealMCPBlueprintCommands.cpp +1364 -1364
  40. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Private/Commands/UnrealMCPBlueprintNodeCommands.cpp +1310 -1310
  41. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Private/Commands/UnrealMCPCommandSchema.cpp +756 -756
  42. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Private/Commands/UnrealMCPCommonUtils.cpp +1177 -1177
  43. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Private/Commands/UnrealMCPEditorCommands.cpp +2618 -2618
  44. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Private/Commands/UnrealMCPProjectCommands.cpp +71 -71
  45. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Private/Commands/UnrealMCPUMGCommands.cpp +543 -543
  46. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Private/MCPServerRunnable.cpp +372 -372
  47. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Private/UnrealMCPBridge.cpp +457 -457
  48. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Private/UnrealMCPModule.cpp +21 -21
  49. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Public/Commands/UnrealMCPBlueprintCommands.h +35 -35
  50. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Public/Commands/UnrealMCPBlueprintNodeCommands.h +30 -30
  51. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Public/Commands/UnrealMCPCommandSchema.h +41 -41
  52. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Public/Commands/UnrealMCPCommonUtils.h +59 -59
  53. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Public/Commands/UnrealMCPEditorCommands.h +61 -61
  54. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Public/Commands/UnrealMCPProjectCommands.h +20 -20
  55. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Public/Commands/UnrealMCPUMGCommands.h +82 -82
  56. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Public/MCPServerRunnable.h +33 -33
  57. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Public/UnrealMCPBridge.h +64 -64
  58. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/FlockbayMCP/Source/FlockbayMCP/Public/UnrealMCPModule.h +22 -22
  59. package/tools/unreal-mcp/upstream/Python/README.md +39 -39
  60. package/tools/unreal-mcp/upstream/Python/pyproject.toml +22 -22
  61. package/tools/unreal-mcp/upstream/Python/scripts/actors/test_cube.py +202 -202
  62. package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_blueprints_with_different_components.py +496 -496
  63. package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_cube_blueprint.py +193 -193
  64. package/tools/unreal-mcp/upstream/Python/scripts/node/test_component_reference.py +266 -266
  65. package/tools/unreal-mcp/upstream/Python/scripts/node/test_create_bird_blueprint_with_input_and_camera.py +617 -617
  66. package/tools/unreal-mcp/upstream/Python/scripts/node/test_input_mapping.py +365 -365
  67. package/tools/unreal-mcp/upstream/Python/scripts/node/test_physics_variables.py +389 -389
  68. package/tools/unreal-mcp/upstream/Python/tools/blueprint_tools.py +419 -419
  69. package/tools/unreal-mcp/upstream/Python/tools/editor_tools.py +369 -369
  70. package/tools/unreal-mcp/upstream/Python/tools/node_tools.py +429 -429
  71. package/tools/unreal-mcp/upstream/Python/tools/project_tools.py +63 -63
  72. package/tools/unreal-mcp/upstream/Python/tools/umg_tools.py +332 -332
  73. package/tools/unreal-mcp/upstream/Python/unreal_mcp_server.py +398 -398
  74. package/tools/unreal-mcp/upstream/Python/uv.lock +521 -521
@@ -1,544 +1,544 @@
1
- #include "Commands/UnrealMCPUMGCommands.h"
2
- #include "Commands/UnrealMCPCommonUtils.h"
3
- #include "Editor.h"
4
- #include "EditorAssetLibrary.h"
5
- #include "AssetRegistry/AssetRegistryModule.h"
6
- #include "Blueprint/UserWidget.h"
7
- #include "Components/TextBlock.h"
8
- #include "WidgetBlueprint.h"
9
- // We'll create widgets using regular Factory classes
10
- #include "Factories/Factory.h"
11
- // Remove problematic includes that don't exist in UE 5.5
12
- // #include "UMGEditorSubsystem.h"
13
- // #include "WidgetBlueprintFactory.h"
14
- #include "WidgetBlueprintEditor.h"
15
- #include "Blueprint/WidgetTree.h"
16
- #include "Components/CanvasPanel.h"
17
- #include "Components/CanvasPanelSlot.h"
18
- #include "JsonObjectConverter.h"
19
- #include "Kismet2/BlueprintEditorUtils.h"
20
- #include "Components/Button.h"
21
- #include "K2Node_FunctionEntry.h"
22
- #include "K2Node_CallFunction.h"
23
- #include "K2Node_VariableGet.h"
24
- #include "K2Node_VariableSet.h"
25
- #include "Kismet/GameplayStatics.h"
26
- #include "Kismet2/KismetEditorUtilities.h"
27
- #include "K2Node_Event.h"
28
-
29
- FUnrealMCPUMGCommands::FUnrealMCPUMGCommands()
30
- {
31
- }
32
-
33
- TSharedPtr<FJsonObject> FUnrealMCPUMGCommands::HandleCommand(const FString& CommandName, const TSharedPtr<FJsonObject>& Params)
34
- {
35
- if (CommandName == TEXT("create_umg_widget_blueprint"))
36
- {
37
- return HandleCreateUMGWidgetBlueprint(Params);
38
- }
39
- else if (CommandName == TEXT("add_text_block_to_widget"))
40
- {
41
- return HandleAddTextBlockToWidget(Params);
42
- }
43
- else if (CommandName == TEXT("add_widget_to_viewport"))
44
- {
45
- return HandleAddWidgetToViewport(Params);
46
- }
47
- else if (CommandName == TEXT("add_button_to_widget"))
48
- {
49
- return HandleAddButtonToWidget(Params);
50
- }
51
- else if (CommandName == TEXT("bind_widget_event"))
52
- {
53
- return HandleBindWidgetEvent(Params);
54
- }
55
- else if (CommandName == TEXT("set_text_block_binding"))
56
- {
57
- return HandleSetTextBlockBinding(Params);
58
- }
59
-
60
- return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Unknown UMG command: %s"), *CommandName));
61
- }
62
-
63
- TSharedPtr<FJsonObject> FUnrealMCPUMGCommands::HandleCreateUMGWidgetBlueprint(const TSharedPtr<FJsonObject>& Params)
64
- {
65
- // Get required parameters
66
- FString BlueprintName;
67
- if (!Params->TryGetStringField(TEXT("name"), BlueprintName))
68
- {
69
- return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'name' parameter"));
70
- }
71
-
72
- // Create the full asset path
73
- FString PackagePath = TEXT("/Game/Widgets/");
74
- FString AssetName = BlueprintName;
75
- FString FullPath = PackagePath + AssetName;
76
-
77
- // Check if asset already exists
78
- if (UEditorAssetLibrary::DoesAssetExist(FullPath))
79
- {
80
- return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Widget Blueprint '%s' already exists"), *BlueprintName));
81
- }
82
-
83
- // Create package
84
- UPackage* Package = CreatePackage(*FullPath);
85
- if (!Package)
86
- {
87
- return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to create package"));
88
- }
89
-
90
- // Create Widget Blueprint using KismetEditorUtilities
91
- UBlueprint* NewBlueprint = FKismetEditorUtilities::CreateBlueprint(
92
- UUserWidget::StaticClass(), // Parent class
93
- Package, // Outer package
94
- FName(*AssetName), // Blueprint name
95
- BPTYPE_Normal, // Blueprint type
96
- UBlueprint::StaticClass(), // Blueprint class
97
- UBlueprintGeneratedClass::StaticClass(), // Generated class
98
- FName("CreateUMGWidget") // Creation method name
99
- );
100
-
101
- // Make sure the Blueprint was created successfully
102
- UWidgetBlueprint* WidgetBlueprint = Cast<UWidgetBlueprint>(NewBlueprint);
103
- if (!WidgetBlueprint)
104
- {
105
- return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to create Widget Blueprint"));
106
- }
107
-
108
- // Add a default Canvas Panel if one doesn't exist
109
- if (!WidgetBlueprint->WidgetTree->RootWidget)
110
- {
111
- UCanvasPanel* RootCanvas = WidgetBlueprint->WidgetTree->ConstructWidget<UCanvasPanel>(UCanvasPanel::StaticClass());
112
- WidgetBlueprint->WidgetTree->RootWidget = RootCanvas;
113
- }
114
-
115
- // Mark the package dirty and notify asset registry
116
- Package->MarkPackageDirty();
117
- FAssetRegistryModule::AssetCreated(WidgetBlueprint);
118
-
119
- // Compile the blueprint
120
- FKismetEditorUtilities::CompileBlueprint(WidgetBlueprint);
121
-
122
- // Create success response
123
- TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
124
- ResultObj->SetStringField(TEXT("name"), BlueprintName);
125
- ResultObj->SetStringField(TEXT("path"), FullPath);
126
- return ResultObj;
127
- }
128
-
129
- TSharedPtr<FJsonObject> FUnrealMCPUMGCommands::HandleAddTextBlockToWidget(const TSharedPtr<FJsonObject>& Params)
130
- {
131
- // Get required parameters
132
- FString BlueprintName;
133
- if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
134
- {
135
- return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
136
- }
137
-
138
- FString WidgetName;
139
- if (!Params->TryGetStringField(TEXT("widget_name"), WidgetName))
140
- {
141
- return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'widget_name' parameter"));
142
- }
143
-
144
- // Find the Widget Blueprint
145
- FString FullPath = TEXT("/Game/Widgets/") + BlueprintName;
146
- UWidgetBlueprint* WidgetBlueprint = Cast<UWidgetBlueprint>(UEditorAssetLibrary::LoadAsset(FullPath));
147
- if (!WidgetBlueprint)
148
- {
149
- return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Widget Blueprint '%s' not found"), *BlueprintName));
150
- }
151
-
152
- // Get optional parameters
153
- FString InitialText = TEXT("New Text Block");
154
- Params->TryGetStringField(TEXT("text"), InitialText);
155
-
156
- FVector2D Position(0.0f, 0.0f);
157
- if (Params->HasField(TEXT("position")))
158
- {
159
- const TArray<TSharedPtr<FJsonValue>>* PosArray;
160
- if (Params->TryGetArrayField(TEXT("position"), PosArray) && PosArray->Num() >= 2)
161
- {
162
- Position.X = (*PosArray)[0]->AsNumber();
163
- Position.Y = (*PosArray)[1]->AsNumber();
164
- }
165
- }
166
-
167
- // Create Text Block widget
168
- UTextBlock* TextBlock = WidgetBlueprint->WidgetTree->ConstructWidget<UTextBlock>(UTextBlock::StaticClass(), *WidgetName);
169
- if (!TextBlock)
170
- {
171
- return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to create Text Block widget"));
172
- }
173
-
174
- // Set initial text
175
- TextBlock->SetText(FText::FromString(InitialText));
176
-
177
- // Add to canvas panel
178
- UCanvasPanel* RootCanvas = Cast<UCanvasPanel>(WidgetBlueprint->WidgetTree->RootWidget);
179
- if (!RootCanvas)
180
- {
181
- return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Root Canvas Panel not found"));
182
- }
183
-
184
- UCanvasPanelSlot* PanelSlot = RootCanvas->AddChildToCanvas(TextBlock);
185
- PanelSlot->SetPosition(Position);
186
-
187
- // Mark the package dirty and compile
188
- WidgetBlueprint->MarkPackageDirty();
189
- FKismetEditorUtilities::CompileBlueprint(WidgetBlueprint);
190
-
191
- // Create success response
192
- TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
193
- ResultObj->SetStringField(TEXT("widget_name"), WidgetName);
194
- ResultObj->SetStringField(TEXT("text"), InitialText);
195
- return ResultObj;
196
- }
197
-
198
- TSharedPtr<FJsonObject> FUnrealMCPUMGCommands::HandleAddWidgetToViewport(const TSharedPtr<FJsonObject>& Params)
199
- {
200
- // Get required parameters
201
- FString BlueprintName;
202
- if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
203
- {
204
- return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
205
- }
206
-
207
- // Find the Widget Blueprint
208
- FString FullPath = TEXT("/Game/Widgets/") + BlueprintName;
209
- UWidgetBlueprint* WidgetBlueprint = Cast<UWidgetBlueprint>(UEditorAssetLibrary::LoadAsset(FullPath));
210
- if (!WidgetBlueprint)
211
- {
212
- return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Widget Blueprint '%s' not found"), *BlueprintName));
213
- }
214
-
215
- // Get optional Z-order parameter
216
- int32 ZOrder = 0;
217
- Params->TryGetNumberField(TEXT("z_order"), ZOrder);
218
-
219
- // Create widget instance
220
- UClass* WidgetClass = WidgetBlueprint->GeneratedClass;
221
- if (!WidgetClass)
222
- {
223
- return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to get widget class"));
224
- }
225
-
226
- // Note: This creates the widget but doesn't add it to viewport
227
- // The actual addition to viewport should be done through Blueprint nodes
228
- // as it requires a game context
229
-
230
- // Create success response with instructions
231
- TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
232
- ResultObj->SetStringField(TEXT("blueprint_name"), BlueprintName);
233
- ResultObj->SetStringField(TEXT("class_path"), WidgetClass->GetPathName());
234
- ResultObj->SetNumberField(TEXT("z_order"), ZOrder);
235
- ResultObj->SetStringField(TEXT("note"), TEXT("Widget class ready. Use CreateWidget and AddToViewport nodes in Blueprint to display in game."));
236
- return ResultObj;
237
- }
238
-
239
- TSharedPtr<FJsonObject> FUnrealMCPUMGCommands::HandleAddButtonToWidget(const TSharedPtr<FJsonObject>& Params)
240
- {
241
- TSharedPtr<FJsonObject> Response = MakeShared<FJsonObject>();
242
-
243
- // Get required parameters
244
- FString BlueprintName;
245
- if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
246
- {
247
- Response->SetStringField(TEXT("error"), TEXT("Missing blueprint_name parameter"));
248
- return Response;
249
- }
250
-
251
- FString WidgetName;
252
- if (!Params->TryGetStringField(TEXT("widget_name"), WidgetName))
253
- {
254
- Response->SetStringField(TEXT("error"), TEXT("Missing widget_name parameter"));
255
- return Response;
256
- }
257
-
258
- FString ButtonText;
259
- if (!Params->TryGetStringField(TEXT("text"), ButtonText))
260
- {
261
- Response->SetStringField(TEXT("error"), TEXT("Missing text parameter"));
262
- return Response;
263
- }
264
-
265
- // Load the Widget Blueprint
266
- const FString BlueprintPath = FString::Printf(TEXT("/Game/Widgets/%s.%s"), *BlueprintName, *BlueprintName);
267
- UWidgetBlueprint* WidgetBlueprint = Cast<UWidgetBlueprint>(UEditorAssetLibrary::LoadAsset(BlueprintPath));
268
- if (!WidgetBlueprint)
269
- {
270
- Response->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to load Widget Blueprint: %s"), *BlueprintPath));
271
- return Response;
272
- }
273
-
274
- // Create Button widget
275
- UButton* Button = NewObject<UButton>(WidgetBlueprint->GeneratedClass->GetDefaultObject(), UButton::StaticClass(), *WidgetName);
276
- if (!Button)
277
- {
278
- Response->SetStringField(TEXT("error"), TEXT("Failed to create Button widget"));
279
- return Response;
280
- }
281
-
282
- // Set button text
283
- UTextBlock* ButtonTextBlock = NewObject<UTextBlock>(Button, UTextBlock::StaticClass(), *(WidgetName + TEXT("_Text")));
284
- if (ButtonTextBlock)
285
- {
286
- ButtonTextBlock->SetText(FText::FromString(ButtonText));
287
- Button->AddChild(ButtonTextBlock);
288
- }
289
-
290
- // Get canvas panel and add button
291
- UCanvasPanel* RootCanvas = Cast<UCanvasPanel>(WidgetBlueprint->WidgetTree->RootWidget);
292
- if (!RootCanvas)
293
- {
294
- Response->SetStringField(TEXT("error"), TEXT("Root widget is not a Canvas Panel"));
295
- return Response;
296
- }
297
-
298
- // Add to canvas and set position
299
- UCanvasPanelSlot* ButtonSlot = RootCanvas->AddChildToCanvas(Button);
300
- if (ButtonSlot)
301
- {
302
- const TArray<TSharedPtr<FJsonValue>>* Position;
303
- if (Params->TryGetArrayField(TEXT("position"), Position) && Position->Num() >= 2)
304
- {
305
- FVector2D Pos(
306
- (*Position)[0]->AsNumber(),
307
- (*Position)[1]->AsNumber()
308
- );
309
- ButtonSlot->SetPosition(Pos);
310
- }
311
- }
312
-
313
- // Save the Widget Blueprint
314
- FKismetEditorUtilities::CompileBlueprint(WidgetBlueprint);
315
- UEditorAssetLibrary::SaveAsset(BlueprintPath, false);
316
-
317
- Response->SetBoolField(TEXT("success"), true);
318
- Response->SetStringField(TEXT("widget_name"), WidgetName);
319
- return Response;
320
- }
321
-
322
- TSharedPtr<FJsonObject> FUnrealMCPUMGCommands::HandleBindWidgetEvent(const TSharedPtr<FJsonObject>& Params)
323
- {
324
- TSharedPtr<FJsonObject> Response = MakeShared<FJsonObject>();
325
-
326
- // Get required parameters
327
- FString BlueprintName;
328
- if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
329
- {
330
- Response->SetStringField(TEXT("error"), TEXT("Missing blueprint_name parameter"));
331
- return Response;
332
- }
333
-
334
- FString WidgetName;
335
- if (!Params->TryGetStringField(TEXT("widget_name"), WidgetName))
336
- {
337
- Response->SetStringField(TEXT("error"), TEXT("Missing widget_name parameter"));
338
- return Response;
339
- }
340
-
341
- FString EventName;
342
- if (!Params->TryGetStringField(TEXT("event_name"), EventName))
343
- {
344
- Response->SetStringField(TEXT("error"), TEXT("Missing event_name parameter"));
345
- return Response;
346
- }
347
-
348
- // Load the Widget Blueprint
349
- const FString BlueprintPath = FString::Printf(TEXT("/Game/Widgets/%s.%s"), *BlueprintName, *BlueprintName);
350
- UWidgetBlueprint* WidgetBlueprint = Cast<UWidgetBlueprint>(UEditorAssetLibrary::LoadAsset(BlueprintPath));
351
- if (!WidgetBlueprint)
352
- {
353
- Response->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to load Widget Blueprint: %s"), *BlueprintPath));
354
- return Response;
355
- }
356
-
357
- // Create the event graph if it doesn't exist
358
- UEdGraph* EventGraph = FBlueprintEditorUtils::FindEventGraph(WidgetBlueprint);
359
- if (!EventGraph)
360
- {
361
- Response->SetStringField(TEXT("error"), TEXT("Failed to find or create event graph"));
362
- return Response;
363
- }
364
-
365
- // Find the widget in the blueprint
366
- UWidget* Widget = WidgetBlueprint->WidgetTree->FindWidget(*WidgetName);
367
- if (!Widget)
368
- {
369
- Response->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to find widget: %s"), *WidgetName));
370
- return Response;
371
- }
372
-
373
- // Create the event node (e.g., OnClicked for buttons)
374
- UK2Node_Event* EventNode = nullptr;
375
-
376
- // Find existing nodes first
377
- TArray<UK2Node_Event*> AllEventNodes;
378
- FBlueprintEditorUtils::GetAllNodesOfClass<UK2Node_Event>(WidgetBlueprint, AllEventNodes);
379
-
380
- for (UK2Node_Event* Node : AllEventNodes)
381
- {
382
- if (Node->CustomFunctionName == FName(*EventName) && Node->EventReference.GetMemberParentClass() == Widget->GetClass())
383
- {
384
- EventNode = Node;
385
- break;
386
- }
387
- }
388
-
389
- // If no existing node, create a new one
390
- if (!EventNode)
391
- {
392
- // Calculate position - place it below existing nodes
393
- float MaxHeight = 0.0f;
394
- for (UEdGraphNode* Node : EventGraph->Nodes)
395
- {
396
- MaxHeight = FMath::Max(MaxHeight, Node->NodePosY);
397
- }
398
-
399
- const FVector2D NodePos(200, MaxHeight + 200);
400
-
401
- // Call CreateNewBoundEventForClass, which returns void, so we can't capture the return value directly
402
- // We'll need to find the node after creating it
403
- FKismetEditorUtilities::CreateNewBoundEventForClass(
404
- Widget->GetClass(),
405
- FName(*EventName),
406
- WidgetBlueprint,
407
- nullptr // We don't need a specific property binding
408
- );
409
-
410
- // Now find the newly created node
411
- TArray<UK2Node_Event*> UpdatedEventNodes;
412
- FBlueprintEditorUtils::GetAllNodesOfClass<UK2Node_Event>(WidgetBlueprint, UpdatedEventNodes);
413
-
414
- for (UK2Node_Event* Node : UpdatedEventNodes)
415
- {
416
- if (Node->CustomFunctionName == FName(*EventName) && Node->EventReference.GetMemberParentClass() == Widget->GetClass())
417
- {
418
- EventNode = Node;
419
-
420
- // Set position of the node
421
- EventNode->NodePosX = NodePos.X;
422
- EventNode->NodePosY = NodePos.Y;
423
-
424
- break;
425
- }
426
- }
427
- }
428
-
429
- if (!EventNode)
430
- {
431
- Response->SetStringField(TEXT("error"), TEXT("Failed to create event node"));
432
- return Response;
433
- }
434
-
435
- // Save the Widget Blueprint
436
- FKismetEditorUtilities::CompileBlueprint(WidgetBlueprint);
437
- UEditorAssetLibrary::SaveAsset(BlueprintPath, false);
438
-
439
- Response->SetBoolField(TEXT("success"), true);
440
- Response->SetStringField(TEXT("event_name"), EventName);
441
- return Response;
442
- }
443
-
444
- TSharedPtr<FJsonObject> FUnrealMCPUMGCommands::HandleSetTextBlockBinding(const TSharedPtr<FJsonObject>& Params)
445
- {
446
- TSharedPtr<FJsonObject> Response = MakeShared<FJsonObject>();
447
-
448
- // Get required parameters
449
- FString BlueprintName;
450
- if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
451
- {
452
- Response->SetStringField(TEXT("error"), TEXT("Missing blueprint_name parameter"));
453
- return Response;
454
- }
455
-
456
- FString WidgetName;
457
- if (!Params->TryGetStringField(TEXT("widget_name"), WidgetName))
458
- {
459
- Response->SetStringField(TEXT("error"), TEXT("Missing widget_name parameter"));
460
- return Response;
461
- }
462
-
463
- FString BindingName;
464
- if (!Params->TryGetStringField(TEXT("binding_name"), BindingName))
465
- {
466
- Response->SetStringField(TEXT("error"), TEXT("Missing binding_name parameter"));
467
- return Response;
468
- }
469
-
470
- // Load the Widget Blueprint
471
- const FString BlueprintPath = FString::Printf(TEXT("/Game/Widgets/%s.%s"), *BlueprintName, *BlueprintName);
472
- UWidgetBlueprint* WidgetBlueprint = Cast<UWidgetBlueprint>(UEditorAssetLibrary::LoadAsset(BlueprintPath));
473
- if (!WidgetBlueprint)
474
- {
475
- Response->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to load Widget Blueprint: %s"), *BlueprintPath));
476
- return Response;
477
- }
478
-
479
- // Create a variable for binding if it doesn't exist
480
- FBlueprintEditorUtils::AddMemberVariable(
481
- WidgetBlueprint,
482
- FName(*BindingName),
483
- FEdGraphPinType(UEdGraphSchema_K2::PC_Text, NAME_None, nullptr, EPinContainerType::None, false, FEdGraphTerminalType())
484
- );
485
-
486
- // Find the TextBlock widget
487
- UTextBlock* TextBlock = Cast<UTextBlock>(WidgetBlueprint->WidgetTree->FindWidget(FName(*WidgetName)));
488
- if (!TextBlock)
489
- {
490
- Response->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to find TextBlock widget: %s"), *WidgetName));
491
- return Response;
492
- }
493
-
494
- // Create binding function
495
- const FString FunctionName = FString::Printf(TEXT("Get%s"), *BindingName);
496
- UEdGraph* FuncGraph = FBlueprintEditorUtils::CreateNewGraph(
497
- WidgetBlueprint,
498
- FName(*FunctionName),
499
- UEdGraph::StaticClass(),
500
- UEdGraphSchema_K2::StaticClass()
501
- );
502
-
503
- if (FuncGraph)
504
- {
505
- // Add the function to the blueprint with proper template parameter
506
- // Template requires null for last parameter when not using a signature-source
507
- FBlueprintEditorUtils::AddFunctionGraph<UClass>(WidgetBlueprint, FuncGraph, false, nullptr);
508
-
509
- // Create entry node
510
- UK2Node_FunctionEntry* EntryNode = nullptr;
511
-
512
- // Create entry node - use the API that exists in UE 5.5
513
- EntryNode = NewObject<UK2Node_FunctionEntry>(FuncGraph);
514
- FuncGraph->AddNode(EntryNode, false, false);
515
- EntryNode->NodePosX = 0;
516
- EntryNode->NodePosY = 0;
517
- EntryNode->FunctionReference.SetExternalMember(FName(*FunctionName), WidgetBlueprint->GeneratedClass);
518
- EntryNode->AllocateDefaultPins();
519
-
520
- // Create get variable node
521
- UK2Node_VariableGet* GetVarNode = NewObject<UK2Node_VariableGet>(FuncGraph);
522
- GetVarNode->VariableReference.SetSelfMember(FName(*BindingName));
523
- FuncGraph->AddNode(GetVarNode, false, false);
524
- GetVarNode->NodePosX = 200;
525
- GetVarNode->NodePosY = 0;
526
- GetVarNode->AllocateDefaultPins();
527
-
528
- // Connect nodes
529
- UEdGraphPin* EntryThenPin = EntryNode->FindPin(UEdGraphSchema_K2::PN_Then);
530
- UEdGraphPin* GetVarOutPin = GetVarNode->FindPin(UEdGraphSchema_K2::PN_ReturnValue);
531
- if (EntryThenPin && GetVarOutPin)
532
- {
533
- EntryThenPin->MakeLinkTo(GetVarOutPin);
534
- }
535
- }
536
-
537
- // Save the Widget Blueprint
538
- FKismetEditorUtilities::CompileBlueprint(WidgetBlueprint);
539
- UEditorAssetLibrary::SaveAsset(BlueprintPath, false);
540
-
541
- Response->SetBoolField(TEXT("success"), true);
542
- Response->SetStringField(TEXT("binding_name"), BindingName);
543
- return Response;
1
+ #include "Commands/UnrealMCPUMGCommands.h"
2
+ #include "Commands/UnrealMCPCommonUtils.h"
3
+ #include "Editor.h"
4
+ #include "EditorAssetLibrary.h"
5
+ #include "AssetRegistry/AssetRegistryModule.h"
6
+ #include "Blueprint/UserWidget.h"
7
+ #include "Components/TextBlock.h"
8
+ #include "WidgetBlueprint.h"
9
+ // We'll create widgets using regular Factory classes
10
+ #include "Factories/Factory.h"
11
+ // Remove problematic includes that don't exist in UE 5.5
12
+ // #include "UMGEditorSubsystem.h"
13
+ // #include "WidgetBlueprintFactory.h"
14
+ #include "WidgetBlueprintEditor.h"
15
+ #include "Blueprint/WidgetTree.h"
16
+ #include "Components/CanvasPanel.h"
17
+ #include "Components/CanvasPanelSlot.h"
18
+ #include "JsonObjectConverter.h"
19
+ #include "Kismet2/BlueprintEditorUtils.h"
20
+ #include "Components/Button.h"
21
+ #include "K2Node_FunctionEntry.h"
22
+ #include "K2Node_CallFunction.h"
23
+ #include "K2Node_VariableGet.h"
24
+ #include "K2Node_VariableSet.h"
25
+ #include "Kismet/GameplayStatics.h"
26
+ #include "Kismet2/KismetEditorUtilities.h"
27
+ #include "K2Node_Event.h"
28
+
29
+ FUnrealMCPUMGCommands::FUnrealMCPUMGCommands()
30
+ {
31
+ }
32
+
33
+ TSharedPtr<FJsonObject> FUnrealMCPUMGCommands::HandleCommand(const FString& CommandName, const TSharedPtr<FJsonObject>& Params)
34
+ {
35
+ if (CommandName == TEXT("create_umg_widget_blueprint"))
36
+ {
37
+ return HandleCreateUMGWidgetBlueprint(Params);
38
+ }
39
+ else if (CommandName == TEXT("add_text_block_to_widget"))
40
+ {
41
+ return HandleAddTextBlockToWidget(Params);
42
+ }
43
+ else if (CommandName == TEXT("add_widget_to_viewport"))
44
+ {
45
+ return HandleAddWidgetToViewport(Params);
46
+ }
47
+ else if (CommandName == TEXT("add_button_to_widget"))
48
+ {
49
+ return HandleAddButtonToWidget(Params);
50
+ }
51
+ else if (CommandName == TEXT("bind_widget_event"))
52
+ {
53
+ return HandleBindWidgetEvent(Params);
54
+ }
55
+ else if (CommandName == TEXT("set_text_block_binding"))
56
+ {
57
+ return HandleSetTextBlockBinding(Params);
58
+ }
59
+
60
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Unknown UMG command: %s"), *CommandName));
61
+ }
62
+
63
+ TSharedPtr<FJsonObject> FUnrealMCPUMGCommands::HandleCreateUMGWidgetBlueprint(const TSharedPtr<FJsonObject>& Params)
64
+ {
65
+ // Get required parameters
66
+ FString BlueprintName;
67
+ if (!Params->TryGetStringField(TEXT("name"), BlueprintName))
68
+ {
69
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'name' parameter"));
70
+ }
71
+
72
+ // Create the full asset path
73
+ FString PackagePath = TEXT("/Game/Widgets/");
74
+ FString AssetName = BlueprintName;
75
+ FString FullPath = PackagePath + AssetName;
76
+
77
+ // Check if asset already exists
78
+ if (UEditorAssetLibrary::DoesAssetExist(FullPath))
79
+ {
80
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Widget Blueprint '%s' already exists"), *BlueprintName));
81
+ }
82
+
83
+ // Create package
84
+ UPackage* Package = CreatePackage(*FullPath);
85
+ if (!Package)
86
+ {
87
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to create package"));
88
+ }
89
+
90
+ // Create Widget Blueprint using KismetEditorUtilities
91
+ UBlueprint* NewBlueprint = FKismetEditorUtilities::CreateBlueprint(
92
+ UUserWidget::StaticClass(), // Parent class
93
+ Package, // Outer package
94
+ FName(*AssetName), // Blueprint name
95
+ BPTYPE_Normal, // Blueprint type
96
+ UBlueprint::StaticClass(), // Blueprint class
97
+ UBlueprintGeneratedClass::StaticClass(), // Generated class
98
+ FName("CreateUMGWidget") // Creation method name
99
+ );
100
+
101
+ // Make sure the Blueprint was created successfully
102
+ UWidgetBlueprint* WidgetBlueprint = Cast<UWidgetBlueprint>(NewBlueprint);
103
+ if (!WidgetBlueprint)
104
+ {
105
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to create Widget Blueprint"));
106
+ }
107
+
108
+ // Add a default Canvas Panel if one doesn't exist
109
+ if (!WidgetBlueprint->WidgetTree->RootWidget)
110
+ {
111
+ UCanvasPanel* RootCanvas = WidgetBlueprint->WidgetTree->ConstructWidget<UCanvasPanel>(UCanvasPanel::StaticClass());
112
+ WidgetBlueprint->WidgetTree->RootWidget = RootCanvas;
113
+ }
114
+
115
+ // Mark the package dirty and notify asset registry
116
+ Package->MarkPackageDirty();
117
+ FAssetRegistryModule::AssetCreated(WidgetBlueprint);
118
+
119
+ // Compile the blueprint
120
+ FKismetEditorUtilities::CompileBlueprint(WidgetBlueprint);
121
+
122
+ // Create success response
123
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
124
+ ResultObj->SetStringField(TEXT("name"), BlueprintName);
125
+ ResultObj->SetStringField(TEXT("path"), FullPath);
126
+ return ResultObj;
127
+ }
128
+
129
+ TSharedPtr<FJsonObject> FUnrealMCPUMGCommands::HandleAddTextBlockToWidget(const TSharedPtr<FJsonObject>& Params)
130
+ {
131
+ // Get required parameters
132
+ FString BlueprintName;
133
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
134
+ {
135
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
136
+ }
137
+
138
+ FString WidgetName;
139
+ if (!Params->TryGetStringField(TEXT("widget_name"), WidgetName))
140
+ {
141
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'widget_name' parameter"));
142
+ }
143
+
144
+ // Find the Widget Blueprint
145
+ FString FullPath = TEXT("/Game/Widgets/") + BlueprintName;
146
+ UWidgetBlueprint* WidgetBlueprint = Cast<UWidgetBlueprint>(UEditorAssetLibrary::LoadAsset(FullPath));
147
+ if (!WidgetBlueprint)
148
+ {
149
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Widget Blueprint '%s' not found"), *BlueprintName));
150
+ }
151
+
152
+ // Get optional parameters
153
+ FString InitialText = TEXT("New Text Block");
154
+ Params->TryGetStringField(TEXT("text"), InitialText);
155
+
156
+ FVector2D Position(0.0f, 0.0f);
157
+ if (Params->HasField(TEXT("position")))
158
+ {
159
+ const TArray<TSharedPtr<FJsonValue>>* PosArray;
160
+ if (Params->TryGetArrayField(TEXT("position"), PosArray) && PosArray->Num() >= 2)
161
+ {
162
+ Position.X = (*PosArray)[0]->AsNumber();
163
+ Position.Y = (*PosArray)[1]->AsNumber();
164
+ }
165
+ }
166
+
167
+ // Create Text Block widget
168
+ UTextBlock* TextBlock = WidgetBlueprint->WidgetTree->ConstructWidget<UTextBlock>(UTextBlock::StaticClass(), *WidgetName);
169
+ if (!TextBlock)
170
+ {
171
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to create Text Block widget"));
172
+ }
173
+
174
+ // Set initial text
175
+ TextBlock->SetText(FText::FromString(InitialText));
176
+
177
+ // Add to canvas panel
178
+ UCanvasPanel* RootCanvas = Cast<UCanvasPanel>(WidgetBlueprint->WidgetTree->RootWidget);
179
+ if (!RootCanvas)
180
+ {
181
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Root Canvas Panel not found"));
182
+ }
183
+
184
+ UCanvasPanelSlot* PanelSlot = RootCanvas->AddChildToCanvas(TextBlock);
185
+ PanelSlot->SetPosition(Position);
186
+
187
+ // Mark the package dirty and compile
188
+ WidgetBlueprint->MarkPackageDirty();
189
+ FKismetEditorUtilities::CompileBlueprint(WidgetBlueprint);
190
+
191
+ // Create success response
192
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
193
+ ResultObj->SetStringField(TEXT("widget_name"), WidgetName);
194
+ ResultObj->SetStringField(TEXT("text"), InitialText);
195
+ return ResultObj;
196
+ }
197
+
198
+ TSharedPtr<FJsonObject> FUnrealMCPUMGCommands::HandleAddWidgetToViewport(const TSharedPtr<FJsonObject>& Params)
199
+ {
200
+ // Get required parameters
201
+ FString BlueprintName;
202
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
203
+ {
204
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
205
+ }
206
+
207
+ // Find the Widget Blueprint
208
+ FString FullPath = TEXT("/Game/Widgets/") + BlueprintName;
209
+ UWidgetBlueprint* WidgetBlueprint = Cast<UWidgetBlueprint>(UEditorAssetLibrary::LoadAsset(FullPath));
210
+ if (!WidgetBlueprint)
211
+ {
212
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Widget Blueprint '%s' not found"), *BlueprintName));
213
+ }
214
+
215
+ // Get optional Z-order parameter
216
+ int32 ZOrder = 0;
217
+ Params->TryGetNumberField(TEXT("z_order"), ZOrder);
218
+
219
+ // Create widget instance
220
+ UClass* WidgetClass = WidgetBlueprint->GeneratedClass;
221
+ if (!WidgetClass)
222
+ {
223
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to get widget class"));
224
+ }
225
+
226
+ // Note: This creates the widget but doesn't add it to viewport
227
+ // The actual addition to viewport should be done through Blueprint nodes
228
+ // as it requires a game context
229
+
230
+ // Create success response with instructions
231
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
232
+ ResultObj->SetStringField(TEXT("blueprint_name"), BlueprintName);
233
+ ResultObj->SetStringField(TEXT("class_path"), WidgetClass->GetPathName());
234
+ ResultObj->SetNumberField(TEXT("z_order"), ZOrder);
235
+ ResultObj->SetStringField(TEXT("note"), TEXT("Widget class ready. Use CreateWidget and AddToViewport nodes in Blueprint to display in game."));
236
+ return ResultObj;
237
+ }
238
+
239
+ TSharedPtr<FJsonObject> FUnrealMCPUMGCommands::HandleAddButtonToWidget(const TSharedPtr<FJsonObject>& Params)
240
+ {
241
+ TSharedPtr<FJsonObject> Response = MakeShared<FJsonObject>();
242
+
243
+ // Get required parameters
244
+ FString BlueprintName;
245
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
246
+ {
247
+ Response->SetStringField(TEXT("error"), TEXT("Missing blueprint_name parameter"));
248
+ return Response;
249
+ }
250
+
251
+ FString WidgetName;
252
+ if (!Params->TryGetStringField(TEXT("widget_name"), WidgetName))
253
+ {
254
+ Response->SetStringField(TEXT("error"), TEXT("Missing widget_name parameter"));
255
+ return Response;
256
+ }
257
+
258
+ FString ButtonText;
259
+ if (!Params->TryGetStringField(TEXT("text"), ButtonText))
260
+ {
261
+ Response->SetStringField(TEXT("error"), TEXT("Missing text parameter"));
262
+ return Response;
263
+ }
264
+
265
+ // Load the Widget Blueprint
266
+ const FString BlueprintPath = FString::Printf(TEXT("/Game/Widgets/%s.%s"), *BlueprintName, *BlueprintName);
267
+ UWidgetBlueprint* WidgetBlueprint = Cast<UWidgetBlueprint>(UEditorAssetLibrary::LoadAsset(BlueprintPath));
268
+ if (!WidgetBlueprint)
269
+ {
270
+ Response->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to load Widget Blueprint: %s"), *BlueprintPath));
271
+ return Response;
272
+ }
273
+
274
+ // Create Button widget
275
+ UButton* Button = NewObject<UButton>(WidgetBlueprint->GeneratedClass->GetDefaultObject(), UButton::StaticClass(), *WidgetName);
276
+ if (!Button)
277
+ {
278
+ Response->SetStringField(TEXT("error"), TEXT("Failed to create Button widget"));
279
+ return Response;
280
+ }
281
+
282
+ // Set button text
283
+ UTextBlock* ButtonTextBlock = NewObject<UTextBlock>(Button, UTextBlock::StaticClass(), *(WidgetName + TEXT("_Text")));
284
+ if (ButtonTextBlock)
285
+ {
286
+ ButtonTextBlock->SetText(FText::FromString(ButtonText));
287
+ Button->AddChild(ButtonTextBlock);
288
+ }
289
+
290
+ // Get canvas panel and add button
291
+ UCanvasPanel* RootCanvas = Cast<UCanvasPanel>(WidgetBlueprint->WidgetTree->RootWidget);
292
+ if (!RootCanvas)
293
+ {
294
+ Response->SetStringField(TEXT("error"), TEXT("Root widget is not a Canvas Panel"));
295
+ return Response;
296
+ }
297
+
298
+ // Add to canvas and set position
299
+ UCanvasPanelSlot* ButtonSlot = RootCanvas->AddChildToCanvas(Button);
300
+ if (ButtonSlot)
301
+ {
302
+ const TArray<TSharedPtr<FJsonValue>>* Position;
303
+ if (Params->TryGetArrayField(TEXT("position"), Position) && Position->Num() >= 2)
304
+ {
305
+ FVector2D Pos(
306
+ (*Position)[0]->AsNumber(),
307
+ (*Position)[1]->AsNumber()
308
+ );
309
+ ButtonSlot->SetPosition(Pos);
310
+ }
311
+ }
312
+
313
+ // Save the Widget Blueprint
314
+ FKismetEditorUtilities::CompileBlueprint(WidgetBlueprint);
315
+ UEditorAssetLibrary::SaveAsset(BlueprintPath, false);
316
+
317
+ Response->SetBoolField(TEXT("success"), true);
318
+ Response->SetStringField(TEXT("widget_name"), WidgetName);
319
+ return Response;
320
+ }
321
+
322
+ TSharedPtr<FJsonObject> FUnrealMCPUMGCommands::HandleBindWidgetEvent(const TSharedPtr<FJsonObject>& Params)
323
+ {
324
+ TSharedPtr<FJsonObject> Response = MakeShared<FJsonObject>();
325
+
326
+ // Get required parameters
327
+ FString BlueprintName;
328
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
329
+ {
330
+ Response->SetStringField(TEXT("error"), TEXT("Missing blueprint_name parameter"));
331
+ return Response;
332
+ }
333
+
334
+ FString WidgetName;
335
+ if (!Params->TryGetStringField(TEXT("widget_name"), WidgetName))
336
+ {
337
+ Response->SetStringField(TEXT("error"), TEXT("Missing widget_name parameter"));
338
+ return Response;
339
+ }
340
+
341
+ FString EventName;
342
+ if (!Params->TryGetStringField(TEXT("event_name"), EventName))
343
+ {
344
+ Response->SetStringField(TEXT("error"), TEXT("Missing event_name parameter"));
345
+ return Response;
346
+ }
347
+
348
+ // Load the Widget Blueprint
349
+ const FString BlueprintPath = FString::Printf(TEXT("/Game/Widgets/%s.%s"), *BlueprintName, *BlueprintName);
350
+ UWidgetBlueprint* WidgetBlueprint = Cast<UWidgetBlueprint>(UEditorAssetLibrary::LoadAsset(BlueprintPath));
351
+ if (!WidgetBlueprint)
352
+ {
353
+ Response->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to load Widget Blueprint: %s"), *BlueprintPath));
354
+ return Response;
355
+ }
356
+
357
+ // Create the event graph if it doesn't exist
358
+ UEdGraph* EventGraph = FBlueprintEditorUtils::FindEventGraph(WidgetBlueprint);
359
+ if (!EventGraph)
360
+ {
361
+ Response->SetStringField(TEXT("error"), TEXT("Failed to find or create event graph"));
362
+ return Response;
363
+ }
364
+
365
+ // Find the widget in the blueprint
366
+ UWidget* Widget = WidgetBlueprint->WidgetTree->FindWidget(*WidgetName);
367
+ if (!Widget)
368
+ {
369
+ Response->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to find widget: %s"), *WidgetName));
370
+ return Response;
371
+ }
372
+
373
+ // Create the event node (e.g., OnClicked for buttons)
374
+ UK2Node_Event* EventNode = nullptr;
375
+
376
+ // Find existing nodes first
377
+ TArray<UK2Node_Event*> AllEventNodes;
378
+ FBlueprintEditorUtils::GetAllNodesOfClass<UK2Node_Event>(WidgetBlueprint, AllEventNodes);
379
+
380
+ for (UK2Node_Event* Node : AllEventNodes)
381
+ {
382
+ if (Node->CustomFunctionName == FName(*EventName) && Node->EventReference.GetMemberParentClass() == Widget->GetClass())
383
+ {
384
+ EventNode = Node;
385
+ break;
386
+ }
387
+ }
388
+
389
+ // If no existing node, create a new one
390
+ if (!EventNode)
391
+ {
392
+ // Calculate position - place it below existing nodes
393
+ float MaxHeight = 0.0f;
394
+ for (UEdGraphNode* Node : EventGraph->Nodes)
395
+ {
396
+ MaxHeight = FMath::Max(MaxHeight, Node->NodePosY);
397
+ }
398
+
399
+ const FVector2D NodePos(200, MaxHeight + 200);
400
+
401
+ // Call CreateNewBoundEventForClass, which returns void, so we can't capture the return value directly
402
+ // We'll need to find the node after creating it
403
+ FKismetEditorUtilities::CreateNewBoundEventForClass(
404
+ Widget->GetClass(),
405
+ FName(*EventName),
406
+ WidgetBlueprint,
407
+ nullptr // We don't need a specific property binding
408
+ );
409
+
410
+ // Now find the newly created node
411
+ TArray<UK2Node_Event*> UpdatedEventNodes;
412
+ FBlueprintEditorUtils::GetAllNodesOfClass<UK2Node_Event>(WidgetBlueprint, UpdatedEventNodes);
413
+
414
+ for (UK2Node_Event* Node : UpdatedEventNodes)
415
+ {
416
+ if (Node->CustomFunctionName == FName(*EventName) && Node->EventReference.GetMemberParentClass() == Widget->GetClass())
417
+ {
418
+ EventNode = Node;
419
+
420
+ // Set position of the node
421
+ EventNode->NodePosX = NodePos.X;
422
+ EventNode->NodePosY = NodePos.Y;
423
+
424
+ break;
425
+ }
426
+ }
427
+ }
428
+
429
+ if (!EventNode)
430
+ {
431
+ Response->SetStringField(TEXT("error"), TEXT("Failed to create event node"));
432
+ return Response;
433
+ }
434
+
435
+ // Save the Widget Blueprint
436
+ FKismetEditorUtilities::CompileBlueprint(WidgetBlueprint);
437
+ UEditorAssetLibrary::SaveAsset(BlueprintPath, false);
438
+
439
+ Response->SetBoolField(TEXT("success"), true);
440
+ Response->SetStringField(TEXT("event_name"), EventName);
441
+ return Response;
442
+ }
443
+
444
+ TSharedPtr<FJsonObject> FUnrealMCPUMGCommands::HandleSetTextBlockBinding(const TSharedPtr<FJsonObject>& Params)
445
+ {
446
+ TSharedPtr<FJsonObject> Response = MakeShared<FJsonObject>();
447
+
448
+ // Get required parameters
449
+ FString BlueprintName;
450
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
451
+ {
452
+ Response->SetStringField(TEXT("error"), TEXT("Missing blueprint_name parameter"));
453
+ return Response;
454
+ }
455
+
456
+ FString WidgetName;
457
+ if (!Params->TryGetStringField(TEXT("widget_name"), WidgetName))
458
+ {
459
+ Response->SetStringField(TEXT("error"), TEXT("Missing widget_name parameter"));
460
+ return Response;
461
+ }
462
+
463
+ FString BindingName;
464
+ if (!Params->TryGetStringField(TEXT("binding_name"), BindingName))
465
+ {
466
+ Response->SetStringField(TEXT("error"), TEXT("Missing binding_name parameter"));
467
+ return Response;
468
+ }
469
+
470
+ // Load the Widget Blueprint
471
+ const FString BlueprintPath = FString::Printf(TEXT("/Game/Widgets/%s.%s"), *BlueprintName, *BlueprintName);
472
+ UWidgetBlueprint* WidgetBlueprint = Cast<UWidgetBlueprint>(UEditorAssetLibrary::LoadAsset(BlueprintPath));
473
+ if (!WidgetBlueprint)
474
+ {
475
+ Response->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to load Widget Blueprint: %s"), *BlueprintPath));
476
+ return Response;
477
+ }
478
+
479
+ // Create a variable for binding if it doesn't exist
480
+ FBlueprintEditorUtils::AddMemberVariable(
481
+ WidgetBlueprint,
482
+ FName(*BindingName),
483
+ FEdGraphPinType(UEdGraphSchema_K2::PC_Text, NAME_None, nullptr, EPinContainerType::None, false, FEdGraphTerminalType())
484
+ );
485
+
486
+ // Find the TextBlock widget
487
+ UTextBlock* TextBlock = Cast<UTextBlock>(WidgetBlueprint->WidgetTree->FindWidget(FName(*WidgetName)));
488
+ if (!TextBlock)
489
+ {
490
+ Response->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to find TextBlock widget: %s"), *WidgetName));
491
+ return Response;
492
+ }
493
+
494
+ // Create binding function
495
+ const FString FunctionName = FString::Printf(TEXT("Get%s"), *BindingName);
496
+ UEdGraph* FuncGraph = FBlueprintEditorUtils::CreateNewGraph(
497
+ WidgetBlueprint,
498
+ FName(*FunctionName),
499
+ UEdGraph::StaticClass(),
500
+ UEdGraphSchema_K2::StaticClass()
501
+ );
502
+
503
+ if (FuncGraph)
504
+ {
505
+ // Add the function to the blueprint with proper template parameter
506
+ // Template requires null for last parameter when not using a signature-source
507
+ FBlueprintEditorUtils::AddFunctionGraph<UClass>(WidgetBlueprint, FuncGraph, false, nullptr);
508
+
509
+ // Create entry node
510
+ UK2Node_FunctionEntry* EntryNode = nullptr;
511
+
512
+ // Create entry node - use the API that exists in UE 5.5
513
+ EntryNode = NewObject<UK2Node_FunctionEntry>(FuncGraph);
514
+ FuncGraph->AddNode(EntryNode, false, false);
515
+ EntryNode->NodePosX = 0;
516
+ EntryNode->NodePosY = 0;
517
+ EntryNode->FunctionReference.SetExternalMember(FName(*FunctionName), WidgetBlueprint->GeneratedClass);
518
+ EntryNode->AllocateDefaultPins();
519
+
520
+ // Create get variable node
521
+ UK2Node_VariableGet* GetVarNode = NewObject<UK2Node_VariableGet>(FuncGraph);
522
+ GetVarNode->VariableReference.SetSelfMember(FName(*BindingName));
523
+ FuncGraph->AddNode(GetVarNode, false, false);
524
+ GetVarNode->NodePosX = 200;
525
+ GetVarNode->NodePosY = 0;
526
+ GetVarNode->AllocateDefaultPins();
527
+
528
+ // Connect nodes
529
+ UEdGraphPin* EntryThenPin = EntryNode->FindPin(UEdGraphSchema_K2::PN_Then);
530
+ UEdGraphPin* GetVarOutPin = GetVarNode->FindPin(UEdGraphSchema_K2::PN_ReturnValue);
531
+ if (EntryThenPin && GetVarOutPin)
532
+ {
533
+ EntryThenPin->MakeLinkTo(GetVarOutPin);
534
+ }
535
+ }
536
+
537
+ // Save the Widget Blueprint
538
+ FKismetEditorUtilities::CompileBlueprint(WidgetBlueprint);
539
+ UEditorAssetLibrary::SaveAsset(BlueprintPath, false);
540
+
541
+ Response->SetBoolField(TEXT("success"), true);
542
+ Response->SetStringField(TEXT("binding_name"), BindingName);
543
+ return Response;
544
544
  }