unreal-engine-mcp-server 0.4.0 → 0.4.4

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 (135) hide show
  1. package/.env.production +1 -1
  2. package/.github/copilot-instructions.md +45 -0
  3. package/.github/workflows/publish-mcp.yml +3 -2
  4. package/README.md +21 -5
  5. package/dist/index.js +124 -31
  6. package/dist/prompts/index.d.ts +10 -3
  7. package/dist/prompts/index.js +186 -7
  8. package/dist/resources/actors.d.ts +19 -1
  9. package/dist/resources/actors.js +55 -64
  10. package/dist/resources/assets.js +46 -62
  11. package/dist/resources/levels.d.ts +21 -3
  12. package/dist/resources/levels.js +29 -54
  13. package/dist/tools/actors.d.ts +3 -14
  14. package/dist/tools/actors.js +246 -302
  15. package/dist/tools/animation.d.ts +57 -102
  16. package/dist/tools/animation.js +429 -450
  17. package/dist/tools/assets.d.ts +13 -2
  18. package/dist/tools/assets.js +52 -44
  19. package/dist/tools/audio.d.ts +22 -13
  20. package/dist/tools/audio.js +467 -121
  21. package/dist/tools/blueprint.d.ts +32 -13
  22. package/dist/tools/blueprint.js +699 -448
  23. package/dist/tools/build_environment_advanced.d.ts +0 -1
  24. package/dist/tools/build_environment_advanced.js +190 -45
  25. package/dist/tools/consolidated-tool-definitions.js +78 -252
  26. package/dist/tools/consolidated-tool-handlers.js +506 -133
  27. package/dist/tools/debug.d.ts +72 -10
  28. package/dist/tools/debug.js +167 -31
  29. package/dist/tools/editor.d.ts +9 -2
  30. package/dist/tools/editor.js +30 -44
  31. package/dist/tools/foliage.d.ts +34 -15
  32. package/dist/tools/foliage.js +97 -107
  33. package/dist/tools/introspection.js +19 -21
  34. package/dist/tools/landscape.d.ts +1 -2
  35. package/dist/tools/landscape.js +311 -168
  36. package/dist/tools/level.d.ts +3 -28
  37. package/dist/tools/level.js +642 -192
  38. package/dist/tools/lighting.d.ts +14 -3
  39. package/dist/tools/lighting.js +236 -123
  40. package/dist/tools/materials.d.ts +25 -7
  41. package/dist/tools/materials.js +102 -79
  42. package/dist/tools/niagara.d.ts +10 -12
  43. package/dist/tools/niagara.js +74 -94
  44. package/dist/tools/performance.d.ts +12 -4
  45. package/dist/tools/performance.js +38 -79
  46. package/dist/tools/physics.d.ts +34 -10
  47. package/dist/tools/physics.js +364 -292
  48. package/dist/tools/rc.js +97 -23
  49. package/dist/tools/sequence.d.ts +1 -0
  50. package/dist/tools/sequence.js +125 -22
  51. package/dist/tools/ui.d.ts +31 -4
  52. package/dist/tools/ui.js +83 -66
  53. package/dist/tools/visual.d.ts +11 -0
  54. package/dist/tools/visual.js +245 -30
  55. package/dist/types/tool-types.d.ts +0 -6
  56. package/dist/types/tool-types.js +1 -8
  57. package/dist/unreal-bridge.d.ts +32 -2
  58. package/dist/unreal-bridge.js +621 -127
  59. package/dist/utils/elicitation.d.ts +57 -0
  60. package/dist/utils/elicitation.js +104 -0
  61. package/dist/utils/error-handler.d.ts +0 -33
  62. package/dist/utils/error-handler.js +4 -111
  63. package/dist/utils/http.d.ts +2 -22
  64. package/dist/utils/http.js +12 -75
  65. package/dist/utils/normalize.d.ts +4 -4
  66. package/dist/utils/normalize.js +15 -7
  67. package/dist/utils/python-output.d.ts +18 -0
  68. package/dist/utils/python-output.js +290 -0
  69. package/dist/utils/python.d.ts +2 -0
  70. package/dist/utils/python.js +4 -0
  71. package/dist/utils/response-validator.js +28 -2
  72. package/dist/utils/result-helpers.d.ts +27 -0
  73. package/dist/utils/result-helpers.js +147 -0
  74. package/dist/utils/safe-json.d.ts +0 -2
  75. package/dist/utils/safe-json.js +0 -43
  76. package/dist/utils/validation.d.ts +16 -0
  77. package/dist/utils/validation.js +70 -7
  78. package/mcp-config-example.json +2 -2
  79. package/package.json +10 -9
  80. package/server.json +37 -14
  81. package/src/index.ts +130 -33
  82. package/src/prompts/index.ts +211 -13
  83. package/src/resources/actors.ts +59 -44
  84. package/src/resources/assets.ts +48 -51
  85. package/src/resources/levels.ts +35 -45
  86. package/src/tools/actors.ts +269 -313
  87. package/src/tools/animation.ts +556 -539
  88. package/src/tools/assets.ts +53 -43
  89. package/src/tools/audio.ts +507 -113
  90. package/src/tools/blueprint.ts +778 -462
  91. package/src/tools/build_environment_advanced.ts +266 -64
  92. package/src/tools/consolidated-tool-definitions.ts +90 -264
  93. package/src/tools/consolidated-tool-handlers.ts +630 -121
  94. package/src/tools/debug.ts +176 -33
  95. package/src/tools/editor.ts +35 -37
  96. package/src/tools/foliage.ts +110 -104
  97. package/src/tools/introspection.ts +24 -22
  98. package/src/tools/landscape.ts +334 -181
  99. package/src/tools/level.ts +683 -182
  100. package/src/tools/lighting.ts +244 -123
  101. package/src/tools/materials.ts +114 -83
  102. package/src/tools/niagara.ts +87 -81
  103. package/src/tools/performance.ts +49 -88
  104. package/src/tools/physics.ts +393 -299
  105. package/src/tools/rc.ts +102 -24
  106. package/src/tools/sequence.ts +136 -28
  107. package/src/tools/ui.ts +101 -70
  108. package/src/tools/visual.ts +250 -29
  109. package/src/types/tool-types.ts +0 -9
  110. package/src/unreal-bridge.ts +658 -140
  111. package/src/utils/elicitation.ts +129 -0
  112. package/src/utils/error-handler.ts +4 -159
  113. package/src/utils/http.ts +16 -115
  114. package/src/utils/normalize.ts +20 -10
  115. package/src/utils/python-output.ts +351 -0
  116. package/src/utils/python.ts +3 -0
  117. package/src/utils/response-validator.ts +25 -2
  118. package/src/utils/result-helpers.ts +193 -0
  119. package/src/utils/safe-json.ts +0 -50
  120. package/src/utils/validation.ts +94 -7
  121. package/tests/run-unreal-tool-tests.mjs +720 -0
  122. package/tsconfig.json +2 -2
  123. package/dist/python-utils.d.ts +0 -29
  124. package/dist/python-utils.js +0 -54
  125. package/dist/types/index.d.ts +0 -323
  126. package/dist/types/index.js +0 -28
  127. package/dist/utils/cache-manager.d.ts +0 -64
  128. package/dist/utils/cache-manager.js +0 -176
  129. package/dist/utils/errors.d.ts +0 -133
  130. package/dist/utils/errors.js +0 -256
  131. package/src/python/editor_compat.py +0 -181
  132. package/src/python-utils.ts +0 -57
  133. package/src/types/index.ts +0 -414
  134. package/src/utils/cache-manager.ts +0 -213
  135. package/src/utils/errors.ts +0 -312
