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.
- package/.env.production +1 -1
- package/.github/copilot-instructions.md +45 -0
- package/.github/workflows/publish-mcp.yml +3 -2
- package/README.md +21 -5
- package/dist/index.js +124 -31
- package/dist/prompts/index.d.ts +10 -3
- package/dist/prompts/index.js +186 -7
- package/dist/resources/actors.d.ts +19 -1
- package/dist/resources/actors.js +55 -64
- package/dist/resources/assets.js +46 -62
- package/dist/resources/levels.d.ts +21 -3
- package/dist/resources/levels.js +29 -54
- package/dist/tools/actors.d.ts +3 -14
- package/dist/tools/actors.js +246 -302
- package/dist/tools/animation.d.ts +57 -102
- package/dist/tools/animation.js +429 -450
- package/dist/tools/assets.d.ts +13 -2
- package/dist/tools/assets.js +52 -44
- package/dist/tools/audio.d.ts +22 -13
- package/dist/tools/audio.js +467 -121
- package/dist/tools/blueprint.d.ts +32 -13
- package/dist/tools/blueprint.js +699 -448
- package/dist/tools/build_environment_advanced.d.ts +0 -1
- package/dist/tools/build_environment_advanced.js +190 -45
- package/dist/tools/consolidated-tool-definitions.js +78 -252
- package/dist/tools/consolidated-tool-handlers.js +506 -133
- package/dist/tools/debug.d.ts +72 -10
- package/dist/tools/debug.js +167 -31
- package/dist/tools/editor.d.ts +9 -2
- package/dist/tools/editor.js +30 -44
- package/dist/tools/foliage.d.ts +34 -15
- package/dist/tools/foliage.js +97 -107
- package/dist/tools/introspection.js +19 -21
- package/dist/tools/landscape.d.ts +1 -2
- package/dist/tools/landscape.js +311 -168
- package/dist/tools/level.d.ts +3 -28
- package/dist/tools/level.js +642 -192
- package/dist/tools/lighting.d.ts +14 -3
- package/dist/tools/lighting.js +236 -123
- package/dist/tools/materials.d.ts +25 -7
- package/dist/tools/materials.js +102 -79
- package/dist/tools/niagara.d.ts +10 -12
- package/dist/tools/niagara.js +74 -94
- package/dist/tools/performance.d.ts +12 -4
- package/dist/tools/performance.js +38 -79
- package/dist/tools/physics.d.ts +34 -10
- package/dist/tools/physics.js +364 -292
- package/dist/tools/rc.js +97 -23
- package/dist/tools/sequence.d.ts +1 -0
- package/dist/tools/sequence.js +125 -22
- package/dist/tools/ui.d.ts +31 -4
- package/dist/tools/ui.js +83 -66
- package/dist/tools/visual.d.ts +11 -0
- package/dist/tools/visual.js +245 -30
- package/dist/types/tool-types.d.ts +0 -6
- package/dist/types/tool-types.js +1 -8
- package/dist/unreal-bridge.d.ts +32 -2
- package/dist/unreal-bridge.js +621 -127
- package/dist/utils/elicitation.d.ts +57 -0
- package/dist/utils/elicitation.js +104 -0
- package/dist/utils/error-handler.d.ts +0 -33
- package/dist/utils/error-handler.js +4 -111
- package/dist/utils/http.d.ts +2 -22
- package/dist/utils/http.js +12 -75
- package/dist/utils/normalize.d.ts +4 -4
- package/dist/utils/normalize.js +15 -7
- package/dist/utils/python-output.d.ts +18 -0
- package/dist/utils/python-output.js +290 -0
- package/dist/utils/python.d.ts +2 -0
- package/dist/utils/python.js +4 -0
- package/dist/utils/response-validator.js +28 -2
- package/dist/utils/result-helpers.d.ts +27 -0
- package/dist/utils/result-helpers.js +147 -0
- package/dist/utils/safe-json.d.ts +0 -2
- package/dist/utils/safe-json.js +0 -43
- package/dist/utils/validation.d.ts +16 -0
- package/dist/utils/validation.js +70 -7
- package/mcp-config-example.json +2 -2
- package/package.json +10 -9
- package/server.json +37 -14
- package/src/index.ts +130 -33
- package/src/prompts/index.ts +211 -13
- package/src/resources/actors.ts +59 -44
- package/src/resources/assets.ts +48 -51
- package/src/resources/levels.ts +35 -45
- package/src/tools/actors.ts +269 -313
- package/src/tools/animation.ts +556 -539
- package/src/tools/assets.ts +53 -43
- package/src/tools/audio.ts +507 -113
- package/src/tools/blueprint.ts +778 -462
- package/src/tools/build_environment_advanced.ts +266 -64
- package/src/tools/consolidated-tool-definitions.ts +90 -264
- package/src/tools/consolidated-tool-handlers.ts +630 -121
- package/src/tools/debug.ts +176 -33
- package/src/tools/editor.ts +35 -37
- package/src/tools/foliage.ts +110 -104
- package/src/tools/introspection.ts +24 -22
- package/src/tools/landscape.ts +334 -181
- package/src/tools/level.ts +683 -182
- package/src/tools/lighting.ts +244 -123
- package/src/tools/materials.ts +114 -83
- package/src/tools/niagara.ts +87 -81
- package/src/tools/performance.ts +49 -88
- package/src/tools/physics.ts +393 -299
- package/src/tools/rc.ts +102 -24
- package/src/tools/sequence.ts +136 -28
- package/src/tools/ui.ts +101 -70
- package/src/tools/visual.ts +250 -29
- package/src/types/tool-types.ts +0 -9
- package/src/unreal-bridge.ts +658 -140
- package/src/utils/elicitation.ts +129 -0
- package/src/utils/error-handler.ts +4 -159
- package/src/utils/http.ts +16 -115
- package/src/utils/normalize.ts +20 -10
- package/src/utils/python-output.ts +351 -0
- package/src/utils/python.ts +3 -0
- package/src/utils/response-validator.ts +25 -2
- package/src/utils/result-helpers.ts +193 -0
- package/src/utils/safe-json.ts +0 -50
- package/src/utils/validation.ts +94 -7
- package/tests/run-unreal-tool-tests.mjs +720 -0
- package/tsconfig.json +2 -2
- package/dist/python-utils.d.ts +0 -29
- package/dist/python-utils.js +0 -54
- package/dist/types/index.d.ts +0 -323
- package/dist/types/index.js +0 -28
- package/dist/utils/cache-manager.d.ts +0 -64
- package/dist/utils/cache-manager.js +0 -176
- package/dist/utils/errors.d.ts +0 -133
- package/dist/utils/errors.js +0 -256
- package/src/python/editor_compat.py +0 -181
- package/src/python-utils.ts +0 -57
- package/src/types/index.ts +0 -414
- package/src/utils/cache-manager.ts +0 -213
- package/src/utils/errors.ts +0 -312
package/dist/resources/actors.js
CHANGED
|
@@ -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
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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 {
|
|
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() ==
|
|
116
|
-
|
|
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
|
-
|
|
119
|
-
|
|
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
|
|
122
|
-
|
|
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}` };
|
package/dist/resources/assets.js
CHANGED
|
@@ -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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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<
|
|
6
|
-
|
|
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
|
}
|
package/dist/resources/levels.js
CHANGED
|
@@ -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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
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 };
|
package/dist/tools/actors.d.ts
CHANGED
|
@@ -14,20 +14,8 @@ export declare class ActorTools {
|
|
|
14
14
|
yaw: number;
|
|
15
15
|
roll: number;
|
|
16
16
|
};
|
|
17
|
-
|
|
18
|
-
|
|
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
|
}
|