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.
Files changed (188) hide show
  1. package/.env.example +1 -1
  2. package/.github/release-drafter-config.yml +51 -0
  3. package/.github/workflows/greetings.yml +5 -1
  4. package/.github/workflows/labeler.yml +2 -1
  5. package/.github/workflows/publish-mcp.yml +2 -4
  6. package/.github/workflows/release-drafter.yml +3 -2
  7. package/.github/workflows/release.yml +3 -3
  8. package/CHANGELOG.md +109 -0
  9. package/CONTRIBUTING.md +1 -1
  10. package/GEMINI.md +115 -0
  11. package/Public/Plugin_setup_guide.mp4 +0 -0
  12. package/README.md +166 -200
  13. package/dist/automation/bridge.d.ts +1 -2
  14. package/dist/automation/bridge.js +24 -23
  15. package/dist/automation/connection-manager.d.ts +1 -0
  16. package/dist/automation/connection-manager.js +10 -0
  17. package/dist/automation/message-handler.js +5 -4
  18. package/dist/automation/request-tracker.d.ts +4 -0
  19. package/dist/automation/request-tracker.js +11 -3
  20. package/dist/config.d.ts +0 -1
  21. package/dist/config.js +0 -1
  22. package/dist/constants.d.ts +4 -0
  23. package/dist/constants.js +4 -0
  24. package/dist/graphql/loaders.d.ts +64 -0
  25. package/dist/graphql/loaders.js +117 -0
  26. package/dist/graphql/resolvers.d.ts +3 -3
  27. package/dist/graphql/resolvers.js +33 -30
  28. package/dist/graphql/server.js +3 -1
  29. package/dist/graphql/types.d.ts +2 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.js +13 -2
  32. package/dist/server-setup.d.ts +0 -1
  33. package/dist/server-setup.js +0 -40
  34. package/dist/tools/actors.d.ts +58 -24
  35. package/dist/tools/actors.js +22 -6
  36. package/dist/tools/assets.d.ts +19 -71
  37. package/dist/tools/assets.js +28 -22
  38. package/dist/tools/base-tool.d.ts +4 -4
  39. package/dist/tools/base-tool.js +1 -1
  40. package/dist/tools/blueprint.d.ts +45 -61
  41. package/dist/tools/blueprint.js +43 -14
  42. package/dist/tools/consolidated-tool-definitions.js +2 -1
  43. package/dist/tools/consolidated-tool-handlers.js +96 -110
  44. package/dist/tools/dynamic-handler-registry.d.ts +11 -9
  45. package/dist/tools/dynamic-handler-registry.js +17 -95
  46. package/dist/tools/editor.d.ts +19 -193
  47. package/dist/tools/editor.js +11 -2
  48. package/dist/tools/environment.d.ts +8 -14
  49. package/dist/tools/foliage.d.ts +18 -143
  50. package/dist/tools/foliage.js +4 -2
  51. package/dist/tools/handlers/actor-handlers.d.ts +1 -1
  52. package/dist/tools/handlers/actor-handlers.js +14 -13
  53. package/dist/tools/handlers/asset-handlers.js +454 -454
  54. package/dist/tools/handlers/sequence-handlers.d.ts +1 -1
  55. package/dist/tools/handlers/sequence-handlers.js +24 -13
  56. package/dist/tools/introspection.d.ts +1 -1
  57. package/dist/tools/introspection.js +1 -1
  58. package/dist/tools/landscape.d.ts +16 -116
  59. package/dist/tools/landscape.js +7 -3
  60. package/dist/tools/level.d.ts +22 -103
  61. package/dist/tools/level.js +26 -18
  62. package/dist/tools/lighting.d.ts +54 -7
  63. package/dist/tools/lighting.js +9 -5
  64. package/dist/tools/materials.d.ts +1 -1
  65. package/dist/tools/materials.js +5 -1
  66. package/dist/tools/niagara.js +37 -2
  67. package/dist/tools/performance.d.ts +0 -1
  68. package/dist/tools/performance.js +0 -1
  69. package/dist/tools/physics.js +5 -1
  70. package/dist/tools/sequence.d.ts +24 -24
  71. package/dist/tools/sequence.js +13 -0
  72. package/dist/tools/ui.d.ts +0 -2
  73. package/dist/types/automation-responses.d.ts +115 -0
  74. package/dist/types/automation-responses.js +2 -0
  75. package/dist/types/responses.d.ts +249 -0
  76. package/dist/types/responses.js +2 -0
  77. package/dist/types/tool-interfaces.d.ts +135 -135
  78. package/dist/types/tool-types.d.ts +2 -0
  79. package/dist/unreal-bridge.js +4 -4
  80. package/dist/utils/command-validator.js +7 -5
  81. package/dist/utils/error-handler.d.ts +24 -2
  82. package/dist/utils/error-handler.js +58 -23
  83. package/dist/utils/normalize.d.ts +7 -4
  84. package/dist/utils/normalize.js +12 -10
  85. package/dist/utils/path-security.d.ts +2 -0
  86. package/dist/utils/path-security.js +24 -0
  87. package/dist/utils/response-factory.d.ts +4 -4
  88. package/dist/utils/response-factory.js +15 -21
  89. package/dist/utils/response-validator.js +88 -73
  90. package/dist/utils/unreal-command-queue.d.ts +2 -0
  91. package/dist/utils/unreal-command-queue.js +8 -1
  92. package/docs/Migration-Guide-v0.5.0.md +1 -9
  93. package/docs/handler-mapping.md +4 -2
  94. package/docs/testing-guide.md +2 -2
  95. package/package.json +12 -6
  96. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridgeSubsystem.cpp +298 -33
  97. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_AnimationHandlers.cpp +7 -8
  98. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintGraphHandlers.cpp +229 -319
  99. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_BlueprintHandlers.cpp +98 -0
  100. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EffectHandlers.cpp +24 -0
  101. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_EnvironmentHandlers.cpp +96 -0
  102. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_LightingHandlers.cpp +52 -5
  103. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_ProcessRequest.cpp +5 -268
  104. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpAutomationBridge_SequenceHandlers.cpp +57 -2
  105. package/plugins/McpAutomationBridge/Source/McpAutomationBridge/Private/McpConnectionManager.cpp +0 -1
  106. package/scripts/run-all-tests.mjs +25 -20
  107. package/server.json +3 -2
  108. package/src/automation/bridge.ts +27 -25
  109. package/src/automation/connection-manager.ts +18 -0
  110. package/src/automation/message-handler.ts +33 -8
  111. package/src/automation/request-tracker.ts +39 -7
  112. package/src/config.ts +1 -1
  113. package/src/constants.ts +7 -0
  114. package/src/graphql/loaders.ts +244 -0
  115. package/src/graphql/resolvers.ts +47 -49
  116. package/src/graphql/server.ts +3 -1
  117. package/src/graphql/types.ts +3 -0
  118. package/src/index.ts +15 -2
  119. package/src/resources/assets.ts +5 -4
  120. package/src/server/tool-registry.ts +3 -3
  121. package/src/server-setup.ts +3 -37
  122. package/src/tools/actors.ts +77 -44
  123. package/src/tools/animation.ts +1 -0
  124. package/src/tools/assets.ts +76 -65
  125. package/src/tools/base-tool.ts +3 -3
  126. package/src/tools/blueprint.ts +170 -104
  127. package/src/tools/consolidated-tool-definitions.ts +2 -1
  128. package/src/tools/consolidated-tool-handlers.ts +129 -150
  129. package/src/tools/dynamic-handler-registry.ts +22 -140
  130. package/src/tools/editor.ts +43 -29
  131. package/src/tools/environment.ts +21 -27
  132. package/src/tools/foliage.ts +28 -25
  133. package/src/tools/handlers/actor-handlers.ts +16 -17
  134. package/src/tools/handlers/asset-handlers.ts +484 -484
  135. package/src/tools/handlers/sequence-handlers.ts +85 -62
  136. package/src/tools/introspection.ts +7 -7
  137. package/src/tools/landscape.ts +34 -28
  138. package/src/tools/level.ts +100 -80
  139. package/src/tools/lighting.ts +25 -20
  140. package/src/tools/materials.ts +9 -3
  141. package/src/tools/niagara.ts +44 -2
  142. package/src/tools/performance.ts +1 -2
  143. package/src/tools/physics.ts +7 -1
  144. package/src/tools/sequence.ts +42 -26
  145. package/src/tools/ui.ts +1 -3
  146. package/src/types/automation-responses.ts +119 -0
  147. package/src/types/responses.ts +355 -0
  148. package/src/types/tool-interfaces.ts +135 -135
  149. package/src/types/tool-types.ts +4 -0
  150. package/src/unreal-bridge.ts +71 -26
  151. package/src/utils/command-validator.ts +47 -5
  152. package/src/utils/error-handler.ts +128 -45
  153. package/src/utils/normalize.test.ts +162 -0
  154. package/src/utils/normalize.ts +38 -16
  155. package/src/utils/path-security.ts +43 -0
  156. package/src/utils/response-factory.ts +29 -24
  157. package/src/utils/response-validator.ts +103 -87
  158. package/src/utils/safe-json.test.ts +90 -0
  159. package/src/utils/unreal-command-queue.ts +13 -1
  160. package/src/utils/validation.test.ts +184 -0
  161. package/tests/test-animation.mjs +358 -33
  162. package/tests/test-asset-graph.mjs +311 -0
  163. package/tests/test-audio.mjs +314 -116
  164. package/tests/test-behavior-tree.mjs +327 -144
  165. package/tests/test-blueprint-graph.mjs +343 -12
  166. package/tests/test-control-editor.mjs +85 -53
  167. package/tests/test-graphql.mjs +58 -8
  168. package/tests/test-input.mjs +349 -0
  169. package/tests/test-inspect.mjs +291 -61
  170. package/tests/test-landscape.mjs +304 -48
  171. package/tests/test-lighting.mjs +428 -0
  172. package/tests/test-manage-level.mjs +70 -51
  173. package/tests/test-performance.mjs +539 -0
  174. package/tests/test-sequence.mjs +82 -46
  175. package/tests/test-system.mjs +72 -33
  176. package/tests/test-wasm.mjs +98 -8
  177. package/vitest.config.ts +35 -0
  178. package/.github/release-drafter.yml +0 -148
  179. package/dist/prompts/index.d.ts +0 -21
  180. package/dist/prompts/index.js +0 -217
  181. package/dist/tools/blueprint/helpers.d.ts +0 -29
  182. package/dist/tools/blueprint/helpers.js +0 -182
  183. package/src/prompts/index.ts +0 -249
  184. package/src/tools/blueprint/helpers.ts +0 -189
  185. package/tests/test-blueprint-events.mjs +0 -35
  186. package/tests/test-extra-tools.mjs +0 -38
  187. package/tests/test-render.mjs +0 -33
  188. package/tests/test-search-assets.mjs +0 -66
