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,709 @@
1
+ #include "Commands/UnrealMCPCommonUtils.h"
2
+ #include "GameFramework/Actor.h"
3
+ #include "Engine/Blueprint.h"
4
+ #include "EdGraph/EdGraph.h"
5
+ #include "EdGraph/EdGraphNode.h"
6
+ #include "EdGraph/EdGraphPin.h"
7
+ #include "K2Node_Event.h"
8
+ #include "K2Node_CallFunction.h"
9
+ #include "K2Node_VariableGet.h"
10
+ #include "K2Node_VariableSet.h"
11
+ #include "K2Node_InputAction.h"
12
+ #include "K2Node_Self.h"
13
+ #include "EdGraphSchema_K2.h"
14
+ #include "Kismet2/BlueprintEditorUtils.h"
15
+ #include "Components/StaticMeshComponent.h"
16
+ #include "Components/LightComponent.h"
17
+ #include "Components/PrimitiveComponent.h"
18
+ #include "Components/SceneComponent.h"
19
+ #include "UObject/UObjectIterator.h"
20
+ #include "Engine/Selection.h"
21
+ #include "EditorAssetLibrary.h"
22
+ #include "AssetRegistry/AssetRegistryModule.h"
23
+ #include "Engine/BlueprintGeneratedClass.h"
24
+ #include "BlueprintNodeSpawner.h"
25
+ #include "BlueprintActionDatabase.h"
26
+ #include "Dom/JsonObject.h"
27
+ #include "Dom/JsonValue.h"
28
+
29
+ // JSON Utilities
30
+ TSharedPtr<FJsonObject> FUnrealMCPCommonUtils::CreateErrorResponse(const FString& Message)
31
+ {
32
+ TSharedPtr<FJsonObject> ResponseObject = MakeShared<FJsonObject>();
33
+ ResponseObject->SetBoolField(TEXT("success"), false);
34
+ ResponseObject->SetStringField(TEXT("error"), Message);
35
+ return ResponseObject;
36
+ }
37
+
38
+ TSharedPtr<FJsonObject> FUnrealMCPCommonUtils::CreateSuccessResponse(const TSharedPtr<FJsonObject>& Data)
39
+ {
40
+ TSharedPtr<FJsonObject> ResponseObject = MakeShared<FJsonObject>();
41
+ ResponseObject->SetBoolField(TEXT("success"), true);
42
+
43
+ if (Data.IsValid())
44
+ {
45
+ ResponseObject->SetObjectField(TEXT("data"), Data);
46
+ }
47
+
48
+ return ResponseObject;
49
+ }
50
+
51
+ void FUnrealMCPCommonUtils::GetIntArrayFromJson(const TSharedPtr<FJsonObject>& JsonObject, const FString& FieldName, TArray<int32>& OutArray)
52
+ {
53
+ OutArray.Reset();
54
+
55
+ if (!JsonObject->HasField(FieldName))
56
+ {
57
+ return;
58
+ }
59
+
60
+ const TArray<TSharedPtr<FJsonValue>>* JsonArray;
61
+ if (JsonObject->TryGetArrayField(FieldName, JsonArray))
62
+ {
63
+ for (const TSharedPtr<FJsonValue>& Value : *JsonArray)
64
+ {
65
+ OutArray.Add((int32)Value->AsNumber());
66
+ }
67
+ }
68
+ }
69
+
70
+ void FUnrealMCPCommonUtils::GetFloatArrayFromJson(const TSharedPtr<FJsonObject>& JsonObject, const FString& FieldName, TArray<float>& OutArray)
71
+ {
72
+ OutArray.Reset();
73
+
74
+ if (!JsonObject->HasField(FieldName))
75
+ {
76
+ return;
77
+ }
78
+
79
+ const TArray<TSharedPtr<FJsonValue>>* JsonArray;
80
+ if (JsonObject->TryGetArrayField(FieldName, JsonArray))
81
+ {
82
+ for (const TSharedPtr<FJsonValue>& Value : *JsonArray)
83
+ {
84
+ OutArray.Add((float)Value->AsNumber());
85
+ }
86
+ }
87
+ }
88
+
89
+ FVector2D FUnrealMCPCommonUtils::GetVector2DFromJson(const TSharedPtr<FJsonObject>& JsonObject, const FString& FieldName)
90
+ {
91
+ FVector2D Result(0.0f, 0.0f);
92
+
93
+ if (!JsonObject->HasField(FieldName))
94
+ {
95
+ return Result;
96
+ }
97
+
98
+ const TArray<TSharedPtr<FJsonValue>>* JsonArray;
99
+ if (JsonObject->TryGetArrayField(FieldName, JsonArray) && JsonArray->Num() >= 2)
100
+ {
101
+ Result.X = (float)(*JsonArray)[0]->AsNumber();
102
+ Result.Y = (float)(*JsonArray)[1]->AsNumber();
103
+ }
104
+
105
+ return Result;
106
+ }
107
+
108
+ FVector FUnrealMCPCommonUtils::GetVectorFromJson(const TSharedPtr<FJsonObject>& JsonObject, const FString& FieldName)
109
+ {
110
+ FVector Result(0.0f, 0.0f, 0.0f);
111
+
112
+ if (!JsonObject->HasField(FieldName))
113
+ {
114
+ return Result;
115
+ }
116
+
117
+ const TArray<TSharedPtr<FJsonValue>>* JsonArray;
118
+ if (JsonObject->TryGetArrayField(FieldName, JsonArray) && JsonArray->Num() >= 3)
119
+ {
120
+ Result.X = (float)(*JsonArray)[0]->AsNumber();
121
+ Result.Y = (float)(*JsonArray)[1]->AsNumber();
122
+ Result.Z = (float)(*JsonArray)[2]->AsNumber();
123
+ }
124
+
125
+ return Result;
126
+ }
127
+
128
+ FRotator FUnrealMCPCommonUtils::GetRotatorFromJson(const TSharedPtr<FJsonObject>& JsonObject, const FString& FieldName)
129
+ {
130
+ FRotator Result(0.0f, 0.0f, 0.0f);
131
+
132
+ if (!JsonObject->HasField(FieldName))
133
+ {
134
+ return Result;
135
+ }
136
+
137
+ const TArray<TSharedPtr<FJsonValue>>* JsonArray;
138
+ if (JsonObject->TryGetArrayField(FieldName, JsonArray) && JsonArray->Num() >= 3)
139
+ {
140
+ Result.Pitch = (float)(*JsonArray)[0]->AsNumber();
141
+ Result.Yaw = (float)(*JsonArray)[1]->AsNumber();
142
+ Result.Roll = (float)(*JsonArray)[2]->AsNumber();
143
+ }
144
+
145
+ return Result;
146
+ }
147
+
148
+ // Blueprint Utilities
149
+ UBlueprint* FUnrealMCPCommonUtils::FindBlueprint(const FString& BlueprintName)
150
+ {
151
+ return FindBlueprintByName(BlueprintName);
152
+ }
153
+
154
+ UBlueprint* FUnrealMCPCommonUtils::FindBlueprintByName(const FString& BlueprintName)
155
+ {
156
+ FString AssetPath = TEXT("/Game/Blueprints/") + BlueprintName;
157
+ return LoadObject<UBlueprint>(nullptr, *AssetPath);
158
+ }
159
+
160
+ UEdGraph* FUnrealMCPCommonUtils::FindOrCreateEventGraph(UBlueprint* Blueprint)
161
+ {
162
+ if (!Blueprint)
163
+ {
164
+ return nullptr;
165
+ }
166
+
167
+ // Try to find the event graph
168
+ for (UEdGraph* Graph : Blueprint->UbergraphPages)
169
+ {
170
+ if (Graph->GetName().Contains(TEXT("EventGraph")))
171
+ {
172
+ return Graph;
173
+ }
174
+ }
175
+
176
+ // Create a new event graph if none exists
177
+ UEdGraph* NewGraph = FBlueprintEditorUtils::CreateNewGraph(Blueprint, FName(TEXT("EventGraph")), UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
178
+ FBlueprintEditorUtils::AddUbergraphPage(Blueprint, NewGraph);
179
+ return NewGraph;
180
+ }
181
+
182
+ // Blueprint node utilities
183
+ UK2Node_Event* FUnrealMCPCommonUtils::CreateEventNode(UEdGraph* Graph, const FString& EventName, const FVector2D& Position)
184
+ {
185
+ if (!Graph)
186
+ {
187
+ return nullptr;
188
+ }
189
+
190
+ UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForGraph(Graph);
191
+ if (!Blueprint)
192
+ {
193
+ return nullptr;
194
+ }
195
+
196
+ // Check for existing event node with this exact name
197
+ for (UEdGraphNode* Node : Graph->Nodes)
198
+ {
199
+ UK2Node_Event* EventNode = Cast<UK2Node_Event>(Node);
200
+ if (EventNode && EventNode->EventReference.GetMemberName() == FName(*EventName))
201
+ {
202
+ UE_LOG(LogTemp, Display, TEXT("Using existing event node with name %s (ID: %s)"),
203
+ *EventName, *EventNode->NodeGuid.ToString());
204
+ return EventNode;
205
+ }
206
+ }
207
+
208
+ // No existing node found, create a new one
209
+ UK2Node_Event* EventNode = nullptr;
210
+
211
+ // Find the function to create the event
212
+ UClass* BlueprintClass = Blueprint->GeneratedClass;
213
+ UFunction* EventFunction = BlueprintClass->FindFunctionByName(FName(*EventName));
214
+
215
+ if (EventFunction)
216
+ {
217
+ EventNode = NewObject<UK2Node_Event>(Graph);
218
+ EventNode->EventReference.SetExternalMember(FName(*EventName), BlueprintClass);
219
+ EventNode->NodePosX = Position.X;
220
+ EventNode->NodePosY = Position.Y;
221
+ Graph->AddNode(EventNode, true);
222
+ EventNode->PostPlacedNewNode();
223
+ EventNode->AllocateDefaultPins();
224
+ UE_LOG(LogTemp, Display, TEXT("Created new event node with name %s (ID: %s)"),
225
+ *EventName, *EventNode->NodeGuid.ToString());
226
+ }
227
+ else
228
+ {
229
+ UE_LOG(LogTemp, Error, TEXT("Failed to find function for event name: %s"), *EventName);
230
+ }
231
+
232
+ return EventNode;
233
+ }
234
+
235
+ UK2Node_CallFunction* FUnrealMCPCommonUtils::CreateFunctionCallNode(UEdGraph* Graph, UFunction* Function, const FVector2D& Position)
236
+ {
237
+ if (!Graph || !Function)
238
+ {
239
+ return nullptr;
240
+ }
241
+
242
+ UK2Node_CallFunction* FunctionNode = NewObject<UK2Node_CallFunction>(Graph);
243
+ FunctionNode->SetFromFunction(Function);
244
+ FunctionNode->NodePosX = Position.X;
245
+ FunctionNode->NodePosY = Position.Y;
246
+ Graph->AddNode(FunctionNode, true);
247
+ FunctionNode->CreateNewGuid();
248
+ FunctionNode->PostPlacedNewNode();
249
+ FunctionNode->AllocateDefaultPins();
250
+
251
+ return FunctionNode;
252
+ }
253
+
254
+ UK2Node_VariableGet* FUnrealMCPCommonUtils::CreateVariableGetNode(UEdGraph* Graph, UBlueprint* Blueprint, const FString& VariableName, const FVector2D& Position)
255
+ {
256
+ if (!Graph || !Blueprint)
257
+ {
258
+ return nullptr;
259
+ }
260
+
261
+ UK2Node_VariableGet* VariableGetNode = NewObject<UK2Node_VariableGet>(Graph);
262
+
263
+ FName VarName(*VariableName);
264
+ FProperty* Property = FindFProperty<FProperty>(Blueprint->GeneratedClass, VarName);
265
+
266
+ if (Property)
267
+ {
268
+ VariableGetNode->VariableReference.SetFromField<FProperty>(Property, false);
269
+ VariableGetNode->NodePosX = Position.X;
270
+ VariableGetNode->NodePosY = Position.Y;
271
+ Graph->AddNode(VariableGetNode, true);
272
+ VariableGetNode->PostPlacedNewNode();
273
+ VariableGetNode->AllocateDefaultPins();
274
+
275
+ return VariableGetNode;
276
+ }
277
+
278
+ return nullptr;
279
+ }
280
+
281
+ UK2Node_VariableSet* FUnrealMCPCommonUtils::CreateVariableSetNode(UEdGraph* Graph, UBlueprint* Blueprint, const FString& VariableName, const FVector2D& Position)
282
+ {
283
+ if (!Graph || !Blueprint)
284
+ {
285
+ return nullptr;
286
+ }
287
+
288
+ UK2Node_VariableSet* VariableSetNode = NewObject<UK2Node_VariableSet>(Graph);
289
+
290
+ FName VarName(*VariableName);
291
+ FProperty* Property = FindFProperty<FProperty>(Blueprint->GeneratedClass, VarName);
292
+
293
+ if (Property)
294
+ {
295
+ VariableSetNode->VariableReference.SetFromField<FProperty>(Property, false);
296
+ VariableSetNode->NodePosX = Position.X;
297
+ VariableSetNode->NodePosY = Position.Y;
298
+ Graph->AddNode(VariableSetNode, true);
299
+ VariableSetNode->PostPlacedNewNode();
300
+ VariableSetNode->AllocateDefaultPins();
301
+
302
+ return VariableSetNode;
303
+ }
304
+
305
+ return nullptr;
306
+ }
307
+
308
+ UK2Node_InputAction* FUnrealMCPCommonUtils::CreateInputActionNode(UEdGraph* Graph, const FString& ActionName, const FVector2D& Position)
309
+ {
310
+ if (!Graph)
311
+ {
312
+ return nullptr;
313
+ }
314
+
315
+ UK2Node_InputAction* InputActionNode = NewObject<UK2Node_InputAction>(Graph);
316
+ InputActionNode->InputActionName = FName(*ActionName);
317
+ InputActionNode->NodePosX = Position.X;
318
+ InputActionNode->NodePosY = Position.Y;
319
+ Graph->AddNode(InputActionNode, true);
320
+ InputActionNode->CreateNewGuid();
321
+ InputActionNode->PostPlacedNewNode();
322
+ InputActionNode->AllocateDefaultPins();
323
+
324
+ return InputActionNode;
325
+ }
326
+
327
+ UK2Node_Self* FUnrealMCPCommonUtils::CreateSelfReferenceNode(UEdGraph* Graph, const FVector2D& Position)
328
+ {
329
+ if (!Graph)
330
+ {
331
+ return nullptr;
332
+ }
333
+
334
+ UK2Node_Self* SelfNode = NewObject<UK2Node_Self>(Graph);
335
+ SelfNode->NodePosX = Position.X;
336
+ SelfNode->NodePosY = Position.Y;
337
+ Graph->AddNode(SelfNode, true);
338
+ SelfNode->CreateNewGuid();
339
+ SelfNode->PostPlacedNewNode();
340
+ SelfNode->AllocateDefaultPins();
341
+
342
+ return SelfNode;
343
+ }
344
+
345
+ bool FUnrealMCPCommonUtils::ConnectGraphNodes(UEdGraph* Graph, UEdGraphNode* SourceNode, const FString& SourcePinName,
346
+ UEdGraphNode* TargetNode, const FString& TargetPinName)
347
+ {
348
+ if (!Graph || !SourceNode || !TargetNode)
349
+ {
350
+ return false;
351
+ }
352
+
353
+ UEdGraphPin* SourcePin = FindPin(SourceNode, SourcePinName, EGPD_Output);
354
+ UEdGraphPin* TargetPin = FindPin(TargetNode, TargetPinName, EGPD_Input);
355
+
356
+ if (SourcePin && TargetPin)
357
+ {
358
+ SourcePin->MakeLinkTo(TargetPin);
359
+ return true;
360
+ }
361
+
362
+ return false;
363
+ }
364
+
365
+ UEdGraphPin* FUnrealMCPCommonUtils::FindPin(UEdGraphNode* Node, const FString& PinName, EEdGraphPinDirection Direction)
366
+ {
367
+ if (!Node)
368
+ {
369
+ return nullptr;
370
+ }
371
+
372
+ // Log all pins for debugging
373
+ UE_LOG(LogTemp, Display, TEXT("FindPin: Looking for pin '%s' (Direction: %d) in node '%s'"),
374
+ *PinName, (int32)Direction, *Node->GetName());
375
+
376
+ for (UEdGraphPin* Pin : Node->Pins)
377
+ {
378
+ UE_LOG(LogTemp, Display, TEXT(" - Available pin: '%s', Direction: %d, Category: %s"),
379
+ *Pin->PinName.ToString(), (int32)Pin->Direction, *Pin->PinType.PinCategory.ToString());
380
+ }
381
+
382
+ // First try exact match
383
+ for (UEdGraphPin* Pin : Node->Pins)
384
+ {
385
+ if (Pin->PinName.ToString() == PinName && (Direction == EGPD_MAX || Pin->Direction == Direction))
386
+ {
387
+ UE_LOG(LogTemp, Display, TEXT(" - Found exact matching pin: '%s'"), *Pin->PinName.ToString());
388
+ return Pin;
389
+ }
390
+ }
391
+
392
+ // If no exact match and we're looking for a component reference, try case-insensitive match
393
+ for (UEdGraphPin* Pin : Node->Pins)
394
+ {
395
+ if (Pin->PinName.ToString().Equals(PinName, ESearchCase::IgnoreCase) &&
396
+ (Direction == EGPD_MAX || Pin->Direction == Direction))
397
+ {
398
+ UE_LOG(LogTemp, Display, TEXT(" - Found case-insensitive matching pin: '%s'"), *Pin->PinName.ToString());
399
+ return Pin;
400
+ }
401
+ }
402
+
403
+ // If we're looking for a component output and didn't find it by name, try to find the first data output pin
404
+ if (Direction == EGPD_Output && Cast<UK2Node_VariableGet>(Node) != nullptr)
405
+ {
406
+ for (UEdGraphPin* Pin : Node->Pins)
407
+ {
408
+ if (Pin->Direction == EGPD_Output && Pin->PinType.PinCategory != UEdGraphSchema_K2::PC_Exec)
409
+ {
410
+ UE_LOG(LogTemp, Display, TEXT(" - Found fallback data output pin: '%s'"), *Pin->PinName.ToString());
411
+ return Pin;
412
+ }
413
+ }
414
+ }
415
+
416
+ UE_LOG(LogTemp, Warning, TEXT(" - No matching pin found for '%s'"), *PinName);
417
+ return nullptr;
418
+ }
419
+
420
+ // Actor utilities
421
+ TSharedPtr<FJsonValue> FUnrealMCPCommonUtils::ActorToJson(AActor* Actor)
422
+ {
423
+ if (!Actor)
424
+ {
425
+ return MakeShared<FJsonValueNull>();
426
+ }
427
+
428
+ TSharedPtr<FJsonObject> ActorObject = MakeShared<FJsonObject>();
429
+ ActorObject->SetStringField(TEXT("name"), Actor->GetName());
430
+ ActorObject->SetStringField(TEXT("class"), Actor->GetClass()->GetName());
431
+
432
+ FVector Location = Actor->GetActorLocation();
433
+ TArray<TSharedPtr<FJsonValue>> LocationArray;
434
+ LocationArray.Add(MakeShared<FJsonValueNumber>(Location.X));
435
+ LocationArray.Add(MakeShared<FJsonValueNumber>(Location.Y));
436
+ LocationArray.Add(MakeShared<FJsonValueNumber>(Location.Z));
437
+ ActorObject->SetArrayField(TEXT("location"), LocationArray);
438
+
439
+ FRotator Rotation = Actor->GetActorRotation();
440
+ TArray<TSharedPtr<FJsonValue>> RotationArray;
441
+ RotationArray.Add(MakeShared<FJsonValueNumber>(Rotation.Pitch));
442
+ RotationArray.Add(MakeShared<FJsonValueNumber>(Rotation.Yaw));
443
+ RotationArray.Add(MakeShared<FJsonValueNumber>(Rotation.Roll));
444
+ ActorObject->SetArrayField(TEXT("rotation"), RotationArray);
445
+
446
+ FVector Scale = Actor->GetActorScale3D();
447
+ TArray<TSharedPtr<FJsonValue>> ScaleArray;
448
+ ScaleArray.Add(MakeShared<FJsonValueNumber>(Scale.X));
449
+ ScaleArray.Add(MakeShared<FJsonValueNumber>(Scale.Y));
450
+ ScaleArray.Add(MakeShared<FJsonValueNumber>(Scale.Z));
451
+ ActorObject->SetArrayField(TEXT("scale"), ScaleArray);
452
+
453
+ return MakeShared<FJsonValueObject>(ActorObject);
454
+ }
455
+
456
+ TSharedPtr<FJsonObject> FUnrealMCPCommonUtils::ActorToJsonObject(AActor* Actor, bool bDetailed)
457
+ {
458
+ if (!Actor)
459
+ {
460
+ return nullptr;
461
+ }
462
+
463
+ TSharedPtr<FJsonObject> ActorObject = MakeShared<FJsonObject>();
464
+ ActorObject->SetStringField(TEXT("name"), Actor->GetName());
465
+ ActorObject->SetStringField(TEXT("class"), Actor->GetClass()->GetName());
466
+
467
+ FVector Location = Actor->GetActorLocation();
468
+ TArray<TSharedPtr<FJsonValue>> LocationArray;
469
+ LocationArray.Add(MakeShared<FJsonValueNumber>(Location.X));
470
+ LocationArray.Add(MakeShared<FJsonValueNumber>(Location.Y));
471
+ LocationArray.Add(MakeShared<FJsonValueNumber>(Location.Z));
472
+ ActorObject->SetArrayField(TEXT("location"), LocationArray);
473
+
474
+ FRotator Rotation = Actor->GetActorRotation();
475
+ TArray<TSharedPtr<FJsonValue>> RotationArray;
476
+ RotationArray.Add(MakeShared<FJsonValueNumber>(Rotation.Pitch));
477
+ RotationArray.Add(MakeShared<FJsonValueNumber>(Rotation.Yaw));
478
+ RotationArray.Add(MakeShared<FJsonValueNumber>(Rotation.Roll));
479
+ ActorObject->SetArrayField(TEXT("rotation"), RotationArray);
480
+
481
+ FVector Scale = Actor->GetActorScale3D();
482
+ TArray<TSharedPtr<FJsonValue>> ScaleArray;
483
+ ScaleArray.Add(MakeShared<FJsonValueNumber>(Scale.X));
484
+ ScaleArray.Add(MakeShared<FJsonValueNumber>(Scale.Y));
485
+ ScaleArray.Add(MakeShared<FJsonValueNumber>(Scale.Z));
486
+ ActorObject->SetArrayField(TEXT("scale"), ScaleArray);
487
+
488
+ return ActorObject;
489
+ }
490
+
491
+ UK2Node_Event* FUnrealMCPCommonUtils::FindExistingEventNode(UEdGraph* Graph, const FString& EventName)
492
+ {
493
+ if (!Graph)
494
+ {
495
+ return nullptr;
496
+ }
497
+
498
+ // Look for existing event nodes
499
+ for (UEdGraphNode* Node : Graph->Nodes)
500
+ {
501
+ UK2Node_Event* EventNode = Cast<UK2Node_Event>(Node);
502
+ if (EventNode && EventNode->EventReference.GetMemberName() == FName(*EventName))
503
+ {
504
+ UE_LOG(LogTemp, Display, TEXT("Found existing event node with name: %s"), *EventName);
505
+ return EventNode;
506
+ }
507
+ }
508
+
509
+ return nullptr;
510
+ }
511
+
512
+ bool FUnrealMCPCommonUtils::SetObjectProperty(UObject* Object, const FString& PropertyName,
513
+ const TSharedPtr<FJsonValue>& Value, FString& OutErrorMessage)
514
+ {
515
+ if (!Object)
516
+ {
517
+ OutErrorMessage = TEXT("Invalid object");
518
+ return false;
519
+ }
520
+
521
+ FProperty* Property = Object->GetClass()->FindPropertyByName(*PropertyName);
522
+ if (!Property)
523
+ {
524
+ OutErrorMessage = FString::Printf(TEXT("Property not found: %s"), *PropertyName);
525
+ return false;
526
+ }
527
+
528
+ void* PropertyAddr = Property->ContainerPtrToValuePtr<void>(Object);
529
+
530
+ // Handle different property types
531
+ if (Property->IsA<FBoolProperty>())
532
+ {
533
+ ((FBoolProperty*)Property)->SetPropertyValue(PropertyAddr, Value->AsBool());
534
+ return true;
535
+ }
536
+ else if (Property->IsA<FIntProperty>())
537
+ {
538
+ int32 IntValue = static_cast<int32>(Value->AsNumber());
539
+ FIntProperty* IntProperty = CastField<FIntProperty>(Property);
540
+ if (IntProperty)
541
+ {
542
+ IntProperty->SetPropertyValue_InContainer(Object, IntValue);
543
+ return true;
544
+ }
545
+ }
546
+ else if (Property->IsA<FFloatProperty>())
547
+ {
548
+ ((FFloatProperty*)Property)->SetPropertyValue(PropertyAddr, Value->AsNumber());
549
+ return true;
550
+ }
551
+ else if (Property->IsA<FStrProperty>())
552
+ {
553
+ ((FStrProperty*)Property)->SetPropertyValue(PropertyAddr, Value->AsString());
554
+ return true;
555
+ }
556
+ else if (Property->IsA<FByteProperty>())
557
+ {
558
+ FByteProperty* ByteProp = CastField<FByteProperty>(Property);
559
+ UEnum* EnumDef = ByteProp ? ByteProp->GetIntPropertyEnum() : nullptr;
560
+
561
+ // If this is a TEnumAsByte property (has associated enum)
562
+ if (EnumDef)
563
+ {
564
+ // Handle numeric value
565
+ if (Value->Type == EJson::Number)
566
+ {
567
+ uint8 ByteValue = static_cast<uint8>(Value->AsNumber());
568
+ ByteProp->SetPropertyValue(PropertyAddr, ByteValue);
569
+
570
+ UE_LOG(LogTemp, Display, TEXT("Setting enum property %s to numeric value: %d"),
571
+ *PropertyName, ByteValue);
572
+ return true;
573
+ }
574
+ // Handle string enum value
575
+ else if (Value->Type == EJson::String)
576
+ {
577
+ FString EnumValueName = Value->AsString();
578
+
579
+ // Try to convert numeric string to number first
580
+ if (EnumValueName.IsNumeric())
581
+ {
582
+ uint8 ByteValue = FCString::Atoi(*EnumValueName);
583
+ ByteProp->SetPropertyValue(PropertyAddr, ByteValue);
584
+
585
+ UE_LOG(LogTemp, Display, TEXT("Setting enum property %s to numeric string value: %s -> %d"),
586
+ *PropertyName, *EnumValueName, ByteValue);
587
+ return true;
588
+ }
589
+
590
+ // Handle qualified enum names (e.g., "Player0" or "EAutoReceiveInput::Player0")
591
+ if (EnumValueName.Contains(TEXT("::")))
592
+ {
593
+ EnumValueName.Split(TEXT("::"), nullptr, &EnumValueName);
594
+ }
595
+
596
+ int64 EnumValue = EnumDef->GetValueByNameString(EnumValueName);
597
+ if (EnumValue == INDEX_NONE)
598
+ {
599
+ // Try with full name as fallback
600
+ EnumValue = EnumDef->GetValueByNameString(Value->AsString());
601
+ }
602
+
603
+ if (EnumValue != INDEX_NONE)
604
+ {
605
+ ByteProp->SetPropertyValue(PropertyAddr, static_cast<uint8>(EnumValue));
606
+
607
+ UE_LOG(LogTemp, Display, TEXT("Setting enum property %s to name value: %s -> %lld"),
608
+ *PropertyName, *EnumValueName, EnumValue);
609
+ return true;
610
+ }
611
+ else
612
+ {
613
+ // Log all possible enum values for debugging
614
+ UE_LOG(LogTemp, Warning, TEXT("Could not find enum value for '%s'. Available options:"), *EnumValueName);
615
+ for (int32 i = 0; i < EnumDef->NumEnums(); i++)
616
+ {
617
+ UE_LOG(LogTemp, Warning, TEXT(" - %s (value: %d)"),
618
+ *EnumDef->GetNameStringByIndex(i), EnumDef->GetValueByIndex(i));
619
+ }
620
+
621
+ OutErrorMessage = FString::Printf(TEXT("Could not find enum value for '%s'"), *EnumValueName);
622
+ return false;
623
+ }
624
+ }
625
+ }
626
+ else
627
+ {
628
+ // Regular byte property
629
+ uint8 ByteValue = static_cast<uint8>(Value->AsNumber());
630
+ ByteProp->SetPropertyValue(PropertyAddr, ByteValue);
631
+ return true;
632
+ }
633
+ }
634
+ else if (Property->IsA<FEnumProperty>())
635
+ {
636
+ FEnumProperty* EnumProp = CastField<FEnumProperty>(Property);
637
+ UEnum* EnumDef = EnumProp ? EnumProp->GetEnum() : nullptr;
638
+ FNumericProperty* UnderlyingNumericProp = EnumProp ? EnumProp->GetUnderlyingProperty() : nullptr;
639
+
640
+ if (EnumDef && UnderlyingNumericProp)
641
+ {
642
+ // Handle numeric value
643
+ if (Value->Type == EJson::Number)
644
+ {
645
+ int64 EnumValue = static_cast<int64>(Value->AsNumber());
646
+ UnderlyingNumericProp->SetIntPropertyValue(PropertyAddr, EnumValue);
647
+
648
+ UE_LOG(LogTemp, Display, TEXT("Setting enum property %s to numeric value: %lld"),
649
+ *PropertyName, EnumValue);
650
+ return true;
651
+ }
652
+ // Handle string enum value
653
+ else if (Value->Type == EJson::String)
654
+ {
655
+ FString EnumValueName = Value->AsString();
656
+
657
+ // Try to convert numeric string to number first
658
+ if (EnumValueName.IsNumeric())
659
+ {
660
+ int64 EnumValue = FCString::Atoi64(*EnumValueName);
661
+ UnderlyingNumericProp->SetIntPropertyValue(PropertyAddr, EnumValue);
662
+
663
+ UE_LOG(LogTemp, Display, TEXT("Setting enum property %s to numeric string value: %s -> %lld"),
664
+ *PropertyName, *EnumValueName, EnumValue);
665
+ return true;
666
+ }
667
+
668
+ // Handle qualified enum names
669
+ if (EnumValueName.Contains(TEXT("::")))
670
+ {
671
+ EnumValueName.Split(TEXT("::"), nullptr, &EnumValueName);
672
+ }
673
+
674
+ int64 EnumValue = EnumDef->GetValueByNameString(EnumValueName);
675
+ if (EnumValue == INDEX_NONE)
676
+ {
677
+ // Try with full name as fallback
678
+ EnumValue = EnumDef->GetValueByNameString(Value->AsString());
679
+ }
680
+
681
+ if (EnumValue != INDEX_NONE)
682
+ {
683
+ UnderlyingNumericProp->SetIntPropertyValue(PropertyAddr, EnumValue);
684
+
685
+ UE_LOG(LogTemp, Display, TEXT("Setting enum property %s to name value: %s -> %lld"),
686
+ *PropertyName, *EnumValueName, EnumValue);
687
+ return true;
688
+ }
689
+ else
690
+ {
691
+ // Log all possible enum values for debugging
692
+ UE_LOG(LogTemp, Warning, TEXT("Could not find enum value for '%s'. Available options:"), *EnumValueName);
693
+ for (int32 i = 0; i < EnumDef->NumEnums(); i++)
694
+ {
695
+ UE_LOG(LogTemp, Warning, TEXT(" - %s (value: %d)"),
696
+ *EnumDef->GetNameStringByIndex(i), EnumDef->GetValueByIndex(i));
697
+ }
698
+
699
+ OutErrorMessage = FString::Printf(TEXT("Could not find enum value for '%s'"), *EnumValueName);
700
+ return false;
701
+ }
702
+ }
703
+ }
704
+ }
705
+
706
+ OutErrorMessage = FString::Printf(TEXT("Unsupported property type: %s for property %s"),
707
+ *Property->GetClass()->GetName(), *PropertyName);
708
+ return false;
709
+ }