@@ -1,3 +1,4 @@
1
+ import { bestEffortInterpretedText, coerceNumber, coerceString, interpretStandardResult } from '../utils/result-helpers.js';
1
2
  export class ActorResources {
2
3
  bridge;
3
4
  cache = new Map();
@@ -41,64 +42,27 @@ for actor in actors:
41
42
  pass
42
43
  print('RESULT:' + json.dumps({'success': True, 'count': len(actor_list), 'actors': actor_list}))
43
44
  `.trim();
44
- const resp = await this.bridge.executePythonWithResult(pythonCode);
45
- if (resp && typeof resp === 'object' && resp.success === true && Array.isArray(resp.actors)) {
46
- this.setCache('listActors', resp);
47
- return resp;
48
- }
49
- // Fallback manual extraction with bracket matching
50
- const raw = await this.bridge.executePython(pythonCode);
51
- let output = '';
52
- if (raw?.LogOutput && Array.isArray(raw.LogOutput))
53
- output = raw.LogOutput.map((l) => l.Output || '').join('');
54
- else if (typeof raw === 'string')
55
- output = raw;
56
- else
57
- output = JSON.stringify(raw);
58
- const marker = 'RESULT:';
59
- const idx = output.lastIndexOf(marker);
60
- if (idx !== -1) {
61
- let i = idx + marker.length;
62
- while (i < output.length && output[i] !== '{')
63
- i++;
64
- if (i < output.length) {
65
- let depth = 0, inStr = false, esc = false, j = i;
66
- for (; j < output.length; j++) {
67
- const ch = output[j];
68
- if (esc) {
69
- esc = false;
70
- continue;
71
- }
72
- if (ch === '\\') {
73
- esc = true;
74
- continue;
75
- }
76
- if (ch === '"') {
77
- inStr = !inStr;
78
- continue;
79
- }
80
- if (!inStr) {
81
- if (ch === '{')
82
- depth++;
83
- else if (ch === '}') {
84
- depth--;
85
- if (depth === 0) {
86
- j++;
87
- break;
88
- }
89
- }
90
- }
91
- }
92
- const jsonStr = output.slice(i, j);
93
- try {
94
- const parsed = JSON.parse(jsonStr);
95
- this.setCache('listActors', parsed);
96
- return parsed;
97
- }
98
- catch { }
99
- }
45
+ const response = await this.bridge.executePython(pythonCode);
46
+ const interpreted = interpretStandardResult(response, {
47
+ successMessage: 'Retrieved actor list',
48
+ failureMessage: 'Failed to retrieve actor list'
49
+ });
50
+ if (interpreted.success && Array.isArray(interpreted.payload.actors)) {
51
+ const actors = interpreted.payload.actors;
52
+ const count = coerceNumber(interpreted.payload.count) ?? actors.length;
53
+ const payload = {
54
+ success: true,
55
+ count,
56
+ actors
57
+ };
58
+ this.setCache('listActors', payload);
59
+ return payload;
100
60
  }
101
- return { success: false, error: 'Failed to parse actors list' };
61
+ return {
62
+ success: false,
63
+ error: coerceString(interpreted.payload.error) ?? interpreted.error ?? 'Failed to parse actors list',
64
+ note: bestEffortInterpretedText(interpreted)
65
+ };
102
66
  }
103
67
  catch (err) {
104
68
  return { success: false, error: `Failed to list actors: ${err}` };
@@ -109,17 +73,44 @@ print('RESULT:' + json.dumps({'success': True, 'count': len(actor_list), 'actors
109
73
  try {
110
74
  const pythonCode = `
111
75
  import unreal
76
+ import json
77
+
112
78
  actor_subsystem = unreal.get_editor_subsystem(unreal.EditorActorSubsystem)
113
- actors = actor_subsystem.get_all_level_actors()
79
+ actors = actor_subsystem.get_all_level_actors() if actor_subsystem else []
80
+
81
+ found = None
114
82
  for actor in actors:
115
- if actor and actor.get_name() == "${actorName}":
116
- print(f"Found actor: {actor.get_path_name()}")
83
+ if actor and actor.get_name() == ${JSON.stringify(actorName)}:
84
+ found = {
85
+ 'success': True,
86
+ 'name': actor.get_name(),
87
+ 'path': actor.get_path_name(),
88
+ 'class': actor.get_class().get_name()
89
+ }
117
90
  break
118
- else:
119
- print(f"Actor not found: ${actorName}")
91
+
92
+ if not found:
93
+ found = {'success': False, 'error': f"Actor not found: {actorName}"}
94
+
95
+ print('RESULT:' + json.dumps(found))
120
96
  `.trim();
121
- const result = await this.bridge.executePython(pythonCode);
122
- return result;
97
+ const response = await this.bridge.executePython(pythonCode);
98
+ const interpreted = interpretStandardResult(response, {
99
+ successMessage: `Actor resolved: ${actorName}`,
100
+ failureMessage: `Actor not found: ${actorName}`
101
+ });
102
+ if (interpreted.success) {
103
+ return {
104
+ success: true,
105
+ name: coerceString(interpreted.payload.name) ?? actorName,
106
+ path: coerceString(interpreted.payload.path),
107
+ class: coerceString(interpreted.payload.class)
108
+ };
109
+ }
110
+ return {
111
+ success: false,
112
+ error: coerceString(interpreted.payload.error) ?? interpreted.error ?? `Actor not found: ${actorName}`
113
+ };
123
114
  }
124
115
  catch (err) {
125
116
  return { error: `Failed to get actor: ${err}` };
@@ -1,3 +1,4 @@
1
+ import { coerceBoolean, coerceString, interpretStandardResult } from '../utils/result-helpers.js';
1
2
  export class AssetResources {
2
3
  bridge;
3
4
  constructor(bridge) {
@@ -167,53 +168,45 @@ except Exception as e:
167
168
  print("RESULT:" + json.dumps({'success': False, 'error': str(e), 'path': _dir}))
168
169
  `.trim();
169
170
  const resp = await this.bridge.executePython(py);
170
- let output = '';
171
- if (resp?.LogOutput && Array.isArray(resp.LogOutput)) {
172
- output = resp.LogOutput.map((l) => l.Output || '').join('');
173
- }
174
- else if (typeof resp === 'string') {
175
- output = resp;
176
- }
177
- else {
178
- output = JSON.stringify(resp);
179
- }
180
- const m = output.match(/RESULT:({.*})/);
181
- if (m) {
182
- try {
183
- const parsed = JSON.parse(m[1]);
184
- if (parsed.success) {
185
- // Map folders and assets to a clear response
186
- const foldersArr = Array.isArray(parsed.folders_list) ? parsed.folders_list.map((f) => ({
187
- Name: f.n,
188
- Path: f.p,
189
- Class: 'Folder',
190
- isFolder: true
191
- })) : [];
192
- const assetsArr = Array.isArray(parsed.assets) ? parsed.assets.map((a) => ({
193
- Name: a.n,
194
- Path: a.p,
195
- Class: a.c || 'Asset',
196
- isFolder: false
197
- })) : [];
198
- const total = foldersArr.length + assetsArr.length;
199
- const summary = {
200
- total,
201
- folders: foldersArr.length,
202
- assets: assetsArr.length
203
- };
204
- return {
205
- success: true,
206
- path: parsed.path || this.normalizeDir(dir),
207
- summary,
208
- foldersList: foldersArr,
209
- assets: assetsArr,
210
- count: total,
211
- note: `Immediate children of ${parsed.path || this.normalizeDir(dir)}: ${foldersArr.length} folder(s), ${assetsArr.length} asset(s)`,
212
- method: 'asset_registry_listing'
213
- };
214
- }
215
- }
216
- catch { }
171
+ const interpreted = interpretStandardResult(resp, {
172
+ successMessage: 'Directory contents retrieved',
173
+ failureMessage: 'Failed to list directory contents'
174
+ });
175
+ if (interpreted.success) {
176
+ const payload = interpreted.payload;
177
+ const foldersArr = Array.isArray(payload.folders_list)
178
+ ? payload.folders_list.map((f) => ({
179
+ Name: coerceString(f?.n) ?? '',
180
+ Path: coerceString(f?.p) ?? '',
181
+ Class: 'Folder',
182
+ isFolder: true
183
+ }))
184
+ : [];
185
+ const assetsArr = Array.isArray(payload.assets)
186
+ ? payload.assets.map((a) => ({
187
+ Name: coerceString(a?.n) ?? '',
188
+ Path: coerceString(a?.p) ?? '',
189
+ Class: coerceString(a?.c) ?? 'Asset',
190
+ isFolder: false
191
+ }))
192
+ : [];
193
+ const total = foldersArr.length + assetsArr.length;
194
+ const summary = {
195
+ total,
196
+ folders: foldersArr.length,
197
+ assets: assetsArr.length
198
+ };
199
+ const resolvedPath = coerceString(payload.path) ?? this.normalizeDir(dir);
200
+ return {
201
+ success: true,
202
+ path: resolvedPath,
203
+ summary,
204
+ foldersList: foldersArr,
205
+ assets: assetsArr,
206
+ count: total,
207
+ note: `Immediate children of ${resolvedPath}: ${foldersArr.length} folder(s), ${assetsArr.length} asset(s)`,
208
+ method: 'asset_registry_listing'
209
+ };
217
210
  }
218
211
  }
219
212
  catch (err) {
@@ -247,21 +240,12 @@ except Exception as e:
247
240
  print("RESULT:{'success': False, 'error': '" + str(e) + "'}")
248
241
  `.trim();
249
242
  const resp = await this.bridge.executePython(py);
250
- let output = '';
251
- if (resp?.LogOutput && Array.isArray(resp.LogOutput))
252
- output = resp.LogOutput.map((l) => l.Output || '').join('');
253
- else if (typeof resp === 'string')
254
- output = resp;
255
- else
256
- output = JSON.stringify(resp);
257
- const m = output.match(/RESULT:({.*})/);
258
- if (m) {
259
- try {
260
- const parsed = JSON.parse(m[1].replace(/'/g, '"'));
261
- if (parsed.success)
262
- return !!parsed.exists;
263
- }
264
- catch { }
243
+ const interpreted = interpretStandardResult(resp, {
244
+ successMessage: 'Asset existence verified',
245
+ failureMessage: 'Failed to verify asset existence'
246
+ });
247
+ if (interpreted.success) {
248
+ return coerceBoolean(interpreted.payload.exists, false) ?? false;
265
249
  }
266
250
  return false;
267
251
  }
@@ -2,15 +2,33 @@ import { UnrealBridge } from '../unreal-bridge.js';
2
2
  export declare class LevelResources {
3
3
  private bridge;
4
4
  constructor(bridge: UnrealBridge);
5
- getCurrentLevel(): Promise<any>;
6
- getLevelName(): Promise<any>;
5
+ getCurrentLevel(): Promise<{
6
+ success: boolean;
7
+ name: string;
8
+ path: string;
9
+ error?: undefined;
10
+ } | {
11
+ success: boolean;
12
+ error: string;
13
+ name?: undefined;
14
+ path?: undefined;
15
+ }>;
16
+ getLevelName(): Promise<{
17
+ success: boolean;
18
+ path: string;
19
+ error?: undefined;
20
+ } | {
21
+ success: boolean;
22
+ error: string;
23
+ path?: undefined;
24
+ }>;
7
25
  saveCurrentLevel(): Promise<{
8
26
  success: boolean;
9
27
  message: string;
10
28
  error?: undefined;
11
29
  } | {
12
- error: string;
13
30
  success: boolean;
31
+ error: string;
14
32
  message?: undefined;
15
33
  }>;
16
34
  }
@@ -1,3 +1,4 @@
1
+ import { coerceString, interpretStandardResult } from '../utils/result-helpers.js';
1
2
  export class LevelResources {
2
3
  bridge;
3
4
  constructor(bridge) {
@@ -8,25 +9,18 @@ export class LevelResources {
8
9
  try {
9
10
  const py = '\nimport unreal, json\ntry:\n # Use UnrealEditorSubsystem instead of deprecated EditorLevelLibrary\n editor_subsys = unreal.get_editor_subsystem(unreal.UnrealEditorSubsystem)\n world = editor_subsys.get_editor_world()\n name = world.get_name() if world else \'None\'\n path = world.get_path_name() if world else \'None\'\n print(\'RESULT:\' + json.dumps({\'success\': True, \'name\': name, \'path\': path}))\nexcept Exception as e:\n print(\'RESULT:\' + json.dumps({\'success\': False, \'error\': str(e)}))\n'.trim();
10
11
  const resp = await this.bridge.executePython(py);
11
- // Handle LogOutput format from executePython
12
- let out = '';
13
- if (resp?.LogOutput && Array.isArray(resp.LogOutput)) {
14
- out = resp.LogOutput.map((log) => log.Output || '').join('');
12
+ const interpreted = interpretStandardResult(resp, {
13
+ successMessage: 'Retrieved current level',
14
+ failureMessage: 'Failed to get current level'
15
+ });
16
+ if (interpreted.success) {
17
+ return {
18
+ success: true,
19
+ name: coerceString(interpreted.payload.name) ?? coerceString(interpreted.payload.level_name) ?? 'None',
20
+ path: coerceString(interpreted.payload.path) ?? 'None'
21
+ };
15
22
  }
16
- else if (typeof resp === 'string') {
17
- out = resp;
18
- }
19
- else {
20
- out = JSON.stringify(resp);
21
- }
22
- const m = out.match(/RESULT:({.*})/);
23
- if (m) {
24
- const parsed = JSON.parse(m[1]);
25
- if (parsed.success)
26
- return parsed;
27
- }
28
- // If Python failed, return error
29
- return { error: 'Failed to get current level', success: false };
23
+ return { success: false, error: interpreted.error ?? interpreted.message };
30
24
  }
31
25
  catch (err) {
32
26
  return { error: `Failed to get current level: ${err}`, success: false };
@@ -37,25 +31,17 @@ export class LevelResources {
37
31
  try {
38
32
  const py = '\nimport unreal, json\ntry:\n # Use UnrealEditorSubsystem instead of deprecated EditorLevelLibrary\n editor_subsys = unreal.get_editor_subsystem(unreal.UnrealEditorSubsystem)\n world = editor_subsys.get_editor_world()\n path = world.get_path_name() if world else \'\'\n print(\'RESULT:\' + json.dumps({\'success\': True, \'path\': path}))\nexcept Exception as e:\n print(\'RESULT:\' + json.dumps({\'success\': False, \'error\': str(e)}))\n'.trim();
39
33
  const resp = await this.bridge.executePython(py);
40
- // Handle LogOutput format from executePython
41
- let out = '';
42
- if (resp?.LogOutput && Array.isArray(resp.LogOutput)) {
43
- out = resp.LogOutput.map((log) => log.Output || '').join('');
44
- }
45
- else if (typeof resp === 'string') {
46
- out = resp;
47
- }
48
- else {
49
- out = JSON.stringify(resp);
34
+ const interpreted = interpretStandardResult(resp, {
35
+ successMessage: 'Retrieved level path',
36
+ failureMessage: 'Failed to get level name'
37
+ });
38
+ if (interpreted.success) {
39
+ return {
40
+ success: true,
41
+ path: coerceString(interpreted.payload.path) ?? ''
42
+ };
50
43
  }
51
- const m = out.match(/RESULT:({.*})/);
52
- if (m) {
53
- const parsed = JSON.parse(m[1]);
54
- if (parsed.success)
55
- return parsed;
56
- }
57
- // If Python failed, return error
58
- return { error: 'Failed to get level name', success: false };
44
+ return { success: false, error: interpreted.error ?? interpreted.message };
59
45
  }
60
46
  catch (err) {
61
47
  return { error: `Failed to get level name: ${err}`, success: false };
@@ -66,25 +52,14 @@ export class LevelResources {
66
52
  try {
67
53
  const py = '\nimport unreal, json\ntry:\n les = unreal.get_editor_subsystem(unreal.LevelEditorSubsystem)\n if not les:\n print(\'RESULT:\' + json.dumps({\'success\': False, \'error\': \'LevelEditorSubsystem not available\'}))\n else:\n les.save_current_level()\n print(\'RESULT:\' + json.dumps({\'success\': True}))\nexcept Exception as e:\n print(\'RESULT:\' + json.dumps({\'success\': False, \'error\': str(e)}))\n'.trim();
68
54
  const resp = await this.bridge.executePython(py);
69
- // Handle LogOutput format from executePython
70
- let out = '';
71
- if (resp?.LogOutput && Array.isArray(resp.LogOutput)) {
72
- out = resp.LogOutput.map((log) => log.Output || '').join('');
73
- }
74
- else if (typeof resp === 'string') {
75
- out = resp;
76
- }
77
- else {
78
- out = JSON.stringify(resp);
79
- }
80
- const m = out.match(/RESULT:({.*})/);
81
- if (m) {
82
- const parsed = JSON.parse(m[1]);
83
- if (parsed.success)
84
- return { success: true, message: 'Level saved' };
55
+ const interpreted = interpretStandardResult(resp, {
56
+ successMessage: 'Level saved',
57
+ failureMessage: 'Failed to save level'
58
+ });
59
+ if (interpreted.success) {
60
+ return { success: true, message: interpreted.message };
85
61
  }
86
- // If Python failed, return error
87
- return { error: 'Failed to save level', success: false };
62
+ return { success: false, error: interpreted.error ?? interpreted.message };
88
63
  }
89
64
  catch (err) {
90
65
  return { error: `Failed to save level: ${err}`, success: false };
@@ -14,20 +14,8 @@ export declare class ActorTools {
14
14
  yaw: number;
15
15
  roll: number;
16
16
  };
17
- }): Promise<any>;
18
- spawnViaPython(params: {
19
- classPath: string;
20
- location?: {
21
- x: number;
22
- y: number;
23
- z: number;
24
- };
25
- rotation?: {
26
- pitch: number;
27
- yaw: number;
28
- roll: number;
29
- };
30
- }): Promise<any>;
17
+ actorName?: string;
18
+ }): Promise<Record<string, unknown>>;
31
19
  spawnViaConsole(params: {
32
20
  classPath: string;
33
21
  location?: {
@@ -45,6 +33,7 @@ export declare class ActorTools {
45
33
  message: string;
46
34
  note: string;
47
35
  }>;
36
+ private getPythonSpawnHelper;
48
37
  private resolveActorClass;
49
38
  private getConsoleClassName;
50
39
  }