@@ -1,4 +1,6 @@
1
1
  import { BaseTool } from './base-tool.js';
2
+ import { sanitizePath } from '../utils/path-security.js';
3
+ import { DEFAULT_OPERATION_TIMEOUT_MS, DEFAULT_ASSET_OP_TIMEOUT_MS, LONG_RUNNING_OP_TIMEOUT_MS } from '../constants.js';
2
4
  export class LevelTools extends BaseTool {
3
5
  managedLevels = new Map();
4
6
  listCache;
@@ -18,6 +20,12 @@ export class LevelTools extends BaseTool {
18
20
  if (!formatted.startsWith('/Game/')) {
19
21
  formatted = `/Game/${formatted.replace(/^\/+/, '')}`;
20
22
  }
23
+ try {
24
+ formatted = sanitizePath(formatted);
25
+ }
26
+ catch (e) {
27
+ throw new Error(`Security validation failed for level path: ${e instanceof Error ? e.message : String(e)}`);
28
+ }
21
29
  formatted = formatted.replace(/\.umap$/i, '');
22
30
  if (formatted.endsWith('/')) {
23
31
  formatted = formatted.slice(0, -1);
@@ -180,6 +188,7 @@ export class LevelTools extends BaseTool {
180
188
  const managedOnly = managed.levels.filter(m => !ueLevels.some(u => u.path === m.path));
181
189
  const finalLevels = [...ueLevels, ...managedOnly];
182
190
  const result = {
191
+ ...response,
183
192
  success: true,
184
193
  message: 'Levels listed from Unreal Engine',
185
194
  levels: finalLevels,
@@ -190,7 +199,6 @@ export class LevelTools extends BaseTool {
190
199
  levels: finalLevels,
191
200
  count: finalLevels.length
192
201
  },
193
- ...response,
194
202
  managedLevels: managed.levels,
195
203
  managedLevelCount: managed.count
196
204
  };
@@ -234,7 +242,7 @@ export class LevelTools extends BaseTool {
234
242
  action: 'export_level',
235
243
  levelPath: resolved,
236
244
  exportPath: params.exportPath
237
- }, { timeoutMs: params.timeoutMs ?? 300000 });
245
+ }, { timeoutMs: params.timeoutMs ?? LONG_RUNNING_OP_TIMEOUT_MS });
238
246
  if (res?.success === false) {
239
247
  return {
240
248
  success: false,
@@ -253,7 +261,7 @@ export class LevelTools extends BaseTool {
253
261
  };
254
262
  }
255
263
  catch (e) {
256
- return { success: false, error: `Export failed: ${e.message}` };
264
+ return { success: false, error: `Export failed: ${e instanceof Error ? e.message : String(e)}` };
257
265
  }
258
266
  }
259
267
  async importLevel(params) {
@@ -265,7 +273,7 @@ export class LevelTools extends BaseTool {
265
273
  action: 'import_level',
266
274
  packagePath: params.packagePath,
267
275
  destinationPath: destination.path
268
- }, { timeoutMs: params.timeoutMs ?? 300000 });
276
+ }, { timeoutMs: params.timeoutMs ?? LONG_RUNNING_OP_TIMEOUT_MS });
269
277
  if (res?.success === false) {
270
278
  return {
271
279
  success: false,
@@ -284,7 +292,7 @@ export class LevelTools extends BaseTool {
284
292
  };
285
293
  }
286
294
  catch (e) {
287
- return { success: false, error: `Import failed: ${e.message}` };
295
+ return { success: false, error: `Import failed: ${e instanceof Error ? e.message : String(e)}` };
288
296
  }
289
297
  }
