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.
- package/README.md +56 -0
- package/bin/flockbay-mcp.mjs +56 -0
- package/bin/flockbay.mjs +78 -0
- package/dist/codex/flockbayMcpStdioBridge.cjs +383 -0
- package/dist/codex/flockbayMcpStdioBridge.d.cts +2 -0
- package/dist/codex/flockbayMcpStdioBridge.d.mts +2 -0
- package/dist/codex/flockbayMcpStdioBridge.mjs +381 -0
- package/dist/flockbayScreenshotGate-DJX3Is5d.mjs +136 -0
- package/dist/flockbayScreenshotGate-DkxU24cR.cjs +138 -0
- package/dist/index--o4BPz5o.cjs +10311 -0
- package/dist/index-CUp3juDS.mjs +10268 -0
- package/dist/index.cjs +43 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +40 -0
- package/dist/lib.cjs +33 -0
- package/dist/lib.d.cts +957 -0
- package/dist/lib.d.mts +957 -0
- package/dist/lib.mjs +23 -0
- package/dist/runCodex-D3eT-TvB.cjs +3449 -0
- package/dist/runCodex-o6PCbHQ7.mjs +3446 -0
- package/dist/runGemini-Bt0oEj_g.mjs +3183 -0
- package/dist/runGemini-CBxZp6I7.cjs +3185 -0
- package/dist/types-C-jnUdn_.cjs +4498 -0
- package/dist/types-DGd6ea2Z.mjs +4450 -0
- package/kits/kit.open_world/kit.json +59 -0
- package/package.json +130 -0
- package/scripts/claude_local_launcher.cjs +73 -0
- package/scripts/claude_remote_launcher.cjs +16 -0
- package/scripts/claude_version_utils.cjs +391 -0
- package/scripts/ripgrep_launcher.cjs +33 -0
- package/scripts/session_hook_forwarder.cjs +49 -0
- package/scripts/test-codex-abort-history.mjs +77 -0
- package/scripts/unpack-tools.cjs +222 -0
- package/tools/licenses/difftastic-LICENSE +21 -0
- package/tools/licenses/ripgrep-LICENSE +3 -0
- package/tools/unreal-mcp/UPSTREAM_VERSION.md +8 -0
- package/tools/unreal-mcp/upstream/Docs/README.md +8 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/README.md +7 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/actor_tools.md +184 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/blueprint_tools.md +268 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/editor_tools.md +104 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/node_tools.md +274 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Config/FilterPlugin.ini +8 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintCommands.cpp +1160 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintNodeCommands.cpp +924 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPCommonUtils.cpp +709 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPEditorCommands.cpp +896 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPProjectCommands.cpp +72 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPUMGCommands.cpp +544 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/MCPServerRunnable.cpp +321 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPBridge.cpp +419 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPModule.cpp +21 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintCommands.h +34 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintNodeCommands.h +27 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPCommonUtils.h +59 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPEditorCommands.h +40 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPProjectCommands.h +20 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPUMGCommands.h +82 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/MCPServerRunnable.h +34 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/UnrealMCPBridge.h +64 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/UnrealMCPModule.h +22 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/UnrealMCP.Build.cs +78 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/UnrealMCP.uplugin +36 -0
- package/tools/unreal-mcp/upstream/Python/README.md +40 -0
- package/tools/unreal-mcp/upstream/Python/pyproject.toml +22 -0
- package/tools/unreal-mcp/upstream/Python/scripts/actors/test_cube.py +203 -0
- package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_blueprints_with_different_components.py +497 -0
- package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_cube_blueprint.py +194 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_component_reference.py +267 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_create_bird_blueprint_with_input_and_camera.py +618 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_input_mapping.py +366 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_physics_variables.py +390 -0
- package/tools/unreal-mcp/upstream/Python/tools/blueprint_tools.py +420 -0
- package/tools/unreal-mcp/upstream/Python/tools/editor_tools.py +369 -0
- package/tools/unreal-mcp/upstream/Python/tools/node_tools.py +430 -0
- package/tools/unreal-mcp/upstream/Python/tools/project_tools.py +64 -0
- package/tools/unreal-mcp/upstream/Python/tools/umg_tools.py +333 -0
- package/tools/unreal-mcp/upstream/Python/unreal_mcp_server.py +398 -0
- package/tools/unreal-mcp/upstream/Python/uv.lock +521 -0
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Test script for blueprint node tools via MCP.
|
|
4
|
+
This script creates a simple flapping bird Blueprint with basic physics and input handling.
|
|
5
|
+
|
|
6
|
+
Commands used:
|
|
7
|
+
1. create_blueprint - Creates a new Blueprint class inheriting from Pawn
|
|
8
|
+
2. add_component_to_blueprint - Adds a StaticMeshComponent named "BirdMesh"
|
|
9
|
+
3. set_physics_properties - Configures physics properties for the mesh
|
|
10
|
+
4. add_blueprint_variable - Adds a Float variable "FlapStrength"
|
|
11
|
+
5. set_static_mesh_properties - Sets the mesh to a sphere
|
|
12
|
+
6. create_input_mapping - Creates a "Flap" action mapped to SpaceBar
|
|
13
|
+
7. find_blueprint_nodes - Searches for existing nodes (e.g., BeginPlay)
|
|
14
|
+
8. add_blueprint_event_node - Creates event nodes (BeginPlay)
|
|
15
|
+
9. add_blueprint_input_action_node - Creates input action node for Flap
|
|
16
|
+
10. add_blueprint_get_self_component_reference - Creates component reference node
|
|
17
|
+
11. add_blueprint_function_node - Creates function nodes (AddImpulse, GetActorOfClass, etc.)
|
|
18
|
+
12. connect_blueprint_nodes - Connects nodes together
|
|
19
|
+
13. compile_blueprint - Compiles the Blueprint
|
|
20
|
+
14. set_pawn_properties - Sets auto-possess properties
|
|
21
|
+
15. spawn_blueprint_actor - Spawns the bird in the level
|
|
22
|
+
16. create_actor - Creates a camera actor
|
|
23
|
+
|
|
24
|
+
Blueprint Graph Layout:
|
|
25
|
+
```
|
|
26
|
+
[BeginPlay] ──────┐
|
|
27
|
+
│
|
|
28
|
+
[InputAction] ───┼─── [BirdMesh] ─── [AddImpulse]
|
|
29
|
+
│
|
|
30
|
+
[GetActorOfClass] ─── [SetViewTargetWithBlend]
|
|
31
|
+
│
|
|
32
|
+
└── [GetPlayerController]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Node Positions:
|
|
36
|
+
- BeginPlay: [-400, 0]
|
|
37
|
+
- InputAction: [-400, 300]
|
|
38
|
+
- BirdMesh: [0, 300]
|
|
39
|
+
- AddImpulse: [400, 300]
|
|
40
|
+
- GetActorOfClass: [0, -200]
|
|
41
|
+
- SetViewTargetWithBlend: [400, -200]
|
|
42
|
+
- GetPlayerController: [0, -100]
|
|
43
|
+
|
|
44
|
+
Connections:
|
|
45
|
+
1. InputAction.Pressed -> AddImpulse.Execute
|
|
46
|
+
2. BirdMesh -> AddImpulse.self
|
|
47
|
+
3. BeginPlay.Then -> GetActorOfClass.Execute
|
|
48
|
+
4. GetActorOfClass.Then -> SetViewTargetWithBlend.Execute
|
|
49
|
+
5. GetActorOfClass.ReturnValue -> SetViewTargetWithBlend.NewViewTarget
|
|
50
|
+
6. GetPlayerController.ReturnValue -> SetViewTargetWithBlend.self
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
import sys
|
|
54
|
+
import os
|
|
55
|
+
import time
|
|
56
|
+
import socket
|
|
57
|
+
import json
|
|
58
|
+
import logging
|
|
59
|
+
from typing import Dict, Any, Optional
|
|
60
|
+
|
|
61
|
+
# Add the parent directory to the path so we can import the server module
|
|
62
|
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
|
63
|
+
|
|
64
|
+
# Set up logging
|
|
65
|
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
66
|
+
logger = logging.getLogger("TestBlueprintNodes")
|
|
67
|
+
|
|
68
|
+
def send_command(sock: socket.socket, command: str, params: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
69
|
+
"""Send a command to the Unreal MCP server and get the response."""
|
|
70
|
+
try:
|
|
71
|
+
# Create command object
|
|
72
|
+
command_obj = {
|
|
73
|
+
"type": command,
|
|
74
|
+
"params": params
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# Convert to JSON and send
|
|
78
|
+
command_json = json.dumps(command_obj)
|
|
79
|
+
logger.info(f"Sending command: {command_json}")
|
|
80
|
+
sock.sendall(command_json.encode('utf-8'))
|
|
81
|
+
|
|
82
|
+
# Receive response
|
|
83
|
+
chunks = []
|
|
84
|
+
while True:
|
|
85
|
+
chunk = sock.recv(4096)
|
|
86
|
+
if not chunk:
|
|
87
|
+
break
|
|
88
|
+
chunks.append(chunk)
|
|
89
|
+
|
|
90
|
+
# Try parsing to see if we have a complete response
|
|
91
|
+
try:
|
|
92
|
+
data = b''.join(chunks)
|
|
93
|
+
json.loads(data.decode('utf-8'))
|
|
94
|
+
# If we can parse it, we have the complete response
|
|
95
|
+
break
|
|
96
|
+
except json.JSONDecodeError:
|
|
97
|
+
# Not a complete JSON object yet, continue receiving
|
|
98
|
+
continue
|
|
99
|
+
|
|
100
|
+
# Parse response
|
|
101
|
+
data = b''.join(chunks)
|
|
102
|
+
response = json.loads(data.decode('utf-8'))
|
|
103
|
+
logger.info(f"Received response: {response}")
|
|
104
|
+
return response
|
|
105
|
+
|
|
106
|
+
except Exception as e:
|
|
107
|
+
logger.error(f"Error sending command: {e}")
|
|
108
|
+
return None
|
|
109
|
+
|
|
110
|
+
def send_mcp_command(command: str, params: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
111
|
+
"""Send a command to the Unreal MCP server with automatic socket lifecycle management."""
|
|
112
|
+
sock = None
|
|
113
|
+
try:
|
|
114
|
+
# Create a new socket for each command
|
|
115
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
116
|
+
sock.connect(("127.0.0.1", 55557))
|
|
117
|
+
|
|
118
|
+
# Send the command and get the response
|
|
119
|
+
return send_command(sock, command, params)
|
|
120
|
+
|
|
121
|
+
except Exception as e:
|
|
122
|
+
logger.error(f"Error in socket communication: {e}")
|
|
123
|
+
return None
|
|
124
|
+
finally:
|
|
125
|
+
# Always close the socket when done
|
|
126
|
+
if sock:
|
|
127
|
+
sock.close()
|
|
128
|
+
|
|
129
|
+
def main():
|
|
130
|
+
"""Main function to test blueprint node tools."""
|
|
131
|
+
try:
|
|
132
|
+
# Step 1: Create a blueprint for the bird
|
|
133
|
+
bp_params = {
|
|
134
|
+
"name": "BirdBP",
|
|
135
|
+
"parent_class": "Pawn"
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
response = send_mcp_command("create_blueprint", bp_params)
|
|
139
|
+
|
|
140
|
+
if not response or response.get("status") != "success":
|
|
141
|
+
logger.error(f"Failed to create blueprint: {response}")
|
|
142
|
+
return
|
|
143
|
+
|
|
144
|
+
# Check if blueprint already existed
|
|
145
|
+
if response.get("result", {}).get("already_exists"):
|
|
146
|
+
logger.info(f"Blueprint 'BirdBP' already exists, reusing it")
|
|
147
|
+
else:
|
|
148
|
+
logger.info("Blueprint created successfully!")
|
|
149
|
+
|
|
150
|
+
# Step 2: Add a static mesh component
|
|
151
|
+
component_params = {
|
|
152
|
+
"blueprint_name": "BirdBP",
|
|
153
|
+
"component_type": "StaticMeshComponent",
|
|
154
|
+
"component_name": "BirdMesh",
|
|
155
|
+
"location": [0.0, 0.0, 0.0],
|
|
156
|
+
"rotation": [0.0, 0.0, 0.0],
|
|
157
|
+
"scale": [0.5, 0.5, 0.5] # Smaller bird
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
response = send_mcp_command("add_component_to_blueprint", component_params)
|
|
161
|
+
|
|
162
|
+
if not response or response.get("status") != "success":
|
|
163
|
+
logger.error(f"Failed to add component: {response}")
|
|
164
|
+
return
|
|
165
|
+
|
|
166
|
+
logger.info("Bird mesh component added successfully!")
|
|
167
|
+
|
|
168
|
+
# Step 3: Add physics properties to the mesh
|
|
169
|
+
physics_params = {
|
|
170
|
+
"blueprint_name": "BirdBP",
|
|
171
|
+
"component_name": "BirdMesh",
|
|
172
|
+
"simulate_physics": True,
|
|
173
|
+
"gravity_enabled": True,
|
|
174
|
+
"mass": 2.0, # Light bird
|
|
175
|
+
"linear_damping": 0.5, # Some air resistance
|
|
176
|
+
"angular_damping": 0.5 # Prevent too much spinning
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
response = send_mcp_command("set_physics_properties", physics_params)
|
|
180
|
+
|
|
181
|
+
if not response or response.get("status") != "success":
|
|
182
|
+
logger.error(f"Failed to set physics properties: {response}")
|
|
183
|
+
return
|
|
184
|
+
|
|
185
|
+
logger.info("Physics properties set successfully!")
|
|
186
|
+
|
|
187
|
+
# Step 4: Add variables for tracking bird state
|
|
188
|
+
response = send_mcp_command("add_blueprint_variable", {
|
|
189
|
+
"blueprint_name": "BirdBP",
|
|
190
|
+
"variable_name": "FlapStrength",
|
|
191
|
+
"variable_type": "Float",
|
|
192
|
+
"default_value": 500.0,
|
|
193
|
+
"is_exposed": True
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
if not response or response.get("status") != "success":
|
|
197
|
+
logger.error(f"Failed to add variable: {response}")
|
|
198
|
+
return
|
|
199
|
+
|
|
200
|
+
logger.info("FlapStrength variable added successfully!")
|
|
201
|
+
|
|
202
|
+
# Step 4b: Set the static mesh of the BirdMesh component to a sphere
|
|
203
|
+
response = send_mcp_command("set_static_mesh_properties", {
|
|
204
|
+
"blueprint_name": "BirdBP",
|
|
205
|
+
"component_name": "BirdMesh",
|
|
206
|
+
"static_mesh": "/Engine/BasicShapes/Sphere.Sphere"
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
if not response or response.get("status") != "success":
|
|
210
|
+
logger.error(f"Failed to set static mesh: {response}")
|
|
211
|
+
return
|
|
212
|
+
|
|
213
|
+
logger.info("Setting Static Mesh Component of Bird to sphere successfully!")
|
|
214
|
+
|
|
215
|
+
# Step 5: Create input mapping for flap action
|
|
216
|
+
response = send_mcp_command("create_input_mapping", {
|
|
217
|
+
"action_name": "Flap",
|
|
218
|
+
"key": "SpaceBar",
|
|
219
|
+
"input_type": "Action"
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
if not response or response.get("status") != "success":
|
|
223
|
+
logger.error(f"Failed to create input mapping: {response}")
|
|
224
|
+
return
|
|
225
|
+
|
|
226
|
+
logger.info("Flap input mapping created successfully!")
|
|
227
|
+
|
|
228
|
+
# Step 6: Create BeginPlay event node - check if it exists first
|
|
229
|
+
begin_play_response = None
|
|
230
|
+
|
|
231
|
+
# First try to find existing BeginPlay nodes
|
|
232
|
+
find_begin_play_params = {
|
|
233
|
+
"blueprint_name": "BirdBP",
|
|
234
|
+
"node_type": "Event",
|
|
235
|
+
"event_name": "ReceiveBeginPlay" # Use the exact Unreal Engine event name
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
response = send_mcp_command("find_blueprint_nodes", find_begin_play_params)
|
|
239
|
+
|
|
240
|
+
if response and response.get("status") == "success":
|
|
241
|
+
# Look for BeginPlay nodes in the response
|
|
242
|
+
nodes = response.get("result", {}).get("node_guids", [])
|
|
243
|
+
if nodes:
|
|
244
|
+
logger.info(f"Found existing ReceiveBeginPlay node, reusing it")
|
|
245
|
+
# Use the first BeginPlay node we find
|
|
246
|
+
begin_play_node_id = nodes[0]
|
|
247
|
+
begin_play_response = {"result": {"success": True, "node_id": begin_play_node_id}}
|
|
248
|
+
|
|
249
|
+
# Only create a new BeginPlay node if we didn't find one
|
|
250
|
+
if begin_play_response is None:
|
|
251
|
+
begin_play_params = {
|
|
252
|
+
"blueprint_name": "BirdBP",
|
|
253
|
+
"event_name": "ReceiveBeginPlay",
|
|
254
|
+
"node_position": [-400, 0] # Move BeginPlay further left
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
response = send_mcp_command("add_blueprint_event_node", begin_play_params)
|
|
258
|
+
|
|
259
|
+
if not response or response.get("status") != "success":
|
|
260
|
+
logger.error(f"Failed to add ReceiveBeginPlay event node: {response}")
|
|
261
|
+
return
|
|
262
|
+
|
|
263
|
+
logger.info("ReceiveBeginPlay event node added successfully!")
|
|
264
|
+
|
|
265
|
+
# Save the node ID for later connections
|
|
266
|
+
begin_play_node_id = begin_play_response.get("result", {}).get("node_id")
|
|
267
|
+
|
|
268
|
+
# Step 7: Create input action event node
|
|
269
|
+
input_action_params = {
|
|
270
|
+
"blueprint_name": "BirdBP",
|
|
271
|
+
"action_name": "Flap",
|
|
272
|
+
"node_position": [-400, 300] # Move input action down and left
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
# Create the InputAction event node using the dedicated function
|
|
276
|
+
response = send_mcp_command("add_blueprint_input_action_node", input_action_params)
|
|
277
|
+
|
|
278
|
+
if not response or response.get("status") != "success":
|
|
279
|
+
logger.error(f"Failed to add Input action node: {response}")
|
|
280
|
+
return
|
|
281
|
+
|
|
282
|
+
logger.info("Input action node added successfully")
|
|
283
|
+
|
|
284
|
+
# Save the node ID for later connections
|
|
285
|
+
input_node_id = response.get("result", {}).get("node_id")
|
|
286
|
+
|
|
287
|
+
# Step 8: Add a get component reference node for BirdMesh
|
|
288
|
+
get_component_params = {
|
|
289
|
+
"blueprint_name": "BirdBP",
|
|
290
|
+
"component_name": "BirdMesh",
|
|
291
|
+
"node_position": [0, 300] # Center the component reference
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
response = send_mcp_command("add_blueprint_get_self_component_reference", get_component_params)
|
|
295
|
+
|
|
296
|
+
if not response or response.get("status") != "success":
|
|
297
|
+
logger.error(f"Failed to add component reference node: {response}")
|
|
298
|
+
return
|
|
299
|
+
|
|
300
|
+
get_component_node_id = response.get("result", {}).get("node_id")
|
|
301
|
+
|
|
302
|
+
# Step 9: Add function node to apply impulse on flap
|
|
303
|
+
function_params = {
|
|
304
|
+
"blueprint_name": "BirdBP",
|
|
305
|
+
"function_name": "AddImpulse",
|
|
306
|
+
"target": "UPrimitiveComponent",
|
|
307
|
+
"params": {
|
|
308
|
+
"Impulse": [0, 0, 1000]
|
|
309
|
+
},
|
|
310
|
+
"node_position": [400, 300] # Move AddImpulse to the right
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
response = send_mcp_command("add_blueprint_function_node", function_params)
|
|
314
|
+
|
|
315
|
+
if not response or response.get("status") != "success":
|
|
316
|
+
logger.error(f"Failed to add AddImpulse function node: {response}")
|
|
317
|
+
# If UPrimitiveComponent fails, try alternatives
|
|
318
|
+
targets_to_try = ["PrimitiveComponent", "SceneComponent", "USceneComponent"]
|
|
319
|
+
|
|
320
|
+
for target in targets_to_try:
|
|
321
|
+
logger.info(f"Trying alternative class for AddImpulse: {target}")
|
|
322
|
+
function_params["target"] = target
|
|
323
|
+
|
|
324
|
+
response = send_mcp_command("add_blueprint_function_node", function_params)
|
|
325
|
+
if response and response.get("status") == "success":
|
|
326
|
+
logger.info(f"Successfully added AddImpulse using target class: {target}")
|
|
327
|
+
break
|
|
328
|
+
else:
|
|
329
|
+
logger.error("All attempts to add AddImpulse function failed")
|
|
330
|
+
return
|
|
331
|
+
|
|
332
|
+
logger.info("AddImpulse function node added successfully!")
|
|
333
|
+
|
|
334
|
+
# Save the node ID for later connections
|
|
335
|
+
add_impulse_node_id = response.get("result", {}).get("node_id")
|
|
336
|
+
|
|
337
|
+
# Step 10: Connect input event to add impulse function
|
|
338
|
+
connect_params = {
|
|
339
|
+
"blueprint_name": "BirdBP",
|
|
340
|
+
"source_node_id": input_node_id,
|
|
341
|
+
"source_pin": "Pressed", # Execute pin on input action event node
|
|
342
|
+
"target_node_id": add_impulse_node_id,
|
|
343
|
+
"target_pin": "Execute" # Execute pin on function node
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
response = send_mcp_command("connect_blueprint_nodes", connect_params)
|
|
347
|
+
|
|
348
|
+
if not response or response.get("status") != "success":
|
|
349
|
+
logger.error(f"Failed to connect nodes: {response}")
|
|
350
|
+
return
|
|
351
|
+
|
|
352
|
+
logger.info("Input node connected to AddImpulse successfully!")
|
|
353
|
+
|
|
354
|
+
# Step 11: Connect get component to add impulse function (target connection)
|
|
355
|
+
connect_target_params = {
|
|
356
|
+
"blueprint_name": "BirdBP",
|
|
357
|
+
"source_node_id": get_component_node_id,
|
|
358
|
+
"source_pin": "BirdMesh", # Use component name as the output pin name (UE5.5 convention)
|
|
359
|
+
"target_node_id": add_impulse_node_id,
|
|
360
|
+
"target_pin": "self" # Change from "Target" to "self" - this is the actual pin name in UE5.5
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
response = send_mcp_command("connect_blueprint_nodes", connect_target_params)
|
|
364
|
+
|
|
365
|
+
if not response or response.get("status") != "success":
|
|
366
|
+
logger.error(f"Failed to connect component to target pin: {response}")
|
|
367
|
+
return
|
|
368
|
+
|
|
369
|
+
logger.info("Component target connected successfully!")
|
|
370
|
+
|
|
371
|
+
# Step 12: Compile the blueprint
|
|
372
|
+
response = send_mcp_command("compile_blueprint", {
|
|
373
|
+
"blueprint_name": "BirdBP"
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
if not response or response.get("status") != "success":
|
|
377
|
+
logger.error(f"Failed to compile blueprint: {response}")
|
|
378
|
+
return
|
|
379
|
+
|
|
380
|
+
logger.info("Blueprint compiled successfully!")
|
|
381
|
+
|
|
382
|
+
# Step 13: Set pawn properties using the new utility function
|
|
383
|
+
response = send_mcp_command("set_pawn_properties", {
|
|
384
|
+
"blueprint_name": "BirdBP",
|
|
385
|
+
"auto_possess_player": "Player0" # Use short enum name as per reflection docs
|
|
386
|
+
})
|
|
387
|
+
|
|
388
|
+
if not response or response.get("status") != "success":
|
|
389
|
+
logger.error(f"Failed to set pawn properties: {response}")
|
|
390
|
+
return
|
|
391
|
+
|
|
392
|
+
logger.info("Pawn properties set successfully!")
|
|
393
|
+
|
|
394
|
+
# Step 14: Add GetActorOfClass node to BirdBP's BeginPlay
|
|
395
|
+
# Note: In UE5.5, class references must use the full path format: /Script/ModuleName.ClassName
|
|
396
|
+
# This format is the standard way Unreal Engine references classes internally:
|
|
397
|
+
# - /Script/ prefix indicates this is a C++ (native) class
|
|
398
|
+
# - ModuleName is the module where the class is defined (e.g., Engine, Game)
|
|
399
|
+
# - ClassName is the actual class name
|
|
400
|
+
# Examples:
|
|
401
|
+
# - /Script/Engine.CameraActor for the camera actor class
|
|
402
|
+
# - /Script/Engine.PlayerController for the player controller class
|
|
403
|
+
get_camera_params = {
|
|
404
|
+
"blueprint_name": "BirdBP",
|
|
405
|
+
"function_name": "GetActorOfClass",
|
|
406
|
+
"target": "UGameplayStatics",
|
|
407
|
+
"params": {
|
|
408
|
+
"ActorClass": "/Script/Engine.CameraActor"
|
|
409
|
+
},
|
|
410
|
+
"node_position": [0, -200] # Move camera setup nodes down
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
response = send_mcp_command("add_blueprint_function_node", get_camera_params)
|
|
414
|
+
|
|
415
|
+
if not response or response.get("status") != "success":
|
|
416
|
+
logger.error(f"Failed to add GetActorOfClass node: {response}")
|
|
417
|
+
return
|
|
418
|
+
|
|
419
|
+
logger.info("GetActorOfClass node added successfully!")
|
|
420
|
+
get_camera_node_id = response.get("result", {}).get("node_id")
|
|
421
|
+
|
|
422
|
+
# Step 15 (formerly 17): Add SetViewTargetWithBlend node
|
|
423
|
+
# Add SetViewTargetWithBlend function node
|
|
424
|
+
set_view_params = {
|
|
425
|
+
"blueprint_name": "BirdBP",
|
|
426
|
+
"function_name": "SetViewTargetWithBlend",
|
|
427
|
+
"target": "PlayerController",
|
|
428
|
+
"params": {
|
|
429
|
+
"BlendTime": 0.0,
|
|
430
|
+
"BlendFunc": "VTBlend_EaseInOut",
|
|
431
|
+
"LockOutgoing": True
|
|
432
|
+
},
|
|
433
|
+
"node_position": [400, -200] # Align with GetActorOfClass
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
response = send_mcp_command("add_blueprint_function_node", set_view_params)
|
|
437
|
+
|
|
438
|
+
if not response or response.get("status") != "success":
|
|
439
|
+
logger.error(f"Failed to add SetViewTargetWithBlend node: {response}")
|
|
440
|
+
return
|
|
441
|
+
|
|
442
|
+
logger.info("SetViewTargetWithBlend node added successfully!")
|
|
443
|
+
set_view_node_id = response.get("result", {}).get("node_id")
|
|
444
|
+
|
|
445
|
+
# Step 16 (formerly 18): Connect BeginPlay to the SetViewTargetWithBlend node
|
|
446
|
+
# Try to find existing BeginPlay node first
|
|
447
|
+
find_begin_play_params = {
|
|
448
|
+
"blueprint_name": "BirdBP",
|
|
449
|
+
"node_type": "Event",
|
|
450
|
+
"event_name": "ReceiveBeginPlay" # Use the exact Unreal Engine event name
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
response = send_mcp_command("find_blueprint_nodes", find_begin_play_params)
|
|
454
|
+
|
|
455
|
+
if response and response.get("status") == "success":
|
|
456
|
+
# Use existing BeginPlay node if found
|
|
457
|
+
nodes = response.get("result", {}).get("nodes", [])
|
|
458
|
+
if nodes:
|
|
459
|
+
logger.info(f"Found existing ReceiveBeginPlay node, reusing it")
|
|
460
|
+
begin_play_node_id = nodes[0].get("node_id")
|
|
461
|
+
else:
|
|
462
|
+
# Create a new BeginPlay node only if none exists
|
|
463
|
+
begin_play_params = {
|
|
464
|
+
"blueprint_name": "BirdBP",
|
|
465
|
+
"event_name": "ReceiveBeginPlay", # Use the exact Unreal Engine event name
|
|
466
|
+
"node_position": [-400, 0] # Move BeginPlay further left
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
response = send_mcp_command("add_blueprint_event_node", begin_play_params)
|
|
470
|
+
|
|
471
|
+
if not response or response.get("status") != "success":
|
|
472
|
+
logger.error(f"Failed to get/create ReceiveBeginPlay node: {response}")
|
|
473
|
+
return
|
|
474
|
+
|
|
475
|
+
begin_play_node_id = response.get("result", {}).get("node_id")
|
|
476
|
+
else:
|
|
477
|
+
logger.error(f"Failed to search for ReceiveBeginPlay nodes: {response}")
|
|
478
|
+
return
|
|
479
|
+
|
|
480
|
+
# Connect BeginPlay to GetActorOfClass (instead of directly to SetViewTargetWithBlend)
|
|
481
|
+
connect_begin_play_params = {
|
|
482
|
+
"blueprint_name": "BirdBP",
|
|
483
|
+
"source_node_id": begin_play_node_id,
|
|
484
|
+
"source_pin": "Then",
|
|
485
|
+
"target_node_id": get_camera_node_id,
|
|
486
|
+
"target_pin": "Execute" # Connect to GetActorOfClass's execute pin (capital E)
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
response = send_mcp_command("connect_blueprint_nodes", connect_begin_play_params)
|
|
490
|
+
|
|
491
|
+
if not response or response.get("status") != "success":
|
|
492
|
+
logger.error(f"Failed to connect BeginPlay to GetActorOfClass: {response}")
|
|
493
|
+
return
|
|
494
|
+
|
|
495
|
+
logger.info("Connected BeginPlay to GetActorOfClass successfully!")
|
|
496
|
+
|
|
497
|
+
# Then connect GetActorOfClass to SetViewTargetWithBlend
|
|
498
|
+
connect_camera_exec_params = {
|
|
499
|
+
"blueprint_name": "BirdBP",
|
|
500
|
+
"source_node_id": get_camera_node_id,
|
|
501
|
+
"source_pin": "Then", # Output execution pin from GetActorOfClass (capital T)
|
|
502
|
+
"target_node_id": set_view_node_id,
|
|
503
|
+
"target_pin": "Execute" # Input execution pin on SetViewTargetWithBlend (capital E)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
response = send_mcp_command("connect_blueprint_nodes", connect_camera_exec_params)
|
|
507
|
+
|
|
508
|
+
if not response or response.get("status") != "success":
|
|
509
|
+
logger.error(f"Failed to connect GetActorOfClass to SetViewTargetWithBlend execution: {response}")
|
|
510
|
+
return
|
|
511
|
+
|
|
512
|
+
logger.info("Connected GetActorOfClass execution to SetViewTargetWithBlend successfully!")
|
|
513
|
+
|
|
514
|
+
# Now connect GetActorOfClass result to SetViewTargetWithBlend's target parameter
|
|
515
|
+
connect_camera_params = {
|
|
516
|
+
"blueprint_name": "BirdBP",
|
|
517
|
+
"source_node_id": get_camera_node_id,
|
|
518
|
+
"source_pin": "ReturnValue",
|
|
519
|
+
"target_node_id": set_view_node_id,
|
|
520
|
+
"target_pin": "NewViewTarget"
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
response = send_mcp_command("connect_blueprint_nodes", connect_camera_params)
|
|
524
|
+
|
|
525
|
+
if not response or response.get("status") != "success":
|
|
526
|
+
logger.error(f"Failed to connect camera to SetViewTargetWithBlend: {response}")
|
|
527
|
+
return
|
|
528
|
+
|
|
529
|
+
logger.info("Connected GetActorOfClass to SetViewTargetWithBlend successfully!")
|
|
530
|
+
|
|
531
|
+
# Step 18 (formerly 20): Get Player Controller for the SetViewTargetWithBlend function
|
|
532
|
+
# Add Get Player Controller node
|
|
533
|
+
get_pc_params = {
|
|
534
|
+
"blueprint_name": "BirdBP",
|
|
535
|
+
"function_name": "GetPlayerController",
|
|
536
|
+
"target": "UGameplayStatics",
|
|
537
|
+
"params": {
|
|
538
|
+
"PlayerIndex": 0
|
|
539
|
+
},
|
|
540
|
+
"node_position": [0, -100] # Place between GetActorOfClass and SetViewTarget
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
response = send_mcp_command("add_blueprint_function_node", get_pc_params)
|
|
544
|
+
|
|
545
|
+
if not response or response.get("status") != "success":
|
|
546
|
+
logger.error(f"Failed to add GetPlayerController node: {response}")
|
|
547
|
+
return
|
|
548
|
+
|
|
549
|
+
logger.info("GetPlayerController node added successfully!")
|
|
550
|
+
get_pc_node_id = response.get("result", {}).get("node_id")
|
|
551
|
+
|
|
552
|
+
# Connect Player Controller to SetViewTargetWithBlend
|
|
553
|
+
connect_pc_params = {
|
|
554
|
+
"blueprint_name": "BirdBP",
|
|
555
|
+
"source_node_id": get_pc_node_id,
|
|
556
|
+
"source_pin": "ReturnValue",
|
|
557
|
+
"target_node_id": set_view_node_id,
|
|
558
|
+
"target_pin": "self"
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
response = send_mcp_command("connect_blueprint_nodes", connect_pc_params)
|
|
562
|
+
|
|
563
|
+
if not response or response.get("status") != "success":
|
|
564
|
+
logger.error(f"Failed to connect player controller to SetViewTargetWithBlend: {response}")
|
|
565
|
+
return
|
|
566
|
+
|
|
567
|
+
logger.info("Connected PlayerController to SetViewTargetWithBlend target successfully!")
|
|
568
|
+
|
|
569
|
+
# Step 19 (formerly 21): Compile the blueprint with the new camera view setup
|
|
570
|
+
response = send_mcp_command("compile_blueprint", {
|
|
571
|
+
"blueprint_name": "BirdBP"
|
|
572
|
+
})
|
|
573
|
+
|
|
574
|
+
if not response or response.get("status") != "success":
|
|
575
|
+
logger.error(f"Failed to compile blueprint: {response}")
|
|
576
|
+
return
|
|
577
|
+
|
|
578
|
+
logger.info("Blueprint with camera view setup compiled successfully!")
|
|
579
|
+
|
|
580
|
+
# Step 20 (formerly 14): Spawn the bird in the level
|
|
581
|
+
response = send_mcp_command("spawn_blueprint_actor", {
|
|
582
|
+
"blueprint_name": "BirdBP",
|
|
583
|
+
"actor_name": "Bird",
|
|
584
|
+
"location": [0.0, 0.0, 200.0], # 200 units up
|
|
585
|
+
"rotation": [0.0, 0.0, 0.0],
|
|
586
|
+
"scale": [1.0, 1.0, 1.0]
|
|
587
|
+
})
|
|
588
|
+
|
|
589
|
+
if not response or response.get("status") != "success":
|
|
590
|
+
logger.error(f"Failed to spawn blueprint actor: {response}")
|
|
591
|
+
return
|
|
592
|
+
|
|
593
|
+
logger.info("Bird spawned successfully!")
|
|
594
|
+
|
|
595
|
+
# Step 21 (formerly 15): Add a camera to the level
|
|
596
|
+
# Create a camera actor
|
|
597
|
+
response = send_mcp_command("create_actor", {
|
|
598
|
+
"name": "GameCamera",
|
|
599
|
+
"type": "CameraActor",
|
|
600
|
+
"location": [500.0, 0.0, 250.0], # Position camera to view the bird from a distance
|
|
601
|
+
"rotation": [0.0, 180.0, 0.0], # Point camera at bird's spawn location
|
|
602
|
+
"scale": [1.0, 1.0, 1.0]
|
|
603
|
+
})
|
|
604
|
+
|
|
605
|
+
if not response or response.get("status") != "success":
|
|
606
|
+
logger.error(f"Failed to create camera actor: {response}")
|
|
607
|
+
return
|
|
608
|
+
|
|
609
|
+
logger.info("Camera actor created successfully!")
|
|
610
|
+
|
|
611
|
+
logger.info("You can now press spacebar to make the bird flap! The camera will automatically view the bird.")
|
|
612
|
+
|
|
613
|
+
except Exception as e:
|
|
614
|
+
logger.error(f"Error: {e}")
|
|
615
|
+
sys.exit(1)
|
|
616
|
+
|
|
617
|
+
if __name__ == "__main__":
|
|
618
|
+
main()
|