flockbay 0.10.15

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 (80) hide show
  1. package/README.md +56 -0
  2. package/bin/flockbay-mcp.mjs +56 -0
  3. package/bin/flockbay.mjs +78 -0
  4. package/dist/codex/flockbayMcpStdioBridge.cjs +383 -0
  5. package/dist/codex/flockbayMcpStdioBridge.d.cts +2 -0
  6. package/dist/codex/flockbayMcpStdioBridge.d.mts +2 -0
  7. package/dist/codex/flockbayMcpStdioBridge.mjs +381 -0
  8. package/dist/flockbayScreenshotGate-DJX3Is5d.mjs +136 -0
  9. package/dist/flockbayScreenshotGate-DkxU24cR.cjs +138 -0
  10. package/dist/index--o4BPz5o.cjs +10311 -0
  11. package/dist/index-CUp3juDS.mjs +10268 -0
  12. package/dist/index.cjs +43 -0
  13. package/dist/index.d.cts +1 -0
  14. package/dist/index.d.mts +1 -0
  15. package/dist/index.mjs +40 -0
  16. package/dist/lib.cjs +33 -0
  17. package/dist/lib.d.cts +957 -0
  18. package/dist/lib.d.mts +957 -0
  19. package/dist/lib.mjs +23 -0
  20. package/dist/runCodex-D3eT-TvB.cjs +3449 -0
  21. package/dist/runCodex-o6PCbHQ7.mjs +3446 -0
  22. package/dist/runGemini-Bt0oEj_g.mjs +3183 -0
  23. package/dist/runGemini-CBxZp6I7.cjs +3185 -0
  24. package/dist/types-C-jnUdn_.cjs +4498 -0
  25. package/dist/types-DGd6ea2Z.mjs +4450 -0
  26. package/kits/kit.open_world/kit.json +59 -0
  27. package/package.json +130 -0
  28. package/scripts/claude_local_launcher.cjs +73 -0
  29. package/scripts/claude_remote_launcher.cjs +16 -0
  30. package/scripts/claude_version_utils.cjs +391 -0
  31. package/scripts/ripgrep_launcher.cjs +33 -0
  32. package/scripts/session_hook_forwarder.cjs +49 -0
  33. package/scripts/test-codex-abort-history.mjs +77 -0
  34. package/scripts/unpack-tools.cjs +222 -0
  35. package/tools/licenses/difftastic-LICENSE +21 -0
  36. package/tools/licenses/ripgrep-LICENSE +3 -0
  37. package/tools/unreal-mcp/UPSTREAM_VERSION.md +8 -0
  38. package/tools/unreal-mcp/upstream/Docs/README.md +8 -0
  39. package/tools/unreal-mcp/upstream/Docs/Tools/README.md +7 -0
  40. package/tools/unreal-mcp/upstream/Docs/Tools/actor_tools.md +184 -0
  41. package/tools/unreal-mcp/upstream/Docs/Tools/blueprint_tools.md +268 -0
  42. package/tools/unreal-mcp/upstream/Docs/Tools/editor_tools.md +104 -0
  43. package/tools/unreal-mcp/upstream/Docs/Tools/node_tools.md +274 -0
  44. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Config/FilterPlugin.ini +8 -0
  45. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintCommands.cpp +1160 -0
  46. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintNodeCommands.cpp +924 -0
  47. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPCommonUtils.cpp +709 -0
  48. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPEditorCommands.cpp +896 -0
  49. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPProjectCommands.cpp +72 -0
  50. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPUMGCommands.cpp +544 -0
  51. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/MCPServerRunnable.cpp +321 -0
  52. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPBridge.cpp +419 -0
  53. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPModule.cpp +21 -0
  54. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintCommands.h +34 -0
  55. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintNodeCommands.h +27 -0
  56. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPCommonUtils.h +59 -0
  57. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPEditorCommands.h +40 -0
  58. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPProjectCommands.h +20 -0
  59. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPUMGCommands.h +82 -0
  60. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/MCPServerRunnable.h +34 -0
  61. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/UnrealMCPBridge.h +64 -0
  62. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/UnrealMCPModule.h +22 -0
  63. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/UnrealMCP.Build.cs +78 -0
  64. package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/UnrealMCP.uplugin +36 -0
  65. package/tools/unreal-mcp/upstream/Python/README.md +40 -0
  66. package/tools/unreal-mcp/upstream/Python/pyproject.toml +22 -0
  67. package/tools/unreal-mcp/upstream/Python/scripts/actors/test_cube.py +203 -0
  68. package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_blueprints_with_different_components.py +497 -0
  69. package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_cube_blueprint.py +194 -0
  70. package/tools/unreal-mcp/upstream/Python/scripts/node/test_component_reference.py +267 -0
  71. package/tools/unreal-mcp/upstream/Python/scripts/node/test_create_bird_blueprint_with_input_and_camera.py +618 -0
  72. package/tools/unreal-mcp/upstream/Python/scripts/node/test_input_mapping.py +366 -0
  73. package/tools/unreal-mcp/upstream/Python/scripts/node/test_physics_variables.py +390 -0
  74. package/tools/unreal-mcp/upstream/Python/tools/blueprint_tools.py +420 -0
  75. package/tools/unreal-mcp/upstream/Python/tools/editor_tools.py +369 -0
  76. package/tools/unreal-mcp/upstream/Python/tools/node_tools.py +430 -0
  77. package/tools/unreal-mcp/upstream/Python/tools/project_tools.py +64 -0
  78. package/tools/unreal-mcp/upstream/Python/tools/umg_tools.py +333 -0
  79. package/tools/unreal-mcp/upstream/Python/unreal_mcp_server.py +398 -0
  80. package/tools/unreal-mcp/upstream/Python/uv.lock +521 -0