290
298
  async saveLevelAs(params) {
@@ -295,7 +303,7 @@ export class LevelTools extends BaseTool {
295
303
  action: 'save_level_as',
296
304
  savePath: target.path
297
305
  }, {
298
- timeoutMs: 60000
306
+ timeoutMs: DEFAULT_ASSET_OP_TIMEOUT_MS
299
307
  });
300
308
  if (response.success === false) {
301
309
  return { success: false, error: response.error || response.message || 'Failed to save level as' };
@@ -382,7 +390,7 @@ export class LevelTools extends BaseTool {
382
390
  const response = await this.sendAutomationRequest('manage_level', {
383
391
  action: 'load',
384
392
  levelPath: params.levelPath
385
- }, { timeoutMs: 30000 });
393
+ }, { timeoutMs: DEFAULT_OPERATION_TIMEOUT_MS });
386
394
  if (response.success) {
387
395
  this.setCurrentLevel(normalizedPath);
388
396
  this.mutateRecord(normalizedPath, {
@@ -391,11 +399,11 @@ export class LevelTools extends BaseTool {
391
399
  visible: true
392
400
  });
393
401
  return {
402
+ ...response,
394
403
  success: true,
395
404
  message: `Level loaded: ${params.levelPath}`,
396
405
  level: normalizedPath,
397
- streaming: false,
398
- ...response
406
+ streaming: false
399
407
  };
400
408
  }
401
409
  }
