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,1160 @@
1
+ #include "Commands/UnrealMCPBlueprintCommands.h"
2
+ #include "Commands/UnrealMCPCommonUtils.h"
3
+ #include "Engine/Blueprint.h"
4
+ #include "Engine/BlueprintGeneratedClass.h"
5
+ #include "Factories/BlueprintFactory.h"
6
+ #include "EdGraphSchema_K2.h"
7
+ #include "K2Node_Event.h"
8
+ #include "K2Node_VariableGet.h"
9
+ #include "K2Node_VariableSet.h"
10
+ #include "Components/StaticMeshComponent.h"
11
+ #include "Components/BoxComponent.h"
12
+ #include "Components/SphereComponent.h"
13
+ #include "Kismet2/BlueprintEditorUtils.h"
14
+ #include "Kismet2/KismetEditorUtilities.h"
15
+ #include "Engine/SimpleConstructionScript.h"
16
+ #include "Engine/SCS_Node.h"
17
+ #include "UObject/Field.h"
18
+ #include "UObject/FieldPath.h"
19
+ #include "EditorAssetLibrary.h"
20
+ #include "AssetRegistry/AssetRegistryModule.h"
21
+ #include "GameFramework/Actor.h"
22
+ #include "GameFramework/Pawn.h"
23
+
24
+ FUnrealMCPBlueprintCommands::FUnrealMCPBlueprintCommands()
25
+ {
26
+ }
27
+
28
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintCommands::HandleCommand(const FString& CommandType, const TSharedPtr<FJsonObject>& Params)
29
+ {
30
+ if (CommandType == TEXT("create_blueprint"))
31
+ {
32
+ return HandleCreateBlueprint(Params);
33
+ }
34
+ else if (CommandType == TEXT("add_component_to_blueprint"))
35
+ {
36
+ return HandleAddComponentToBlueprint(Params);
37
+ }
38
+ else if (CommandType == TEXT("set_component_property"))
39
+ {
40
+ return HandleSetComponentProperty(Params);
41
+ }
42
+ else if (CommandType == TEXT("set_physics_properties"))
43
+ {
44
+ return HandleSetPhysicsProperties(Params);
45
+ }
46
+ else if (CommandType == TEXT("compile_blueprint"))
47
+ {
48
+ return HandleCompileBlueprint(Params);
49
+ }
50
+ else if (CommandType == TEXT("spawn_blueprint_actor"))
51
+ {
52
+ return HandleSpawnBlueprintActor(Params);
53
+ }
54
+ else if (CommandType == TEXT("set_blueprint_property"))
55
+ {
56
+ return HandleSetBlueprintProperty(Params);
57
+ }
58
+ else if (CommandType == TEXT("set_static_mesh_properties"))
59
+ {
60
+ return HandleSetStaticMeshProperties(Params);
61
+ }
62
+ else if (CommandType == TEXT("set_pawn_properties"))
63
+ {
64
+ return HandleSetPawnProperties(Params);
65
+ }
66
+
67
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Unknown blueprint command: %s"), *CommandType));
68
+ }
69
+
70
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintCommands::HandleCreateBlueprint(const TSharedPtr<FJsonObject>& Params)
71
+ {
72
+ // Get required parameters
73
+ FString BlueprintName;
74
+ if (!Params->TryGetStringField(TEXT("name"), BlueprintName))
75
+ {
76
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'name' parameter"));
77
+ }
78
+
79
+ // Check if blueprint already exists
80
+ FString PackagePath = TEXT("/Game/Blueprints/");
81
+ FString AssetName = BlueprintName;
82
+ if (UEditorAssetLibrary::DoesAssetExist(PackagePath + AssetName))
83
+ {
84
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint already exists: %s"), *BlueprintName));
85
+ }
86
+
87
+ // Create the blueprint factory
88
+ UBlueprintFactory* Factory = NewObject<UBlueprintFactory>();
89
+
90
+ // Handle parent class
91
+ FString ParentClass;
92
+ Params->TryGetStringField(TEXT("parent_class"), ParentClass);
93
+
94
+ // Default to Actor if no parent class specified
95
+ UClass* SelectedParentClass = AActor::StaticClass();
96
+
97
+ // Try to find the specified parent class
98
+ if (!ParentClass.IsEmpty())
99
+ {
100
+ FString ClassName = ParentClass;
101
+ if (!ClassName.StartsWith(TEXT("A")))
102
+ {
103
+ ClassName = TEXT("A") + ClassName;
104
+ }
105
+
106
+ // First try direct StaticClass lookup for common classes
107
+ UClass* FoundClass = nullptr;
108
+ if (ClassName == TEXT("APawn"))
109
+ {
110
+ FoundClass = APawn::StaticClass();
111
+ }
112
+ else if (ClassName == TEXT("AActor"))
113
+ {
114
+ FoundClass = AActor::StaticClass();
115
+ }
116
+ else
117
+ {
118
+ // Try loading the class using LoadClass which is more reliable than FindObject
119
+ const FString ClassPath = FString::Printf(TEXT("/Script/Engine.%s"), *ClassName);
120
+ FoundClass = LoadClass<AActor>(nullptr, *ClassPath);
121
+
122
+ if (!FoundClass)
123
+ {
124
+ // Try alternate paths if not found
125
+ const FString GameClassPath = FString::Printf(TEXT("/Script/Game.%s"), *ClassName);
126
+ FoundClass = LoadClass<AActor>(nullptr, *GameClassPath);
127
+ }
128
+ }
129
+
130
+ if (FoundClass)
131
+ {
132
+ SelectedParentClass = FoundClass;
133
+ UE_LOG(LogTemp, Log, TEXT("Successfully set parent class to '%s'"), *ClassName);
134
+ }
135
+ else
136
+ {
137
+ UE_LOG(LogTemp, Warning, TEXT("Could not find specified parent class '%s' at paths: /Script/Engine.%s or /Script/Game.%s, defaulting to AActor"),
138
+ *ClassName, *ClassName, *ClassName);
139
+ }
140
+ }
141
+
142
+ Factory->ParentClass = SelectedParentClass;
143
+
144
+ // Create the blueprint
145
+ UPackage* Package = CreatePackage(*(PackagePath + AssetName));
146
+ UBlueprint* NewBlueprint = Cast<UBlueprint>(Factory->FactoryCreateNew(UBlueprint::StaticClass(), Package, *AssetName, RF_Standalone | RF_Public, nullptr, GWarn));
147
+
148
+ if (NewBlueprint)
149
+ {
150
+ // Notify the asset registry
151
+ FAssetRegistryModule::AssetCreated(NewBlueprint);
152
+
153
+ // Mark the package dirty
154
+ Package->MarkPackageDirty();
155
+
156
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
157
+ ResultObj->SetStringField(TEXT("name"), AssetName);
158
+ ResultObj->SetStringField(TEXT("path"), PackagePath + AssetName);
159
+ return ResultObj;
160
+ }
161
+
162
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to create blueprint"));
163
+ }
164
+
165
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintCommands::HandleAddComponentToBlueprint(const TSharedPtr<FJsonObject>& Params)
166
+ {
167
+ // Get required parameters
168
+ FString BlueprintName;
169
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
170
+ {
171
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
172
+ }
173
+
174
+ FString ComponentType;
175
+ if (!Params->TryGetStringField(TEXT("component_type"), ComponentType))
176
+ {
177
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'type' parameter"));
178
+ }
179
+
180
+ FString ComponentName;
181
+ if (!Params->TryGetStringField(TEXT("component_name"), ComponentName))
182
+ {
183
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'name' parameter"));
184
+ }
185
+
186
+ // Find the blueprint
187
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
188
+ if (!Blueprint)
189
+ {
190
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
191
+ }
192
+
193
+ // Create the component - dynamically find the component class by name
194
+ UClass* ComponentClass = nullptr;
195
+
196
+ // Try to find the class with exact name first
197
+ ComponentClass = FindObject<UClass>(ANY_PACKAGE, *ComponentType);
198
+
199
+ // If not found, try with "Component" suffix
200
+ if (!ComponentClass && !ComponentType.EndsWith(TEXT("Component")))
201
+ {
202
+ FString ComponentTypeWithSuffix = ComponentType + TEXT("Component");
203
+ ComponentClass = FindObject<UClass>(ANY_PACKAGE, *ComponentTypeWithSuffix);
204
+ }
205
+
206
+ // If still not found, try with "U" prefix
207
+ if (!ComponentClass && !ComponentType.StartsWith(TEXT("U")))
208
+ {
209
+ FString ComponentTypeWithPrefix = TEXT("U") + ComponentType;
210
+ ComponentClass = FindObject<UClass>(ANY_PACKAGE, *ComponentTypeWithPrefix);
211
+
212
+ // Try with both prefix and suffix
213
+ if (!ComponentClass && !ComponentType.EndsWith(TEXT("Component")))
214
+ {
215
+ FString ComponentTypeWithBoth = TEXT("U") + ComponentType + TEXT("Component");
216
+ ComponentClass = FindObject<UClass>(ANY_PACKAGE, *ComponentTypeWithBoth);
217
+ }
218
+ }
219
+
220
+ // Verify that the class is a valid component type
221
+ if (!ComponentClass || !ComponentClass->IsChildOf(UActorComponent::StaticClass()))
222
+ {
223
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Unknown component type: %s"), *ComponentType));
224
+ }
225
+
226
+ // Add the component to the blueprint
227
+ USCS_Node* NewNode = Blueprint->SimpleConstructionScript->CreateNode(ComponentClass, *ComponentName);
228
+ if (NewNode)
229
+ {
230
+ // Set transform if provided
231
+ USceneComponent* SceneComponent = Cast<USceneComponent>(NewNode->ComponentTemplate);
232
+ if (SceneComponent)
233
+ {
234
+ if (Params->HasField(TEXT("location")))
235
+ {
236
+ SceneComponent->SetRelativeLocation(FUnrealMCPCommonUtils::GetVectorFromJson(Params, TEXT("location")));
237
+ }
238
+ if (Params->HasField(TEXT("rotation")))
239
+ {
240
+ SceneComponent->SetRelativeRotation(FUnrealMCPCommonUtils::GetRotatorFromJson(Params, TEXT("rotation")));
241
+ }
242
+ if (Params->HasField(TEXT("scale")))
243
+ {
244
+ SceneComponent->SetRelativeScale3D(FUnrealMCPCommonUtils::GetVectorFromJson(Params, TEXT("scale")));
245
+ }
246
+ }
247
+
248
+ // Add to root if no parent specified
249
+ Blueprint->SimpleConstructionScript->AddNode(NewNode);
250
+
251
+ // Compile the blueprint
252
+ FKismetEditorUtilities::CompileBlueprint(Blueprint);
253
+
254
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
255
+ ResultObj->SetStringField(TEXT("component_name"), ComponentName);
256
+ ResultObj->SetStringField(TEXT("component_type"), ComponentType);
257
+ return ResultObj;
258
+ }
259
+
260
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to add component to blueprint"));
261
+ }
262
+
263
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintCommands::HandleSetComponentProperty(const TSharedPtr<FJsonObject>& Params)
264
+ {
265
+ // Get required parameters
266
+ FString BlueprintName;
267
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
268
+ {
269
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
270
+ }
271
+
272
+ FString ComponentName;
273
+ if (!Params->TryGetStringField(TEXT("component_name"), ComponentName))
274
+ {
275
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'component_name' parameter"));
276
+ }
277
+
278
+ FString PropertyName;
279
+ if (!Params->TryGetStringField(TEXT("property_name"), PropertyName))
280
+ {
281
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'property_name' parameter"));
282
+ }
283
+
284
+ // Log all input parameters for debugging
285
+ UE_LOG(LogTemp, Warning, TEXT("SetComponentProperty - Blueprint: %s, Component: %s, Property: %s"),
286
+ *BlueprintName, *ComponentName, *PropertyName);
287
+
288
+ // Log property_value if available
289
+ if (Params->HasField(TEXT("property_value")))
290
+ {
291
+ TSharedPtr<FJsonValue> JsonValue = Params->Values.FindRef(TEXT("property_value"));
292
+ FString ValueType;
293
+
294
+ switch(JsonValue->Type)
295
+ {
296
+ case EJson::Boolean: ValueType = FString::Printf(TEXT("Boolean: %s"), JsonValue->AsBool() ? TEXT("true") : TEXT("false")); break;
297
+ case EJson::Number: ValueType = FString::Printf(TEXT("Number: %f"), JsonValue->AsNumber()); break;
298
+ case EJson::String: ValueType = FString::Printf(TEXT("String: %s"), *JsonValue->AsString()); break;
299
+ case EJson::Array: ValueType = TEXT("Array"); break;
300
+ case EJson::Object: ValueType = TEXT("Object"); break;
301
+ default: ValueType = TEXT("Unknown"); break;
302
+ }
303
+
304
+ UE_LOG(LogTemp, Warning, TEXT("SetComponentProperty - Value Type: %s"), *ValueType);
305
+ }
306
+ else
307
+ {
308
+ UE_LOG(LogTemp, Warning, TEXT("SetComponentProperty - No property_value provided"));
309
+ }
310
+
311
+ // Find the blueprint
312
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
313
+ if (!Blueprint)
314
+ {
315
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - Blueprint not found: %s"), *BlueprintName);
316
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
317
+ }
318
+ else
319
+ {
320
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Blueprint found: %s (Class: %s)"),
321
+ *BlueprintName,
322
+ Blueprint->GeneratedClass ? *Blueprint->GeneratedClass->GetName() : TEXT("NULL"));
323
+ }
324
+
325
+ // Find the component
326
+ USCS_Node* ComponentNode = nullptr;
327
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Searching for component %s in blueprint nodes"), *ComponentName);
328
+
329
+ if (!Blueprint->SimpleConstructionScript)
330
+ {
331
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - SimpleConstructionScript is NULL for blueprint %s"), *BlueprintName);
332
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Invalid blueprint construction script"));
333
+ }
334
+
335
+ for (USCS_Node* Node : Blueprint->SimpleConstructionScript->GetAllNodes())
336
+ {
337
+ if (Node)
338
+ {
339
+ UE_LOG(LogTemp, Verbose, TEXT("SetComponentProperty - Found node: %s"), *Node->GetVariableName().ToString());
340
+ if (Node->GetVariableName().ToString() == ComponentName)
341
+ {
342
+ ComponentNode = Node;
343
+ break;
344
+ }
345
+ }
346
+ else
347
+ {
348
+ UE_LOG(LogTemp, Warning, TEXT("SetComponentProperty - Found NULL node in blueprint"));
349
+ }
350
+ }
351
+
352
+ if (!ComponentNode)
353
+ {
354
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - Component not found: %s"), *ComponentName);
355
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Component not found: %s"), *ComponentName));
356
+ }
357
+ else
358
+ {
359
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Component found: %s (Class: %s)"),
360
+ *ComponentName,
361
+ ComponentNode->ComponentTemplate ? *ComponentNode->ComponentTemplate->GetClass()->GetName() : TEXT("NULL"));
362
+ }
363
+
364
+ // Get the component template
365
+ UObject* ComponentTemplate = ComponentNode->ComponentTemplate;
366
+ if (!ComponentTemplate)
367
+ {
368
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - Component template is NULL for %s"), *ComponentName);
369
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Invalid component template"));
370
+ }
371
+
372
+ // Check if this is a Spring Arm component and log special debug info
373
+ if (ComponentTemplate->GetClass()->GetName().Contains(TEXT("SpringArm")))
374
+ {
375
+ UE_LOG(LogTemp, Warning, TEXT("SetComponentProperty - SpringArm component detected! Class: %s"),
376
+ *ComponentTemplate->GetClass()->GetPathName());
377
+
378
+ // Log all properties of the SpringArm component class
379
+ UE_LOG(LogTemp, Warning, TEXT("SetComponentProperty - SpringArm properties:"));
380
+ for (TFieldIterator<FProperty> PropIt(ComponentTemplate->GetClass()); PropIt; ++PropIt)
381
+ {
382
+ FProperty* Prop = *PropIt;
383
+ UE_LOG(LogTemp, Warning, TEXT(" - %s (%s)"), *Prop->GetName(), *Prop->GetCPPType());
384
+ }
385
+
386
+ // Special handling for Spring Arm properties
387
+ if (Params->HasField(TEXT("property_value")))
388
+ {
389
+ TSharedPtr<FJsonValue> JsonValue = Params->Values.FindRef(TEXT("property_value"));
390
+
391
+ // Get the property using the new FField system
392
+ FProperty* Property = FindFProperty<FProperty>(ComponentTemplate->GetClass(), *PropertyName);
393
+ if (!Property)
394
+ {
395
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - Property %s not found on SpringArm component"), *PropertyName);
396
+ return FUnrealMCPCommonUtils::CreateErrorResponse(
397
+ FString::Printf(TEXT("Property %s not found on SpringArm component"), *PropertyName));
398
+ }
399
+
400
+ // Create a scope guard to ensure property cleanup
401
+ struct FScopeGuard
402
+ {
403
+ UObject* Object;
404
+ FScopeGuard(UObject* InObject) : Object(InObject)
405
+ {
406
+ if (Object)
407
+ {
408
+ Object->Modify();
409
+ }
410
+ }
411
+ ~FScopeGuard()
412
+ {
413
+ if (Object)
414
+ {
415
+ Object->PostEditChange();
416
+ }
417
+ }
418
+ } ScopeGuard(ComponentTemplate);
419
+
420
+ bool bSuccess = false;
421
+ FString ErrorMessage;
422
+
423
+ // Handle specific Spring Arm property types
424
+ if (FFloatProperty* FloatProp = CastField<FFloatProperty>(Property))
425
+ {
426
+ if (JsonValue->Type == EJson::Number)
427
+ {
428
+ const float Value = JsonValue->AsNumber();
429
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Setting float property %s to %f"), *PropertyName, Value);
430
+ FloatProp->SetPropertyValue_InContainer(ComponentTemplate, Value);
431
+ bSuccess = true;
432
+ }
433
+ }
434
+ else if (FBoolProperty* BoolProp = CastField<FBoolProperty>(Property))
435
+ {
436
+ if (JsonValue->Type == EJson::Boolean)
437
+ {
438
+ const bool Value = JsonValue->AsBool();
439
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Setting bool property %s to %d"), *PropertyName, Value);
440
+ BoolProp->SetPropertyValue_InContainer(ComponentTemplate, Value);
441
+ bSuccess = true;
442
+ }
443
+ }
444
+ else if (FStructProperty* StructProp = CastField<FStructProperty>(Property))
445
+ {
446
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Handling struct property %s of type %s"),
447
+ *PropertyName, *StructProp->Struct->GetName());
448
+
449
+ // Special handling for common Spring Arm struct properties
450
+ if (StructProp->Struct == TBaseStructure<FVector>::Get())
451
+ {
452
+ if (JsonValue->Type == EJson::Array)
453
+ {
454
+ const TArray<TSharedPtr<FJsonValue>>& Arr = JsonValue->AsArray();
455
+ if (Arr.Num() == 3)
456
+ {
457
+ FVector Vec(
458
+ Arr[0]->AsNumber(),
459
+ Arr[1]->AsNumber(),
460
+ Arr[2]->AsNumber()
461
+ );
462
+ void* PropertyAddr = StructProp->ContainerPtrToValuePtr<void>(ComponentTemplate);
463
+ StructProp->CopySingleValue(PropertyAddr, &Vec);
464
+ bSuccess = true;
465
+ }
466
+ }
467
+ }
468
+ else if (StructProp->Struct == TBaseStructure<FRotator>::Get())
469
+ {
470
+ if (JsonValue->Type == EJson::Array)
471
+ {
472
+ const TArray<TSharedPtr<FJsonValue>>& Arr = JsonValue->AsArray();
473
+ if (Arr.Num() == 3)
474
+ {
475
+ FRotator Rot(
476
+ Arr[0]->AsNumber(),
477
+ Arr[1]->AsNumber(),
478
+ Arr[2]->AsNumber()
479
+ );
480
+ void* PropertyAddr = StructProp->ContainerPtrToValuePtr<void>(ComponentTemplate);
481
+ StructProp->CopySingleValue(PropertyAddr, &Rot);
482
+ bSuccess = true;
483
+ }
484
+ }
485
+ }
486
+ }
487
+
488
+ if (bSuccess)
489
+ {
490
+ // Mark the blueprint as modified
491
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Successfully set SpringArm property %s"), *PropertyName);
492
+ FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
493
+
494
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
495
+ ResultObj->SetStringField(TEXT("component"), ComponentName);
496
+ ResultObj->SetStringField(TEXT("property"), PropertyName);
497
+ ResultObj->SetBoolField(TEXT("success"), true);
498
+ return ResultObj;
499
+ }
500
+ else
501
+ {
502
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - Failed to set SpringArm property %s"), *PropertyName);
503
+ return FUnrealMCPCommonUtils::CreateErrorResponse(
504
+ FString::Printf(TEXT("Failed to set SpringArm property %s"), *PropertyName));
505
+ }
506
+ }
507
+ }
508
+
509
+ // Regular property handling for non-Spring Arm components continues...
510
+
511
+ // Set the property value
512
+ if (Params->HasField(TEXT("property_value")))
513
+ {
514
+ TSharedPtr<FJsonValue> JsonValue = Params->Values.FindRef(TEXT("property_value"));
515
+
516
+ // Get the property
517
+ FProperty* Property = FindFProperty<FProperty>(ComponentTemplate->GetClass(), *PropertyName);
518
+ if (!Property)
519
+ {
520
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - Property %s not found on component %s"),
521
+ *PropertyName, *ComponentName);
522
+
523
+ // List all available properties for this component
524
+ UE_LOG(LogTemp, Warning, TEXT("SetComponentProperty - Available properties for %s:"), *ComponentName);
525
+ for (TFieldIterator<FProperty> PropIt(ComponentTemplate->GetClass()); PropIt; ++PropIt)
526
+ {
527
+ FProperty* Prop = *PropIt;
528
+ UE_LOG(LogTemp, Warning, TEXT(" - %s (%s)"), *Prop->GetName(), *Prop->GetCPPType());
529
+ }
530
+
531
+ return FUnrealMCPCommonUtils::CreateErrorResponse(
532
+ FString::Printf(TEXT("Property %s not found on component %s"), *PropertyName, *ComponentName));
533
+ }
534
+ else
535
+ {
536
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Property found: %s (Type: %s)"),
537
+ *PropertyName, *Property->GetCPPType());
538
+ }
539
+
540
+ bool bSuccess = false;
541
+ FString ErrorMessage;
542
+
543
+ // Handle different property types
544
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Attempting to set property %s"), *PropertyName);
545
+
546
+ // Add try-catch block to catch and log any crashes
547
+ try
548
+ {
549
+ if (FStructProperty* StructProp = CastField<FStructProperty>(Property))
550
+ {
551
+ // Handle vector properties
552
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Property is a struct: %s"),
553
+ StructProp->Struct ? *StructProp->Struct->GetName() : TEXT("NULL"));
554
+
555
+ if (StructProp->Struct == TBaseStructure<FVector>::Get())
556
+ {
557
+ if (JsonValue->Type == EJson::Array)
558
+ {
559
+ // Handle array input [x, y, z]
560
+ const TArray<TSharedPtr<FJsonValue>>& Arr = JsonValue->AsArray();
561
+ if (Arr.Num() == 3)
562
+ {
563
+ FVector Vec(
564
+ Arr[0]->AsNumber(),
565
+ Arr[1]->AsNumber(),
566
+ Arr[2]->AsNumber()
567
+ );
568
+ void* PropertyAddr = StructProp->ContainerPtrToValuePtr<void>(ComponentTemplate);
569
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Setting Vector(%f, %f, %f)"),
570
+ Vec.X, Vec.Y, Vec.Z);
571
+ StructProp->CopySingleValue(PropertyAddr, &Vec);
572
+ bSuccess = true;
573
+ }
574
+ else
575
+ {
576
+ ErrorMessage = FString::Printf(TEXT("Vector property requires 3 values, got %d"), Arr.Num());
577
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - %s"), *ErrorMessage);
578
+ }
579
+ }
580
+ else if (JsonValue->Type == EJson::Number)
581
+ {
582
+ // Handle scalar input (sets all components to same value)
583
+ float Value = JsonValue->AsNumber();
584
+ FVector Vec(Value, Value, Value);
585
+ void* PropertyAddr = StructProp->ContainerPtrToValuePtr<void>(ComponentTemplate);
586
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Setting Vector(%f, %f, %f) from scalar"),
587
+ Vec.X, Vec.Y, Vec.Z);
588
+ StructProp->CopySingleValue(PropertyAddr, &Vec);
589
+ bSuccess = true;
590
+ }
591
+ else
592
+ {
593
+ ErrorMessage = TEXT("Vector property requires either a single number or array of 3 numbers");
594
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - %s"), *ErrorMessage);
595
+ }
596
+ }
597
+ else
598
+ {
599
+ // Handle other struct properties using default handler
600
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Using generic struct handler for %s"),
601
+ *PropertyName);
602
+ bSuccess = FUnrealMCPCommonUtils::SetObjectProperty(ComponentTemplate, PropertyName, JsonValue, ErrorMessage);
603
+ if (!bSuccess)
604
+ {
605
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - Failed to set struct property: %s"), *ErrorMessage);
606
+ }
607
+ }
608
+ }
609
+ else if (FEnumProperty* EnumProp = CastField<FEnumProperty>(Property))
610
+ {
611
+ // Handle enum properties
612
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Property is an enum"));
613
+ if (JsonValue->Type == EJson::String)
614
+ {
615
+ FString EnumValueName = JsonValue->AsString();
616
+ UEnum* Enum = EnumProp->GetEnum();
617
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Setting enum from string: %s"), *EnumValueName);
618
+
619
+ if (Enum)
620
+ {
621
+ int64 EnumValue = Enum->GetValueByNameString(EnumValueName);
622
+
623
+ if (EnumValue != INDEX_NONE)
624
+ {
625
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Found enum value: %lld"), EnumValue);
626
+ EnumProp->GetUnderlyingProperty()->SetIntPropertyValue(
627
+ ComponentTemplate,
628
+ EnumValue
629
+ );
630
+ bSuccess = true;
631
+ }
632
+ else
633
+ {
634
+ // List all possible enum values
635
+ UE_LOG(LogTemp, Warning, TEXT("SetComponentProperty - Available enum values for %s:"),
636
+ *Enum->GetName());
637
+ for (int32 i = 0; i < Enum->NumEnums(); i++)
638
+ {
639
+ UE_LOG(LogTemp, Warning, TEXT(" - %s (%lld)"),
640
+ *Enum->GetNameStringByIndex(i),
641
+ Enum->GetValueByIndex(i));
642
+ }
643
+
644
+ ErrorMessage = FString::Printf(TEXT("Invalid enum value '%s' for property %s"),
645
+ *EnumValueName, *PropertyName);
646
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - %s"), *ErrorMessage);
647
+ }
648
+ }
649
+ else
650
+ {
651
+ ErrorMessage = TEXT("Enum object is NULL");
652
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - %s"), *ErrorMessage);
653
+ }
654
+ }
655
+ else if (JsonValue->Type == EJson::Number)
656
+ {
657
+ // Allow setting enum by integer value
658
+ int64 EnumValue = JsonValue->AsNumber();
659
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Setting enum from number: %lld"), EnumValue);
660
+ EnumProp->GetUnderlyingProperty()->SetIntPropertyValue(
661
+ ComponentTemplate,
662
+ EnumValue
663
+ );
664
+ bSuccess = true;
665
+ }
666
+ else
667
+ {
668
+ ErrorMessage = TEXT("Enum property requires either a string name or integer value");
669
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - %s"), *ErrorMessage);
670
+ }
671
+ }
672
+ else if (FNumericProperty* NumericProp = CastField<FNumericProperty>(Property))
673
+ {
674
+ // Handle numeric properties
675
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Property is numeric: IsInteger=%d, IsFloat=%d"),
676
+ NumericProp->IsInteger(), NumericProp->IsFloatingPoint());
677
+
678
+ if (JsonValue->Type == EJson::Number)
679
+ {
680
+ double Value = JsonValue->AsNumber();
681
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Setting numeric value: %f"), Value);
682
+
683
+ if (NumericProp->IsInteger())
684
+ {
685
+ NumericProp->SetIntPropertyValue(ComponentTemplate, (int64)Value);
686
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Set integer value: %lld"), (int64)Value);
687
+ bSuccess = true;
688
+ }
689
+ else if (NumericProp->IsFloatingPoint())
690
+ {
691
+ NumericProp->SetFloatingPointPropertyValue(ComponentTemplate, Value);
692
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Set float value: %f"), Value);
693
+ bSuccess = true;
694
+ }
695
+ }
696
+ else
697
+ {
698
+ ErrorMessage = TEXT("Numeric property requires a number value");
699
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - %s"), *ErrorMessage);
700
+ }
701
+ }
702
+ else
703
+ {
704
+ // Handle all other property types using default handler
705
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Using generic property handler for %s (Type: %s)"),
706
+ *PropertyName, *Property->GetCPPType());
707
+ bSuccess = FUnrealMCPCommonUtils::SetObjectProperty(ComponentTemplate, PropertyName, JsonValue, ErrorMessage);
708
+ if (!bSuccess)
709
+ {
710
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - Failed to set property: %s"), *ErrorMessage);
711
+ }
712
+ }
713
+ }
714
+ catch (const std::exception& Ex)
715
+ {
716
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - EXCEPTION: %s"), ANSI_TO_TCHAR(Ex.what()));
717
+ return FUnrealMCPCommonUtils::CreateErrorResponse(
718
+ FString::Printf(TEXT("Exception while setting property %s: %s"), *PropertyName, ANSI_TO_TCHAR(Ex.what())));
719
+ }
720
+ catch (...)
721
+ {
722
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - UNKNOWN EXCEPTION occurred while setting property %s"), *PropertyName);
723
+ return FUnrealMCPCommonUtils::CreateErrorResponse(
724
+ FString::Printf(TEXT("Unknown exception while setting property %s"), *PropertyName));
725
+ }
726
+
727
+ if (bSuccess)
728
+ {
729
+ // Mark the blueprint as modified
730
+ UE_LOG(LogTemp, Log, TEXT("SetComponentProperty - Successfully set property %s on component %s"),
731
+ *PropertyName, *ComponentName);
732
+ FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
733
+
734
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
735
+ ResultObj->SetStringField(TEXT("component"), ComponentName);
736
+ ResultObj->SetStringField(TEXT("property"), PropertyName);
737
+ ResultObj->SetBoolField(TEXT("success"), true);
738
+ return ResultObj;
739
+ }
740
+ else
741
+ {
742
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - Failed to set property %s: %s"),
743
+ *PropertyName, *ErrorMessage);
744
+ return FUnrealMCPCommonUtils::CreateErrorResponse(ErrorMessage);
745
+ }
746
+ }
747
+
748
+ UE_LOG(LogTemp, Error, TEXT("SetComponentProperty - Missing 'property_value' parameter"));
749
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'property_value' parameter"));
750
+ }
751
+
752
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintCommands::HandleSetPhysicsProperties(const TSharedPtr<FJsonObject>& Params)
753
+ {
754
+ // Get required parameters
755
+ FString BlueprintName;
756
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
757
+ {
758
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
759
+ }
760
+
761
+ FString ComponentName;
762
+ if (!Params->TryGetStringField(TEXT("component_name"), ComponentName))
763
+ {
764
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'component_name' parameter"));
765
+ }
766
+
767
+ // Find the blueprint
768
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
769
+ if (!Blueprint)
770
+ {
771
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
772
+ }
773
+
774
+ // Find the component
775
+ USCS_Node* ComponentNode = nullptr;
776
+ for (USCS_Node* Node : Blueprint->SimpleConstructionScript->GetAllNodes())
777
+ {
778
+ if (Node && Node->GetVariableName().ToString() == ComponentName)
779
+ {
780
+ ComponentNode = Node;
781
+ break;
782
+ }
783
+ }
784
+
785
+ if (!ComponentNode)
786
+ {
787
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Component not found: %s"), *ComponentName));
788
+ }
789
+
790
+ UPrimitiveComponent* PrimComponent = Cast<UPrimitiveComponent>(ComponentNode->ComponentTemplate);
791
+ if (!PrimComponent)
792
+ {
793
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Component is not a primitive component"));
794
+ }
795
+
796
+ // Set physics properties
797
+ if (Params->HasField(TEXT("simulate_physics")))
798
+ {
799
+ PrimComponent->SetSimulatePhysics(Params->GetBoolField(TEXT("simulate_physics")));
800
+ }
801
+
802
+ if (Params->HasField(TEXT("mass")))
803
+ {
804
+ float Mass = Params->GetNumberField(TEXT("mass"));
805
+ // In UE5.5, use proper overrideMass instead of just scaling
806
+ PrimComponent->SetMassOverrideInKg(NAME_None, Mass);
807
+ UE_LOG(LogTemp, Display, TEXT("Set mass for component %s to %f kg"), *ComponentName, Mass);
808
+ }
809
+
810
+ if (Params->HasField(TEXT("linear_damping")))
811
+ {
812
+ PrimComponent->SetLinearDamping(Params->GetNumberField(TEXT("linear_damping")));
813
+ }
814
+
815
+ if (Params->HasField(TEXT("angular_damping")))
816
+ {
817
+ PrimComponent->SetAngularDamping(Params->GetNumberField(TEXT("angular_damping")));
818
+ }
819
+
820
+ // Mark the blueprint as modified
821
+ FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
822
+
823
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
824
+ ResultObj->SetStringField(TEXT("component"), ComponentName);
825
+ return ResultObj;
826
+ }
827
+
828
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintCommands::HandleCompileBlueprint(const TSharedPtr<FJsonObject>& Params)
829
+ {
830
+ // Get required parameters
831
+ FString BlueprintName;
832
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
833
+ {
834
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
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
+ // Compile the blueprint
845
+ FKismetEditorUtilities::CompileBlueprint(Blueprint);
846
+
847
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
848
+ ResultObj->SetStringField(TEXT("name"), BlueprintName);
849
+ ResultObj->SetBoolField(TEXT("compiled"), true);
850
+ return ResultObj;
851
+ }
852
+
853
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintCommands::HandleSpawnBlueprintActor(const TSharedPtr<FJsonObject>& Params)
854
+ {
855
+ // Get required parameters
856
+ FString BlueprintName;
857
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
858
+ {
859
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
860
+ }
861
+
862
+ FString ActorName;
863
+ if (!Params->TryGetStringField(TEXT("actor_name"), ActorName))
864
+ {
865
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'actor_name' parameter"));
866
+ }
867
+
868
+ // Find the blueprint
869
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
870
+ if (!Blueprint)
871
+ {
872
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
873
+ }
874
+
875
+ // Get transform parameters
876
+ FVector Location(0.0f, 0.0f, 0.0f);
877
+ FRotator Rotation(0.0f, 0.0f, 0.0f);
878
+
879
+ if (Params->HasField(TEXT("location")))
880
+ {
881
+ Location = FUnrealMCPCommonUtils::GetVectorFromJson(Params, TEXT("location"));
882
+ }
883
+ if (Params->HasField(TEXT("rotation")))
884
+ {
885
+ Rotation = FUnrealMCPCommonUtils::GetRotatorFromJson(Params, TEXT("rotation"));
886
+ }
887
+
888
+ // Spawn the actor
889
+ UWorld* World = GEditor->GetEditorWorldContext().World();
890
+ if (!World)
891
+ {
892
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to get editor world"));
893
+ }
894
+
895
+ FTransform SpawnTransform;
896
+ SpawnTransform.SetLocation(Location);
897
+ SpawnTransform.SetRotation(FQuat(Rotation));
898
+
899
+ AActor* NewActor = World->SpawnActor<AActor>(Blueprint->GeneratedClass, SpawnTransform);
900
+ if (NewActor)
901
+ {
902
+ NewActor->SetActorLabel(*ActorName);
903
+ return FUnrealMCPCommonUtils::ActorToJsonObject(NewActor, true);
904
+ }
905
+
906
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to spawn blueprint actor"));
907
+ }
908
+
909
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintCommands::HandleSetBlueprintProperty(const TSharedPtr<FJsonObject>& Params)
910
+ {
911
+ // Get required parameters
912
+ FString BlueprintName;
913
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
914
+ {
915
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
916
+ }
917
+
918
+ FString PropertyName;
919
+ if (!Params->TryGetStringField(TEXT("property_name"), PropertyName))
920
+ {
921
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'property_name' parameter"));
922
+ }
923
+
924
+ // Find the blueprint
925
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
926
+ if (!Blueprint)
927
+ {
928
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
929
+ }
930
+
931
+ // Get the default object
932
+ UObject* DefaultObject = Blueprint->GeneratedClass->GetDefaultObject();
933
+ if (!DefaultObject)
934
+ {
935
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to get default object"));
936
+ }
937
+
938
+ // Set the property value
939
+ if (Params->HasField(TEXT("property_value")))
940
+ {
941
+ TSharedPtr<FJsonValue> JsonValue = Params->Values.FindRef(TEXT("property_value"));
942
+
943
+ FString ErrorMessage;
944
+ if (FUnrealMCPCommonUtils::SetObjectProperty(DefaultObject, PropertyName, JsonValue, ErrorMessage))
945
+ {
946
+ // Mark the blueprint as modified
947
+ FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
948
+
949
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
950
+ ResultObj->SetStringField(TEXT("property"), PropertyName);
951
+ ResultObj->SetBoolField(TEXT("success"), true);
952
+ return ResultObj;
953
+ }
954
+ else
955
+ {
956
+ return FUnrealMCPCommonUtils::CreateErrorResponse(ErrorMessage);
957
+ }
958
+ }
959
+
960
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'property_value' parameter"));
961
+ }
962
+
963
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintCommands::HandleSetStaticMeshProperties(const TSharedPtr<FJsonObject>& Params)
964
+ {
965
+ // Get required parameters
966
+ FString BlueprintName;
967
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
968
+ {
969
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
970
+ }
971
+
972
+ FString ComponentName;
973
+ if (!Params->TryGetStringField(TEXT("component_name"), ComponentName))
974
+ {
975
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'component_name' parameter"));
976
+ }
977
+
978
+ // Find the blueprint
979
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
980
+ if (!Blueprint)
981
+ {
982
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
983
+ }
984
+
985
+ // Find the component
986
+ USCS_Node* ComponentNode = nullptr;
987
+ for (USCS_Node* Node : Blueprint->SimpleConstructionScript->GetAllNodes())
988
+ {
989
+ if (Node && Node->GetVariableName().ToString() == ComponentName)
990
+ {
991
+ ComponentNode = Node;
992
+ break;
993
+ }
994
+ }
995
+
996
+ if (!ComponentNode)
997
+ {
998
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Component not found: %s"), *ComponentName));
999
+ }
1000
+
1001
+ UStaticMeshComponent* MeshComponent = Cast<UStaticMeshComponent>(ComponentNode->ComponentTemplate);
1002
+ if (!MeshComponent)
1003
+ {
1004
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Component is not a static mesh component"));
1005
+ }
1006
+
1007
+ // Set static mesh properties
1008
+ if (Params->HasField(TEXT("static_mesh")))
1009
+ {
1010
+ FString MeshPath = Params->GetStringField(TEXT("static_mesh"));
1011
+ UStaticMesh* Mesh = Cast<UStaticMesh>(UEditorAssetLibrary::LoadAsset(MeshPath));
1012
+ if (Mesh)
1013
+ {
1014
+ MeshComponent->SetStaticMesh(Mesh);
1015
+ }
1016
+ }
1017
+
1018
+ if (Params->HasField(TEXT("material")))
1019
+ {
1020
+ FString MaterialPath = Params->GetStringField(TEXT("material"));
1021
+ UMaterialInterface* Material = Cast<UMaterialInterface>(UEditorAssetLibrary::LoadAsset(MaterialPath));
1022
+ if (Material)
1023
+ {
1024
+ MeshComponent->SetMaterial(0, Material);
1025
+ }
1026
+ }
1027
+
1028
+ // Mark the blueprint as modified
1029
+ FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
1030
+
1031
+ TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
1032
+ ResultObj->SetStringField(TEXT("component"), ComponentName);
1033
+ return ResultObj;
1034
+ }
1035
+
1036
+ TSharedPtr<FJsonObject> FUnrealMCPBlueprintCommands::HandleSetPawnProperties(const TSharedPtr<FJsonObject>& Params)
1037
+ {
1038
+ // Get required parameters
1039
+ FString BlueprintName;
1040
+ if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
1041
+ {
1042
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
1043
+ }
1044
+
1045
+ // Find the blueprint
1046
+ UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
1047
+ if (!Blueprint)
1048
+ {
1049
+ return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
1050
+ }
1051
+
1052
+ // Get the default object
1053
+ UObject* DefaultObject = Blueprint->GeneratedClass->GetDefaultObject();
1054
+ if (!DefaultObject)
1055
+ {
1056
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to get default object"));
1057
+ }
1058
+
1059
+ // Track if any properties were set successfully
1060
+ bool bAnyPropertiesSet = false;
1061
+ TSharedPtr<FJsonObject> ResultsObj = MakeShared<FJsonObject>();
1062
+
1063
+ // Set auto possess player if specified
1064
+ if (Params->HasField(TEXT("auto_possess_player")))
1065
+ {
1066
+ TSharedPtr<FJsonValue> AutoPossessValue = Params->Values.FindRef(TEXT("auto_possess_player"));
1067
+
1068
+ FString ErrorMessage;
1069
+ if (FUnrealMCPCommonUtils::SetObjectProperty(DefaultObject, TEXT("AutoPossessPlayer"), AutoPossessValue, ErrorMessage))
1070
+ {
1071
+ bAnyPropertiesSet = true;
1072
+ TSharedPtr<FJsonObject> PropResultObj = MakeShared<FJsonObject>();
1073
+ PropResultObj->SetBoolField(TEXT("success"), true);
1074
+ ResultsObj->SetObjectField(TEXT("AutoPossessPlayer"), PropResultObj);
1075
+ }
1076
+ else
1077
+ {
1078
+ TSharedPtr<FJsonObject> PropResultObj = MakeShared<FJsonObject>();
1079
+ PropResultObj->SetBoolField(TEXT("success"), false);
1080
+ PropResultObj->SetStringField(TEXT("error"), ErrorMessage);
1081
+ ResultsObj->SetObjectField(TEXT("AutoPossessPlayer"), PropResultObj);
1082
+ }
1083
+ }
1084
+
1085
+ // Set controller rotation properties
1086
+ const TCHAR* RotationProps[] = {
1087
+ TEXT("bUseControllerRotationYaw"),
1088
+ TEXT("bUseControllerRotationPitch"),
1089
+ TEXT("bUseControllerRotationRoll")
1090
+ };
1091
+
1092
+ const TCHAR* ParamNames[] = {
1093
+ TEXT("use_controller_rotation_yaw"),
1094
+ TEXT("use_controller_rotation_pitch"),
1095
+ TEXT("use_controller_rotation_roll")
1096
+ };
1097
+
1098
+ for (int32 i = 0; i < 3; i++)
1099
+ {
1100
+ if (Params->HasField(ParamNames[i]))
1101
+ {
1102
+ TSharedPtr<FJsonValue> Value = Params->Values.FindRef(ParamNames[i]);
1103
+
1104
+ FString ErrorMessage;
1105
+ if (FUnrealMCPCommonUtils::SetObjectProperty(DefaultObject, RotationProps[i], Value, ErrorMessage))
1106
+ {
1107
+ bAnyPropertiesSet = true;
1108
+ TSharedPtr<FJsonObject> PropResultObj = MakeShared<FJsonObject>();
1109
+ PropResultObj->SetBoolField(TEXT("success"), true);
1110
+ ResultsObj->SetObjectField(RotationProps[i], PropResultObj);
1111
+ }
1112
+ else
1113
+ {
1114
+ TSharedPtr<FJsonObject> PropResultObj = MakeShared<FJsonObject>();
1115
+ PropResultObj->SetBoolField(TEXT("success"), false);
1116
+ PropResultObj->SetStringField(TEXT("error"), ErrorMessage);
1117
+ ResultsObj->SetObjectField(RotationProps[i], PropResultObj);
1118
+ }
1119
+ }
1120
+ }
1121
+
1122
+ // Set can be damaged property
1123
+ if (Params->HasField(TEXT("can_be_damaged")))
1124
+ {
1125
+ TSharedPtr<FJsonValue> Value = Params->Values.FindRef(TEXT("can_be_damaged"));
1126
+
1127
+ FString ErrorMessage;
1128
+ if (FUnrealMCPCommonUtils::SetObjectProperty(DefaultObject, TEXT("bCanBeDamaged"), Value, ErrorMessage))
1129
+ {
1130
+ bAnyPropertiesSet = true;
1131
+ TSharedPtr<FJsonObject> PropResultObj = MakeShared<FJsonObject>();
1132
+ PropResultObj->SetBoolField(TEXT("success"), true);
1133
+ ResultsObj->SetObjectField(TEXT("bCanBeDamaged"), PropResultObj);
1134
+ }
1135
+ else
1136
+ {
1137
+ TSharedPtr<FJsonObject> PropResultObj = MakeShared<FJsonObject>();
1138
+ PropResultObj->SetBoolField(TEXT("success"), false);
1139
+ PropResultObj->SetStringField(TEXT("error"), ErrorMessage);
1140
+ ResultsObj->SetObjectField(TEXT("bCanBeDamaged"), PropResultObj);
1141
+ }
1142
+ }
1143
+
1144
+ // Mark the blueprint as modified if any properties were set
1145
+ if (bAnyPropertiesSet)
1146
+ {
1147
+ FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
1148
+ }
1149
+ else if (ResultsObj->Values.Num() == 0)
1150
+ {
1151
+ // No properties were specified
1152
+ return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("No properties specified to set"));
1153
+ }
1154
+
1155
+ TSharedPtr<FJsonObject> ResponseObj = MakeShared<FJsonObject>();
1156
+ ResponseObj->SetStringField(TEXT("blueprint"), BlueprintName);
1157
+ ResponseObj->SetBoolField(TEXT("success"), bAnyPropertiesSet);
1158
+ ResponseObj->SetObjectField(TEXT("results"), ResultsObj);
1159
+ return ResponseObj;
1160
+ }