@@ -0,0 +1,924 @@
1
+ #include "Commands/UnrealMCPBlueprintNodeCommands.h"
2
+ #include "Commands/UnrealMCPCommonUtils.h"
3
+ #include "Engine/Blueprint.h"
4
+ #include "Engine/BlueprintGeneratedClass.h"
5
+ #include "EdGraph/EdGraph.h"
6
+ #include "EdGraph/EdGraphNode.h"
7
+ #include "EdGraph/EdGraphPin.h"
8
+ #include "K2Node_Event.h"
9
+ #include "K2Node_CallFunction.h"
10
+ #include "K2Node_VariableGet.h"
11
+ #include "K2Node_InputAction.h"
12
+ #include "K2Node_Self.h"
13
+ #include "Kismet2/BlueprintEditorUtils.h"
14
+ #include "Kismet2/KismetEditorUtilities.h"
15
+ #include "GameFramework/InputSettings.h"
16
+ #include "Camera/CameraActor.h"
17
+ #include "Kismet/GameplayStatics.h"
18
+ #include "EdGraphSchema_K2.h"
19
+
20
+ // Declare the log category
21
+ DEFINE_LOG_CATEGORY_STATIC(LogUnrealMCP, Log, All);
22
+
23
+ FUnrealMCPBlueprintNodeCommands::FUnrealMCPBlueprintNodeCommands()
24
+ {
25
+ }
26
+
27
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleCommand(const FString& CommandType, const TSharedPtr<FJsonObject>& Params)
28
+ {
29
+ if (CommandType == TEXT("connect_blueprint_nodes"))
30
+ {
31
+ return HandleConnectBlueprintNodes(Params);
32
+ }
33
+ else if (CommandType == TEXT("add_blueprint_get_self_component_reference"))
34
+ {
35
+ return HandleAddBlueprintGetSelfComponentReference(Params);
36
+ }
37
+ else if (CommandType == TEXT("add_blueprint_event_node"))
38
+ {
39
+ return HandleAddBlueprintEvent(Params);
40
+ }
41
+ else if (CommandType == TEXT("add_blueprint_function_node"))
42
+ {
43
+ return HandleAddBlueprintFunctionCall(Params);
44
+ }
45
+ else if (CommandType == TEXT("add_blueprint_variable"))
46
+ {
47
+ return HandleAddBlueprintVariable(Params);
48
+ }
49
+ else if (CommandType == TEXT("add_blueprint_input_action_node"))
50
+ {
51
+ return HandleAddBlueprintInputActionNode(Params);
52
+ }
53
+ else if (CommandType == TEXT("add_blueprint_self_reference"))
54
+ {
55
+ return HandleAddBlueprintSelfReference(Params);
56
+ }
57
+ else if (CommandType == TEXT("find_blueprint_nodes"))
58
+ {
59
+ return HandleFindBlueprintNodes(Params);
60
+ }
61
+
62
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Unknown blueprint node command: %s"), *CommandType));
63
+ }
64
+
65
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleConnectBlueprintNodes(const TSharedPtr<FJsonObject>& Params)
66
+ {
67
+ // Get required parameters
68
+ FString BlueprintName;
69
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
70
+ {
71
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
72
+ }
73
+
74
+ FString SourceNodeId;
75
+ if (!Params->TryGetStringField(TEXT("source_node_id"), SourceNodeId))
76
+ {
77
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'source_node_id' parameter"));
78
+ }
79
+
80
+ FString TargetNodeId;
81
+ if (!Params->TryGetStringField(TEXT("target_node_id"), TargetNodeId))
82
+ {
83
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'target_node_id' parameter"));
84
+ }
85
+
86
+ FString SourcePinName;
87
+ if (!Params->TryGetStringField(TEXT("source_pin"), SourcePinName))
88
+ {
89
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'source_pin' parameter"));
90
+ }
91
+
92
+ FString TargetPinName;
93
+ if (!Params->TryGetStringField(TEXT("target_pin"), TargetPinName))
94
+ {
95
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'target_pin' parameter"));
96
+ }
97
+
98
+ // Find the blueprint
99
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
100
+ if (!Blueprint)
101
+ {
102
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
103
+ }
104
+
105
+ // Get the event graph
106
+ UEdGraph* EventGraph = FUnrealMCPCommonUtils::FindOrCreateEventGraph(Blueprint);
107
+ if (!EventGraph)
108
+ {
109
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to get event graph"));
110
+ }
111
+
112
+ // Find the nodes
113
+ UEdGraphNode* SourceNode = nullptr;
114
+ UEdGraphNode* TargetNode = nullptr;
115
+ for (UEdGraphNode* Node : EventGraph->Nodes)
116
+ {
117
+ if (Node->NodeGuid.ToString() == SourceNodeId)
118
+ {
119
+ SourceNode = Node;
120
+ }
121
+ else if (Node->NodeGuid.ToString() == TargetNodeId)
122
+ {
123
+ TargetNode = Node;
124
+ }
125
+ }
126
+
127
+ if (!SourceNode || !TargetNode)
128
+ {
129
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Source or target node not found"));
130
+ }
131
+
132
+ // Connect the nodes
133
+ if (FUnrealMCPCommonUtils::ConnectGraphNodes(EventGraph, SourceNode, SourcePinName, TargetNode, TargetPinName))
134
+ {
135
+ // Mark the blueprint as modified
136
+ FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
137
+
138
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
139
+ ResultObj->SetStringField(TEXT("source_node_id"), SourceNodeId);
140
+ ResultObj->SetStringField(TEXT("target_node_id"), TargetNodeId);
141
+ return ResultObj;
142
+ }
143
+
144
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to connect nodes"));
145
+ }
146
+
147
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintGetSelfComponentReference(const TSharedPtr<FJsonObject>& Params)
148
+ {
149
+ // Get required parameters
150
+ FString BlueprintName;
151
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
152
+ {
153
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
154
+ }
155
+
156
+ FString ComponentName;
157
+ if (!Params->TryGetStringField(TEXT("component_name"), ComponentName))
158
+ {
159
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'component_name' parameter"));
160
+ }
161
+
162
+ // Get position parameters (optional)
163
+ FVector2D NodePosition(0.0f, 0.0f);
164
+ if (Params->HasField(TEXT("node_position")))
165
+ {
166
+ NodePosition = FUnrealMCPCommonUtils::GetVector2DFromJson(Params, TEXT("node_position"));
167
+ }
168
+
169
+ // Find the blueprint
170
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
171
+ if (!Blueprint)
172
+ {
173
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
174
+ }
175
+
176
+ // Get the event graph
177
+ UEdGraph* EventGraph = FUnrealMCPCommonUtils::FindOrCreateEventGraph(Blueprint);
178
+ if (!EventGraph)
179
+ {
180
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to get event graph"));
181
+ }
182
+
183
+ // We'll skip component verification since the GetAllNodes API may have changed in UE5.5
184
+
185
+ // Create the variable get node directly
186
+ UK2Node_VariableGet* GetComponentNode = NewObject<UK2Node_VariableGet>(EventGraph);
187
+ if (!GetComponentNode)
188
+ {
189
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to create get component node"));
190
+ }
191
+
192
+ // Set up the variable reference properly for UE5.5
193
+ FMemberReference& VarRef = GetComponentNode->VariableReference;
194
+ VarRef.SetSelfMember(FName(*ComponentName));
195
+
196
+ // Set node position
197
+ GetComponentNode->NodePosX = NodePosition.X;
198
+ GetComponentNode->NodePosY = NodePosition.Y;
199
+
200
+ // Add to graph
201
+ EventGraph->AddNode(GetComponentNode);
202
+ GetComponentNode->CreateNewGuid();
203
+ GetComponentNode->PostPlacedNewNode();
204
+ GetComponentNode->AllocateDefaultPins();
205
+
206
+ // Explicitly reconstruct node for UE5.5
207
+ GetComponentNode->ReconstructNode();
208
+
209
+ // Mark the blueprint as modified
210
+ FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
211
+
212
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
213
+ ResultObj->SetStringField(TEXT("node_id"), GetComponentNode->NodeGuid.ToString());
214
+ return ResultObj;
215
+ }
216
+
217
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintEvent(const TSharedPtr<FJsonObject>& Params)
218
+ {
219
+ // Get required parameters
220
+ FString BlueprintName;
221
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
222
+ {
223
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
224
+ }
225
+
226
+ FString EventName;
227
+ if (!Params->TryGetStringField(TEXT("event_name"), EventName))
228
+ {
229
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'event_name' parameter"));
230
+ }
231
+
232
+ // Get position parameters (optional)
233
+ FVector2D NodePosition(0.0f, 0.0f);
234
+ if (Params->HasField(TEXT("node_position")))
235
+ {
236
+ NodePosition = FUnrealMCPCommonUtils::GetVector2DFromJson(Params, TEXT("node_position"));
237
+ }
238
+
239
+ // Find the blueprint
240
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
241
+ if (!Blueprint)
242
+ {
243
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
244
+ }
245
+
246
+ // Get the event graph
247
+ UEdGraph* EventGraph = FUnrealMCPCommonUtils::FindOrCreateEventGraph(Blueprint);
248
+ if (!EventGraph)
249
+ {
250
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to get event graph"));
251
+ }
252
+
253
+ // Create the event node
254
+ UK2Node_Event* EventNode = FUnrealMCPCommonUtils::CreateEventNode(EventGraph, EventName, NodePosition);
255
+ if (!EventNode)
256
+ {
257
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to create event node"));
258
+ }
259
+
260
+ // Mark the blueprint as modified
261
+ FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
262
+
263
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
264
+ ResultObj->SetStringField(TEXT("node_id"), EventNode->NodeGuid.ToString());
265
+ return ResultObj;
266
+ }
267
+
268
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintFunctionCall(const TSharedPtr<FJsonObject>& Params)
269
+ {
270
+ // Get required parameters
271
+ FString BlueprintName;
272
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
273
+ {
274
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
275
+ }
276
+
277
+ FString FunctionName;
278
+ if (!Params->TryGetStringField(TEXT("function_name"), FunctionName))
279
+ {
280
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'function_name' parameter"));
281
+ }
282
+
283
+ // Get position parameters (optional)
284
+ FVector2D NodePosition(0.0f, 0.0f);
285
+ if (Params->HasField(TEXT("node_position")))
286
+ {
287
+ NodePosition = FUnrealMCPCommonUtils::GetVector2DFromJson(Params, TEXT("node_position"));
288
+ }
289
+
290
+ // Check for target parameter (optional)
291
+ FString Target;
292
+ Params->TryGetStringField(TEXT("target"), Target);
293
+
294
+ // Find the blueprint
295
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
296
+ if (!Blueprint)
297
+ {
298
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
299
+ }
300
+
301
+ // Get the event graph
302
+ UEdGraph* EventGraph = FUnrealMCPCommonUtils::FindOrCreateEventGraph(Blueprint);
303
+ if (!EventGraph)
304
+ {
305
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to get event graph"));
306
+ }
307
+
308
+ // Find the function
309
+ UFunction* Function = nullptr;
310
+ UK2Node_CallFunction* FunctionNode = nullptr;
311
+
312
+ // Add extensive logging for debugging
313
+ UE_LOG(LogTemp, Display, TEXT("Looking for function '%s' in target '%s'"),
314
+ *FunctionName, Target.IsEmpty() ? TEXT("Blueprint") : *Target);
315
+
316
+ // Check if we have a target class specified
317
+ if (!Target.IsEmpty())
318
+ {
319
+ // Try to find the target class
320
+ UClass* TargetClass = nullptr;
321
+
322
+ // First try without a prefix
323
+ TargetClass = FindObject<UClass>(ANY_PACKAGE, *Target);
324
+ UE_LOG(LogTemp, Display, TEXT("Tried to find class '%s': %s"),
325
+ *Target, TargetClass ? TEXT("Found") : TEXT("Not found"));
326
+
327
+ // If not found, try with U prefix (common convention for UE classes)
328
+ if (!TargetClass && !Target.StartsWith(TEXT("U")))
329
+ {
330
+ FString TargetWithPrefix = FString(TEXT("U")) + Target;
331
+ TargetClass = FindObject<UClass>(ANY_PACKAGE, *TargetWithPrefix);
332
+ UE_LOG(LogTemp, Display, TEXT("Tried to find class '%s': %s"),
333
+ *TargetWithPrefix, TargetClass ? TEXT("Found") : TEXT("Not found"));
334
+ }
335
+
336
+ // If still not found, try with common component names
337
+ if (!TargetClass)
338
+ {
339
+ // Try some common component class names
340
+ TArray<FString> PossibleClassNames;
341
+ PossibleClassNames.Add(FString(TEXT("U")) + Target + TEXT("Component"));
342
+ PossibleClassNames.Add(Target + TEXT("Component"));
343
+
344
+ for (const FString& ClassName : PossibleClassNames)
345
+ {
346
+ TargetClass = FindObject<UClass>(ANY_PACKAGE, *ClassName);
347
+ if (TargetClass)
348
+ {
349
+ UE_LOG(LogTemp, Display, TEXT("Found class using alternative name '%s'"), *ClassName);
350
+ break;
351
+ }
352
+ }
353
+ }
354
+
355
+ // Special case handling for common classes like UGameplayStatics
356
+ if (!TargetClass && Target == TEXT("UGameplayStatics"))
357
+ {
358
+ // For UGameplayStatics, use a direct reference to known class
359
+ TargetClass = FindObject<UClass>(ANY_PACKAGE, TEXT("UGameplayStatics"));
360
+ if (!TargetClass)
361
+ {
362
+ // Try loading it from its known package
363
+ TargetClass = LoadObject<UClass>(nullptr, TEXT("/Script/Engine.GameplayStatics"));
364
+ UE_LOG(LogTemp, Display, TEXT("Explicitly loading GameplayStatics: %s"),
365
+ TargetClass ? TEXT("Success") : TEXT("Failed"));
366
+ }
367
+ }
368
+
369
+ // If we found a target class, look for the function there
370
+ if (TargetClass)
371
+ {
372
+ UE_LOG(LogTemp, Display, TEXT("Looking for function '%s' in class '%s'"),
373
+ *FunctionName, *TargetClass->GetName());
374
+
375
+ // First try exact name
376
+ Function = TargetClass->FindFunctionByName(*FunctionName);
377
+
378
+ // If not found, try class hierarchy
379
+ UClass* CurrentClass = TargetClass;
380
+ while (!Function && CurrentClass)
381
+ {
382
+ UE_LOG(LogTemp, Display, TEXT("Searching in class: %s"), *CurrentClass->GetName());
383
+
384
+ // Try exact match
385
+ Function = CurrentClass->FindFunctionByName(*FunctionName);
386
+
387
+ // Try case-insensitive match
388
+ if (!Function)
389
+ {
390
+ for (TFieldIterator<UFunction> FuncIt(CurrentClass); FuncIt; ++FuncIt)
391
+ {
392
+ UFunction* AvailableFunc = *FuncIt;
393
+ UE_LOG(LogTemp, Display, TEXT(" - Available function: %s"), *AvailableFunc->GetName());
394
+
395
+ if (AvailableFunc->GetName().Equals(FunctionName, ESearchCase::IgnoreCase))
396
+ {
397
+ UE_LOG(LogTemp, Display, TEXT(" - Found case-insensitive match: %s"), *AvailableFunc->GetName());
398
+ Function = AvailableFunc;
399
+ break;
400
+ }
401
+ }
402
+ }
403
+
404
+ // Move to parent class
405
+ CurrentClass = CurrentClass->GetSuperClass();
406
+ }
407
+
408
+ // Special handling for known functions
409
+ if (!Function)
410
+ {
411
+ if (TargetClass->GetName() == TEXT("GameplayStatics") &&
412
+ (FunctionName == TEXT("GetActorOfClass") || FunctionName.Equals(TEXT("GetActorOfClass"), ESearchCase::IgnoreCase)))
413
+ {
414
+ UE_LOG(LogTemp, Display, TEXT("Using special case handling for GameplayStatics::GetActorOfClass"));
415
+
416
+ // Create the function node directly
417
+ FunctionNode = NewObject<UK2Node_CallFunction>(EventGraph);
418
+ if (FunctionNode)
419
+ {
420
+ // Direct setup for known function
421
+ FunctionNode->FunctionReference.SetExternalMember(
422
+ FName(TEXT("GetActorOfClass")),
423
+ TargetClass
424
+ );
425
+
426
+ FunctionNode->NodePosX = NodePosition.X;
427
+ FunctionNode->NodePosY = NodePosition.Y;
428
+ EventGraph->AddNode(FunctionNode);
429
+ FunctionNode->CreateNewGuid();
430
+ FunctionNode->PostPlacedNewNode();
431
+ FunctionNode->AllocateDefaultPins();
432
+
433
+ UE_LOG(LogTemp, Display, TEXT("Created GetActorOfClass node directly"));
434
+
435
+ // List all pins
436
+ for (UEdGraphPin* Pin : FunctionNode->Pins)
437
+ {
438
+ UE_LOG(LogTemp, Display, TEXT(" - Pin: %s, Direction: %d, Category: %s"),
439
+ *Pin->PinName.ToString(), (int32)Pin->Direction, *Pin->PinType.PinCategory.ToString());
440
+ }
441
+ }
442
+ }
443
+ }
444
+ }
445
+ }
446
+
447
+ // If we still haven't found the function, try in the blueprint's class
448
+ if (!Function && !FunctionNode)
449
+ {
450
+ UE_LOG(LogTemp, Display, TEXT("Trying to find function in blueprint class"));
451
+ Function = Blueprint->GeneratedClass->FindFunctionByName(*FunctionName);
452
+ }
453
+
454
+ // Create the function call node if we found the function
455
+ if (Function && !FunctionNode)
456
+ {
457
+ FunctionNode = FUnrealMCPCommonUtils::CreateFunctionCallNode(EventGraph, Function, NodePosition);
458
+ }
459
+
460
+ if (!FunctionNode)
461
+ {
462
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Function not found: %s in target %s"), *FunctionName, Target.IsEmpty() ? TEXT("Blueprint") : *Target));
463
+ }
464
+
465
+ // Set parameters if provided
466
+ if (Params->HasField(TEXT("params")))
467
+ {
468
+ const TSharedPtr<FJsonObject>* ParamsObj;
469
+ if (Params->TryGetObjectField(TEXT("params"), ParamsObj))
470
+ {
471
+ // Process parameters
472
+ for (const TPair<FString, TSharedPtr<FJsonValue>>& Param : (*ParamsObj)->Values)
473
+ {
474
+ const FString& ParamName = Param.Key;
475
+ const TSharedPtr<FJsonValue>& ParamValue = Param.Value;
476
+
477
+ // Find the parameter pin
478
+ UEdGraphPin* ParamPin = FUnrealMCPCommonUtils::FindPin(FunctionNode, ParamName, EGPD_Input);
479
+ if (ParamPin)
480
+ {
481
+ UE_LOG(LogTemp, Display, TEXT("Found parameter pin '%s' of category '%s'"),
482
+ *ParamName, *ParamPin->PinType.PinCategory.ToString());
483
+ UE_LOG(LogTemp, Display, TEXT(" Current default value: '%s'"), *ParamPin->DefaultValue);
484
+ if (ParamPin->PinType.PinSubCategoryObject.IsValid())
485
+ {
486
+ UE_LOG(LogTemp, Display, TEXT(" Pin subcategory: '%s'"),
487
+ *ParamPin->PinType.PinSubCategoryObject->GetName());
488
+ }
489
+
490
+ // Set parameter based on type
491
+ if (ParamValue->Type == EJson::String)
492
+ {
493
+ FString StringVal = ParamValue->AsString();
494
+ UE_LOG(LogTemp, Display, TEXT(" Setting string parameter '%s' to: '%s'"),
495
+ *ParamName, *StringVal);
496
+
497
+ // Handle class reference parameters (e.g., ActorClass in GetActorOfClass)
498
+ if (ParamPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Class)
499
+ {
500
+ // For class references, we require the exact class name with proper prefix
501
+ // - Actor classes must start with 'A' (e.g., ACameraActor)
502
+ // - Non-actor classes must start with 'U' (e.g., UObject)
503
+ const FString& ClassName = StringVal;
504
+
505
+ // TODO: This likely won't work in UE5.5+, so don't rely on it.
506
+ UClass* Class = FindObject<UClass>(ANY_PACKAGE, *ClassName);
507
+
508
+ if (!Class)
509
+ {
510
+ Class = LoadObject<UClass>(nullptr, *ClassName);
511
+ UE_LOG(LogUnrealMCP, Display, TEXT("FindObject<UClass> failed. Assuming soft path path: %s"), *ClassName);
512
+ }
513
+
514
+ // If not found, try with Engine module path
515
+ if (!Class)
516
+ {
517
+ FString EngineClassName = FString::Printf(TEXT("/Script/Engine.%s"), *ClassName);
518
+ Class = LoadObject<UClass>(nullptr, *EngineClassName);
519
+ UE_LOG(LogUnrealMCP, Display, TEXT("Trying Engine module path: %s"), *EngineClassName);
520
+ }
521
+
522
+ if (!Class)
523
+ {
524
+ UE_LOG(LogUnrealMCP, Error, TEXT("Failed to find class '%s'. Make sure to use the exact class name with proper prefix (A for actors, U for non-actors)"), *ClassName);
525
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Failed to find class '%s'"), *ClassName));
526
+ }
527
+
528
+ const UEdGraphSchema_K2* K2Schema = Cast<const UEdGraphSchema_K2>(EventGraph->GetSchema());
529
+ if (!K2Schema)
530
+ {
531
+ UE_LOG(LogUnrealMCP, Error, TEXT("Failed to get K2Schema"));
532
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to get K2Schema"));
533
+ }
534
+
535
+ K2Schema->TrySetDefaultObject(*ParamPin, Class);
536
+ if (ParamPin->DefaultObject != Class)
537
+ {
538
+ UE_LOG(LogUnrealMCP, Error, TEXT("Failed to set class reference for pin '%s' to '%s'"), *ParamPin->PinName.ToString(), *ClassName);
539
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Failed to set class reference for pin '%s'"), *ParamPin->PinName.ToString()));
540
+ }
541
+
542
+ UE_LOG(LogUnrealMCP, Log, TEXT("Successfully set class reference for pin '%s' to '%s'"), *ParamPin->PinName.ToString(), *ClassName);
543
+ continue;
544
+ }
545
+ else if (ParamPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Int)
546
+ {
547
+ // Ensure we're using an integer value (no decimal)
548
+ int32 IntValue = FMath::RoundToInt(ParamValue->AsNumber());
549
+ ParamPin->DefaultValue = FString::FromInt(IntValue);
550
+ UE_LOG(LogTemp, Display, TEXT(" Set integer parameter '%s' to: %d (string: '%s')"),
551
+ *ParamName, IntValue, *ParamPin->DefaultValue);
552
+ }
553
+ else if (ParamPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Float)
554
+ {
555
+ // For other numeric types
556
+ float FloatValue = ParamValue->AsNumber();
557
+ ParamPin->DefaultValue = FString::SanitizeFloat(FloatValue);
558
+ UE_LOG(LogTemp, Display, TEXT(" Set float parameter '%s' to: %f (string: '%s')"),
559
+ *ParamName, FloatValue, *ParamPin->DefaultValue);
560
+ }
561
+ else if (ParamPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Boolean)
562
+ {
563
+ bool BoolValue = ParamValue->AsBool();
564
+ ParamPin->DefaultValue = BoolValue ? TEXT("true") : TEXT("false");
565
+ UE_LOG(LogTemp, Display, TEXT(" Set boolean parameter '%s' to: %s"),
566
+ *ParamName, *ParamPin->DefaultValue);
567
+ }
568
+ else if (ParamPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Struct && ParamPin->PinType.PinSubCategoryObject == TBaseStructure<FVector>::Get())
569
+ {
570
+ // Handle array parameters - like Vector parameters
571
+ const TArray<TSharedPtr<FJsonValue>>* ArrayValue;
572
+ if (ParamValue->TryGetArray(ArrayValue))
573
+ {
574
+ // Check if this could be a vector (array of 3 numbers)
575
+ if (ArrayValue->Num() == 3)
576
+ {
577
+ // Create a proper vector string: (X=0.0,Y=0.0,Z=1000.0)
578
+ float X = (*ArrayValue)[0]->AsNumber();
579
+ float Y = (*ArrayValue)[1]->AsNumber();
580
+ float Z = (*ArrayValue)[2]->AsNumber();
581
+
582
+ FString VectorString = FString::Printf(TEXT("(X=%f,Y=%f,Z=%f)"), X, Y, Z);
583
+ ParamPin->DefaultValue = VectorString;
584
+
585
+ UE_LOG(LogTemp, Display, TEXT(" Set vector parameter '%s' to: %s"),
586
+ *ParamName, *VectorString);
587
+ UE_LOG(LogTemp, Display, TEXT(" Final pin value: '%s'"),
588
+ *ParamPin->DefaultValue);
589
+ }
590
+ else
591
+ {
592
+ UE_LOG(LogTemp, Warning, TEXT("Array parameter type not fully supported yet"));
593
+ }
594
+ }
595
+ }
596
+ }
597
+ else if (ParamValue->Type == EJson::Number)
598
+ {
599
+ // Handle integer vs float parameters correctly
600
+ if (ParamPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Int)
601
+ {
602
+ // Ensure we're using an integer value (no decimal)
603
+ int32 IntValue = FMath::RoundToInt(ParamValue->AsNumber());
604
+ ParamPin->DefaultValue = FString::FromInt(IntValue);
605
+ UE_LOG(LogTemp, Display, TEXT(" Set integer parameter '%s' to: %d (string: '%s')"),
606
+ *ParamName, IntValue, *ParamPin->DefaultValue);
607
+ }
608
+ else
609
+ {
610
+ // For other numeric types
611
+ float FloatValue = ParamValue->AsNumber();
612
+ ParamPin->DefaultValue = FString::SanitizeFloat(FloatValue);
613
+ UE_LOG(LogTemp, Display, TEXT(" Set float parameter '%s' to: %f (string: '%s')"),
614
+ *ParamName, FloatValue, *ParamPin->DefaultValue);
615
+ }
616
+ }
617
+ else if (ParamValue->Type == EJson::Boolean)
618
+ {
619
+ bool BoolValue = ParamValue->AsBool();
620
+ ParamPin->DefaultValue = BoolValue ? TEXT("true") : TEXT("false");
621
+ UE_LOG(LogTemp, Display, TEXT(" Set boolean parameter '%s' to: %s"),
622
+ *ParamName, *ParamPin->DefaultValue);
623
+ }
624
+ else if (ParamValue->Type == EJson::Array)
625
+ {
626
+ UE_LOG(LogTemp, Display, TEXT(" Processing array parameter '%s'"), *ParamName);
627
+ // Handle array parameters - like Vector parameters
628
+ const TArray<TSharedPtr<FJsonValue>>* ArrayValue;
629
+ if (ParamValue->TryGetArray(ArrayValue))
630
+ {
631
+ // Check if this could be a vector (array of 3 numbers)
632
+ if (ArrayValue->Num() == 3 &&
633
+ (ParamPin->PinType.PinCategory == UEdGraphSchema_K2::PC_Struct) &&
634
+ (ParamPin->PinType.PinSubCategoryObject == TBaseStructure<FVector>::Get()))
635
+ {
636
+ // Create a proper vector string: (X=0.0,Y=0.0,Z=1000.0)
637
+ float X = (*ArrayValue)[0]->AsNumber();
638
+ float Y = (*ArrayValue)[1]->AsNumber();
639
+ float Z = (*ArrayValue)[2]->AsNumber();
640
+
641
+ FString VectorString = FString::Printf(TEXT("(X=%f,Y=%f,Z=%f)"), X, Y, Z);
642
+ ParamPin->DefaultValue = VectorString;
643
+
644
+ UE_LOG(LogTemp, Display, TEXT(" Set vector parameter '%s' to: %s"),
645
+ *ParamName, *VectorString);
646
+ UE_LOG(LogTemp, Display, TEXT(" Final pin value: '%s'"),
647
+ *ParamPin->DefaultValue);
648
+ }
649
+ else
650
+ {
651
+ UE_LOG(LogTemp, Warning, TEXT("Array parameter type not fully supported yet"));
652
+ }
653
+ }
654
+ }
655
+ // Add handling for other types as needed
656
+ }
657
+ else
658
+ {
659
+ UE_LOG(LogTemp, Warning, TEXT("Parameter pin '%s' not found"), *ParamName);
660
+ }
661
+ }
662
+ }
663
+ }
664
+
665
+ // Mark the blueprint as modified
666
+ FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
667
+
668
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
669
+ ResultObj->SetStringField(TEXT("node_id"), FunctionNode->NodeGuid.ToString());
670
+ return ResultObj;
671
+ }
672
+
673
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintVariable(const TSharedPtr<FJsonObject>& Params)
674
+ {
675
+ // Get required parameters
676
+ FString BlueprintName;
677
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
678
+ {
679
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
680
+ }
681
+
682
+ FString VariableName;
683
+ if (!Params->TryGetStringField(TEXT("variable_name"), VariableName))
684
+ {
685
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'variable_name' parameter"));
686
+ }
687
+
688
+ FString VariableType;
689
+ if (!Params->TryGetStringField(TEXT("variable_type"), VariableType))
690
+ {
691
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'variable_type' parameter"));
692
+ }
693
+
694
+ // Get optional parameters
695
+ bool IsExposed = false;
696
+ if (Params->HasField(TEXT("is_exposed")))
697
+ {
698
+ IsExposed = Params->GetBoolField(TEXT("is_exposed"));
699
+ }
700
+
701
+ // Find the blueprint
702
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
703
+ if (!Blueprint)
704
+ {
705
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
706
+ }
707
+
708
+ // Create variable based on type
709
+ FEdGraphPinType PinType;
710
+
711
+ // Set up pin type based on variable_type string
712
+ if (VariableType == TEXT("Boolean"))
713
+ {
714
+ PinType.PinCategory = UEdGraphSchema_K2::PC_Boolean;
715
+ }
716
+ else if (VariableType == TEXT("Integer") || VariableType == TEXT("Int"))
717
+ {
718
+ PinType.PinCategory = UEdGraphSchema_K2::PC_Int;
719
+ }
720
+ else if (VariableType == TEXT("Float"))
721
+ {
722
+ PinType.PinCategory = UEdGraphSchema_K2::PC_Float;
723
+ }
724
+ else if (VariableType == TEXT("String"))
725
+ {
726
+ PinType.PinCategory = UEdGraphSchema_K2::PC_String;
727
+ }
728
+ else if (VariableType == TEXT("Vector"))
729
+ {
730
+ PinType.PinCategory = UEdGraphSchema_K2::PC_Struct;
731
+ PinType.PinSubCategoryObject = TBaseStructure<FVector>::Get();
732
+ }
733
+ else
734
+ {
735
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Unsupported variable type: %s"), *VariableType));
736
+ }
737
+
738
+ // Create the variable
739
+ FBlueprintEditorUtils::AddMemberVariable(Blueprint, FName(*VariableName), PinType);
740
+
741
+ // Set variable properties
742
+ FBPVariableDescription* NewVar = nullptr;
743
+ for (FBPVariableDescription& Variable : Blueprint->NewVariables)
744
+ {
745
+ if (Variable.VarName == FName(*VariableName))
746
+ {
747
+ NewVar = &Variable;
748
+ break;
749
+ }
750
+ }
751
+
752
+ if (NewVar)
753
+ {
754
+ // Set exposure in editor
755
+ if (IsExposed)
756
+ {
757
+ NewVar->PropertyFlags |= CPF_Edit;
758
+ }
759
+ }
760
+
761
+ // Mark the blueprint as modified
762
+ FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
763
+
764
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
765
+ ResultObj->SetStringField(TEXT("variable_name"), VariableName);
766
+ ResultObj->SetStringField(TEXT("variable_type"), VariableType);
767
+ return ResultObj;
768
+ }
769
+
770
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintInputActionNode(const TSharedPtr<FJsonObject>& Params)
771
+ {
772
+ // Get required parameters
773
+ FString BlueprintName;
774
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
775
+ {
776
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
777
+ }
778
+
779
+ FString ActionName;
780
+ if (!Params->TryGetStringField(TEXT("action_name"), ActionName))
781
+ {
782
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'action_name' parameter"));
783
+ }
784
+
785
+ // Get position parameters (optional)
786
+ FVector2D NodePosition(0.0f, 0.0f);
787
+ if (Params->HasField(TEXT("node_position")))
788
+ {
789
+ NodePosition = FUnrealMCPCommonUtils::GetVector2DFromJson(Params, TEXT("node_position"));
790
+ }
791
+
792
+ // Find the blueprint
793
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
794
+ if (!Blueprint)
795
+ {
796
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
797
+ }
798
+
799
+ // Get the event graph
800
+ UEdGraph* EventGraph = FUnrealMCPCommonUtils::FindOrCreateEventGraph(Blueprint);
801
+ if (!EventGraph)
802
+ {
803
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to get event graph"));
804
+ }
805
+
806
+ // Create the input action node
807
+ UK2Node_InputAction* InputActionNode = FUnrealMCPCommonUtils::CreateInputActionNode(EventGraph, ActionName, NodePosition);
808
+ if (!InputActionNode)
809
+ {
810
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to create input action node"));
811
+ }
812
+
813
+ // Mark the blueprint as modified
814
+ FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
815
+
816
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
817
+ ResultObj->SetStringField(TEXT("node_id"), InputActionNode->NodeGuid.ToString());
818
+ return ResultObj;
819
+ }
820
+
821
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintSelfReference(const TSharedPtr<FJsonObject>& Params)
822
+ {
823
+ // Get required parameters
824
+ FString BlueprintName;
825
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
826
+ {
827
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
828
+ }
829
+
830
+ // Get position parameters (optional)
831
+ FVector2D NodePosition(0.0f, 0.0f);
832
+ if (Params->HasField(TEXT("node_position")))
833
+ {
834
+ NodePosition = FUnrealMCPCommonUtils::GetVector2DFromJson(Params, TEXT("node_position"));
835
+ }
836
+
837
+ // Find the blueprint
838
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
839
+ if (!Blueprint)
840
+ {
841
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
842
+ }
843
+
844
+ // Get the event graph
845
+ UEdGraph* EventGraph = FUnrealMCPCommonUtils::FindOrCreateEventGraph(Blueprint);
846
+ if (!EventGraph)
847
+ {
848
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to get event graph"));
849
+ }
850
+
851
+ // Create the self node
852
+ UK2Node_Self* SelfNode = FUnrealMCPCommonUtils::CreateSelfReferenceNode(EventGraph, NodePosition);
853
+ if (!SelfNode)
854
+ {
855
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to create self node"));
856
+ }
857
+
858
+ // Mark the blueprint as modified
859
+ FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
860
+
861
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
862
+ ResultObj->SetStringField(TEXT("node_id"), SelfNode->NodeGuid.ToString());
863
+ return ResultObj;
864
+ }
865
+
866
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleFindBlueprintNodes(const TSharedPtr<FJsonObject>& Params)
867
+ {
868
+ // Get required parameters
869
+ FString BlueprintName;
870
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
871
+ {
872
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
873
+ }
874
+
875
+ FString NodeType;
876
+ if (!Params->TryGetStringField(TEXT("node_type"), NodeType))
877
+ {
878
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'node_type' parameter"));
879
+ }
880
+
881
+ // Find the blueprint
882
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
883
+ if (!Blueprint)
884
+ {
885
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
886
+ }
887
+
888
+ // Get the event graph
889
+ UEdGraph* EventGraph = FUnrealMCPCommonUtils::FindOrCreateEventGraph(Blueprint);
890
+ if (!EventGraph)
891
+ {
892
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to get event graph"));
893
+ }
894
+
895
+ // Create a JSON array for the node GUIDs
896
+ TArray<TSharedPtr<FJsonValue>> NodeGuidArray;
897
+
898
+ // Filter nodes by the exact requested type
899
+ if (NodeType == TEXT("Event"))
900
+ {
901
+ FString EventName;
902
+ if (!Params->TryGetStringField(TEXT("event_name"), EventName))
903
+ {
904
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'event_name' parameter for Event node search"));
905
+ }
906
+
907
+ // Look for nodes with exact event name (e.g., ReceiveBeginPlay)
908
+ for (UEdGraphNode* Node : EventGraph->Nodes)
909
+ {
910
+ UK2Node_Event* EventNode = Cast<UK2Node_Event>(Node);
911
+ if (EventNode && EventNode->EventReference.GetMemberName() == FName(*EventName))
912
+ {
913
+ UE_LOG(LogTemp, Display, TEXT("Found event node with name %s: %s"), *EventName, *EventNode->NodeGuid.ToString());
914
+ NodeGuidArray.Add(MakeShared<FJsonValueString>(EventNode->NodeGuid.ToString()));
915
+ }
916
+ }
917
+ }
918
+ // Add other node types as needed (InputAction, etc.)
919
+
920
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
921
+ ResultObj->SetArrayField(TEXT("node_guids"), NodeGuidArray);
922
+
923
+ return ResultObj;
924
+ }