@@ -461,15 +469,15 @@ export class LevelTools extends BaseTool {
461
469
  payload.savePath = params.savePath;
462
470
  }
463
471
  const response = await this.sendAutomationRequest('manage_level', payload, {
464
- timeoutMs: 60000
472
+ timeoutMs: DEFAULT_ASSET_OP_TIMEOUT_MS
465
473
  });
466
474
  if (response.success === false) {
467
475
  return { success: false, error: response.error || response.message || 'Failed to save level' };
468
476
  }
469
477
  const result = {
478
+ ...response,
470
479
  success: true,
471
- message: response.message || 'Level saved',
472
- ...response
480
+ message: response.message || 'Level saved'
473
481
  };
474
482
  if (response.skipped) {
475
483
  result.skipped = response.skipped;
@@ -498,7 +506,7 @@ export class LevelTools extends BaseTool {
498
506
  levelPath: fullPath,
499
507
  useWorldPartition: isPartitioned
500
508
  }, {
501
- timeoutMs: 60000
509
+ timeoutMs: DEFAULT_ASSET_OP_TIMEOUT_MS
502
510
  });
503
511
  if (response.success === false) {
504
512
  return {
@@ -509,13 +517,13 @@ export class LevelTools extends BaseTool {
509
517
  };
510
518
  }
511
519
  const result = {
520
+ ...response,
512
521
  success: true,
513
522
  message: response.message || 'Level created',
514
523
  path: response.levelPath || fullPath,
515
524
  packagePath: response.packagePath ?? fullPath,
516
525
  objectPath: response.objectPath,
517
- partitioned: isPartitioned,
518
- ...response
526
+ partitioned: isPartitioned
519
527
  };
520
528
  if (response.warnings) {
521
529
  result.warnings = response.warnings;
@@ -551,7 +559,7 @@ export class LevelTools extends BaseTool {
551
559
  subLevelPath: sub,
552
560
  parentPath: parent,
553
561
  streamingMethod: params.streamingMethod
554
- }, { timeoutMs: 30000 });
562
+ }, { timeoutMs: DEFAULT_OPERATION_TIMEOUT_MS });
555
563
  if (response && (response.error === 'PACKAGE_NOT_FOUND' || response.error === 'ADD_FAILED') && !sub.endsWith('.umap')) {
556
564
  const subWithExt = sub + '.umap';
557
565
  response = await this.sendAutomationRequest('manage_level', {
@@ -560,7 +568,7 @@ export class LevelTools extends BaseTool {
560
568
  subLevelPath: subWithExt,
561
569
  parentPath: parent,
562
570
  streamingMethod: params.streamingMethod
563
- }, { timeoutMs: 30000 });
571
+ }, { timeoutMs: DEFAULT_OPERATION_TIMEOUT_MS });
564
572
  }
565
573
  if (response.success) {
566
574
  this.ensureRecord(sub, { loaded: true, visible: true, streaming: true });
@@ -608,7 +616,7 @@ export class LevelTools extends BaseTool {
608
616
  shouldBeLoaded: params.shouldBeLoaded,
609
617
  shouldBeVisible
610
618
  }, {
611
- timeoutMs: 60000
619
+ timeoutMs: DEFAULT_ASSET_OP_TIMEOUT_MS
612
620
  });
