unreal-engine-mcp-server 0.2.1 → 0.3.1
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 +6 -1
- package/Dockerfile +11 -28
- package/README.md +0 -17
- package/dist/index.js +108 -40
- package/dist/resources/actors.js +71 -13
- package/dist/resources/assets.d.ts +1 -1
- package/dist/resources/assets.js +3 -3
- package/dist/tools/consolidated-tool-definitions.js +278 -14
- package/dist/tools/consolidated-tool-handlers.js +5 -2
- package/dist/tools/tool-definitions.js +211 -37
- package/dist/tools/tool-handlers.js +42 -9
- package/dist/unreal-bridge.d.ts +4 -1
- package/dist/unreal-bridge.js +211 -53
- package/dist/utils/http.js +4 -2
- package/dist/utils/response-validator.js +5 -4
- package/dist/utils/safe-json.js +1 -1
- package/package.json +4 -11
- package/server.json +2 -2
- package/src/index.ts +107 -42
- package/src/resources/actors.ts +51 -13
- package/src/resources/assets.ts +3 -3
- package/src/tools/consolidated-tool-definitions.ts +278 -14
- package/src/tools/consolidated-tool-handlers.ts +6 -2
- package/src/tools/tool-definitions.ts +211 -37
- package/src/tools/tool-handlers.ts +41 -9
- package/src/unreal-bridge.ts +163 -60
- package/src/utils/http.ts +7 -4
- package/src/utils/response-validator.ts +5 -4
- package/src/utils/safe-json.ts +1 -1
|
@@ -3,7 +3,18 @@ export const toolDefinitions = [
|
|
|
3
3
|
// Asset Tools
|
|
4
4
|
{
|
|
5
5
|
name: 'list_assets',
|
|
6
|
-
description:
|
|
6
|
+
description: `List assets in a folder of the project.
|
|
7
|
+
|
|
8
|
+
When to use:
|
|
9
|
+
- Browse project content (use /Game; /Content is auto-mapped by the server).
|
|
10
|
+
- Get a quick inventory of assets in a subfolder to refine subsequent actions.
|
|
11
|
+
|
|
12
|
+
Notes:
|
|
13
|
+
- For /Game, the server may limit results for performance; prefer subfolders (e.g., /Game/ThirdPerson).
|
|
14
|
+
- Returns a structured list with Name/Path/Class/PackagePath when available.
|
|
15
|
+
|
|
16
|
+
Example:
|
|
17
|
+
- {"directory":"/Game/ThirdPerson","recursive":false}`,
|
|
7
18
|
inputSchema: {
|
|
8
19
|
type: 'object',
|
|
9
20
|
properties: {
|
|
@@ -34,7 +45,17 @@ export const toolDefinitions = [
|
|
|
34
45
|
},
|
|
35
46
|
{
|
|
36
47
|
name: 'import_asset',
|
|
37
|
-
description:
|
|
48
|
+
description: `Import a file from disk into the project (e.g., FBX, PNG, WAV, EXR).
|
|
49
|
+
|
|
50
|
+
When to use:
|
|
51
|
+
- Bring external content into /Game at a specific destination path.
|
|
52
|
+
|
|
53
|
+
Notes:
|
|
54
|
+
- destinationPath is a package path like /Game/Environment/Trees.
|
|
55
|
+
- Keep file names simple (avoid spaces and special characters).
|
|
56
|
+
|
|
57
|
+
Example:
|
|
58
|
+
- {"sourcePath":"C:/Temp/Tree.fbx","destinationPath":"/Game/Environment/Trees"}`,
|
|
38
59
|
inputSchema: {
|
|
39
60
|
type: 'object',
|
|
40
61
|
properties: {
|
|
@@ -56,7 +77,17 @@ export const toolDefinitions = [
|
|
|
56
77
|
// Actor Tools
|
|
57
78
|
{
|
|
58
79
|
name: 'spawn_actor',
|
|
59
|
-
description:
|
|
80
|
+
description: `Spawn a new actor in the current level.
|
|
81
|
+
|
|
82
|
+
When to use:
|
|
83
|
+
- Place a class (e.g., StaticMeshActor, CameraActor) or spawn from an asset path (e.g., /Engine/BasicShapes/Cube).
|
|
84
|
+
|
|
85
|
+
Notes:
|
|
86
|
+
- If an asset path is provided, a StaticMeshActor is auto-spawned with the mesh set.
|
|
87
|
+
- location/rotation are optional; defaults are used if omitted.
|
|
88
|
+
|
|
89
|
+
Example:
|
|
90
|
+
- {"classPath":"/Engine/BasicShapes/Cube","location":{"x":0,"y":0,"z":100}}`,
|
|
60
91
|
inputSchema: {
|
|
61
92
|
type: 'object',
|
|
62
93
|
properties: {
|
|
@@ -91,7 +122,13 @@ export const toolDefinitions = [
|
|
|
91
122
|
},
|
|
92
123
|
{
|
|
93
124
|
name: 'delete_actor',
|
|
94
|
-
description:
|
|
125
|
+
description: `Delete one or more actors by name/label.
|
|
126
|
+
|
|
127
|
+
When to use:
|
|
128
|
+
- Remove actors matching a label/name (case-insensitive).
|
|
129
|
+
|
|
130
|
+
Example:
|
|
131
|
+
- {"actorName":"Cube_1"}`,
|
|
95
132
|
inputSchema: {
|
|
96
133
|
type: 'object',
|
|
97
134
|
properties: {
|
|
@@ -111,7 +148,13 @@ export const toolDefinitions = [
|
|
|
111
148
|
// Material Tools
|
|
112
149
|
{
|
|
113
150
|
name: 'create_material',
|
|
114
|
-
description:
|
|
151
|
+
description: `Create a simple Material asset at a path.
|
|
152
|
+
|
|
153
|
+
When to use:
|
|
154
|
+
- Quickly scaffold a basic material you can edit later.
|
|
155
|
+
|
|
156
|
+
Example:
|
|
157
|
+
- {"name":"M_Mask","path":"/Game/Materials"}`,
|
|
115
158
|
inputSchema: {
|
|
116
159
|
type: 'object',
|
|
117
160
|
properties: {
|
|
@@ -132,7 +175,13 @@ export const toolDefinitions = [
|
|
|
132
175
|
},
|
|
133
176
|
{
|
|
134
177
|
name: 'apply_material_to_actor',
|
|
135
|
-
description:
|
|
178
|
+
description: `Assign a material to an actor's mesh component.
|
|
179
|
+
|
|
180
|
+
When to use:
|
|
181
|
+
- Swap an actor's material by path; slotIndex defaults to 0.
|
|
182
|
+
|
|
183
|
+
Example:
|
|
184
|
+
- {"actorPath":"/Game/LevelActors/Cube_1","materialPath":"/Game/Materials/M_Mask","slotIndex":0}`,
|
|
136
185
|
inputSchema: {
|
|
137
186
|
type: 'object',
|
|
138
187
|
properties: {
|
|
@@ -153,7 +202,10 @@ export const toolDefinitions = [
|
|
|
153
202
|
// Editor Tools
|
|
154
203
|
{
|
|
155
204
|
name: 'play_in_editor',
|
|
156
|
-
description:
|
|
205
|
+
description: `Start a Play-In-Editor (PIE) session.
|
|
206
|
+
|
|
207
|
+
When to use:
|
|
208
|
+
- Begin simulating the level in the editor.`,
|
|
157
209
|
inputSchema: {
|
|
158
210
|
type: 'object',
|
|
159
211
|
properties: {}
|
|
@@ -169,7 +221,10 @@ export const toolDefinitions = [
|
|
|
169
221
|
},
|
|
170
222
|
{
|
|
171
223
|
name: 'stop_play_in_editor',
|
|
172
|
-
description:
|
|
224
|
+
description: `Stop the active PIE session.
|
|
225
|
+
|
|
226
|
+
When to use:
|
|
227
|
+
- End simulation and return to the editor.`,
|
|
173
228
|
inputSchema: {
|
|
174
229
|
type: 'object',
|
|
175
230
|
properties: {}
|
|
@@ -185,7 +240,16 @@ export const toolDefinitions = [
|
|
|
185
240
|
},
|
|
186
241
|
{
|
|
187
242
|
name: 'set_camera',
|
|
188
|
-
description:
|
|
243
|
+
description: `Reposition the editor viewport camera.
|
|
244
|
+
|
|
245
|
+
When to use:
|
|
246
|
+
- Move/aim the camera in the editor for framing.
|
|
247
|
+
|
|
248
|
+
Notes:
|
|
249
|
+
- Accepts object or array formats; values are normalized.
|
|
250
|
+
|
|
251
|
+
Example:
|
|
252
|
+
- {"location":{"x":0,"y":-600,"z":250},"rotation":{"pitch":0,"yaw":0,"roll":0}}`,
|
|
189
253
|
inputSchema: {
|
|
190
254
|
type: 'object',
|
|
191
255
|
properties: {
|
|
@@ -220,7 +284,13 @@ export const toolDefinitions = [
|
|
|
220
284
|
// Animation Tools
|
|
221
285
|
{
|
|
222
286
|
name: 'create_animation_blueprint',
|
|
223
|
-
description:
|
|
287
|
+
description: `Create an Animation Blueprint for a skeleton.
|
|
288
|
+
|
|
289
|
+
When to use:
|
|
290
|
+
- Generate a starter Anim BP for a given skeleton.
|
|
291
|
+
|
|
292
|
+
Example:
|
|
293
|
+
- {"name":"ABP_Hero","skeletonPath":"/Game/Characters/Hero/SK_Hero_Skeleton","savePath":"/Game/Characters/Hero"}`,
|
|
224
294
|
inputSchema: {
|
|
225
295
|
type: 'object',
|
|
226
296
|
properties: {
|
|
@@ -241,7 +311,13 @@ export const toolDefinitions = [
|
|
|
241
311
|
},
|
|
242
312
|
{
|
|
243
313
|
name: 'play_animation_montage',
|
|
244
|
-
description:
|
|
314
|
+
description: `Play a Montage/Animation on an actor.
|
|
315
|
+
|
|
316
|
+
When to use:
|
|
317
|
+
- Trigger a montage on a possessed or editor actor.
|
|
318
|
+
|
|
319
|
+
Example:
|
|
320
|
+
- {"actorName":"Hero","montagePath":"/Game/Anim/MT_Attack","playRate":1.0}`,
|
|
245
321
|
inputSchema: {
|
|
246
322
|
type: 'object',
|
|
247
323
|
properties: {
|
|
@@ -263,7 +339,13 @@ export const toolDefinitions = [
|
|
|
263
339
|
// Physics Tools
|
|
264
340
|
{
|
|
265
341
|
name: 'setup_ragdoll',
|
|
266
|
-
description:
|
|
342
|
+
description: `Enable simple ragdoll using a physics asset.
|
|
343
|
+
|
|
344
|
+
When to use:
|
|
345
|
+
- Toggle ragdoll behavior on a character skeleton.
|
|
346
|
+
|
|
347
|
+
Example:
|
|
348
|
+
- {"skeletonPath":"/Game/Characters/Hero/SK_Hero_Skeleton","physicsAssetName":"PHYS_Hero","blendWeight":1.0}`,
|
|
267
349
|
inputSchema: {
|
|
268
350
|
type: 'object',
|
|
269
351
|
properties: {
|
|
@@ -284,7 +366,10 @@ export const toolDefinitions = [
|
|
|
284
366
|
},
|
|
285
367
|
{
|
|
286
368
|
name: 'apply_force',
|
|
287
|
-
description:
|
|
369
|
+
description: `Apply a world-space force vector to an actor with physics enabled.
|
|
370
|
+
|
|
371
|
+
Example:
|
|
372
|
+
- {"actorName":"PhysicsBox","force":{"x":0,"y":0,"z":5000}}`,
|
|
288
373
|
inputSchema: {
|
|
289
374
|
type: 'object',
|
|
290
375
|
properties: {
|
|
@@ -313,7 +398,13 @@ export const toolDefinitions = [
|
|
|
313
398
|
// Niagara Tools
|
|
314
399
|
{
|
|
315
400
|
name: 'create_particle_effect',
|
|
316
|
-
description:
|
|
401
|
+
description: `Create a simple particle/FX by tag.
|
|
402
|
+
|
|
403
|
+
When to use:
|
|
404
|
+
- Quickly drop a generic Fire/Smoke/Water effect for previews.
|
|
405
|
+
|
|
406
|
+
Example:
|
|
407
|
+
- {"effectType":"Smoke","name":"SMK1","location":{"x":100,"y":0,"z":50}}`,
|
|
317
408
|
inputSchema: {
|
|
318
409
|
type: 'object',
|
|
319
410
|
properties: {
|
|
@@ -342,7 +433,10 @@ export const toolDefinitions = [
|
|
|
342
433
|
},
|
|
343
434
|
{
|
|
344
435
|
name: 'spawn_niagara_system',
|
|
345
|
-
description:
|
|
436
|
+
description: `Spawn a Niagara system at a location.
|
|
437
|
+
|
|
438
|
+
Example:
|
|
439
|
+
- {"systemPath":"/Game/FX/NS_Explosion","location":{"x":0,"y":0,"z":200},"scale":1.0}`,
|
|
346
440
|
inputSchema: {
|
|
347
441
|
type: 'object',
|
|
348
442
|
properties: {
|
|
@@ -371,7 +465,10 @@ export const toolDefinitions = [
|
|
|
371
465
|
// Blueprint Tools
|
|
372
466
|
{
|
|
373
467
|
name: 'create_blueprint',
|
|
374
|
-
description:
|
|
468
|
+
description: `Create a new Blueprint asset at a path.
|
|
469
|
+
|
|
470
|
+
Example:
|
|
471
|
+
- {"name":"BP_Switch","blueprintType":"Actor","savePath":"/Game/Blueprints"}`,
|
|
375
472
|
inputSchema: {
|
|
376
473
|
type: 'object',
|
|
377
474
|
properties: {
|
|
@@ -392,7 +489,10 @@ export const toolDefinitions = [
|
|
|
392
489
|
},
|
|
393
490
|
{
|
|
394
491
|
name: 'add_blueprint_component',
|
|
395
|
-
description:
|
|
492
|
+
description: `Add a component to an existing Blueprint.
|
|
493
|
+
|
|
494
|
+
Example:
|
|
495
|
+
- {"blueprintName":"BP_Switch","componentType":"PointLightComponent","componentName":"KeyLight"}`,
|
|
396
496
|
inputSchema: {
|
|
397
497
|
type: 'object',
|
|
398
498
|
properties: {
|
|
@@ -415,7 +515,10 @@ export const toolDefinitions = [
|
|
|
415
515
|
// Level Tools
|
|
416
516
|
{
|
|
417
517
|
name: 'load_level',
|
|
418
|
-
description:
|
|
518
|
+
description: `Load a level by path (e.g., /Game/Maps/Lobby).
|
|
519
|
+
|
|
520
|
+
Example:
|
|
521
|
+
- {"levelPath":"/Game/Maps/Lobby","streaming":false}`,
|
|
419
522
|
inputSchema: {
|
|
420
523
|
type: 'object',
|
|
421
524
|
properties: {
|
|
@@ -435,7 +538,10 @@ export const toolDefinitions = [
|
|
|
435
538
|
},
|
|
436
539
|
{
|
|
437
540
|
name: 'save_level',
|
|
438
|
-
description:
|
|
541
|
+
description: `Save the current level to a path or by name.
|
|
542
|
+
|
|
543
|
+
Example:
|
|
544
|
+
- {"levelName":"Lobby","savePath":"/Game/Maps"}`,
|
|
439
545
|
inputSchema: {
|
|
440
546
|
type: 'object',
|
|
441
547
|
properties: {
|
|
@@ -454,7 +560,10 @@ export const toolDefinitions = [
|
|
|
454
560
|
},
|
|
455
561
|
{
|
|
456
562
|
name: 'stream_level',
|
|
457
|
-
description:
|
|
563
|
+
description: `Stream in/out a sublevel and set visibility.
|
|
564
|
+
|
|
565
|
+
Example:
|
|
566
|
+
- {"levelName":"Sublevel_A","shouldBeLoaded":true,"shouldBeVisible":true}`,
|
|
458
567
|
inputSchema: {
|
|
459
568
|
type: 'object',
|
|
460
569
|
properties: {
|
|
@@ -477,7 +586,11 @@ export const toolDefinitions = [
|
|
|
477
586
|
// Lighting Tools
|
|
478
587
|
{
|
|
479
588
|
name: 'create_light',
|
|
480
|
-
description:
|
|
589
|
+
description: `Create a light (Directional/Point/Spot/Rect/Sky) with optional transform/intensity.
|
|
590
|
+
|
|
591
|
+
Examples:
|
|
592
|
+
- {"lightType":"Directional","name":"KeyLight","intensity":5.0}
|
|
593
|
+
- {"lightType":"Point","name":"Fill","location":{"x":0,"y":100,"z":200},"intensity":2000}`,
|
|
481
594
|
inputSchema: {
|
|
482
595
|
type: 'object',
|
|
483
596
|
properties: {
|
|
@@ -506,7 +619,13 @@ export const toolDefinitions = [
|
|
|
506
619
|
},
|
|
507
620
|
{
|
|
508
621
|
name: 'build_lighting',
|
|
509
|
-
description:
|
|
622
|
+
description: `Start a lighting build.
|
|
623
|
+
|
|
624
|
+
When to use:
|
|
625
|
+
- Bake lights for preview or final output (choose quality).
|
|
626
|
+
|
|
627
|
+
Example:
|
|
628
|
+
- {"quality":"High"}`,
|
|
510
629
|
inputSchema: {
|
|
511
630
|
type: 'object',
|
|
512
631
|
properties: {
|
|
@@ -525,7 +644,13 @@ export const toolDefinitions = [
|
|
|
525
644
|
// Landscape Tools
|
|
526
645
|
{
|
|
527
646
|
name: 'create_landscape',
|
|
528
|
-
description:
|
|
647
|
+
description: `Attempt to create a landscape.
|
|
648
|
+
|
|
649
|
+
Notes:
|
|
650
|
+
- Native Python APIs are limited; you may be guided to use Landscape Mode in the editor.
|
|
651
|
+
|
|
652
|
+
Example:
|
|
653
|
+
- {"name":"Landscape_Basic","sizeX":1024,"sizeY":1024}`,
|
|
529
654
|
inputSchema: {
|
|
530
655
|
type: 'object',
|
|
531
656
|
properties: {
|
|
@@ -547,7 +672,10 @@ export const toolDefinitions = [
|
|
|
547
672
|
},
|
|
548
673
|
{
|
|
549
674
|
name: 'sculpt_landscape',
|
|
550
|
-
description:
|
|
675
|
+
description: `Sculpt a landscape using editor tools (best-effort; some operations may require manual Landscape Mode).
|
|
676
|
+
|
|
677
|
+
Example:
|
|
678
|
+
- {"landscapeName":"Landscape_Basic","tool":"Smooth","brushSize":300,"strength":0.5}`,
|
|
551
679
|
inputSchema: {
|
|
552
680
|
type: 'object',
|
|
553
681
|
properties: {
|
|
@@ -569,7 +697,10 @@ export const toolDefinitions = [
|
|
|
569
697
|
// Foliage Tools
|
|
570
698
|
{
|
|
571
699
|
name: 'add_foliage_type',
|
|
572
|
-
description:
|
|
700
|
+
description: `Create or load a FoliageType asset for instanced foliage workflows.
|
|
701
|
+
|
|
702
|
+
Example:
|
|
703
|
+
- {"name":"FT_Grass","meshPath":"/Game/Foliage/SM_Grass","density":300}`,
|
|
573
704
|
inputSchema: {
|
|
574
705
|
type: 'object',
|
|
575
706
|
properties: {
|
|
@@ -590,7 +721,13 @@ export const toolDefinitions = [
|
|
|
590
721
|
},
|
|
591
722
|
{
|
|
592
723
|
name: 'paint_foliage',
|
|
593
|
-
description:
|
|
724
|
+
description: `Paint foliage onto the world.
|
|
725
|
+
|
|
726
|
+
When to use:
|
|
727
|
+
- Scatter instances using an existing FoliageType.
|
|
728
|
+
|
|
729
|
+
Example:
|
|
730
|
+
- {"foliageType":"/Game/Foliage/Types/FT_Grass","position":{"x":0,"y":0,"z":0},"brushSize":300}`,
|
|
594
731
|
inputSchema: {
|
|
595
732
|
type: 'object',
|
|
596
733
|
properties: {
|
|
@@ -619,7 +756,10 @@ export const toolDefinitions = [
|
|
|
619
756
|
// Debug Visualization Tools
|
|
620
757
|
{
|
|
621
758
|
name: 'draw_debug_shape',
|
|
622
|
-
description:
|
|
759
|
+
description: `Draw a debug shape.
|
|
760
|
+
|
|
761
|
+
Example:
|
|
762
|
+
- {"shape":"Sphere","position":{"x":0,"y":0,"z":0},"size":100,"color":[255,0,0,255],"duration":3}`,
|
|
623
763
|
inputSchema: {
|
|
624
764
|
type: 'object',
|
|
625
765
|
properties: {
|
|
@@ -652,7 +792,10 @@ export const toolDefinitions = [
|
|
|
652
792
|
},
|
|
653
793
|
{
|
|
654
794
|
name: 'set_view_mode',
|
|
655
|
-
description:
|
|
795
|
+
description: `Set the viewport view mode.
|
|
796
|
+
|
|
797
|
+
Example:
|
|
798
|
+
- {"mode":"Wireframe"}`,
|
|
656
799
|
inputSchema: {
|
|
657
800
|
type: 'object',
|
|
658
801
|
properties: {
|
|
@@ -672,7 +815,10 @@ export const toolDefinitions = [
|
|
|
672
815
|
// Performance Tools
|
|
673
816
|
{
|
|
674
817
|
name: 'start_profiling',
|
|
675
|
-
description:
|
|
818
|
+
description: `Start performance profiling.
|
|
819
|
+
|
|
820
|
+
Example:
|
|
821
|
+
- {"type":"GPU","duration":10}`,
|
|
676
822
|
inputSchema: {
|
|
677
823
|
type: 'object',
|
|
678
824
|
properties: {
|
|
@@ -692,7 +838,10 @@ export const toolDefinitions = [
|
|
|
692
838
|
},
|
|
693
839
|
{
|
|
694
840
|
name: 'show_fps',
|
|
695
|
-
description:
|
|
841
|
+
description: `Show/hide the FPS counter.
|
|
842
|
+
|
|
843
|
+
Example:
|
|
844
|
+
- {"enabled":true,"verbose":false}`,
|
|
696
845
|
inputSchema: {
|
|
697
846
|
type: 'object',
|
|
698
847
|
properties: {
|
|
@@ -712,7 +861,10 @@ export const toolDefinitions = [
|
|
|
712
861
|
},
|
|
713
862
|
{
|
|
714
863
|
name: 'set_scalability',
|
|
715
|
-
description:
|
|
864
|
+
description: `Set scalability/quality levels.
|
|
865
|
+
|
|
866
|
+
Example:
|
|
867
|
+
- {"category":"Shadows","level":2}`,
|
|
716
868
|
inputSchema: {
|
|
717
869
|
type: 'object',
|
|
718
870
|
properties: {
|
|
@@ -733,7 +885,10 @@ export const toolDefinitions = [
|
|
|
733
885
|
// Audio Tools
|
|
734
886
|
{
|
|
735
887
|
name: 'play_sound',
|
|
736
|
-
description:
|
|
888
|
+
description: `Play a sound.
|
|
889
|
+
|
|
890
|
+
Example:
|
|
891
|
+
- {"soundPath":"/Game/Audio/SFX/Click","volume":0.5,"is3D":true}`,
|
|
737
892
|
inputSchema: {
|
|
738
893
|
type: 'object',
|
|
739
894
|
properties: {
|
|
@@ -762,7 +917,10 @@ export const toolDefinitions = [
|
|
|
762
917
|
},
|
|
763
918
|
{
|
|
764
919
|
name: 'create_ambient_sound',
|
|
765
|
-
description:
|
|
920
|
+
description: `Create an ambient sound actor.
|
|
921
|
+
|
|
922
|
+
Example:
|
|
923
|
+
- {"name":"Amb_Wind","soundPath":"/Game/Audio/Amb/AMB_Wind","location":{"x":0,"y":0,"z":0},"radius":1000}`,
|
|
766
924
|
inputSchema: {
|
|
767
925
|
type: 'object',
|
|
768
926
|
properties: {
|
|
@@ -792,7 +950,10 @@ export const toolDefinitions = [
|
|
|
792
950
|
// UI Tools
|
|
793
951
|
{
|
|
794
952
|
name: 'create_widget',
|
|
795
|
-
description:
|
|
953
|
+
description: `Create a UI widget.
|
|
954
|
+
|
|
955
|
+
Example:
|
|
956
|
+
- {"name":"HUDMain","type":"HUD","savePath":"/Game/UI"}`,
|
|
796
957
|
inputSchema: {
|
|
797
958
|
type: 'object',
|
|
798
959
|
properties: {
|
|
@@ -813,7 +974,10 @@ export const toolDefinitions = [
|
|
|
813
974
|
},
|
|
814
975
|
{
|
|
815
976
|
name: 'show_widget',
|
|
816
|
-
description:
|
|
977
|
+
description: `Show or hide a widget.
|
|
978
|
+
|
|
979
|
+
Example:
|
|
980
|
+
- {"widgetName":"HUDMain","visible":true}`,
|
|
817
981
|
inputSchema: {
|
|
818
982
|
type: 'object',
|
|
819
983
|
properties: {
|
|
@@ -833,7 +997,10 @@ export const toolDefinitions = [
|
|
|
833
997
|
},
|
|
834
998
|
{
|
|
835
999
|
name: 'create_hud',
|
|
836
|
-
description:
|
|
1000
|
+
description: `Create a HUD description/layout.
|
|
1001
|
+
|
|
1002
|
+
Example:
|
|
1003
|
+
- {"name":"GameHUD","elements":[{"type":"Text","position":[10,10]}]}`,
|
|
837
1004
|
inputSchema: {
|
|
838
1005
|
type: 'object',
|
|
839
1006
|
properties: {
|
|
@@ -866,7 +1033,14 @@ export const toolDefinitions = [
|
|
|
866
1033
|
// Console command (universal tool)
|
|
867
1034
|
{
|
|
868
1035
|
name: 'console_command',
|
|
869
|
-
description:
|
|
1036
|
+
description: `Execute a console command.
|
|
1037
|
+
|
|
1038
|
+
When to use:
|
|
1039
|
+
- Quick toggles like "stat fps", "viewmode wireframe", or r.* cvars.
|
|
1040
|
+
|
|
1041
|
+
Examples:
|
|
1042
|
+
- {"command":"stat fps"}
|
|
1043
|
+
- {"command":"r.ScreenPercentage 75"}`,
|
|
870
1044
|
inputSchema: {
|
|
871
1045
|
type: 'object',
|
|
872
1046
|
properties: {
|
|
@@ -32,15 +32,23 @@ export async function handleToolCall(name, args, tools) {
|
|
|
32
32
|
message = 'Failed to list assets: directory path cannot be empty';
|
|
33
33
|
break;
|
|
34
34
|
}
|
|
35
|
+
// Normalize virtual content path: map /Content -> /Game (case-insensitive)
|
|
36
|
+
const rawDir = String(args.directory).trim();
|
|
37
|
+
let normDir = rawDir.replace(/^\/?content(\/|$)/i, '/Game$1');
|
|
38
|
+
// Ensure leading slash
|
|
39
|
+
if (!normDir.startsWith('/'))
|
|
40
|
+
normDir = '/' + normDir;
|
|
41
|
+
// Collapse duplicate slashes
|
|
42
|
+
normDir = normDir.replace(/\\+/g, '/').replace(/\/+/g, '/');
|
|
35
43
|
// Try multiple approaches to list assets
|
|
36
44
|
try {
|
|
37
|
-
console.log('[list_assets] Starting asset listing for directory:',
|
|
38
|
-
// First try: Use Python for most reliable listing
|
|
45
|
+
console.log('[list_assets] Starting asset listing for directory:', normDir);
|
|
46
|
+
// First try: Use Python for most reliable listing (recursive if /Game)
|
|
39
47
|
const pythonCode = `
|
|
40
48
|
import unreal
|
|
41
49
|
import json
|
|
42
50
|
|
|
43
|
-
directory = '${
|
|
51
|
+
directory = '${normDir || '/Game'}'
|
|
44
52
|
# Use recursive for /Game to find assets in subdirectories, but limit depth
|
|
45
53
|
recursive = True if directory == '/Game' else False
|
|
46
54
|
|
|
@@ -141,8 +149,9 @@ except Exception as e:
|
|
|
141
149
|
const searchResult = await tools.bridge.httpCall('/remote/search/assets', 'PUT', {
|
|
142
150
|
Query: '', // Empty query to match all (wildcard doesn't work)
|
|
143
151
|
Filter: {
|
|
144
|
-
PackagePaths: [
|
|
145
|
-
|
|
152
|
+
PackagePaths: [normDir || '/Game'],
|
|
153
|
+
// Recursively search so we actually find assets in subfolders
|
|
154
|
+
RecursivePaths: true,
|
|
146
155
|
ClassNames: [], // Empty to get all types
|
|
147
156
|
RecursiveClasses: true
|
|
148
157
|
},
|
|
@@ -165,7 +174,7 @@ except Exception as e:
|
|
|
165
174
|
functionName: 'ExecuteConsoleCommand',
|
|
166
175
|
parameters: {
|
|
167
176
|
WorldContextObject: null,
|
|
168
|
-
Command: `AssetRegistry.DumpAssets ${
|
|
177
|
+
Command: `AssetRegistry.DumpAssets ${normDir || '/Game'}`,
|
|
169
178
|
SpecificPlayer: null
|
|
170
179
|
},
|
|
171
180
|
generateTransaction: false
|
|
@@ -186,6 +195,24 @@ except Exception as e:
|
|
|
186
195
|
}
|
|
187
196
|
// Include full asset list with details in the message
|
|
188
197
|
console.log('[list_assets] Formatting message - result has assets?', !!(result && result.assets), 'count:', result?.assets?.length);
|
|
198
|
+
if (result && result.assets && result.assets.length > 0) {
|
|
199
|
+
// If Python/HTTP gives only paths, generate Name from path
|
|
200
|
+
result.assets = result.assets.map((asset) => {
|
|
201
|
+
if (!asset.Name && asset.Path) {
|
|
202
|
+
const base = String(asset.Path).split('/').pop() || '';
|
|
203
|
+
const name = base.includes('.') ? base.split('.').pop() : base;
|
|
204
|
+
return { ...asset, Name: name };
|
|
205
|
+
}
|
|
206
|
+
return asset;
|
|
207
|
+
});
|
|
208
|
+
// Group assets by type for better organization
|
|
209
|
+
result.assets = result.assets.map((a) => {
|
|
210
|
+
if (a && !a.Path && a.AssetPath) {
|
|
211
|
+
return { ...a, Path: a.AssetPath, PackagePath: a.AssetPath.split('/').slice(0, -1).join('/') };
|
|
212
|
+
}
|
|
213
|
+
return a;
|
|
214
|
+
});
|
|
215
|
+
}
|
|
189
216
|
if (result && result.assets && result.assets.length > 0) {
|
|
190
217
|
// Group assets by type for better organization
|
|
191
218
|
const assetsByType = {};
|
|
@@ -197,7 +224,7 @@ except Exception as e:
|
|
|
197
224
|
assetsByType[type].push(asset);
|
|
198
225
|
});
|
|
199
226
|
// Format output with proper structure
|
|
200
|
-
let assetDetails = `📁 Asset Directory: ${
|
|
227
|
+
let assetDetails = `📁 Asset Directory: ${normDir || '/Game'}\n`;
|
|
201
228
|
assetDetails += `📊 Total Assets: ${result.assets.length}\n\n`;
|
|
202
229
|
// Sort types alphabetically
|
|
203
230
|
const sortedTypes = Object.keys(assetsByType).sort();
|
|
@@ -223,7 +250,7 @@ except Exception as e:
|
|
|
223
250
|
// Also keep the structured data in the result for programmatic access
|
|
224
251
|
}
|
|
225
252
|
else {
|
|
226
|
-
message = `No assets found in ${
|
|
253
|
+
message = `No assets found in ${normDir || '/Game'}`;
|
|
227
254
|
}
|
|
228
255
|
break;
|
|
229
256
|
case 'import_asset':
|
|
@@ -529,7 +556,13 @@ print(f"RESULT:{json.dumps(result)}")
|
|
|
529
556
|
// Landscape Tools
|
|
530
557
|
case 'create_landscape':
|
|
531
558
|
result = await tools.landscapeTools.createLandscape(args);
|
|
532
|
-
|
|
559
|
+
// Never claim success unless the tool says so; prefer error/message from UE/Python
|
|
560
|
+
if (result && typeof result === 'object') {
|
|
561
|
+
message = result.message || result.error || (result.success ? `Landscape ${args.name} created` : `Failed to create landscape ${args.name}`);
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
message = `Failed to create landscape ${args.name}`;
|
|
565
|
+
}
|
|
533
566
|
break;
|
|
534
567
|
case 'sculpt_landscape':
|
|
535
568
|
result = await tools.landscapeTools.sculptLandscape(args);
|
package/dist/unreal-bridge.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare class UnrealBridge {
|
|
|
14
14
|
private reconnectAttempts;
|
|
15
15
|
private readonly MAX_RECONNECT_ATTEMPTS;
|
|
16
16
|
private readonly BASE_RECONNECT_DELAY;
|
|
17
|
+
private autoReconnectEnabled;
|
|
17
18
|
private commandQueue;
|
|
18
19
|
private isProcessing;
|
|
19
20
|
private readonly MIN_COMMAND_DELAY;
|
|
@@ -32,6 +33,7 @@ export declare class UnrealBridge {
|
|
|
32
33
|
* @param retryDelayMs Delay between retry attempts in milliseconds
|
|
33
34
|
* @returns Promise that resolves when connected or rejects after all attempts fail
|
|
34
35
|
*/
|
|
36
|
+
private connectPromise?;
|
|
35
37
|
tryConnect(maxAttempts?: number, timeoutMs?: number, retryDelayMs?: number): Promise<boolean>;
|
|
36
38
|
connect(timeoutMs?: number): Promise<void>;
|
|
37
39
|
httpCall<T = any>(path: string, method?: 'GET' | 'POST' | 'PUT', body?: any): Promise<T>;
|
|
@@ -39,6 +41,7 @@ export declare class UnrealBridge {
|
|
|
39
41
|
getExposed(): Promise<any>;
|
|
40
42
|
executeConsoleCommand(command: string): Promise<any>;
|
|
41
43
|
executePython(command: string): Promise<any>;
|
|
44
|
+
setAutoReconnectEnabled(enabled: boolean): void;
|
|
42
45
|
private scheduleReconnect;
|
|
43
46
|
disconnect(): Promise<void>;
|
|
44
47
|
/**
|
|
@@ -49,7 +52,7 @@ export declare class UnrealBridge {
|
|
|
49
52
|
/**
|
|
50
53
|
* Execute Python script and parse the result
|
|
51
54
|
*/
|
|
52
|
-
|
|
55
|
+
executePythonWithResult(script: string): Promise<any>;
|
|
53
56
|
/**
|
|
54
57
|
* Get the Unreal Engine version via Python and parse major/minor/patch.
|
|
55
58
|
*/
|