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,497 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Comprehensive test suite for creating and spawning Blueprints with various component types in Unreal Engine via MCP.
4
+
5
+ The script runs three main test scenarios:
6
+
7
+ 1. Static Mesh Components Test:
8
+ - Creates three different Blueprints with StaticMeshComponents:
9
+ * BP_CubeMesh: A basic cube at [0, 0, 100]
10
+ * BP_SphereMesh: A sphere at [100, 0, 100]
11
+ * BP_CylinderMesh: A cylinder at [0, 100, 100], rotated 90° and stretched (scale: [0.75, 0.75, 2.0])
12
+
13
+ 2. Collision Components Test:
14
+ - Tests creation of physics collision shapes:
15
+ * BP_BoxCollision: Box collision with 'BlockAll' profile
16
+ * BP_SphereCollision: Sphere collision with 'OverlapAll' profile and 100 unit radius
17
+
18
+ 3. Scene Component Hierarchy Test (Currently Disabled):
19
+ - Demonstrates component parenting with:
20
+ * Root SceneComponent
21
+ * Child cube mesh offset 50 units right
22
+ * Child sphere mesh offset 50 units left
23
+
24
+ Each test follows a consistent workflow:
25
+ 1. Create the Blueprint
26
+ 2. Add and configure components
27
+ 3. Set necessary properties (meshes, collision profiles, etc.)
28
+ 4. Compile the Blueprint
29
+ 5. Spawn an instance in the level
30
+
31
+ The script provides detailed logging and error handling for each operation,
32
+ making it useful both as a test suite and as an example of the MCP Blueprint API usage.
33
+ """
34
+
35
+ import sys
36
+ import os
37
+ import time
38
+ import socket
39
+ import json
40
+ import logging
41
+ from typing import Dict, Any, Optional, List
42
+
43
+ # Add the parent directory to the path so we can import the server module
44
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
45
+
46
+ # Set up logging
47
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
48
+ logger = logging.getLogger("TestComponentCreation")
49
+
50
+ def send_command(command: str, params: Dict[str, Any]) -> Optional[Dict[str, Any]]:
51
+ """Send a command to the Unreal MCP server and get the response."""
52
+ try:
53
+ # Connect to Unreal MCP server (fresh connection for each command)
54
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
55
+ sock.connect(("127.0.0.1", 55557))
56
+
57
+ try:
58
+ # Create command object
59
+ command_obj = {
60
+ "type": command,
61
+ "params": params
62
+ }
63
+
64
+ # Convert to JSON and send
65
+ command_json = json.dumps(command_obj)
66
+ logger.info(f"Sending command: {command_json}")
67
+ sock.sendall(command_json.encode('utf-8'))
68
+
69
+ # Receive response
70
+ chunks = []
71
+ while True:
72
+ chunk = sock.recv(4096)
73
+ if not chunk:
74
+ break
75
+ chunks.append(chunk)
76
+
77
+ # Try parsing to see if we have a complete response
78
+ try:
79
+ data = b''.join(chunks)
80
+ json.loads(data.decode('utf-8'))
81
+ # If we can parse it, we have the complete response
82
+ break
83
+ except json.JSONDecodeError:
84
+ # Not a complete JSON object yet, continue receiving
85
+ continue
86
+
87
+ # Parse response
88
+ data = b''.join(chunks)
89
+ response = json.loads(data.decode('utf-8'))
90
+ logger.info(f"Received response: {response}")
91
+ return response
92
+
93
+ finally:
94
+ # Always close the socket
95
+ sock.close()
96
+
97
+ except Exception as e:
98
+ logger.error(f"Error sending command: {e}")
99
+ return None
100
+
101
+ def create_blueprint(name: str, parent_class: str = "Actor") -> bool:
102
+ """Create a blueprint with the given name and parent class."""
103
+ bp_params = {
104
+ "name": name,
105
+ "parent_class": parent_class
106
+ }
107
+
108
+ response = send_command("create_blueprint", bp_params)
109
+
110
+ # Check response
111
+ if not response or response.get("status") != "success":
112
+ logger.error(f"Failed to create blueprint: {response}")
113
+ return False
114
+
115
+ # Check if blueprint already existed
116
+ if response.get("result", {}).get("already_exists"):
117
+ logger.info(f"Blueprint '{name}' already exists, reusing it")
118
+ else:
119
+ logger.info(f"Blueprint '{name}' created successfully!")
120
+
121
+ return True
122
+
123
+ def add_component(
124
+ blueprint_name: str,
125
+ component_type: str,
126
+ component_name: str,
127
+ location: List[float] = [],
128
+ rotation: List[float] = [],
129
+ scale: List[float] = [],
130
+ properties: Dict[str, Any] = {}
131
+ ) -> bool:
132
+ """Add a component to the specified blueprint."""
133
+ component_params: Dict[str, Any] = {
134
+ "blueprint_name": blueprint_name,
135
+ "component_type": component_type,
136
+ "component_name": component_name
137
+ }
138
+
139
+ # Add optional parameters if provided
140
+ if location:
141
+ component_params["location"] = location
142
+ if rotation:
143
+ component_params["rotation"] = rotation
144
+ if scale:
145
+ component_params["scale"] = scale
146
+ if properties:
147
+ component_params["component_properties"] = properties
148
+
149
+ response = send_command("add_component_to_blueprint", component_params)
150
+
151
+ # Check response
152
+ if not response or response.get("status") != "success":
153
+ logger.error(f"Failed to add {component_type} component '{component_name}': {response}")
154
+ return False
155
+
156
+ logger.info(f"Component '{component_name}' of type '{component_type}' added successfully!")
157
+ return True
158
+
159
+ def set_static_mesh(
160
+ blueprint_name: str,
161
+ component_name: str,
162
+ mesh_type: str
163
+ ) -> bool:
164
+ """Set the static mesh for a component."""
165
+ # Convert simple shape name to full asset path if needed
166
+ if mesh_type in ["Cube", "Sphere", "Cylinder", "Cone", "Plane"]:
167
+ static_mesh = f"/Engine/BasicShapes/{mesh_type}.{mesh_type}"
168
+ else:
169
+ # Assume it's already a full path
170
+ static_mesh = mesh_type
171
+
172
+ params = {
173
+ "blueprint_name": blueprint_name,
174
+ "component_name": component_name,
175
+ "static_mesh": static_mesh
176
+ }
177
+
178
+ response = send_command("set_static_mesh_properties", params)
179
+
180
+ # Check response
181
+ if not response or response.get("status") != "success":
182
+ logger.error(f"Failed to set static mesh '{mesh_type}' for component '{component_name}': {response}")
183
+ return False
184
+
185
+ logger.info(f"Static mesh '{mesh_type}' set for component '{component_name}' successfully!")
186
+ return True
187
+
188
+ def compile_blueprint(blueprint_name: str) -> bool:
189
+ """Compile the specified blueprint."""
190
+ compile_params = {
191
+ "blueprint_name": blueprint_name
192
+ }
193
+
194
+ response = send_command("compile_blueprint", compile_params)
195
+
196
+ # Check response
197
+ if not response or response.get("status") != "success":
198
+ logger.error(f"Failed to compile blueprint '{blueprint_name}': {response}")
199
+ return False
200
+
201
+ logger.info(f"Blueprint '{blueprint_name}' compiled successfully!")
202
+ return True
203
+
204
+ def spawn_blueprint_actor(blueprint_name: str, actor_name: str, location: List[float] = []) -> bool:
205
+ """Spawn an actor from the specified blueprint."""
206
+ spawn_params: Dict[str, Any] = {
207
+ "blueprint_name": blueprint_name,
208
+ "actor_name": actor_name
209
+ }
210
+
211
+ # Add location if provided
212
+ if location:
213
+ spawn_params["location"] = location
214
+ else:
215
+ spawn_params["location"] = [0.0, 0.0, 100.0] # Default 100 units up
216
+
217
+ response = send_command("spawn_blueprint_actor", spawn_params)
218
+
219
+ # Check response
220
+ if not response or response.get("status") != "success":
221
+ logger.error(f"Failed to spawn actor from blueprint '{blueprint_name}': {response}")
222
+ return False
223
+
224
+ logger.info(f"Actor '{actor_name}' spawned from blueprint '{blueprint_name}' successfully!")
225
+ return True
226
+
227
+ def test_static_mesh_components():
228
+ """Test creating blueprints with different static mesh components."""
229
+ logger.info("\n=== Testing Static Mesh Components ===\n")
230
+
231
+ # Test cube mesh
232
+ logger.info("Testing cube mesh component...")
233
+ bp_cube_name = "BP_CubeMesh"
234
+ if not create_blueprint(bp_cube_name):
235
+ return False
236
+
237
+ if not add_component(
238
+ blueprint_name=bp_cube_name,
239
+ component_type="StaticMeshComponent",
240
+ component_name="CubeMeshComponent",
241
+ location=[0.0, 0.0, 0.0],
242
+ scale=[1.0, 1.0, 1.0],
243
+ properties={"bVisible": True}
244
+ ):
245
+ return False
246
+
247
+ if not set_static_mesh(
248
+ blueprint_name=bp_cube_name,
249
+ component_name="CubeMeshComponent",
250
+ mesh_type="Cube"
251
+ ):
252
+ return False
253
+
254
+ if not compile_blueprint(bp_cube_name):
255
+ return False
256
+
257
+ if not spawn_blueprint_actor(bp_cube_name, "CubeMeshActor", [0.0, 0.0, 100.0]):
258
+ return False
259
+
260
+ # Test sphere mesh
261
+ logger.info("Testing sphere mesh component...")
262
+ bp_sphere_name = "BP_SphereMesh"
263
+ if not create_blueprint(bp_sphere_name):
264
+ return False
265
+
266
+ if not add_component(
267
+ blueprint_name=bp_sphere_name,
268
+ component_type="StaticMeshComponent",
269
+ component_name="SphereMeshComponent",
270
+ location=[0.0, 0.0, 0.0],
271
+ scale=[1.0, 1.0, 1.0],
272
+ properties={"bVisible": True}
273
+ ):
274
+ return False
275
+
276
+ if not set_static_mesh(
277
+ blueprint_name=bp_sphere_name,
278
+ component_name="SphereMeshComponent",
279
+ mesh_type="Sphere"
280
+ ):
281
+ return False
282
+
283
+ if not compile_blueprint(bp_sphere_name):
284
+ return False
285
+
286
+ if not spawn_blueprint_actor(bp_sphere_name, "SphereMeshActor", [100.0, 0.0, 100.0]):
287
+ return False
288
+
289
+ # Test cylinder mesh
290
+ logger.info("Testing cylinder mesh component...")
291
+ bp_cylinder_name = "BP_CylinderMesh"
292
+ if not create_blueprint(bp_cylinder_name):
293
+ return False
294
+
295
+ if not add_component(
296
+ blueprint_name=bp_cylinder_name,
297
+ component_type="StaticMeshComponent",
298
+ component_name="CylinderMeshComponent",
299
+ location=[0.0, 0.0, 0.0],
300
+ rotation=[0.0, 0.0, 90.0], # Rotated 90 degrees
301
+ scale=[0.75, 0.75, 2.0], # Stretched in Z
302
+ properties={"bVisible": True}
303
+ ):
304
+ return False
305
+
306
+ if not set_static_mesh(
307
+ blueprint_name=bp_cylinder_name,
308
+ component_name="CylinderMeshComponent",
309
+ mesh_type="Cylinder"
310
+ ):
311
+ return False
312
+
313
+ if not compile_blueprint(bp_cylinder_name):
314
+ return False
315
+
316
+ if not spawn_blueprint_actor(bp_cylinder_name, "CylinderMeshActor", [0.0, 100.0, 100.0]):
317
+ return False
318
+
319
+ return True
320
+
321
+ def test_collision_components():
322
+ """Test creating blueprints with different collision components."""
323
+ logger.info("\n=== Testing Collision Components ===\n")
324
+
325
+ # Test box collision component
326
+ logger.info("Testing box collision component...")
327
+ bp_box_name = "BP_BoxCollision"
328
+ if not create_blueprint(bp_box_name):
329
+ return False
330
+
331
+ if not add_component(
332
+ blueprint_name=bp_box_name,
333
+ component_type="BoxComponent",
334
+ component_name="BoxCollisionComponent",
335
+ location=[0.0, 0.0, 0.0],
336
+ scale=[1.0, 1.0, 1.0],
337
+ properties={
338
+ "bVisible": True,
339
+ "CollisionProfileName": "BlockAll"
340
+ }
341
+ ):
342
+ return False
343
+
344
+ if not compile_blueprint(bp_box_name):
345
+ return False
346
+
347
+ if not spawn_blueprint_actor(bp_box_name, "BoxCollisionActor", [0.0, 0.0, 100.0]):
348
+ return False
349
+
350
+ # Test sphere collision component
351
+ logger.info("Testing sphere collision component...")
352
+ bp_sphere_name = "BP_SphereCollision"
353
+ if not create_blueprint(bp_sphere_name):
354
+ return False
355
+
356
+ if not add_component(
357
+ blueprint_name=bp_sphere_name,
358
+ component_type="SphereComponent",
359
+ component_name="SphereCollisionComponent",
360
+ location=[0.0, 0.0, 0.0],
361
+ scale=[1.0, 1.0, 1.0],
362
+ properties={
363
+ "bVisible": True,
364
+ "CollisionProfileName": "OverlapAll",
365
+ "SphereRadius": 100.0 # Custom radius
366
+ }
367
+ ):
368
+ return False
369
+
370
+ if not compile_blueprint(bp_sphere_name):
371
+ return False
372
+
373
+ if not spawn_blueprint_actor(bp_sphere_name, "SphereCollisionActor", [100.0, 0.0, 100.0]):
374
+ return False
375
+
376
+ return True
377
+
378
+ def test_scene_component_hierarchy():
379
+ """Test creating a blueprint with a hierarchy of scene components."""
380
+ logger.info("\n=== Testing Scene Component Hierarchy ===\n")
381
+
382
+ # Create a blueprint for the hierarchy test
383
+ bp_name = "BP_ComponentHierarchy"
384
+ if not create_blueprint(bp_name):
385
+ return False
386
+
387
+ # Add a root scene component
388
+ logger.info("Adding root SceneComponent...")
389
+ if not add_component(
390
+ blueprint_name=bp_name,
391
+ component_type="SceneComponent",
392
+ component_name="RootSceneComponent",
393
+ location=[0.0, 0.0, 0.0]
394
+ ):
395
+ return False
396
+
397
+ # Compile the blueprint after adding the root component
398
+ logger.info("Compiling blueprint after adding root component...")
399
+ if not compile_blueprint(bp_name):
400
+ return False
401
+
402
+ # Add cube mesh as first child
403
+ logger.info("Adding cube mesh as first child...")
404
+ cube_component_name = "ChildCubeMeshComponent"
405
+ if not add_component(
406
+ blueprint_name=bp_name,
407
+ component_type="StaticMeshComponent",
408
+ component_name=cube_component_name,
409
+ location=[50.0, 0.0, 0.0]
410
+ ):
411
+ return False
412
+
413
+ # Compile the blueprint after adding the first child
414
+ logger.info("Compiling blueprint after adding first child...")
415
+ if not compile_blueprint(bp_name):
416
+ return False
417
+
418
+ # Set mesh type for cube
419
+ if not set_static_mesh(
420
+ blueprint_name=bp_name,
421
+ component_name=cube_component_name,
422
+ mesh_type="Cube"
423
+ ):
424
+ return False
425
+
426
+ # Compile the blueprint after setting the mesh
427
+ logger.info("Compiling blueprint after setting first mesh...")
428
+ if not compile_blueprint(bp_name):
429
+ return False
430
+
431
+ # Add sphere mesh as second child
432
+ logger.info("Adding sphere mesh as second child...")
433
+ sphere_component_name = "ChildSphereMeshComponent"
434
+ if not add_component(
435
+ blueprint_name=bp_name,
436
+ component_type="StaticMeshComponent",
437
+ component_name=sphere_component_name,
438
+ location=[-50.0, 0.0, 0.0]
439
+ ):
440
+ return False
441
+
442
+ # Compile the blueprint after adding the second child
443
+ logger.info("Compiling blueprint after adding second child...")
444
+ if not compile_blueprint(bp_name):
445
+ return False
446
+
447
+ # Set mesh type for sphere
448
+ if not set_static_mesh(
449
+ blueprint_name=bp_name,
450
+ component_name=sphere_component_name,
451
+ mesh_type="Sphere"
452
+ ):
453
+ return False
454
+
455
+ # Final compilation
456
+ logger.info("Final blueprint compilation...")
457
+ if not compile_blueprint(bp_name):
458
+ return False
459
+
460
+ # Spawn an actor from the blueprint
461
+ logger.info("Spawning hierarchy actor...")
462
+ if not spawn_blueprint_actor(bp_name, "HierarchyTestActor", [0.0, 0.0, 100.0]):
463
+ return False
464
+
465
+ return True
466
+
467
+ def main():
468
+ """Main function to test different component creation scenarios."""
469
+ try:
470
+ # Test different component scenarios
471
+ tests = [
472
+ test_static_mesh_components,
473
+ test_collision_components,
474
+ # test_scene_component_hierarchy # TODO: Not working
475
+ ]
476
+
477
+ success_count = 0
478
+
479
+ for test_func in tests:
480
+ if test_func():
481
+ success_count += 1
482
+ logger.info(f"{test_func.__name__} completed successfully!")
483
+ else:
484
+ logger.error(f"{test_func.__name__} failed!")
485
+
486
+ # Add a delay between tests
487
+ time.sleep(2)
488
+
489
+ # Report overall results
490
+ logger.info(f"\n=== Test Results: {success_count}/{len(tests)} tests passed ===\n")
491
+
492
+ except Exception as e:
493
+ logger.error(f"Error during testing: {e}")
494
+ sys.exit(1)
495
+
496
+ if __name__ == "__main__":
497
+ main()
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ Test script for creating and manipulating a basic Blueprint in Unreal Engine via MCP.
4
+
5
+ This script demonstrates the core Blueprint creation and manipulation workflow:
6
+ 1. Creates a new Blueprint class (TestBP) derived from Actor
7
+ 2. Adds a StaticMeshComponent named 'CubeVisual' to the Blueprint
8
+ 3. Sets the component's mesh to a basic cube shape (/Engine/BasicShapes/Cube.Cube)
9
+ 4. Compiles the Blueprint to apply the changes
10
+ 5. Spawns an instance of the Blueprint in the level at [0, 0, 100]
11
+
12
+ The script serves as both a test of the MCP Blueprint manipulation functionality
13
+ and a basic example of how to programmatically create and modify Blueprints
14
+ through the MCP interface.
15
+ """
16
+
17
+ import sys
18
+ import os
19
+ import time
20
+ import socket
21
+ import json
22
+ import logging
23
+ from typing import Dict, Any, Optional
24
+
25
+ # Add the parent directory to the path so we can import the server module
26
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
27
+
28
+ # Set up logging
29
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
30
+ logger = logging.getLogger("TestBasicBlueprint")
31
+
32
+ def send_command(sock: socket.socket, command: str, params: Dict[str, Any]) -> Optional[Dict[str, Any]]:
33
+ """Send a command to the Unreal MCP server and get the response."""
34
+ try:
35
+ # Create command object
36
+ command_obj = {
37
+ "type": command,
38
+ "params": params
39
+ }
40
+
41
+ # Convert to JSON and send
42
+ command_json = json.dumps(command_obj)
43
+ logger.info(f"Sending command: {command_json}")
44
+ sock.sendall(command_json.encode('utf-8'))
45
+
46
+ # Receive response
47
+ chunks = []
48
+ while True:
49
+ chunk = sock.recv(4096)
50
+ if not chunk:
51
+ break
52
+ chunks.append(chunk)
53
+
54
+ # Try parsing to see if we have a complete response
55
+ try:
56
+ data = b''.join(chunks)
57
+ json.loads(data.decode('utf-8'))
58
+ # If we can parse it, we have the complete response
59
+ break
60
+ except json.JSONDecodeError:
61
+ # Not a complete JSON object yet, continue receiving
62
+ continue
63
+
64
+ # Parse response
65
+ data = b''.join(chunks)
66
+ response = json.loads(data.decode('utf-8'))
67
+ logger.info(f"Received response: {response}")
68
+ return response
69
+
70
+ except Exception as e:
71
+ logger.error(f"Error sending command: {e}")
72
+ return None
73
+
74
+ def main():
75
+ """Main function to test creating a basic blueprint."""
76
+ try:
77
+ # Connect to Unreal MCP server
78
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
79
+ sock.connect(("127.0.0.1", 55557))
80
+
81
+ try:
82
+ # Step 1: Create a blueprint
83
+ bp_params = {
84
+ "name": "TestBP",
85
+ "parent_class": "Actor"
86
+ }
87
+
88
+ response = send_command(sock, "create_blueprint", bp_params)
89
+
90
+ # Fixed response check to handle nested structure
91
+ if not response or response.get("status") != "success":
92
+ logger.error(f"Failed to create blueprint: {response}")
93
+ return
94
+
95
+ # Check if blueprint already existed
96
+ if response.get("result", {}).get("already_exists"):
97
+ logger.info(f"Blueprint 'TestBP' already exists, reusing it")
98
+ else:
99
+ logger.info("Blueprint created successfully!")
100
+
101
+ # Step 2: Add a static mesh component
102
+ component_params = {
103
+ "blueprint_name": "TestBP",
104
+ "component_type": "StaticMeshComponent",
105
+ "component_name": "CubeVisual",
106
+ "location": [0.0, 0.0, 0.0],
107
+ "rotation": [0.0, 0.0, 0.0],
108
+ "scale": [1.0, 1.0, 1.0]
109
+ }
110
+
111
+ # Close and reopen connection for each command
112
+ sock.close()
113
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
114
+ sock.connect(("127.0.0.1", 55557))
115
+
116
+ response = send_command(sock, "add_component_to_blueprint", component_params)
117
+
118
+ # Fixed response check to handle nested structure
119
+ if not response or response.get("status") != "success":
120
+ logger.error(f"Failed to add component: {response}")
121
+ return
122
+
123
+ logger.info("Component added successfully!")
124
+
125
+ # Step 3: Set the static mesh properties
126
+ sock.close()
127
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
128
+ sock.connect(("127.0.0.1", 55557))
129
+
130
+ mesh_params = {
131
+ "blueprint_name": "TestBP",
132
+ "component_name": "CubeVisual",
133
+ "static_mesh": "/Engine/BasicShapes/Cube.Cube"
134
+ }
135
+
136
+ response = send_command(sock, "set_static_mesh_properties", mesh_params)
137
+
138
+ # Fixed response check to handle nested structure
139
+ if not response or response.get("status") != "success":
140
+ logger.error(f"Failed to set static mesh properties: {response}")
141
+ return
142
+
143
+ logger.info("Static mesh properties set successfully!")
144
+
145
+ # Step 4: Compile the blueprint
146
+ sock.close()
147
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
148
+ sock.connect(("127.0.0.1", 55557))
149
+
150
+ compile_params = {
151
+ "blueprint_name": "TestBP"
152
+ }
153
+
154
+ response = send_command(sock, "compile_blueprint", compile_params)
155
+
156
+ # Fixed response check to handle nested structure
157
+ if not response or response.get("status") != "success":
158
+ logger.error(f"Failed to compile blueprint: {response}")
159
+ return
160
+
161
+ logger.info("Blueprint compiled successfully!")
162
+
163
+ # Step 5: Spawn an instance of the blueprint
164
+ sock.close()
165
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
166
+ sock.connect(("127.0.0.1", 55557))
167
+
168
+ spawn_params = {
169
+ "blueprint_name": "TestBP",
170
+ "actor_name": "TestBPInstance",
171
+ "location": [0.0, 0.0, 100.0], # 100 units up
172
+ "rotation": [0.0, 0.0, 0.0],
173
+ "scale": [1.0, 1.0, 1.0]
174
+ }
175
+
176
+ response = send_command(sock, "spawn_blueprint_actor", spawn_params)
177
+
178
+ # Fixed response check to handle nested structure
179
+ if not response or response.get("status") != "success":
180
+ logger.error(f"Failed to spawn blueprint actor: {response}")
181
+ return
182
+
183
+ logger.info("Blueprint actor spawned successfully!")
184
+
185
+ finally:
186
+ # Close the socket
187
+ sock.close()
188
+
189
+ except Exception as e:
190
+ logger.error(f"Error: {e}")
191
+ sys.exit(1)
192
+
193
+ if __name__ == "__main__":
194
+ main()