613
621
  if (response.success === false) {
614
622
  const errorCode = typeof response.error === 'string' ? response.error : '';
@@ -19,8 +19,16 @@ export declare class LightingTools {
19
19
  castShadows?: boolean;
20
20
  temperature?: number;
21
21
  useAsAtmosphereSunLight?: boolean;
22
- properties?: Record<string, any>;
23
- }): Promise<any>;
22
+ properties?: Record<string, unknown>;
23
+ }): Promise<{
24
+ success: boolean;
25
+ message: string;
26
+ error?: undefined;
27
+ } | {
28
+ success: boolean;
29
+ error: string;
30
+ message?: undefined;
31
+ }>;
24
32
  createPointLight(params: {
25
33
  name: string;
26
34
  location?: [number, number, number];
@@ -34,7 +42,15 @@ export declare class LightingTools {
34
42
  yaw: number;
35
43
  roll: number;
36
44
  };
37
- }): Promise<any>;
45
+ }): Promise<{
46
+ success: boolean;
47
+ message: string;
48
+ error?: undefined;
49
+ } | {
50
+ success: boolean;
51
+ error: string;
52
+ message?: undefined;
53
+ }>;
38
54
  createSpotLight(params: {
39
55
  name: string;
40
56
  location: [number, number, number];
@@ -49,7 +65,15 @@ export declare class LightingTools {
49
65
  radius?: number;
50
66
  color?: [number, number, number];
51
67
  castShadows?: boolean;
52
- }): Promise<any>;
68
+ }): Promise<{
69
+ success: boolean;
70
+ message: string;
71
+ error?: undefined;
72
+ } | {
73
+ success: boolean;
74
+ error: string;
75
+ message?: undefined;
76
+ }>;
53
77
  createRectLight(params: {
54
78
  name: string;
55
79
  location: [number, number, number];
@@ -63,7 +87,15 @@ export declare class LightingTools {
63
87
  intensity?: number;
64
88
  color?: [number, number, number];
65
89
  castShadows?: boolean;
66
- }): Promise<any>;
90
+ }): Promise<{
91
+ success: boolean;
92
+ message: string;
93
+ error?: undefined;
94
+ } | {
95
+ success: boolean;
96
+ error: string;
97
+ message?: undefined;
98
+ }>;
67
99
  createDynamicLight(params: {
68
100
  name?: string;
69
101
  lightType?: 'Point' | 'Spot' | 'Directional' | 'Rect' | string;
@@ -84,7 +116,15 @@ export declare class LightingTools {
84
116
  enabled?: boolean;
85
117
  frequency?: number;
86
118
  };
87
- }): Promise<any>;
119
+ }): Promise<{
120
+ success: boolean;
121
+ message: string;
122
+ error?: undefined;
123
+ } | {
124
+ success: boolean;
125
+ error: string;
126
+ message?: undefined;
127
+ }>;
88
128
  createSkyLight(params: {
89
129
  name: string;
90
130
  sourceType?: 'CapturedScene' | 'SpecifiedCubemap';
@@ -148,7 +188,14 @@ export declare class LightingTools {
148
188
  buildOnlySelected?: boolean;
149
189
  buildReflectionCaptures?: boolean;
150
190
  levelPath?: string;
151
- }): Promise<any>;
191
+ }): Promise<{
192
+ success: boolean;
193
+ error: string;
194
+ } | {
195
+ success: boolean;
196
+ message: string;
197
+ error?: undefined;
198
+ }>;
152
199
  createLightingEnabledLevel(params?: {
153
200
  levelName?: string;
154
201
  copyActors?: boolean;
@@ -1,4 +1,5 @@
1
1
  import { ensureVector3 } from '../utils/validation.js';
2
+ import { wasmIntegration } from '../wasm/index.js';
2
3
  export class LightingTools {
3
4
  bridge;
4
5
  automationBridge;
@@ -32,7 +33,10 @@ export class LightingTools {
32
33
  name: params.name,
33
34
  };
34
35
  if (params.location) {
35
- payload.location = { x: params.location[0], y: params.location[1], z: params.location[2] };
36
+ const zeroVector = [0, 0, 0];
37
+ const processedLocation = wasmIntegration.vectorAdd(zeroVector, params.location);
38
+ console.error('[WASM] Using vectorAdd for light positioning');
39
+ payload.location = { x: processedLocation[0], y: processedLocation[1], z: processedLocation[2] };
36
40
  }
37
41
  if (params.rotation) {
38
42
  if (Array.isArray(params.rotation)) {
@@ -124,7 +128,7 @@ export class LightingTools {
124
128
  return { success: true, message: `Directional light '${name}' spawned` };
125
129
  }
126
130
  catch (e) {
127
- return { success: false, error: `Failed to create directional light: ${e?.message ?? e}` };
131
+ return { success: false, error: `Failed to create directional light: ${(e instanceof Error ? e.message : String(e)) ?? e}` };
128
132
  }
129
133
  }
130
134
  async createPointLight(params) {
@@ -198,7 +202,7 @@ export class LightingTools {
198
202
  return { success: true, message: `Point light '${name}' spawned at ${location.join(', ')}` };
199
203
  }
200
204
  catch (e) {
201
- return { success: false, error: `Failed to create point light: ${e?.message ?? e}` };
205
+ return { success: false, error: `Failed to create point light: ${(e instanceof Error ? e.message : String(e)) ?? e}` };
202
206
  }
203
207
  }
204
208
  async createSpotLight(params) {
@@ -298,7 +302,7 @@ export class LightingTools {
298
302
  return { success: true, message: `Spot light '${name}' spawned at ${params.location.join(', ')}` };
299
303
  }
300
304
  catch (e) {
301
- return { success: false, error: `Failed to create spot light: ${e?.message ?? e}` };
305
+ return { success: false, error: `Failed to create spot light: ${(e instanceof Error ? e.message : String(e)) ?? e}` };
302
306
  }
303
307
  }
304
308
  async createRectLight(params) {
@@ -384,7 +388,7 @@ export class LightingTools {
384
388
  return { success: true, message: `Rect light '${name}' spawned at ${params.location.join(', ')}` };
385
389
  }
386
390
  catch (e) {
387
- return { success: false, error: `Failed to create rect light: ${e?.message ?? e}` };
391
+ return { success: false, error: `Failed to create rect light: ${(e instanceof Error ? e.message : String(e)) ?? e}` };
388
392
  }
389
393
  }
390
394
  async createDynamicLight(params) {
@@ -43,7 +43,7 @@ export declare class MaterialTools {
43
43
  transport?: undefined;
44
44
  warnings?: undefined;
45
45
  }>;
46
- createMaterialInstance(name: string, path: string, parentMaterial: string, parameters?: Record<string, any>): Promise<any>;
46
+ createMaterialInstance(name: string, path: string, parentMaterial: string, parameters?: Record<string, unknown>): Promise<any>;
47
47
  addNode(params: {
48
48
  materialPath: string;
49
49
  nodeType: string;
@@ -129,7 +129,11 @@ export class MaterialTools {
129
129
  return { success: false, error: resp?.error ?? resp?.message ?? 'CREATE_MATERIAL_INSTANCE_FAILED' };
130
130
  }
131
131
  }
132
- catch (_e) {
132
+ catch (e) {
133
+ const msg = e instanceof Error ? e.message : String(e);
134
+ if (!msg.includes('unknown') && !msg.includes('UNKNOWN_PLUGIN_ACTION')) {
135
+ console.warn(`[MaterialTools] Plugin create_material_instance failed with specific error (falling back to python): ${msg}`);
136
+ }
133
137
  }
134
138
  }
135
139
  const createParams = {
@@ -1,4 +1,5 @@
1
1
  import { sanitizeAssetName, validateAssetParams } from '../utils/validation.js';
2
+ import { wasmIntegration } from '../wasm/index.js';
2
3
  export class NiagaraTools {
3
4
  bridge;
4
5
  automationBridge;
@@ -12,6 +13,16 @@ export class NiagaraTools {
12
13
  if (!this.automationBridge || typeof this.automationBridge.sendAutomationRequest !== 'function') {
13
14
  throw new Error('Automation Bridge not available. Niagara system creation requires plugin support.');
14
15
  }
16
+ if (params.emitters) {
17
+ for (const emitter of params.emitters) {
18
+ if (emitter.shapeSize) {
19
+ const zeroVector = [0, 0, 0];
20
+ const processedSize = wasmIntegration.vectorAdd(zeroVector, emitter.shapeSize);
21
+ console.error('[WASM] Using vectorAdd for Niagara emitter shape size');
22
+ emitter.shapeSize = [processedSize[0], processedSize[1], processedSize[2]];
23
+ }
24
+ }
25
+ }
15
26
  const path = params.savePath || '/Game/Effects/Niagara';
16
27
  const response = await this.automationBridge.sendAutomationRequest('create_niagara_system', { name: params.name, savePath: path, template: params.template }, { timeoutMs: 60000 });
17
28
  if (response && response.success !== false) {
@@ -82,8 +93,19 @@ export class NiagaraTools {
82
93
  return [value.x ?? 0, value.y ?? 0, value.z ?? 0];
83
94
  };
84
95
  const requestPayload = { systemPath: params.systemPath };
85
- const start = toVector(params.start);
86
- const end = toVector(params.end);
96
+ let start = toVector(params.start);
97
+ let end = toVector(params.end);
98
+ const zeroVector = [0, 0, 0];
99
+ if (start) {
100
+ const processed = wasmIntegration.vectorAdd(zeroVector, start);
101
+ console.error('[WASM] Using vectorAdd for Niagara ribbon start');
102
+ start = [processed[0], processed[1], processed[2]];
103
+ }
104
+ if (end) {
105
+ const processed = wasmIntegration.vectorAdd(zeroVector, end);
106
+ console.error('[WASM] Using vectorAdd for Niagara ribbon end');
107
+ end = [processed[0], processed[1], processed[2]];
108
+ }
87
109
  if (start)
88
110
  requestPayload.start = start;
89
111
  if (end)
@@ -148,6 +170,19 @@ export class NiagaraTools {
148
170
  if (!this.automationBridge || typeof this.automationBridge.sendAutomationRequest !== 'function') {
149
171
  return { success: false, error: 'AUTOMATION_BRIDGE_UNAVAILABLE', message: 'addEmitter requires automation bridge' };
150
172
  }
173
+ if (params.properties) {
174
+ const zeroVector = [0, 0, 0];
175
+ if (params.properties.velocityMin) {
176
+ const processed = wasmIntegration.vectorAdd(zeroVector, params.properties.velocityMin);
177
+ console.error('[WASM] Using vectorAdd for Niagara velocity min');
178
+ params.properties.velocityMin = [processed[0], processed[1], processed[2]];
179
+ }
180
+ if (params.properties.velocityMax) {
181
+ const processed = wasmIntegration.vectorAdd(zeroVector, params.properties.velocityMax);
182
+ console.error('[WASM] Using vectorAdd for Niagara velocity max');
183
+ params.properties.velocityMax = [processed[0], processed[1], processed[2]];
184
+ }
185
+ }
151
186
  try {
152
187
  const resp = await this.automationBridge.sendAutomationRequest('manage_niagara_graph', {
153
188
  subAction: 'add_emitter',
@@ -131,7 +131,6 @@ export declare class PerformanceTools {
131
131
  }>;
132
132
  optimizeDrawCalls(params: {
133
133
  enableInstancing?: boolean;
134
- enableBatching?: boolean;
135
134
  mergeActors?: boolean;
136
135
  actors?: string[];
137
136
  }): Promise<{
@@ -354,7 +354,6 @@ export class PerformanceTools {
354
354
  }
355
355
  const payload = {
356
356
  enableInstancing: params.enableInstancing,
357
- enableBatching: params.enableBatching,
358
357
  mergeActors: params.mergeActors,
359
358
  actors: actors
360
359
  };
@@ -1,5 +1,6 @@
1
1
  import { validateAssetParams, resolveSkeletalMeshPath, concurrencyDelay } from '../utils/validation.js';
2
2
  import { coerceString, coerceStringArray } from '../utils/result-helpers.js';
3
+ import { wasmIntegration } from '../wasm/index.js';
3
4
  export class PhysicsTools {
4
5
  bridge;
5
6
  automationBridge;
@@ -309,10 +310,13 @@ export class PhysicsTools {
309
310
  throw new Error('Automation Bridge not available. Physics force application requires plugin support.');
310
311
  }
311
312
  try {
313
+ const zeroVector = [0, 0, 0];
314
+ const normalizedVector = wasmIntegration.vectorAdd(zeroVector, params.vector);
315
+ console.error('[WASM] Using vectorAdd for physics force vector processing');
312
316
  const response = await this.automationBridge.sendAutomationRequest('apply_force', {
313
317
  actorName: params.actorName,
314
318
  forceType: params.forceType,
315
- vector: params.vector,
319
+ vector: normalizedVector,
316
320
  boneName: params.boneName,
317
321
  isLocal: params.isLocal
318
322
  }, {
@@ -1,5 +1,5 @@
1
1
  import { BaseTool } from './base-tool.js';
2
- import { ISequenceTools } from '../types/tool-interfaces.js';
2
+ import { ISequenceTools, StandardActionResponse } from '../types/tool-interfaces.js';
3
3
  export interface LevelSequence {
4
4
  path: string;
5
5
  name: string;
@@ -28,80 +28,80 @@ export declare class SequenceTools extends BaseTool implements ISequenceTools {
28
28
  name: string;
29
29
  path?: string;
30
30
  timeoutMs?: number;
31
- }): Promise<any>;
31
+ }): Promise<StandardActionResponse>;
32
32
  open(params: {
33
33
  path: string;
34
- }): Promise<any>;
34
+ }): Promise<StandardActionResponse>;
35
35
  addCamera(params: {
36
36
  spawnable?: boolean;
37
37
  path?: string;
38
- }): Promise<any>;
38
+ }): Promise<StandardActionResponse>;
39
39
  addActor(params: {
40
40
  actorName: string;
41
41
  createBinding?: boolean;
42
42
  path?: string;
43
- }): Promise<any>;
43
+ }): Promise<StandardActionResponse>;
44
44
  play(params?: {
45
45
  path?: string;
46
46
  startTime?: number;
47
47
  loopMode?: 'once' | 'loop' | 'pingpong';
48
- }): Promise<any>;
48
+ }): Promise<StandardActionResponse>;
49
49
  pause(params?: {
50
50
  path?: string;
51
- }): Promise<any>;
51
+ }): Promise<StandardActionResponse>;
52
52
  stop(params?: {
53
53
  path?: string;
54
- }): Promise<any>;
54
+ }): Promise<StandardActionResponse>;
55
55
  setSequenceProperties(params: {
56
56
  path?: string;
57
57
  frameRate?: number;
58
58
  lengthInFrames?: number;
59
59
  playbackStart?: number;
60
60
  playbackEnd?: number;
61
- }): Promise<any>;
61
+ }): Promise<StandardActionResponse>;
62
62
  setDisplayRate(params: {
63
63
  path?: string;
64
64
  frameRate: string | number;
65
- }): Promise<any>;
65
+ }): Promise<StandardActionResponse>;
66
66
  getSequenceProperties(params: {
67
67
  path?: string;
68
- }): Promise<any>;
68
+ }): Promise<StandardActionResponse>;
69
69
  setPlaybackSpeed(params: {
70
70
  speed: number;
71
71
  path?: string;
72
- }): Promise<any>;
72
+ }): Promise<StandardActionResponse>;
73
73
  getBindings(params?: {
74
74
  path?: string;
75
- }): Promise<any>;
75
+ }): Promise<StandardActionResponse>;
76
76
  addActors(params: {
77
77
  actorNames: string[];
78
78
  path?: string;
79
- }): Promise<any>;
79
+ }): Promise<StandardActionResponse>;
80
80
  removeActors(params: {
81
81
  actorNames: string[];
82
82
  path?: string;
83
- }): Promise<any>;
83
+ }): Promise<StandardActionResponse>;
84
84
  addSpawnableFromClass(params: {
85
85
  className: string;
86
86
  path?: string;
87
- }): Promise<any>;
87
+ }): Promise<StandardActionResponse>;
88
88
  list(params?: {
89
89
  path?: string;
90
- }): Promise<any>;
90
+ }): Promise<StandardActionResponse>;
91
91
  duplicate(params: {
92
92
  path: string;
93
93
  destinationPath: string;
94
- }): Promise<any>;
94
+ }): Promise<StandardActionResponse>;
95
95
  rename(params: {
96
96
  path: string;
97
97
  newName: string;
98
- }): Promise<any>;
98
+ }): Promise<StandardActionResponse>;
99
99
  deleteSequence(params: {
100
100
  path: string;
101
- }): Promise<any>;
101
+ }): Promise<StandardActionResponse>;
102
102
  getMetadata(params: {
103
103
  path?: string;
104
- }): Promise<any>;
104
+ }): Promise<StandardActionResponse>;
105
105
  addKeyframe(params: {
106
106
  path?: string;
107
107
  bindingId?: string;
@@ -125,14 +125,14 @@ export declare class SequenceTools extends BaseTool implements ISequenceTools {
125
125
  z: number;
126
126
  };
127
127
  };
128
- }): Promise<any>;
128
+ }): Promise<StandardActionResponse>;
129
129
  listTracks(params: {
130
130
  path: string;
131
- }): Promise<any>;
131
+ }): Promise<StandardActionResponse>;
132
132
  setWorkRange(params: {
133
133
  path?: string;
134
134
  start: number;
135
135
  end: number;
136
- }): Promise<any>;
136
+ }): Promise<StandardActionResponse>;
137
137
  }
