unreal-engine-mcp-server 0.5.0 → 0.5.2
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/.env.example +1 -1
- package/.github/release-drafter-config.yml +51 -0
- package/.github/workflows/greetings.yml +5 -1
- package/.github/workflows/labeler.yml +2 -1
- package/.github/workflows/publish-mcp.yml +2 -4
- package/.github/workflows/release-drafter.yml +3 -2
- package/.github/workflows/release.yml +3 -3
- package/CHANGELOG.md +109 -0
- package/CONTRIBUTING.md +1 -1
- package/GEMINI.md +115 -0
- package/Public/Plugin_setup_guide.mp4 +0 -0
- package/README.md +166 -200
- package/dist/automation/bridge.d.ts +1 -2
- package/dist/automation/bridge.js +24 -23
- package/dist/automation/connection-manager.d.ts +1 -0
- package/dist/automation/connection-manager.js +10 -0
- package/dist/automation/message-handler.js +5 -4
- package/dist/automation/request-tracker.d.ts +4 -0
- package/dist/automation/request-tracker.js +11 -3
- package/dist/config.d.ts +0 -1
- package/dist/config.js +0 -1
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +4 -0
- package/dist/graphql/loaders.d.ts +64 -0
- package/dist/graphql/loaders.js +117 -0
- package/dist/graphql/resolvers.d.ts +3 -3
- package/dist/graphql/resolvers.js +33 -30
- package/dist/graphql/server.js +3 -1
- package/dist/graphql/types.d.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +13 -2
- package/dist/server-setup.d.ts +0 -1
- package/dist/server-setup.js +0 -40
- package/dist/tools/actors.d.ts +58 -24
- package/dist/tools/actors.js +22 -6
- package/dist/tools/assets.d.ts +19 -71
- package/dist/tools/assets.js +28 -22
- package/dist/tools/base-tool.d.ts +4 -4
- package/dist/tools/base-tool.js +1 -1
- package/dist/tools/blueprint.d.ts +45 -61
- package/dist/tools/blueprint.js +43 -14
- package/dist/tools/consolidated-tool-definitions.js +2 -1
- package/dist/tools/consolidated-tool-handlers.js +96 -110
- package/dist/tools/dynamic-handler-registry.d.ts +11 -9
- package/dist/tools/dynamic-handler-registry.js +17 -95
- package/dist/tools/editor.d.ts +19 -193
- package/dist/tools/editor.js +11 -2
- package/dist/tools/environment.d.ts +8 -14
- package/dist/tools/foliage.d.ts +18 -143
- package/dist/tools/foliage.js +4 -2
- package/dist/tools/handlers/actor-handlers.d.ts +1 -1
- package/dist/tools/handlers/actor-handlers.js +14 -13
- package/dist/tools/handlers/asset-handlers.js +454 -454
- package/dist/tools/handlers/sequence-handlers.d.ts +1 -1
- package/dist/tools/handlers/sequence-handlers.js +24 -13
- package/dist/tools/introspection.d.ts +1 -1
- package/dist/tools/introspection.js +1 -1
- package/dist/tools/landscape.d.ts +16 -116
- package/dist/tools/landscape.js +7 -3
- package/dist/tools/level.d.ts +22 -103
- package/dist/tools/level.js +26 -18
- package/dist/tools/lighting.d.ts +54 -7
- package/dist/tools/lighting.js +9 -5
- package/dist/tools/materials.d.ts +1 -1
- package/dist/tools/materials.js +5 -1
- package/dist/tools/niagara.js +37 -2
- package/dist/tools/performance.d.ts +0 -1
- package/dist/tools/performance.js +0 -1
- package/dist/tools/physics.js +5 -1
- package/dist/tools/sequence.d.ts +24 -24
- package/dist/tools/sequence.js +13 -0
- package/dist/tools/ui.d.ts +0 -2
- package/dist/types/automation-responses.d.ts +115 -0
- package/dist/types/automation-responses.js +2 -0
- package/dist/types/responses.d.ts +249 -0
- package/dist/types/responses.js +2 -0
- package/dist/types/tool-interfaces.d.ts +135 -135
- package/dist/types/tool-types.d.ts +2 -0
- package/dist/unreal-bridge.js +4 -4
- package/dist/utils/command-validator.js +7 -5
- package/dist/utils/error-handler.d.ts +24 -2
- package/dist/utils/error-handler.js +58 -23
- package/dist/utils/normalize.d.ts +7 -4
- package/dist/utils/normalize.js +12 -10
- package/dist/utils/path-security.d.ts +2 -0
- package/dist/utils/path-security.js +24 -0
- package/dist/utils/response-factory.d.ts +4 -4
- package/dist/utils/response-factory.js +15 -21
- package/dist/utils/response-validator.js +88 -73
- package/dist/utils/unreal-command-queue.d.ts +2 -0
- package/dist/utils/unreal-command-queue.js +8 -1
- package/docs/Migration-Guide-v0.5.0.md +1 -9
- package/docs/handler-mapping.md +4 -2
- package/docs/testing-guide.md +2 -2
- package/package.json +12 -6
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSubsystem.cpp +298 -33
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AnimationHandlers.cpp +7 -8
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintGraphHandlers.cpp +229 -319
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers.cpp +98 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EffectHandlers.cpp +24 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EnvironmentHandlers.cpp +96 -0
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LightingHandlers.cpp +52 -5
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ProcessRequest.cpp +5 -268
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequenceHandlers.cpp +57 -2
- package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpConnectionManager.cpp +0 -1
- package/scripts/run-all-tests.mjs +25 -20
- package/server.json +3 -2
- package/src/automation/bridge.ts +27 -25
- package/src/automation/connection-manager.ts +18 -0
- package/src/automation/message-handler.ts +33 -8
- package/src/automation/request-tracker.ts +39 -7
- package/src/config.ts +1 -1
- package/src/constants.ts +7 -0
- package/src/graphql/loaders.ts +244 -0
- package/src/graphql/resolvers.ts +47 -49
- package/src/graphql/server.ts +3 -1
- package/src/graphql/types.ts +3 -0
- package/src/index.ts +15 -2
- package/src/resources/assets.ts +5 -4
- package/src/server/tool-registry.ts +3 -3
- package/src/server-setup.ts +3 -37
- package/src/tools/actors.ts +77 -44
- package/src/tools/animation.ts +1 -0
- package/src/tools/assets.ts +76 -65
- package/src/tools/base-tool.ts +3 -3
- package/src/tools/blueprint.ts +170 -104
- package/src/tools/consolidated-tool-definitions.ts +2 -1
- package/src/tools/consolidated-tool-handlers.ts +129 -150
- package/src/tools/dynamic-handler-registry.ts +22 -140
- package/src/tools/editor.ts +43 -29
- package/src/tools/environment.ts +21 -27
- package/src/tools/foliage.ts +28 -25
- package/src/tools/handlers/actor-handlers.ts +16 -17
- package/src/tools/handlers/asset-handlers.ts +484 -484
- package/src/tools/handlers/sequence-handlers.ts +85 -62
- package/src/tools/introspection.ts +7 -7
- package/src/tools/landscape.ts +34 -28
- package/src/tools/level.ts +100 -80
- package/src/tools/lighting.ts +25 -20
- package/src/tools/materials.ts +9 -3
- package/src/tools/niagara.ts +44 -2
- package/src/tools/performance.ts +1 -2
- package/src/tools/physics.ts +7 -1
- package/src/tools/sequence.ts +42 -26
- package/src/tools/ui.ts +1 -3
- package/src/types/automation-responses.ts +119 -0
- package/src/types/responses.ts +355 -0
- package/src/types/tool-interfaces.ts +135 -135
- package/src/types/tool-types.ts +4 -0
- package/src/unreal-bridge.ts +71 -26
- package/src/utils/command-validator.ts +47 -5
- package/src/utils/error-handler.ts +128 -45
- package/src/utils/normalize.test.ts +162 -0
- package/src/utils/normalize.ts +38 -16
- package/src/utils/path-security.ts +43 -0
- package/src/utils/response-factory.ts +29 -24
- package/src/utils/response-validator.ts +103 -87
- package/src/utils/safe-json.test.ts +90 -0
- package/src/utils/unreal-command-queue.ts +13 -1
- package/src/utils/validation.test.ts +184 -0
- package/tests/test-animation.mjs +358 -33
- package/tests/test-asset-graph.mjs +311 -0
- package/tests/test-audio.mjs +314 -116
- package/tests/test-behavior-tree.mjs +327 -144
- package/tests/test-blueprint-graph.mjs +343 -12
- package/tests/test-control-editor.mjs +85 -53
- package/tests/test-graphql.mjs +58 -8
- package/tests/test-input.mjs +349 -0
- package/tests/test-inspect.mjs +291 -61
- package/tests/test-landscape.mjs +304 -48
- package/tests/test-lighting.mjs +428 -0
- package/tests/test-manage-level.mjs +70 -51
- package/tests/test-performance.mjs +539 -0
- package/tests/test-sequence.mjs +82 -46
- package/tests/test-system.mjs +72 -33
- package/tests/test-wasm.mjs +98 -8
- package/vitest.config.ts +35 -0
- package/.github/release-drafter.yml +0 -148
- package/dist/prompts/index.d.ts +0 -21
- package/dist/prompts/index.js +0 -217
- package/dist/tools/blueprint/helpers.d.ts +0 -29
- package/dist/tools/blueprint/helpers.js +0 -182
- package/src/prompts/index.ts +0 -249
- package/src/tools/blueprint/helpers.ts +0 -189
- package/tests/test-blueprint-events.mjs +0 -35
- package/tests/test-extra-tools.mjs +0 -38
- package/tests/test-render.mjs +0 -33
- package/tests/test-search-assets.mjs +0 -66
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Blueprint Graph Test Suite
|
|
4
|
-
*
|
|
3
|
+
* Comprehensive Blueprint Graph Test Suite
|
|
4
|
+
* Tool: manage_blueprint_graph
|
|
5
|
+
* Coverage: All 9 actions with success, error, and edge cases
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
8
|
import { runToolTests } from './test-runner.mjs';
|
|
8
9
|
|
|
9
10
|
// Use a unique blueprint name per run to avoid collisions
|
|
10
11
|
const ts = new Date().toISOString().replace(/[^0-9]/g, '').slice(0, 12);
|
|
11
|
-
const BP_NAME = `
|
|
12
|
+
const BP_NAME = `BP_GraphFull_${ts}`;
|
|
12
13
|
const BP_PATH = `/Game/Blueprints/${BP_NAME}`;
|
|
13
14
|
|
|
14
15
|
const testCases = [
|
|
16
|
+
// === SETUP ===
|
|
15
17
|
{
|
|
16
18
|
scenario: 'Create blueprint for graph tests',
|
|
17
19
|
toolName: 'manage_blueprint',
|
|
@@ -25,7 +27,73 @@ const testCases = [
|
|
|
25
27
|
expected: 'success'
|
|
26
28
|
},
|
|
27
29
|
{
|
|
28
|
-
scenario: '
|
|
30
|
+
scenario: 'Add variable for node tests',
|
|
31
|
+
toolName: 'manage_blueprint',
|
|
32
|
+
arguments: {
|
|
33
|
+
action: 'add_variable',
|
|
34
|
+
name: BP_PATH,
|
|
35
|
+
variableName: 'TestFloat',
|
|
36
|
+
variableType: 'Float',
|
|
37
|
+
defaultValue: 0.0
|
|
38
|
+
},
|
|
39
|
+
expected: 'success'
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
scenario: 'Add second variable',
|
|
43
|
+
toolName: 'manage_blueprint',
|
|
44
|
+
arguments: {
|
|
45
|
+
action: 'add_variable',
|
|
46
|
+
name: BP_PATH,
|
|
47
|
+
variableName: 'TestBool',
|
|
48
|
+
variableType: 'Bool',
|
|
49
|
+
defaultValue: false
|
|
50
|
+
},
|
|
51
|
+
expected: 'success'
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
// === GET GRAPH DETAILS ===
|
|
55
|
+
{
|
|
56
|
+
scenario: 'Get EventGraph details',
|
|
57
|
+
toolName: 'manage_blueprint_graph',
|
|
58
|
+
arguments: {
|
|
59
|
+
action: 'get_graph_details',
|
|
60
|
+
blueprintPath: BP_PATH,
|
|
61
|
+
graphName: 'EventGraph'
|
|
62
|
+
},
|
|
63
|
+
expected: 'success'
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
// === CREATE NODES ===
|
|
67
|
+
{
|
|
68
|
+
scenario: 'Create VariableGet node',
|
|
69
|
+
toolName: 'manage_blueprint_graph',
|
|
70
|
+
arguments: {
|
|
71
|
+
action: 'create_node',
|
|
72
|
+
blueprintPath: BP_PATH,
|
|
73
|
+
graphName: 'EventGraph',
|
|
74
|
+
nodeType: 'VariableGet',
|
|
75
|
+
memberName: 'TestFloat',
|
|
76
|
+
x: 0,
|
|
77
|
+
y: 0
|
|
78
|
+
},
|
|
79
|
+
expected: 'success'
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
scenario: 'Create VariableSet node',
|
|
83
|
+
toolName: 'manage_blueprint_graph',
|
|
84
|
+
arguments: {
|
|
85
|
+
action: 'create_node',
|
|
86
|
+
blueprintPath: BP_PATH,
|
|
87
|
+
graphName: 'EventGraph',
|
|
88
|
+
nodeType: 'VariableSet',
|
|
89
|
+
memberName: 'TestFloat',
|
|
90
|
+
x: 200,
|
|
91
|
+
y: 0
|
|
92
|
+
},
|
|
93
|
+
expected: 'success'
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
scenario: 'Create Literal node (object)',
|
|
29
97
|
toolName: 'manage_blueprint_graph',
|
|
30
98
|
arguments: {
|
|
31
99
|
action: 'create_node',
|
|
@@ -35,10 +103,255 @@ const testCases = [
|
|
|
35
103
|
literalType: 'object',
|
|
36
104
|
objectPath: '/Engine/BasicShapes/Cube.Cube',
|
|
37
105
|
x: 0,
|
|
106
|
+
y: 100
|
|
107
|
+
},
|
|
108
|
+
expected: 'success'
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
scenario: 'Create CallFunction node',
|
|
112
|
+
toolName: 'manage_blueprint_graph',
|
|
113
|
+
arguments: {
|
|
114
|
+
action: 'create_node',
|
|
115
|
+
blueprintPath: BP_PATH,
|
|
116
|
+
graphName: 'EventGraph',
|
|
117
|
+
nodeType: 'CallFunction',
|
|
118
|
+
memberName: 'PrintString',
|
|
119
|
+
x: 300,
|
|
120
|
+
y: 0
|
|
121
|
+
},
|
|
122
|
+
expected: 'success'
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
scenario: 'Create Event node (BeginPlay)',
|
|
126
|
+
toolName: 'manage_blueprint_graph',
|
|
127
|
+
arguments: {
|
|
128
|
+
action: 'create_node',
|
|
129
|
+
blueprintPath: BP_PATH,
|
|
130
|
+
graphName: 'EventGraph',
|
|
131
|
+
nodeType: 'Event',
|
|
132
|
+
memberName: 'ReceiveBeginPlay',
|
|
133
|
+
x: -200,
|
|
134
|
+
y: 0
|
|
135
|
+
},
|
|
136
|
+
expected: 'success'
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
scenario: 'Create Branch node',
|
|
140
|
+
toolName: 'manage_blueprint_graph',
|
|
141
|
+
arguments: {
|
|
142
|
+
action: 'create_node',
|
|
143
|
+
blueprintPath: BP_PATH,
|
|
144
|
+
graphName: 'EventGraph',
|
|
145
|
+
nodeType: 'Branch',
|
|
146
|
+
x: 100,
|
|
147
|
+
y: 150
|
|
148
|
+
},
|
|
149
|
+
expected: 'success'
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
scenario: 'Create Sequence node',
|
|
153
|
+
toolName: 'manage_blueprint_graph',
|
|
154
|
+
arguments: {
|
|
155
|
+
action: 'create_node',
|
|
156
|
+
blueprintPath: BP_PATH,
|
|
157
|
+
graphName: 'EventGraph',
|
|
158
|
+
nodeType: 'Sequence',
|
|
159
|
+
x: 200,
|
|
160
|
+
y: 150
|
|
161
|
+
},
|
|
162
|
+
expected: 'success'
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
scenario: 'Create ForEachLoop node',
|
|
166
|
+
toolName: 'manage_blueprint_graph',
|
|
167
|
+
arguments: {
|
|
168
|
+
action: 'create_node',
|
|
169
|
+
blueprintPath: BP_PATH,
|
|
170
|
+
graphName: 'EventGraph',
|
|
171
|
+
nodeType: 'ForEachLoop',
|
|
172
|
+
x: 300,
|
|
173
|
+
y: 150
|
|
174
|
+
},
|
|
175
|
+
expected: 'success'
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
scenario: 'Create Delay node',
|
|
179
|
+
toolName: 'manage_blueprint_graph',
|
|
180
|
+
arguments: {
|
|
181
|
+
action: 'create_node',
|
|
182
|
+
blueprintPath: BP_PATH,
|
|
183
|
+
graphName: 'EventGraph',
|
|
184
|
+
nodeType: 'Delay',
|
|
185
|
+
x: 400,
|
|
186
|
+
y: 0
|
|
187
|
+
},
|
|
188
|
+
expected: 'success'
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
scenario: 'Create SpawnActor node',
|
|
192
|
+
toolName: 'manage_blueprint_graph',
|
|
193
|
+
arguments: {
|
|
194
|
+
action: 'create_node',
|
|
195
|
+
blueprintPath: BP_PATH,
|
|
196
|
+
graphName: 'EventGraph',
|
|
197
|
+
nodeType: 'SpawnActor',
|
|
198
|
+
x: 500,
|
|
38
199
|
y: 0
|
|
39
200
|
},
|
|
40
201
|
expected: 'success'
|
|
41
202
|
},
|
|
203
|
+
|
|
204
|
+
// === CREATE REROUTE NODE ===
|
|
205
|
+
{
|
|
206
|
+
scenario: 'Create Reroute node',
|
|
207
|
+
toolName: 'manage_blueprint_graph',
|
|
208
|
+
arguments: {
|
|
209
|
+
action: 'create_reroute_node',
|
|
210
|
+
blueprintPath: BP_PATH,
|
|
211
|
+
graphName: 'EventGraph',
|
|
212
|
+
x: 150,
|
|
213
|
+
y: 50
|
|
214
|
+
},
|
|
215
|
+
expected: 'success'
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
// === GET NODE DETAILS ===
|
|
219
|
+
{
|
|
220
|
+
scenario: 'Get node details',
|
|
221
|
+
toolName: 'manage_blueprint_graph',
|
|
222
|
+
arguments: {
|
|
223
|
+
action: 'get_node_details',
|
|
224
|
+
blueprintPath: BP_PATH,
|
|
225
|
+
graphName: 'EventGraph'
|
|
226
|
+
},
|
|
227
|
+
expected: 'success'
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
// === GET PIN DETAILS ===
|
|
231
|
+
{
|
|
232
|
+
scenario: 'Get pin details',
|
|
233
|
+
toolName: 'manage_blueprint_graph',
|
|
234
|
+
arguments: {
|
|
235
|
+
action: 'get_pin_details',
|
|
236
|
+
blueprintPath: BP_PATH,
|
|
237
|
+
graphName: 'EventGraph'
|
|
238
|
+
},
|
|
239
|
+
expected: 'success'
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
// === SET NODE PROPERTY ===
|
|
243
|
+
{
|
|
244
|
+
scenario: 'Set Delay duration',
|
|
245
|
+
toolName: 'manage_blueprint_graph',
|
|
246
|
+
arguments: {
|
|
247
|
+
action: 'set_node_property',
|
|
248
|
+
blueprintPath: BP_PATH,
|
|
249
|
+
graphName: 'EventGraph',
|
|
250
|
+
nodeId: 'Delay_0',
|
|
251
|
+
propertyName: 'Duration',
|
|
252
|
+
value: 2.0
|
|
253
|
+
},
|
|
254
|
+
expected: 'success|not_found'
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
// === CONNECT PINS ===
|
|
258
|
+
{
|
|
259
|
+
scenario: 'Connect BeginPlay to SetVariable',
|
|
260
|
+
toolName: 'manage_blueprint_graph',
|
|
261
|
+
arguments: {
|
|
262
|
+
action: 'connect_pins',
|
|
263
|
+
blueprintPath: BP_PATH,
|
|
264
|
+
graphName: 'EventGraph',
|
|
265
|
+
fromPin: 'ReceiveBeginPlay.Execute',
|
|
266
|
+
linkedTo: 'SetTestFloat.Execute'
|
|
267
|
+
},
|
|
268
|
+
expected: 'success|not_found'
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
// === BREAK PIN LINKS ===
|
|
272
|
+
{
|
|
273
|
+
scenario: 'Break pin links',
|
|
274
|
+
toolName: 'manage_blueprint_graph',
|
|
275
|
+
arguments: {
|
|
276
|
+
action: 'break_pin_links',
|
|
277
|
+
blueprintPath: BP_PATH,
|
|
278
|
+
graphName: 'EventGraph',
|
|
279
|
+
pinName: 'SetTestFloat.Execute'
|
|
280
|
+
},
|
|
281
|
+
expected: 'success|not_found'
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
// === DELETE NODE ===
|
|
285
|
+
{
|
|
286
|
+
scenario: 'Delete ForEachLoop node',
|
|
287
|
+
toolName: 'manage_blueprint_graph',
|
|
288
|
+
arguments: {
|
|
289
|
+
action: 'delete_node',
|
|
290
|
+
blueprintPath: BP_PATH,
|
|
291
|
+
graphName: 'EventGraph',
|
|
292
|
+
nodeId: 'ForEachLoop_0'
|
|
293
|
+
},
|
|
294
|
+
expected: 'success|not_found'
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
// === ERROR CASES ===
|
|
298
|
+
{
|
|
299
|
+
scenario: 'Error: Get invalid graph details',
|
|
300
|
+
toolName: 'manage_blueprint_graph',
|
|
301
|
+
arguments: {
|
|
302
|
+
action: 'get_graph_details',
|
|
303
|
+
blueprintPath: BP_PATH,
|
|
304
|
+
graphName: 'InvalidGraphName_DOES_NOT_EXIST'
|
|
305
|
+
},
|
|
306
|
+
expected: 'error|graph_not_found'
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
scenario: 'Error: Create node in invalid graph',
|
|
310
|
+
toolName: 'manage_blueprint_graph',
|
|
311
|
+
arguments: {
|
|
312
|
+
action: 'create_node',
|
|
313
|
+
blueprintPath: BP_PATH,
|
|
314
|
+
graphName: 'NonExistentGraph',
|
|
315
|
+
nodeType: 'VariableGet',
|
|
316
|
+
memberName: 'TestFloat'
|
|
317
|
+
},
|
|
318
|
+
expected: 'error|graph_not_found'
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
scenario: 'Error: Connect invalid pins',
|
|
322
|
+
toolName: 'manage_blueprint_graph',
|
|
323
|
+
arguments: {
|
|
324
|
+
action: 'connect_pins',
|
|
325
|
+
blueprintPath: BP_PATH,
|
|
326
|
+
graphName: 'EventGraph',
|
|
327
|
+
fromPin: 'Invalid.Pin',
|
|
328
|
+
linkedTo: 'Also.Invalid'
|
|
329
|
+
},
|
|
330
|
+
expected: 'error|not_found'
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
scenario: 'Error: Delete non-existent node',
|
|
334
|
+
toolName: 'manage_blueprint_graph',
|
|
335
|
+
arguments: {
|
|
336
|
+
action: 'delete_node',
|
|
337
|
+
blueprintPath: BP_PATH,
|
|
338
|
+
graphName: 'EventGraph',
|
|
339
|
+
nodeId: 'NonExistentNode_XYZ'
|
|
340
|
+
},
|
|
341
|
+
expected: 'error|not_found'
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
scenario: 'Error: Create node in invalid blueprint',
|
|
345
|
+
toolName: 'manage_blueprint_graph',
|
|
346
|
+
arguments: {
|
|
347
|
+
action: 'create_node',
|
|
348
|
+
blueprintPath: '/Game/Blueprints/DOES_NOT_EXIST',
|
|
349
|
+
graphName: 'EventGraph',
|
|
350
|
+
nodeType: 'VariableGet',
|
|
351
|
+
memberName: 'TestFloat'
|
|
352
|
+
},
|
|
353
|
+
expected: 'error|not_found'
|
|
354
|
+
},
|
|
42
355
|
{
|
|
43
356
|
scenario: 'Error: Literal object path not found',
|
|
44
357
|
toolName: 'manage_blueprint_graph',
|
|
@@ -54,26 +367,44 @@ const testCases = [
|
|
|
54
367
|
},
|
|
55
368
|
expected: 'error|object_not_found'
|
|
56
369
|
},
|
|
370
|
+
|
|
371
|
+
// === EDGE CASES ===
|
|
57
372
|
{
|
|
58
|
-
scenario: '
|
|
373
|
+
scenario: 'Edge: Negative node position',
|
|
59
374
|
toolName: 'manage_blueprint_graph',
|
|
60
375
|
arguments: {
|
|
61
|
-
action: '
|
|
376
|
+
action: 'create_node',
|
|
62
377
|
blueprintPath: BP_PATH,
|
|
63
|
-
graphName: 'EventGraph'
|
|
378
|
+
graphName: 'EventGraph',
|
|
379
|
+
nodeType: 'VariableGet',
|
|
380
|
+
memberName: 'TestFloat',
|
|
381
|
+
x: -1000,
|
|
382
|
+
y: -1000
|
|
64
383
|
},
|
|
65
384
|
expected: 'success'
|
|
66
385
|
},
|
|
67
386
|
{
|
|
68
|
-
scenario: '
|
|
387
|
+
scenario: 'Edge: Very large node position',
|
|
69
388
|
toolName: 'manage_blueprint_graph',
|
|
70
389
|
arguments: {
|
|
71
|
-
action: '
|
|
390
|
+
action: 'create_node',
|
|
72
391
|
blueprintPath: BP_PATH,
|
|
73
|
-
graphName: '
|
|
392
|
+
graphName: 'EventGraph',
|
|
393
|
+
nodeType: 'VariableGet',
|
|
394
|
+
memberName: 'TestFloat',
|
|
395
|
+
x: 10000,
|
|
396
|
+
y: 10000
|
|
74
397
|
},
|
|
75
|
-
expected: '
|
|
398
|
+
expected: 'success'
|
|
399
|
+
},
|
|
400
|
+
|
|
401
|
+
// === CLEANUP ===
|
|
402
|
+
{
|
|
403
|
+
scenario: 'Cleanup: Delete test blueprint',
|
|
404
|
+
toolName: 'manage_asset',
|
|
405
|
+
arguments: { action: 'delete', assetPaths: [BP_PATH] },
|
|
406
|
+
expected: 'success'
|
|
76
407
|
}
|
|
77
408
|
];
|
|
78
409
|
|
|
79
|
-
await runToolTests('
|
|
410
|
+
await runToolTests('Blueprint Graph Full', testCases);
|
|
@@ -1,80 +1,112 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Comprehensive Editor Control Test Suite
|
|
4
4
|
* Tool: control_editor
|
|
5
|
+
* Coverage: All 24 actions with success, error, and edge cases
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
8
|
import { runToolTests } from './test-runner.mjs';
|
|
8
9
|
|
|
9
10
|
const testCases = [
|
|
11
|
+
// === PRE-FIX ===
|
|
10
12
|
{
|
|
11
13
|
scenario: 'Pre-Fix: Remove Invalid Data Layers (Native)',
|
|
12
14
|
toolName: 'manage_level',
|
|
13
15
|
arguments: {
|
|
14
16
|
action: 'cleanup_invalid_datalayers'
|
|
15
17
|
},
|
|
16
|
-
// We expect success if supported, or error if not.
|
|
17
|
-
// Since we just added it, it should succeed if plugin is rebuilt.
|
|
18
|
-
// If plugin is NOT rebuilt yet, this will fail with valid error or "unknown action" depending on how it falls through.
|
|
19
|
-
// But since the user is expected to rebuild, we expect success.
|
|
20
18
|
expected: 'success'
|
|
21
19
|
},
|
|
20
|
+
|
|
21
|
+
// === PIE CONTROL (play, stop, stop_pie, pause, resume) ===
|
|
22
22
|
{ scenario: 'Start PIE (Play in Editor)', toolName: 'control_editor', arguments: { action: 'play' }, expected: 'success - PIE started' },
|
|
23
|
+
{ scenario: 'Pause PIE', toolName: 'control_editor', arguments: { action: 'pause' }, expected: 'success - PIE paused' },
|
|
24
|
+
{ scenario: 'Resume PIE', toolName: 'control_editor', arguments: { action: 'resume' }, expected: 'success - PIE resumed' },
|
|
23
25
|
{ scenario: 'Stop PIE', toolName: 'control_editor', arguments: { action: 'stop' }, expected: 'success - PIE stopped' },
|
|
24
|
-
{ scenario: '
|
|
26
|
+
{ scenario: 'Stop PIE (alias)', toolName: 'control_editor', arguments: { action: 'stop_pie' }, expected: 'success - PIE stopped' },
|
|
27
|
+
|
|
28
|
+
// === GAME SPEED ===
|
|
29
|
+
{ scenario: 'Set game speed 0.5x', toolName: 'control_editor', arguments: { action: 'set_game_speed', speed: 0.5 }, expected: 'success' },
|
|
30
|
+
{ scenario: 'Set game speed 2x', toolName: 'control_editor', arguments: { action: 'set_game_speed', speed: 2.0 }, expected: 'success' },
|
|
31
|
+
{ scenario: 'Set game speed 1x (reset)', toolName: 'control_editor', arguments: { action: 'set_game_speed', speed: 1.0 }, expected: 'success' },
|
|
32
|
+
|
|
33
|
+
// === EJECT / POSSESS ===
|
|
34
|
+
{ scenario: 'Eject from possessed pawn', toolName: 'control_editor', arguments: { action: 'eject' }, expected: 'success|handled' },
|
|
35
|
+
{ scenario: 'Possess pawn', toolName: 'control_editor', arguments: { action: 'possess' }, expected: 'success|handled' },
|
|
36
|
+
|
|
37
|
+
// === CAMERA CONTROL ===
|
|
38
|
+
{ scenario: 'Set camera location and rotation', toolName: 'control_editor', arguments: { action: 'set_camera', location: { x: 0, y: 0, z: 500 }, rotation: { pitch: -45, yaw: 0, roll: 0 } }, expected: 'success - camera set' },
|
|
39
|
+
{ scenario: 'Set camera position only', toolName: 'control_editor', arguments: { action: 'set_camera_position', location: { x: 100, y: 100, z: 300 } }, expected: 'success' },
|
|
40
|
+
{ scenario: 'Set camera rotation only', toolName: 'control_editor', arguments: { action: 'set_camera', rotation: { pitch: -30, yaw: 45, roll: 0 } }, expected: 'success' },
|
|
25
41
|
{ scenario: 'Focus camera on actor', toolName: 'control_editor', arguments: { action: 'set_camera', targetActor: 'TC_Cube' }, expected: 'success - camera focused' },
|
|
42
|
+
{ scenario: 'Set camera FOV 90', toolName: 'control_editor', arguments: { action: 'set_camera_fov', fov: 90 }, expected: 'success' },
|
|
43
|
+
{ scenario: 'Set camera FOV 60', toolName: 'control_editor', arguments: { action: 'set_camera_fov', fov: 60 }, expected: 'success' },
|
|
44
|
+
{ scenario: 'Set camera FOV extreme (120)', toolName: 'control_editor', arguments: { action: 'set_camera_fov', fov: 120 }, expected: 'success' },
|
|
45
|
+
|
|
46
|
+
// === VIEW MODE ===
|
|
26
47
|
{ scenario: 'Set view mode to Lit', toolName: 'control_editor', arguments: { action: 'set_view_mode', viewMode: 'Lit' }, expected: 'success - view mode set' },
|
|
27
48
|
{ scenario: 'Set view mode to Wireframe', toolName: 'control_editor', arguments: { action: 'set_view_mode', viewMode: 'Wireframe' }, expected: 'success - view mode set' },
|
|
49
|
+
{ scenario: 'Set view mode to Unlit', toolName: 'control_editor', arguments: { action: 'set_view_mode', viewMode: 'Unlit' }, expected: 'success' },
|
|
50
|
+
{ scenario: 'Set view mode to PathTracing', toolName: 'control_editor', arguments: { action: 'set_view_mode', viewMode: 'PathTracing' }, expected: 'success|not_supported' },
|
|
51
|
+
|
|
52
|
+
// === VIEWPORT SETTINGS ===
|
|
53
|
+
{ scenario: 'Set viewport resolution 1920x1080', toolName: 'control_editor', arguments: { action: 'set_viewport_resolution', width: 1920, height: 1080 }, expected: 'success' },
|
|
54
|
+
{ scenario: 'Set viewport resolution 1280x720', toolName: 'control_editor', arguments: { action: 'set_viewport_resolution', width: 1280, height: 720 }, expected: 'success' },
|
|
55
|
+
{ scenario: 'Set viewport realtime on', toolName: 'control_editor', arguments: { action: 'set_viewport_realtime', enabled: true }, expected: 'success' },
|
|
56
|
+
{ scenario: 'Set viewport realtime off', toolName: 'control_editor', arguments: { action: 'set_viewport_realtime', enabled: false }, expected: 'success' },
|
|
57
|
+
|
|
58
|
+
// === SCREENSHOT ===
|
|
28
59
|
{ scenario: 'Take screenshot', toolName: 'control_editor', arguments: { action: 'screenshot', filename: 'TC_Screenshot' }, expected: 'success - screenshot taken' },
|
|
60
|
+
{ scenario: 'Take screenshot with resolution', toolName: 'control_editor', arguments: { action: 'screenshot', filename: 'TC_Screenshot_HD', width: 1920, height: 1080 }, expected: 'success' },
|
|
61
|
+
|
|
62
|
+
// === RECORDING ===
|
|
29
63
|
{ scenario: 'Start recording', toolName: 'control_editor', arguments: { action: 'start_recording', filename: 'TC_Record', frameRate: 30 }, expected: 'success - recording started' },
|
|
30
64
|
{ scenario: 'Stop recording', toolName: 'control_editor', arguments: { action: 'stop_recording' }, expected: 'success - recording stopped' },
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
{ scenario: 'Step
|
|
34
|
-
{ scenario: '
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
{ scenario: '
|
|
40
|
-
{ scenario: '
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
},
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
expected: "timeout|error"
|
|
77
|
-
}
|
|
65
|
+
|
|
66
|
+
// === FRAME STEPPING ===
|
|
67
|
+
{ scenario: 'Step single frame', toolName: 'control_editor', arguments: { action: 'step_frame' }, expected: 'success - frame stepped' },
|
|
68
|
+
{ scenario: 'Step multiple frames', toolName: 'control_editor', arguments: { action: 'step_frame', steps: 5 }, expected: 'success' },
|
|
69
|
+
|
|
70
|
+
// === BOOKMARKS ===
|
|
71
|
+
{ scenario: 'Create camera bookmark', toolName: 'control_editor', arguments: { action: 'create_bookmark', bookmarkName: 'TC_Bookmark_1' }, expected: 'success - bookmark created' },
|
|
72
|
+
{ scenario: 'Create second bookmark', toolName: 'control_editor', arguments: { action: 'create_bookmark', bookmarkName: 'TC_Bookmark_2' }, expected: 'success' },
|
|
73
|
+
{ scenario: 'Jump to bookmark 1', toolName: 'control_editor', arguments: { action: 'jump_to_bookmark', bookmarkName: 'TC_Bookmark_1' }, expected: 'success - jumped to bookmark' },
|
|
74
|
+
{ scenario: 'Jump to bookmark 2', toolName: 'control_editor', arguments: { action: 'jump_to_bookmark', bookmarkName: 'TC_Bookmark_2' }, expected: 'success' },
|
|
75
|
+
|
|
76
|
+
// === PREFERENCES ===
|
|
77
|
+
{ scenario: 'Set editor preferences - grid', toolName: 'control_editor', arguments: { action: 'set_preferences', category: 'Editor', preferences: { UseGrid: true, SnapToGrid: true } }, expected: 'success - editor preferences set' },
|
|
78
|
+
{ scenario: 'Set editor preferences - realtime', toolName: 'control_editor', arguments: { action: 'set_preferences', category: 'Viewport', preferences: { bRealtimeUpdate: true } }, expected: 'success' },
|
|
79
|
+
|
|
80
|
+
// === CONSOLE COMMANDS ===
|
|
81
|
+
{ scenario: 'Execute console command (stat fps)', toolName: 'control_editor', arguments: { action: 'execute_command', command: 'stat fps' }, expected: 'success' },
|
|
82
|
+
{ scenario: 'Console command (alias)', toolName: 'control_editor', arguments: { action: 'console_command', command: 'stat unit' }, expected: 'success' },
|
|
83
|
+
{ scenario: 'Console command - toggle stat', toolName: 'control_editor', arguments: { action: 'console_command', command: 'stat none' }, expected: 'success' },
|
|
84
|
+
|
|
85
|
+
// === OPEN ASSET ===
|
|
86
|
+
{ scenario: 'Open asset in editor', toolName: 'control_editor', arguments: { action: 'open_asset', assetPath: '/Engine/BasicShapes/Cube' }, expected: 'success' },
|
|
87
|
+
{ scenario: 'Open material asset', toolName: 'control_editor', arguments: { action: 'open_asset', assetPath: '/Engine/EngineMaterials/DefaultMaterial' }, expected: 'success' },
|
|
88
|
+
|
|
89
|
+
// === SIMULATE INPUT ===
|
|
90
|
+
{ scenario: 'Simulate key press W', toolName: 'control_editor', arguments: { action: 'simulate_input', keyName: 'W', eventType: 'KeyDown' }, expected: 'success' },
|
|
91
|
+
{ scenario: 'Simulate key release W', toolName: 'control_editor', arguments: { action: 'simulate_input', keyName: 'W', eventType: 'KeyUp' }, expected: 'success' },
|
|
92
|
+
{ scenario: 'Simulate key press and release Space', toolName: 'control_editor', arguments: { action: 'simulate_input', keyName: 'SpaceBar', eventType: 'Both' }, expected: 'success' },
|
|
93
|
+
|
|
94
|
+
// === ERROR CASES ===
|
|
95
|
+
{ scenario: 'Error: Invalid view mode', toolName: 'control_editor', arguments: { action: 'set_view_mode', viewMode: 'InvalidMode' }, expected: 'error|unknown_viewmode' },
|
|
96
|
+
{ scenario: 'Error: Invalid bookmark', toolName: 'control_editor', arguments: { action: 'jump_to_bookmark', bookmarkName: 'NonExistent_Bookmark_XYZ' }, expected: 'error|not_found' },
|
|
97
|
+
{ scenario: 'Error: Empty command', toolName: 'control_editor', arguments: { action: 'console_command', command: '' }, expected: 'error|empty' },
|
|
98
|
+
{ scenario: 'Error: Invalid resolution', toolName: 'control_editor', arguments: { action: 'set_viewport_resolution', width: -100, height: -100 }, expected: 'error|validation' },
|
|
99
|
+
{ scenario: 'Error: Open non-existent asset', toolName: 'control_editor', arguments: { action: 'open_asset', assetPath: '/Game/NonExistent/Asset' }, expected: 'error|not_found' },
|
|
100
|
+
{ scenario: 'Error: Screenshot invalid resolution', toolName: 'control_editor', arguments: { action: 'screenshot', resolution: 'invalidxres' }, expected: 'error' },
|
|
101
|
+
|
|
102
|
+
// === EDGE CASES ===
|
|
103
|
+
{ scenario: 'Edge: Extreme FOV (1 degree)', toolName: 'control_editor', arguments: { action: 'set_camera_fov', fov: 1 }, expected: 'success' },
|
|
104
|
+
{ scenario: 'Edge: Negative speed', toolName: 'control_editor', arguments: { action: 'set_game_speed', speed: -1 }, expected: 'success|handled' },
|
|
105
|
+
{ scenario: 'Edge: Zero speed (frozen)', toolName: 'control_editor', arguments: { action: 'set_game_speed', speed: 0 }, expected: 'success' },
|
|
106
|
+
{ scenario: 'Edge: Very high speed', toolName: 'control_editor', arguments: { action: 'set_game_speed', speed: 10.0 }, expected: 'success' },
|
|
107
|
+
|
|
108
|
+
// === TIMEOUT TEST ===
|
|
109
|
+
{ scenario: 'Timeout short fail', toolName: 'control_editor', arguments: { action: 'play', timeoutMs: 1 }, expected: 'timeout|error' }
|
|
78
110
|
];
|
|
79
111
|
|
|
80
112
|
await runToolTests('Editor Control', testCases);
|
package/tests/test-graphql.mjs
CHANGED
|
@@ -150,10 +150,19 @@ async function testGraphQLServer() {
|
|
|
150
150
|
log.info('You can test it with: curl -X POST -H "Content-Type: application/json" -d \'{"query": "{ assets { edges { node { name path } } } }"\' http://127.0.0.1:4000/graphql');
|
|
151
151
|
|
|
152
152
|
// Run tests
|
|
153
|
-
await runGraphQLTests();
|
|
154
|
-
|
|
155
|
-
//
|
|
156
|
-
log.info('\
|
|
153
|
+
const results = await runGraphQLTests();
|
|
154
|
+
|
|
155
|
+
// Auto-exit after tests complete
|
|
156
|
+
log.info('\nTests completed. Shutting down...');
|
|
157
|
+
await graphQLServer.stop();
|
|
158
|
+
|
|
159
|
+
if (results.failed > 0) {
|
|
160
|
+
log.info(`\n❌ ${results.failed}/${results.total} tests failed`);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
} else {
|
|
163
|
+
log.info(`\n✅ All ${results.passed}/${results.total} tests passed`);
|
|
164
|
+
process.exit(0);
|
|
165
|
+
}
|
|
157
166
|
} catch (error) {
|
|
158
167
|
log.error('Failed to start GraphQL server:', error);
|
|
159
168
|
process.exit(1);
|
|
@@ -259,6 +268,37 @@ async function runGraphQLTests() {
|
|
|
259
268
|
}
|
|
260
269
|
}
|
|
261
270
|
`
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
name: 'Error Handling - Invalid Query',
|
|
274
|
+
query: `
|
|
275
|
+
{
|
|
276
|
+
invalidField {
|
|
277
|
+
name
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
`,
|
|
281
|
+
expectError: true
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
name: 'Pagination Test',
|
|
285
|
+
query: `
|
|
286
|
+
{
|
|
287
|
+
assets(pagination: { limit: 1, offset: 0 }) {
|
|
288
|
+
edges {
|
|
289
|
+
node {
|
|
290
|
+
name
|
|
291
|
+
}
|
|
292
|
+
cursor
|
|
293
|
+
}
|
|
294
|
+
pageInfo {
|
|
295
|
+
hasNextPage
|
|
296
|
+
hasPreviousPage
|
|
297
|
+
}
|
|
298
|
+
totalCount
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
`
|
|
262
302
|
}
|
|
263
303
|
];
|
|
264
304
|
|
|
@@ -278,11 +318,21 @@ async function runGraphQLTests() {
|
|
|
278
318
|
const result = await response.json();
|
|
279
319
|
|
|
280
320
|
if (result.errors) {
|
|
281
|
-
|
|
282
|
-
|
|
321
|
+
if (test.expectError) {
|
|
322
|
+
log.info(` ✅ ${test.name} - Expected error received`);
|
|
323
|
+
passed++;
|
|
324
|
+
} else {
|
|
325
|
+
log.error(` ❌ ${test.name} - GraphQL Errors:`, JSON.stringify(result.errors));
|
|
326
|
+
failed++;
|
|
327
|
+
}
|
|
283
328
|
} else if (result.data) {
|
|
284
|
-
|
|
285
|
-
|
|
329
|
+
if (test.expectError) {
|
|
330
|
+
log.error(` ❌ ${test.name} - Expected error but got data`);
|
|
331
|
+
failed++;
|
|
332
|
+
} else {
|
|
333
|
+
log.info(` ✅ ${test.name} - Success`);
|
|
334
|
+
passed++;
|
|
335
|
+
}
|
|
286
336
|
} else {
|
|
287
337
|
log.error(` ❌ ${test.name} - No data returned`);
|
|
288
338
|
failed++;
|