unreal-engine-mcp-server 0.3.1 → 0.4.3
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 +1 -1
- package/README.md +22 -7
- package/dist/index.js +137 -46
- 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.d.ts +3 -2
- package/dist/resources/assets.js +117 -109
- package/dist/resources/levels.d.ts +21 -3
- package/dist/resources/levels.js +31 -56
- 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 +58 -46
- 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 +236 -87
- package/dist/tools/consolidated-tool-definitions.d.ts +232 -15
- package/dist/tools/consolidated-tool-definitions.js +124 -255
- package/dist/tools/consolidated-tool-handlers.js +749 -766
- package/dist/tools/debug.d.ts +72 -10
- package/dist/tools/debug.js +170 -36
- 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 +98 -24
- package/dist/tools/sequence.d.ts +1 -0
- package/dist/tools/sequence.js +146 -24
- 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.d.ts +6 -1
- package/dist/utils/response-validator.js +66 -13
- 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 +11 -10
- package/server.json +37 -14
- package/src/index.ts +146 -50
- package/src/prompts/index.ts +211 -13
- package/src/resources/actors.ts +59 -44
- package/src/resources/assets.ts +123 -102
- package/src/resources/levels.ts +37 -47
- package/src/tools/actors.ts +269 -313
- package/src/tools/animation.ts +556 -539
- package/src/tools/assets.ts +59 -45
- package/src/tools/audio.ts +507 -113
- package/src/tools/blueprint.ts +778 -462
- package/src/tools/build_environment_advanced.ts +312 -106
- package/src/tools/consolidated-tool-definitions.ts +136 -267
- package/src/tools/consolidated-tool-handlers.ts +871 -795
- package/src/tools/debug.ts +179 -38
- 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 +103 -25
- package/src/tools/sequence.ts +157 -30
- 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 +68 -17
- 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/tools/tool-definitions.d.ts +0 -4919
- package/dist/tools/tool-definitions.js +0 -1065
- package/dist/tools/tool-handlers.d.ts +0 -47
- package/dist/tools/tool-handlers.js +0 -863
- 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/tools/tool-definitions.ts +0 -1081
- package/src/tools/tool-handlers.ts +0 -973
- package/src/types/index.ts +0 -414
- package/src/utils/cache-manager.ts +0 -213
- package/src/utils/errors.ts +0 -312
package/src/tools/debug.ts
CHANGED
|
@@ -1,42 +1,95 @@
|
|
|
1
1
|
// Debug visualization tools for Unreal Engine
|
|
2
2
|
import { UnrealBridge } from '../unreal-bridge.js';
|
|
3
|
+
import { bestEffortInterpretedText, coerceString, interpretStandardResult } from '../utils/result-helpers.js';
|
|
4
|
+
import { parseStandardResult } from '../utils/python-output.js';
|
|
3
5
|
|
|
4
6
|
export class DebugVisualizationTools {
|
|
5
7
|
constructor(private bridge: UnrealBridge) {}
|
|
6
8
|
|
|
7
|
-
// Execute console command (kept for legacy operations)
|
|
8
|
-
private async _executeCommand(command: string) {
|
|
9
|
-
return this.bridge.httpCall('/remote/object/call', 'PUT', {
|
|
10
|
-
objectPath: '/Script/Engine.Default__KismetSystemLibrary',
|
|
11
|
-
functionName: 'ExecuteConsoleCommand',
|
|
12
|
-
parameters: {
|
|
13
|
-
WorldContextObject: null,
|
|
14
|
-
Command: command,
|
|
15
|
-
SpecificPlayer: null
|
|
16
|
-
},
|
|
17
|
-
generateTransaction: false
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
|
|
21
9
|
// Helper to draw via Python SystemLibrary with the editor world
|
|
22
|
-
private async pyDraw(scriptBody: string) {
|
|
10
|
+
private async pyDraw(scriptBody: string, meta?: { action: string; params?: Record<string, unknown> }) {
|
|
11
|
+
const action = (meta?.action || 'debug_draw').replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
12
|
+
const payloadObject = meta?.params ?? {};
|
|
13
|
+
const payloadJson = JSON.stringify(payloadObject).replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
14
|
+
const indentedBody = scriptBody
|
|
15
|
+
.split(/\r?\n/)
|
|
16
|
+
.map(line => ` ${line}`)
|
|
17
|
+
.join('\n');
|
|
18
|
+
|
|
23
19
|
const script = `
|
|
24
20
|
import unreal
|
|
25
|
-
|
|
21
|
+
import json
|
|
22
|
+
|
|
23
|
+
payload = json.loads('${payloadJson}')
|
|
26
24
|
ues = unreal.get_editor_subsystem(unreal.UnrealEditorSubsystem)
|
|
27
|
-
if ues:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
world
|
|
32
|
-
|
|
25
|
+
if not ues:
|
|
26
|
+
raise Exception('UnrealEditorSubsystem not available')
|
|
27
|
+
world = ues.get_editor_world()
|
|
28
|
+
if not world:
|
|
29
|
+
raise Exception('Editor world unavailable')
|
|
30
|
+
try:
|
|
31
|
+
${indentedBody}
|
|
32
|
+
print('DEBUG_DRAW:' + json.dumps({'action': '${action}', 'params': payload}))
|
|
33
|
+
print('RESULT:' + json.dumps({'success': True, 'action': '${action}', 'params': payload}))
|
|
34
|
+
except Exception as e:
|
|
35
|
+
print('DEBUG_DRAW_ERROR:' + str(e))
|
|
36
|
+
print('RESULT:' + json.dumps({'success': False, 'action': '${action}', 'error': str(e)}))
|
|
33
37
|
`.trim()
|
|
34
38
|
.replace(/\r?\n/g, '\n');
|
|
39
|
+
|
|
35
40
|
try {
|
|
36
|
-
await this.bridge.executePython(script);
|
|
37
|
-
|
|
41
|
+
const response = await this.bridge.executePython(script);
|
|
42
|
+
let interpreted = interpretStandardResult(response, {
|
|
43
|
+
successMessage: `${action} executed`,
|
|
44
|
+
failureMessage: `${action} failed`
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const parsed = parseStandardResult(response);
|
|
48
|
+
const parsedPayload = parsed.data ?? {};
|
|
49
|
+
const parsedSuccessValue = (parsedPayload as any).success;
|
|
50
|
+
const normalizedSuccess = typeof parsedSuccessValue === 'string'
|
|
51
|
+
? ['true', '1', 'yes'].includes(parsedSuccessValue.toLowerCase())
|
|
52
|
+
: parsedSuccessValue === true;
|
|
53
|
+
|
|
54
|
+
if (!interpreted.success && normalizedSuccess) {
|
|
55
|
+
interpreted = {
|
|
56
|
+
...interpreted,
|
|
57
|
+
success: true,
|
|
58
|
+
error: undefined,
|
|
59
|
+
message: interpreted.message || `${action} executed`,
|
|
60
|
+
payload: { ...parsedPayload }
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const finalSuccess = interpreted.success || normalizedSuccess;
|
|
65
|
+
|
|
66
|
+
const resolvedAction = coerceString(interpreted.payload.action) ?? action;
|
|
67
|
+
const fallbackOutput = typeof parsed.text === 'string' ? parsed.text : '';
|
|
68
|
+
const rawOutput = bestEffortInterpretedText(interpreted) ?? (fallbackOutput ? fallbackOutput : undefined);
|
|
69
|
+
|
|
70
|
+
if (finalSuccess) {
|
|
71
|
+
return {
|
|
72
|
+
...interpreted.payload,
|
|
73
|
+
success: true,
|
|
74
|
+
action: resolvedAction,
|
|
75
|
+
warnings: interpreted.warnings,
|
|
76
|
+
details: interpreted.details,
|
|
77
|
+
rawOutput,
|
|
78
|
+
raw: parsed.raw ?? interpreted.raw
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
success: false,
|
|
84
|
+
action: resolvedAction,
|
|
85
|
+
error: interpreted.error ?? `${resolvedAction} failed`,
|
|
86
|
+
warnings: interpreted.warnings,
|
|
87
|
+
details: interpreted.details,
|
|
88
|
+
rawOutput,
|
|
89
|
+
raw: parsed.raw ?? interpreted.raw
|
|
90
|
+
};
|
|
38
91
|
} catch (e) {
|
|
39
|
-
return { success: false, error: String(e) };
|
|
92
|
+
return { success: false, error: String(e), action: meta?.action || 'debug_draw' };
|
|
40
93
|
}
|
|
41
94
|
}
|
|
42
95
|
|
|
@@ -60,7 +113,16 @@ end = unreal.Vector(${ex}, ${ey}, ${ez})
|
|
|
60
113
|
color = unreal.LinearColor(${sr}/255.0, ${sg}/255.0, ${sb}/255.0, ${sa}/255.0)
|
|
61
114
|
unreal.SystemLibrary.draw_debug_line(world, start, end, color, ${duration}, ${thickness})
|
|
62
115
|
`;
|
|
63
|
-
return this.pyDraw(script
|
|
116
|
+
return this.pyDraw(script, {
|
|
117
|
+
action: 'debug_line',
|
|
118
|
+
params: {
|
|
119
|
+
start: params.start,
|
|
120
|
+
end: params.end,
|
|
121
|
+
color,
|
|
122
|
+
duration,
|
|
123
|
+
thickness
|
|
124
|
+
}
|
|
125
|
+
});
|
|
64
126
|
}
|
|
65
127
|
|
|
66
128
|
// Draw debug box using Python SystemLibrary
|
|
@@ -87,7 +149,17 @@ rot = unreal.Rotator(${rp}, ${ry}, ${rr})
|
|
|
87
149
|
color = unreal.LinearColor(${cr}/255.0, ${cg}/255.0, ${cb}/255.0, ${ca}/255.0)
|
|
88
150
|
unreal.SystemLibrary.draw_debug_box(world, center, extent, color, rot, ${duration}, ${thickness})
|
|
89
151
|
`;
|
|
90
|
-
return this.pyDraw(script
|
|
152
|
+
return this.pyDraw(script, {
|
|
153
|
+
action: 'debug_box',
|
|
154
|
+
params: {
|
|
155
|
+
center: params.center,
|
|
156
|
+
extent: params.extent,
|
|
157
|
+
rotation,
|
|
158
|
+
color,
|
|
159
|
+
duration,
|
|
160
|
+
thickness
|
|
161
|
+
}
|
|
162
|
+
});
|
|
91
163
|
}
|
|
92
164
|
|
|
93
165
|
// Draw debug sphere using Python SystemLibrary
|
|
@@ -110,7 +182,17 @@ center = unreal.Vector(${cx}, ${cy}, ${cz})
|
|
|
110
182
|
color = unreal.LinearColor(${cr}/255.0, ${cg}/255.0, ${cb}/255.0, ${ca}/255.0)
|
|
111
183
|
unreal.SystemLibrary.draw_debug_sphere(world, center, ${params.radius}, ${segments}, color, ${duration}, ${thickness})
|
|
112
184
|
`;
|
|
113
|
-
return this.pyDraw(script
|
|
185
|
+
return this.pyDraw(script, {
|
|
186
|
+
action: 'debug_sphere',
|
|
187
|
+
params: {
|
|
188
|
+
center: params.center,
|
|
189
|
+
radius: params.radius,
|
|
190
|
+
segments,
|
|
191
|
+
color,
|
|
192
|
+
duration,
|
|
193
|
+
thickness
|
|
194
|
+
}
|
|
195
|
+
});
|
|
114
196
|
}
|
|
115
197
|
|
|
116
198
|
// The rest keep console-command fallbacks or editor helpers as before
|
|
@@ -130,7 +212,17 @@ unreal.SystemLibrary.draw_debug_sphere(world, center, ${params.radius}, ${segmen
|
|
|
130
212
|
const [rp, ry, rr] = rotation;
|
|
131
213
|
const [cr, cg, cb, ca] = color;
|
|
132
214
|
const script = `\ncenter = unreal.Vector(${cx}, ${cy}, ${cz})\nrot = unreal.Rotator(${rp}, ${ry}, ${rr})\ncolor = unreal.LinearColor(${cr}/255.0, ${cg}/255.0, ${cb}/255.0, ${ca}/255.0)\nunreal.SystemLibrary.draw_debug_capsule(world, center, ${params.halfHeight}, ${params.radius}, rot, color, ${duration}, 1.0)\n`;
|
|
133
|
-
return this.pyDraw(script
|
|
215
|
+
return this.pyDraw(script, {
|
|
216
|
+
action: 'debug_capsule',
|
|
217
|
+
params: {
|
|
218
|
+
center: params.center,
|
|
219
|
+
halfHeight: params.halfHeight,
|
|
220
|
+
radius: params.radius,
|
|
221
|
+
rotation,
|
|
222
|
+
color,
|
|
223
|
+
duration
|
|
224
|
+
}
|
|
225
|
+
});
|
|
134
226
|
}
|
|
135
227
|
|
|
136
228
|
async drawDebugCone(params: {
|
|
@@ -149,7 +241,19 @@ unreal.SystemLibrary.draw_debug_sphere(world, center, ${params.radius}, ${segmen
|
|
|
149
241
|
const [dx, dy, dz] = params.direction;
|
|
150
242
|
const [cr, cg, cb, ca] = color;
|
|
151
243
|
const script = `\norigin = unreal.Vector(${ox}, ${oy}, ${oz})\ndir = unreal.Vector(${dx}, ${dy}, ${dz})\ncolor = unreal.LinearColor(${cr}/255.0, ${cg}/255.0, ${cb}/255.0, ${ca}/255.0)\nunreal.SystemLibrary.draw_debug_cone(world, origin, dir, ${params.length}, ${params.angleWidth}, ${params.angleHeight}, ${params.numSides || 12}, color, ${duration}, 1.0)\n`;
|
|
152
|
-
return this.pyDraw(script
|
|
244
|
+
return this.pyDraw(script, {
|
|
245
|
+
action: 'debug_cone',
|
|
246
|
+
params: {
|
|
247
|
+
origin: params.origin,
|
|
248
|
+
direction: params.direction,
|
|
249
|
+
length: params.length,
|
|
250
|
+
angleWidth: params.angleWidth,
|
|
251
|
+
angleHeight: params.angleHeight,
|
|
252
|
+
numSides: params.numSides || 12,
|
|
253
|
+
color,
|
|
254
|
+
duration
|
|
255
|
+
}
|
|
256
|
+
});
|
|
153
257
|
}
|
|
154
258
|
|
|
155
259
|
async drawDebugString(params: {
|
|
@@ -164,7 +268,16 @@ unreal.SystemLibrary.draw_debug_sphere(world, center, ${params.radius}, ${segmen
|
|
|
164
268
|
const [x, y, z] = params.location;
|
|
165
269
|
const [r, g, b, a] = color;
|
|
166
270
|
const script = `\nloc = unreal.Vector(${x}, ${y}, ${z})\ncolor = unreal.LinearColor(${r}/255.0, ${g}/255.0, ${b}/255.0, ${a}/255.0)\nunreal.SystemLibrary.draw_debug_string(world, loc, "${params.text.replace(/"/g, '\\"')}", None, color, ${duration})\n`;
|
|
167
|
-
return this.pyDraw(script
|
|
271
|
+
return this.pyDraw(script, {
|
|
272
|
+
action: 'debug_string',
|
|
273
|
+
params: {
|
|
274
|
+
location: params.location,
|
|
275
|
+
text: params.text,
|
|
276
|
+
color,
|
|
277
|
+
duration,
|
|
278
|
+
fontSize: params.fontSize
|
|
279
|
+
}
|
|
280
|
+
});
|
|
168
281
|
}
|
|
169
282
|
|
|
170
283
|
async drawDebugArrow(params: {
|
|
@@ -182,7 +295,17 @@ unreal.SystemLibrary.draw_debug_sphere(world, center, ${params.radius}, ${segmen
|
|
|
182
295
|
const [ex, ey, ez] = params.end;
|
|
183
296
|
const [r, g, b, a] = color;
|
|
184
297
|
const script = `\nstart = unreal.Vector(${sx}, ${sy}, ${sz})\nend = unreal.Vector(${ex}, ${ey}, ${ez})\ncolor = unreal.LinearColor(${r}/255.0, ${g}/255.0, ${b}/255.0, ${a}/255.0)\nunreal.SystemLibrary.draw_debug_arrow(world, start, end, ${params.arrowSize || 10.0}, color, ${duration}, ${thickness})\n`;
|
|
185
|
-
return this.pyDraw(script
|
|
298
|
+
return this.pyDraw(script, {
|
|
299
|
+
action: 'debug_arrow',
|
|
300
|
+
params: {
|
|
301
|
+
start: params.start,
|
|
302
|
+
end: params.end,
|
|
303
|
+
arrowSize: params.arrowSize || 10.0,
|
|
304
|
+
color,
|
|
305
|
+
duration,
|
|
306
|
+
thickness
|
|
307
|
+
}
|
|
308
|
+
});
|
|
186
309
|
}
|
|
187
310
|
|
|
188
311
|
async drawDebugPoint(params: {
|
|
@@ -197,7 +320,15 @@ unreal.SystemLibrary.draw_debug_sphere(world, center, ${params.radius}, ${segmen
|
|
|
197
320
|
const [x, y, z] = params.location;
|
|
198
321
|
const [r, g, b, a] = color;
|
|
199
322
|
const script = `\nloc = unreal.Vector(${x}, ${y}, ${z})\ncolor = unreal.LinearColor(${r}/255.0, ${g}/255.0, ${b}/255.0, ${a}/255.0)\nunreal.SystemLibrary.draw_debug_point(world, loc, ${size}, color, ${duration})\n`;
|
|
200
|
-
return this.pyDraw(script
|
|
323
|
+
return this.pyDraw(script, {
|
|
324
|
+
action: 'debug_point',
|
|
325
|
+
params: {
|
|
326
|
+
location: params.location,
|
|
327
|
+
size,
|
|
328
|
+
color,
|
|
329
|
+
duration
|
|
330
|
+
}
|
|
331
|
+
});
|
|
201
332
|
}
|
|
202
333
|
|
|
203
334
|
async drawDebugCoordinateSystem(params: {
|
|
@@ -234,7 +365,19 @@ unreal.SystemLibrary.draw_debug_sphere(world, center, ${params.radius}, ${segmen
|
|
|
234
365
|
const [rp, ry, rr] = params.rotation;
|
|
235
366
|
const [r, g, b, a] = color;
|
|
236
367
|
const script = `\norigin = unreal.Vector(${ox}, ${oy}, ${oz})\nrot = unreal.Rotator(${rp}, ${ry}, ${rr})\ncolor = unreal.LinearColor(${r}/255.0, ${g}/255.0, ${b}/255.0, ${a}/255.0)\nunreal.SystemLibrary.draw_debug_frustum(world, origin, rot, ${params.fov}, ${aspectRatio}, ${nearPlane}, ${farPlane}, color, ${duration})\n`;
|
|
237
|
-
return this.pyDraw(script
|
|
368
|
+
return this.pyDraw(script, {
|
|
369
|
+
action: 'debug_frustum',
|
|
370
|
+
params: {
|
|
371
|
+
origin: params.origin,
|
|
372
|
+
rotation: params.rotation,
|
|
373
|
+
fov: params.fov,
|
|
374
|
+
aspectRatio,
|
|
375
|
+
nearPlane,
|
|
376
|
+
farPlane,
|
|
377
|
+
color,
|
|
378
|
+
duration
|
|
379
|
+
}
|
|
380
|
+
});
|
|
238
381
|
}
|
|
239
382
|
|
|
240
383
|
async clearDebugDrawings() {
|
|
@@ -245,16 +388,14 @@ unreal.SystemLibrary.draw_debug_sphere(world, center, ${params.radius}, ${segmen
|
|
|
245
388
|
enabled: boolean;
|
|
246
389
|
type?: 'Simple' | 'Complex' | 'Both';
|
|
247
390
|
}) {
|
|
248
|
-
|
|
391
|
+
const commands: string[] = [];
|
|
249
392
|
if (params.enabled) {
|
|
250
393
|
const typeCmd = params.type === 'Simple' ? '1' : params.type === 'Complex' ? '2' : '3';
|
|
251
394
|
commands.push(`show Collision ${typeCmd}`);
|
|
252
395
|
} else {
|
|
253
396
|
commands.push('show Collision 0');
|
|
254
397
|
}
|
|
255
|
-
|
|
256
|
-
await this.bridge.executeConsoleCommand(cmd);
|
|
257
|
-
}
|
|
398
|
+
await this.bridge.executeConsoleCommands(commands);
|
|
258
399
|
return { success: true, message: `Collision visualization ${params.enabled ? 'enabled' : 'disabled'}` };
|
|
259
400
|
}
|
|
260
401
|
|
package/src/tools/editor.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { UnrealBridge } from '../unreal-bridge.js';
|
|
2
2
|
import { toVec3Object, toRotObject } from '../utils/normalize.js';
|
|
3
|
+
import { bestEffortInterpretedText, coerceString, interpretStandardResult } from '../utils/result-helpers.js';
|
|
3
4
|
|
|
4
5
|
export class EditorTools {
|
|
5
6
|
constructor(private bridge: UnrealBridge) {}
|
|
@@ -69,26 +70,13 @@ else:
|
|
|
69
70
|
`.trim();
|
|
70
71
|
|
|
71
72
|
const resp: any = await this.bridge.executePython(pythonCmd);
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return { success: true, message: `PIE started (via ${method})` };
|
|
80
|
-
}
|
|
81
|
-
} catch {
|
|
82
|
-
try {
|
|
83
|
-
// Fallback: handle non-JSON python dict-style output
|
|
84
|
-
const sanitized = m[1].replace(/'/g, '"').replace(/\bTrue\b/g, 'true').replace(/\bFalse\b/g, 'false');
|
|
85
|
-
const parsed = JSON.parse(sanitized);
|
|
86
|
-
if (parsed.success) {
|
|
87
|
-
const method = parsed.method || 'LevelEditorSubsystem';
|
|
88
|
-
return { success: true, message: `PIE started (via ${method})` };
|
|
89
|
-
}
|
|
90
|
-
} catch {}
|
|
91
|
-
}
|
|
73
|
+
const interpreted = interpretStandardResult(resp, {
|
|
74
|
+
successMessage: 'PIE started',
|
|
75
|
+
failureMessage: 'Failed to start PIE'
|
|
76
|
+
});
|
|
77
|
+
if (interpreted.success) {
|
|
78
|
+
const method = coerceString(interpreted.payload.method) ?? 'LevelEditorSubsystem';
|
|
79
|
+
return { success: true, message: `PIE started (via ${method})` };
|
|
92
80
|
}
|
|
93
81
|
// If not verified, fall through to fallback
|
|
94
82
|
} catch (err) {
|
|
@@ -129,19 +117,21 @@ else:
|
|
|
129
117
|
print('RESULT:' + json.dumps({'success': False, 'error': 'LevelEditorSubsystem not available'}))
|
|
130
118
|
`.trim();
|
|
131
119
|
const resp: any = await this.bridge.executePython(pythonCmd);
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
120
|
+
const interpreted = interpretStandardResult(resp, {
|
|
121
|
+
successMessage: 'PIE stopped successfully',
|
|
122
|
+
failureMessage: 'Failed to stop PIE'
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
if (interpreted.success) {
|
|
126
|
+
const method = coerceString(interpreted.payload.method) ?? 'LevelEditorSubsystem';
|
|
127
|
+
return { success: true, message: `PIE stopped via ${method}` };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (interpreted.error) {
|
|
131
|
+
return { success: false, error: interpreted.error };
|
|
142
132
|
}
|
|
143
|
-
|
|
144
|
-
return { success:
|
|
133
|
+
|
|
134
|
+
return { success: false, error: 'Failed to stop PIE' };
|
|
145
135
|
} catch {
|
|
146
136
|
// Fallback to console command
|
|
147
137
|
await this.bridge.executeConsoleCommand('stop');
|
|
@@ -196,12 +186,20 @@ except Exception as e:
|
|
|
196
186
|
print('RESULT:' + json.dumps({'success': False, 'error': str(e)}))
|
|
197
187
|
`.trim();
|
|
198
188
|
const resp: any = await this.bridge.executePython(py);
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
189
|
+
const interpreted = interpretStandardResult(resp, {
|
|
190
|
+
successMessage: 'Lighting build started',
|
|
191
|
+
failureMessage: 'Failed to build lighting'
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
if (interpreted.success) {
|
|
195
|
+
return { success: true, message: interpreted.message };
|
|
203
196
|
}
|
|
204
|
-
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
success: false,
|
|
200
|
+
error: interpreted.error ?? 'Failed to build lighting',
|
|
201
|
+
details: bestEffortInterpretedText(interpreted)
|
|
202
|
+
};
|
|
205
203
|
} catch (err) {
|
|
206
204
|
return { success: false, error: `Failed to build lighting: ${err}` };
|
|
207
205
|
}
|