138
138
  //# sourceMappingURL=sequence.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import { BaseTool } from './base-tool.js';
2
+ import { wasmIntegration } from '../wasm/index.js';
2
3
  export class SequenceTools extends BaseTool {
3
4
  sequenceCache = new Map();
4
5
  activeSequencePath;
@@ -214,6 +215,18 @@ export class SequenceTools extends BaseTool {
214
215
  frame: params.frame,
215
216
  value: params.value
216
217
  });
218
+ if (params.property === 'Transform' && params.value) {
219
+ const loc = params.value.location;
220
+ const rot = params.value.rotation;
221
+ const scale = params.value.scale;
222
+ if (loc && rot && scale) {
223
+ const locArr = [loc.x, loc.y, loc.z];
224
+ const rotArr = [rot.pitch, rot.yaw, rot.roll];
225
+ const scaleArr = [scale.x, scale.y, scale.z];
226
+ wasmIntegration.composeTransform(locArr, rotArr, scaleArr);
227
+ console.error('[WASM] Using composeTransform for keyframe validation');
228
+ }
229
+ }
217
230
  if (!resp.success && this.isUnknownActionResponse(resp)) {
218
231
  return { success: false, error: 'UNKNOWN_PLUGIN_ACTION', message: 'Automation plugin does not implement sequence_add_keyframe' };
219
232
  }
@@ -69,7 +69,6 @@ export declare class UITools {
69
69
  setWidgetText(_params: {
70
70
  key: string;
71
71
  value: string;
72
- componentName?: string;
73
72
  }): Promise<{
74
73
  success: boolean;
75
74
  message: string;
@@ -81,7 +80,6 @@ export declare class UITools {
81
80
  setWidgetImage(_params: {
82
81
  key: string;
83
82
  texturePath: string;
84
- componentName?: string;
85
83
  }): Promise<{
86
84
  success: boolean;
87
85
  message: string;