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
|
@@ -4,7 +4,18 @@ export const toolDefinitions = [
|
|
|
4
4
|
// Asset Tools
|
|
5
5
|
{
|
|
6
6
|
name: 'list_assets',
|
|
7
|
-
description:
|
|
7
|
+
description: `List assets in a folder of the project.
|
|
8
|
+
|
|
9
|
+
When to use:
|
|
10
|
+
- Browse project content (use /Game; /Content is auto-mapped by the server).
|
|
11
|
+
- Get a quick inventory of assets in a subfolder to refine subsequent actions.
|
|
12
|
+
|
|
13
|
+
Notes:
|
|
14
|
+
- For /Game, the server may limit results for performance; prefer subfolders (e.g., /Game/ThirdPerson).
|
|
15
|
+
- Returns a structured list with Name/Path/Class/PackagePath when available.
|
|
16
|
+
|
|
17
|
+
Example:
|
|
18
|
+
- {"directory":"/Game/ThirdPerson","recursive":false}`,
|
|
8
19
|
inputSchema: {
|
|
9
20
|
type: 'object',
|
|
10
21
|
properties: {
|
|
@@ -35,7 +46,17 @@ export const toolDefinitions = [
|
|
|
35
46
|
},
|
|
36
47
|
{
|
|
37
48
|
name: 'import_asset',
|
|
38
|
-
description:
|
|
49
|
+
description: `Import a file from disk into the project (e.g., FBX, PNG, WAV, EXR).
|
|
50
|
+
|
|
51
|
+
When to use:
|
|
52
|
+
- Bring external content into /Game at a specific destination path.
|
|
53
|
+
|
|
54
|
+
Notes:
|
|
55
|
+
- destinationPath is a package path like /Game/Environment/Trees.
|
|
56
|
+
- Keep file names simple (avoid spaces and special characters).
|
|
57
|
+
|
|
58
|
+
Example:
|
|
59
|
+
- {"sourcePath":"C:/Temp/Tree.fbx","destinationPath":"/Game/Environment/Trees"}`,
|
|
39
60
|
inputSchema: {
|
|
40
61
|
type: 'object',
|
|
41
62
|
properties: {
|
|
@@ -58,7 +79,17 @@ export const toolDefinitions = [
|
|
|
58
79
|
// Actor Tools
|
|
59
80
|
{
|
|
60
81
|
name: 'spawn_actor',
|
|
61
|
-
description:
|
|
82
|
+
description: `Spawn a new actor in the current level.
|
|
83
|
+
|
|
84
|
+
When to use:
|
|
85
|
+
- Place a class (e.g., StaticMeshActor, CameraActor) or spawn from an asset path (e.g., /Engine/BasicShapes/Cube).
|
|
86
|
+
|
|
87
|
+
Notes:
|
|
88
|
+
- If an asset path is provided, a StaticMeshActor is auto-spawned with the mesh set.
|
|
89
|
+
- location/rotation are optional; defaults are used if omitted.
|
|
90
|
+
|
|
91
|
+
Example:
|
|
92
|
+
- {"classPath":"/Engine/BasicShapes/Cube","location":{"x":0,"y":0,"z":100}}`,
|
|
62
93
|
inputSchema: {
|
|
63
94
|
type: 'object',
|
|
64
95
|
properties: {
|
|
@@ -93,7 +124,13 @@ export const toolDefinitions = [
|
|
|
93
124
|
},
|
|
94
125
|
{
|
|
95
126
|
name: 'delete_actor',
|
|
96
|
-
description:
|
|
127
|
+
description: `Delete one or more actors by name/label.
|
|
128
|
+
|
|
129
|
+
When to use:
|
|
130
|
+
- Remove actors matching a label/name (case-insensitive).
|
|
131
|
+
|
|
132
|
+
Example:
|
|
133
|
+
- {"actorName":"Cube_1"}`,
|
|
97
134
|
inputSchema: {
|
|
98
135
|
type: 'object',
|
|
99
136
|
properties: {
|
|
@@ -114,7 +151,13 @@ export const toolDefinitions = [
|
|
|
114
151
|
// Material Tools
|
|
115
152
|
{
|
|
116
153
|
name: 'create_material',
|
|
117
|
-
description:
|
|
154
|
+
description: `Create a simple Material asset at a path.
|
|
155
|
+
|
|
156
|
+
When to use:
|
|
157
|
+
- Quickly scaffold a basic material you can edit later.
|
|
158
|
+
|
|
159
|
+
Example:
|
|
160
|
+
- {"name":"M_Mask","path":"/Game/Materials"}`,
|
|
118
161
|
inputSchema: {
|
|
119
162
|
type: 'object',
|
|
120
163
|
properties: {
|
|
@@ -135,7 +178,13 @@ export const toolDefinitions = [
|
|
|
135
178
|
},
|
|
136
179
|
{
|
|
137
180
|
name: 'apply_material_to_actor',
|
|
138
|
-
description:
|
|
181
|
+
description: `Assign a material to an actor's mesh component.
|
|
182
|
+
|
|
183
|
+
When to use:
|
|
184
|
+
- Swap an actor's material by path; slotIndex defaults to 0.
|
|
185
|
+
|
|
186
|
+
Example:
|
|
187
|
+
- {"actorPath":"/Game/LevelActors/Cube_1","materialPath":"/Game/Materials/M_Mask","slotIndex":0}`,
|
|
139
188
|
inputSchema: {
|
|
140
189
|
type: 'object',
|
|
141
190
|
properties: {
|
|
@@ -157,7 +206,10 @@ export const toolDefinitions = [
|
|
|
157
206
|
// Editor Tools
|
|
158
207
|
{
|
|
159
208
|
name: 'play_in_editor',
|
|
160
|
-
description:
|
|
209
|
+
description: `Start a Play-In-Editor (PIE) session.
|
|
210
|
+
|
|
211
|
+
When to use:
|
|
212
|
+
- Begin simulating the level in the editor.`,
|
|
161
213
|
inputSchema: {
|
|
162
214
|
type: 'object',
|
|
163
215
|
properties: {}
|
|
@@ -173,7 +225,10 @@ export const toolDefinitions = [
|
|
|
173
225
|
},
|
|
174
226
|
{
|
|
175
227
|
name: 'stop_play_in_editor',
|
|
176
|
-
description:
|
|
228
|
+
description: `Stop the active PIE session.
|
|
229
|
+
|
|
230
|
+
When to use:
|
|
231
|
+
- End simulation and return to the editor.`,
|
|
177
232
|
inputSchema: {
|
|
178
233
|
type: 'object',
|
|
179
234
|
properties: {}
|
|
@@ -189,7 +244,16 @@ export const toolDefinitions = [
|
|
|
189
244
|
},
|
|
190
245
|
{
|
|
191
246
|
name: 'set_camera',
|
|
192
|
-
description:
|
|
247
|
+
description: `Reposition the editor viewport camera.
|
|
248
|
+
|
|
249
|
+
When to use:
|
|
250
|
+
- Move/aim the camera in the editor for framing.
|
|
251
|
+
|
|
252
|
+
Notes:
|
|
253
|
+
- Accepts object or array formats; values are normalized.
|
|
254
|
+
|
|
255
|
+
Example:
|
|
256
|
+
- {"location":{"x":0,"y":-600,"z":250},"rotation":{"pitch":0,"yaw":0,"roll":0}}`,
|
|
193
257
|
inputSchema: {
|
|
194
258
|
type: 'object',
|
|
195
259
|
properties: {
|
|
@@ -225,7 +289,13 @@ export const toolDefinitions = [
|
|
|
225
289
|
// Animation Tools
|
|
226
290
|
{
|
|
227
291
|
name: 'create_animation_blueprint',
|
|
228
|
-
description:
|
|
292
|
+
description: `Create an Animation Blueprint for a skeleton.
|
|
293
|
+
|
|
294
|
+
When to use:
|
|
295
|
+
- Generate a starter Anim BP for a given skeleton.
|
|
296
|
+
|
|
297
|
+
Example:
|
|
298
|
+
- {"name":"ABP_Hero","skeletonPath":"/Game/Characters/Hero/SK_Hero_Skeleton","savePath":"/Game/Characters/Hero"}`,
|
|
229
299
|
inputSchema: {
|
|
230
300
|
type: 'object',
|
|
231
301
|
properties: {
|
|
@@ -246,7 +316,13 @@ export const toolDefinitions = [
|
|
|
246
316
|
},
|
|
247
317
|
{
|
|
248
318
|
name: 'play_animation_montage',
|
|
249
|
-
description:
|
|
319
|
+
description: `Play a Montage/Animation on an actor.
|
|
320
|
+
|
|
321
|
+
When to use:
|
|
322
|
+
- Trigger a montage on a possessed or editor actor.
|
|
323
|
+
|
|
324
|
+
Example:
|
|
325
|
+
- {"actorName":"Hero","montagePath":"/Game/Anim/MT_Attack","playRate":1.0}`,
|
|
250
326
|
inputSchema: {
|
|
251
327
|
type: 'object',
|
|
252
328
|
properties: {
|
|
@@ -269,7 +345,13 @@ export const toolDefinitions = [
|
|
|
269
345
|
// Physics Tools
|
|
270
346
|
{
|
|
271
347
|
name: 'setup_ragdoll',
|
|
272
|
-
description:
|
|
348
|
+
description: `Enable simple ragdoll using a physics asset.
|
|
349
|
+
|
|
350
|
+
When to use:
|
|
351
|
+
- Toggle ragdoll behavior on a character skeleton.
|
|
352
|
+
|
|
353
|
+
Example:
|
|
354
|
+
- {"skeletonPath":"/Game/Characters/Hero/SK_Hero_Skeleton","physicsAssetName":"PHYS_Hero","blendWeight":1.0}`,
|
|
273
355
|
inputSchema: {
|
|
274
356
|
type: 'object',
|
|
275
357
|
properties: {
|
|
@@ -290,7 +372,10 @@ export const toolDefinitions = [
|
|
|
290
372
|
},
|
|
291
373
|
{
|
|
292
374
|
name: 'apply_force',
|
|
293
|
-
description:
|
|
375
|
+
description: `Apply a world-space force vector to an actor with physics enabled.
|
|
376
|
+
|
|
377
|
+
Example:
|
|
378
|
+
- {"actorName":"PhysicsBox","force":{"x":0,"y":0,"z":5000}}`,
|
|
294
379
|
inputSchema: {
|
|
295
380
|
type: 'object',
|
|
296
381
|
properties: {
|
|
@@ -320,7 +405,13 @@ export const toolDefinitions = [
|
|
|
320
405
|
// Niagara Tools
|
|
321
406
|
{
|
|
322
407
|
name: 'create_particle_effect',
|
|
323
|
-
description:
|
|
408
|
+
description: `Create a simple particle/FX by tag.
|
|
409
|
+
|
|
410
|
+
When to use:
|
|
411
|
+
- Quickly drop a generic Fire/Smoke/Water effect for previews.
|
|
412
|
+
|
|
413
|
+
Example:
|
|
414
|
+
- {"effectType":"Smoke","name":"SMK1","location":{"x":100,"y":0,"z":50}}`,
|
|
324
415
|
inputSchema: {
|
|
325
416
|
type: 'object',
|
|
326
417
|
properties: {
|
|
@@ -349,7 +440,10 @@ export const toolDefinitions = [
|
|
|
349
440
|
},
|
|
350
441
|
{
|
|
351
442
|
name: 'spawn_niagara_system',
|
|
352
|
-
description:
|
|
443
|
+
description: `Spawn a Niagara system at a location.
|
|
444
|
+
|
|
445
|
+
Example:
|
|
446
|
+
- {"systemPath":"/Game/FX/NS_Explosion","location":{"x":0,"y":0,"z":200},"scale":1.0}`,
|
|
353
447
|
inputSchema: {
|
|
354
448
|
type: 'object',
|
|
355
449
|
properties: {
|
|
@@ -379,7 +473,10 @@ export const toolDefinitions = [
|
|
|
379
473
|
// Blueprint Tools
|
|
380
474
|
{
|
|
381
475
|
name: 'create_blueprint',
|
|
382
|
-
description:
|
|
476
|
+
description: `Create a new Blueprint asset at a path.
|
|
477
|
+
|
|
478
|
+
Example:
|
|
479
|
+
- {"name":"BP_Switch","blueprintType":"Actor","savePath":"/Game/Blueprints"}`,
|
|
383
480
|
inputSchema: {
|
|
384
481
|
type: 'object',
|
|
385
482
|
properties: {
|
|
@@ -400,7 +497,10 @@ export const toolDefinitions = [
|
|
|
400
497
|
},
|
|
401
498
|
{
|
|
402
499
|
name: 'add_blueprint_component',
|
|
403
|
-
description:
|
|
500
|
+
description: `Add a component to an existing Blueprint.
|
|
501
|
+
|
|
502
|
+
Example:
|
|
503
|
+
- {"blueprintName":"BP_Switch","componentType":"PointLightComponent","componentName":"KeyLight"}`,
|
|
404
504
|
inputSchema: {
|
|
405
505
|
type: 'object',
|
|
406
506
|
properties: {
|
|
@@ -424,7 +524,10 @@ export const toolDefinitions = [
|
|
|
424
524
|
// Level Tools
|
|
425
525
|
{
|
|
426
526
|
name: 'load_level',
|
|
427
|
-
description:
|
|
527
|
+
description: `Load a level by path (e.g., /Game/Maps/Lobby).
|
|
528
|
+
|
|
529
|
+
Example:
|
|
530
|
+
- {"levelPath":"/Game/Maps/Lobby","streaming":false}`,
|
|
428
531
|
inputSchema: {
|
|
429
532
|
type: 'object',
|
|
430
533
|
properties: {
|
|
@@ -444,7 +547,10 @@ export const toolDefinitions = [
|
|
|
444
547
|
},
|
|
445
548
|
{
|
|
446
549
|
name: 'save_level',
|
|
447
|
-
description:
|
|
550
|
+
description: `Save the current level to a path or by name.
|
|
551
|
+
|
|
552
|
+
Example:
|
|
553
|
+
- {"levelName":"Lobby","savePath":"/Game/Maps"}`,
|
|
448
554
|
inputSchema: {
|
|
449
555
|
type: 'object',
|
|
450
556
|
properties: {
|
|
@@ -463,7 +569,10 @@ export const toolDefinitions = [
|
|
|
463
569
|
},
|
|
464
570
|
{
|
|
465
571
|
name: 'stream_level',
|
|
466
|
-
description:
|
|
572
|
+
description: `Stream in/out a sublevel and set visibility.
|
|
573
|
+
|
|
574
|
+
Example:
|
|
575
|
+
- {"levelName":"Sublevel_A","shouldBeLoaded":true,"shouldBeVisible":true}`,
|
|
467
576
|
inputSchema: {
|
|
468
577
|
type: 'object',
|
|
469
578
|
properties: {
|
|
@@ -487,7 +596,11 @@ export const toolDefinitions = [
|
|
|
487
596
|
// Lighting Tools
|
|
488
597
|
{
|
|
489
598
|
name: 'create_light',
|
|
490
|
-
description:
|
|
599
|
+
description: `Create a light (Directional/Point/Spot/Rect/Sky) with optional transform/intensity.
|
|
600
|
+
|
|
601
|
+
Examples:
|
|
602
|
+
- {"lightType":"Directional","name":"KeyLight","intensity":5.0}
|
|
603
|
+
- {"lightType":"Point","name":"Fill","location":{"x":0,"y":100,"z":200},"intensity":2000}`,
|
|
491
604
|
inputSchema: {
|
|
492
605
|
type: 'object',
|
|
493
606
|
properties: {
|
|
@@ -516,7 +629,13 @@ export const toolDefinitions = [
|
|
|
516
629
|
},
|
|
517
630
|
{
|
|
518
631
|
name: 'build_lighting',
|
|
519
|
-
description:
|
|
632
|
+
description: `Start a lighting build.
|
|
633
|
+
|
|
634
|
+
When to use:
|
|
635
|
+
- Bake lights for preview or final output (choose quality).
|
|
636
|
+
|
|
637
|
+
Example:
|
|
638
|
+
- {"quality":"High"}`,
|
|
520
639
|
inputSchema: {
|
|
521
640
|
type: 'object',
|
|
522
641
|
properties: {
|
|
@@ -536,7 +655,13 @@ export const toolDefinitions = [
|
|
|
536
655
|
// Landscape Tools
|
|
537
656
|
{
|
|
538
657
|
name: 'create_landscape',
|
|
539
|
-
description:
|
|
658
|
+
description: `Attempt to create a landscape.
|
|
659
|
+
|
|
660
|
+
Notes:
|
|
661
|
+
- Native Python APIs are limited; you may be guided to use Landscape Mode in the editor.
|
|
662
|
+
|
|
663
|
+
Example:
|
|
664
|
+
- {"name":"Landscape_Basic","sizeX":1024,"sizeY":1024}`,
|
|
540
665
|
inputSchema: {
|
|
541
666
|
type: 'object',
|
|
542
667
|
properties: {
|
|
@@ -558,7 +683,10 @@ export const toolDefinitions = [
|
|
|
558
683
|
},
|
|
559
684
|
{
|
|
560
685
|
name: 'sculpt_landscape',
|
|
561
|
-
description:
|
|
686
|
+
description: `Sculpt a landscape using editor tools (best-effort; some operations may require manual Landscape Mode).
|
|
687
|
+
|
|
688
|
+
Example:
|
|
689
|
+
- {"landscapeName":"Landscape_Basic","tool":"Smooth","brushSize":300,"strength":0.5}`,
|
|
562
690
|
inputSchema: {
|
|
563
691
|
type: 'object',
|
|
564
692
|
properties: {
|
|
@@ -581,7 +709,10 @@ export const toolDefinitions = [
|
|
|
581
709
|
// Foliage Tools
|
|
582
710
|
{
|
|
583
711
|
name: 'add_foliage_type',
|
|
584
|
-
description:
|
|
712
|
+
description: `Create or load a FoliageType asset for instanced foliage workflows.
|
|
713
|
+
|
|
714
|
+
Example:
|
|
715
|
+
- {"name":"FT_Grass","meshPath":"/Game/Foliage/SM_Grass","density":300}`,
|
|
585
716
|
inputSchema: {
|
|
586
717
|
type: 'object',
|
|
587
718
|
properties: {
|
|
@@ -602,7 +733,13 @@ export const toolDefinitions = [
|
|
|
602
733
|
},
|
|
603
734
|
{
|
|
604
735
|
name: 'paint_foliage',
|
|
605
|
-
description:
|
|
736
|
+
description: `Paint foliage onto the world.
|
|
737
|
+
|
|
738
|
+
When to use:
|
|
739
|
+
- Scatter instances using an existing FoliageType.
|
|
740
|
+
|
|
741
|
+
Example:
|
|
742
|
+
- {"foliageType":"/Game/Foliage/Types/FT_Grass","position":{"x":0,"y":0,"z":0},"brushSize":300}`,
|
|
606
743
|
inputSchema: {
|
|
607
744
|
type: 'object',
|
|
608
745
|
properties: {
|
|
@@ -632,7 +769,10 @@ export const toolDefinitions = [
|
|
|
632
769
|
// Debug Visualization Tools
|
|
633
770
|
{
|
|
634
771
|
name: 'draw_debug_shape',
|
|
635
|
-
description:
|
|
772
|
+
description: `Draw a debug shape.
|
|
773
|
+
|
|
774
|
+
Example:
|
|
775
|
+
- {"shape":"Sphere","position":{"x":0,"y":0,"z":0},"size":100,"color":[255,0,0,255],"duration":3}`,
|
|
636
776
|
inputSchema: {
|
|
637
777
|
type: 'object',
|
|
638
778
|
properties: {
|
|
@@ -665,7 +805,10 @@ export const toolDefinitions = [
|
|
|
665
805
|
},
|
|
666
806
|
{
|
|
667
807
|
name: 'set_view_mode',
|
|
668
|
-
description:
|
|
808
|
+
description: `Set the viewport view mode.
|
|
809
|
+
|
|
810
|
+
Example:
|
|
811
|
+
- {"mode":"Wireframe"}`,
|
|
669
812
|
inputSchema: {
|
|
670
813
|
type: 'object',
|
|
671
814
|
properties: {
|
|
@@ -686,7 +829,10 @@ export const toolDefinitions = [
|
|
|
686
829
|
// Performance Tools
|
|
687
830
|
{
|
|
688
831
|
name: 'start_profiling',
|
|
689
|
-
description:
|
|
832
|
+
description: `Start performance profiling.
|
|
833
|
+
|
|
834
|
+
Example:
|
|
835
|
+
- {"type":"GPU","duration":10}`,
|
|
690
836
|
inputSchema: {
|
|
691
837
|
type: 'object',
|
|
692
838
|
properties: {
|
|
@@ -706,7 +852,10 @@ export const toolDefinitions = [
|
|
|
706
852
|
},
|
|
707
853
|
{
|
|
708
854
|
name: 'show_fps',
|
|
709
|
-
description:
|
|
855
|
+
description: `Show/hide the FPS counter.
|
|
856
|
+
|
|
857
|
+
Example:
|
|
858
|
+
- {"enabled":true,"verbose":false}`,
|
|
710
859
|
inputSchema: {
|
|
711
860
|
type: 'object',
|
|
712
861
|
properties: {
|
|
@@ -726,7 +875,10 @@ export const toolDefinitions = [
|
|
|
726
875
|
},
|
|
727
876
|
{
|
|
728
877
|
name: 'set_scalability',
|
|
729
|
-
description:
|
|
878
|
+
description: `Set scalability/quality levels.
|
|
879
|
+
|
|
880
|
+
Example:
|
|
881
|
+
- {"category":"Shadows","level":2}`,
|
|
730
882
|
inputSchema: {
|
|
731
883
|
type: 'object',
|
|
732
884
|
properties: {
|
|
@@ -748,7 +900,10 @@ export const toolDefinitions = [
|
|
|
748
900
|
// Audio Tools
|
|
749
901
|
{
|
|
750
902
|
name: 'play_sound',
|
|
751
|
-
description:
|
|
903
|
+
description: `Play a sound.
|
|
904
|
+
|
|
905
|
+
Example:
|
|
906
|
+
- {"soundPath":"/Game/Audio/SFX/Click","volume":0.5,"is3D":true}`,
|
|
752
907
|
inputSchema: {
|
|
753
908
|
type: 'object',
|
|
754
909
|
properties: {
|
|
@@ -777,7 +932,10 @@ export const toolDefinitions = [
|
|
|
777
932
|
},
|
|
778
933
|
{
|
|
779
934
|
name: 'create_ambient_sound',
|
|
780
|
-
description:
|
|
935
|
+
description: `Create an ambient sound actor.
|
|
936
|
+
|
|
937
|
+
Example:
|
|
938
|
+
- {"name":"Amb_Wind","soundPath":"/Game/Audio/Amb/AMB_Wind","location":{"x":0,"y":0,"z":0},"radius":1000}`,
|
|
781
939
|
inputSchema: {
|
|
782
940
|
type: 'object',
|
|
783
941
|
properties: {
|
|
@@ -808,7 +966,10 @@ export const toolDefinitions = [
|
|
|
808
966
|
// UI Tools
|
|
809
967
|
{
|
|
810
968
|
name: 'create_widget',
|
|
811
|
-
description:
|
|
969
|
+
description: `Create a UI widget.
|
|
970
|
+
|
|
971
|
+
Example:
|
|
972
|
+
- {"name":"HUDMain","type":"HUD","savePath":"/Game/UI"}`,
|
|
812
973
|
inputSchema: {
|
|
813
974
|
type: 'object',
|
|
814
975
|
properties: {
|
|
@@ -829,7 +990,10 @@ export const toolDefinitions = [
|
|
|
829
990
|
},
|
|
830
991
|
{
|
|
831
992
|
name: 'show_widget',
|
|
832
|
-
description:
|
|
993
|
+
description: `Show or hide a widget.
|
|
994
|
+
|
|
995
|
+
Example:
|
|
996
|
+
- {"widgetName":"HUDMain","visible":true}`,
|
|
833
997
|
inputSchema: {
|
|
834
998
|
type: 'object',
|
|
835
999
|
properties: {
|
|
@@ -849,7 +1013,10 @@ export const toolDefinitions = [
|
|
|
849
1013
|
},
|
|
850
1014
|
{
|
|
851
1015
|
name: 'create_hud',
|
|
852
|
-
description:
|
|
1016
|
+
description: `Create a HUD description/layout.
|
|
1017
|
+
|
|
1018
|
+
Example:
|
|
1019
|
+
- {"name":"GameHUD","elements":[{"type":"Text","position":[10,10]}]}`,
|
|
853
1020
|
inputSchema: {
|
|
854
1021
|
type: 'object',
|
|
855
1022
|
properties: {
|
|
@@ -883,7 +1050,14 @@ export const toolDefinitions = [
|
|
|
883
1050
|
// Console command (universal tool)
|
|
884
1051
|
{
|
|
885
1052
|
name: 'console_command',
|
|
886
|
-
description:
|
|
1053
|
+
description: `Execute a console command.
|
|
1054
|
+
|
|
1055
|
+
When to use:
|
|
1056
|
+
- Quick toggles like "stat fps", "viewmode wireframe", or r.* cvars.
|
|
1057
|
+
|
|
1058
|
+
Examples:
|
|
1059
|
+
- {"command":"stat fps"}
|
|
1060
|
+
- {"command":"r.ScreenPercentage 75"}`,
|
|
887
1061
|
inputSchema: {
|
|
888
1062
|
type: 'object',
|
|
889
1063
|
properties: {
|
|
@@ -86,16 +86,24 @@ export async function handleToolCall(
|
|
|
86
86
|
break;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
// Normalize virtual content path: map /Content -> /Game (case-insensitive)
|
|
90
|
+
const rawDir: string = String(args.directory).trim();
|
|
91
|
+
let normDir = rawDir.replace(/^\/?content(\/|$)/i, '/Game$1');
|
|
92
|
+
// Ensure leading slash
|
|
93
|
+
if (!normDir.startsWith('/')) normDir = '/' + normDir;
|
|
94
|
+
// Collapse duplicate slashes
|
|
95
|
+
normDir = normDir.replace(/\\+/g, '/').replace(/\/+/g, '/');
|
|
96
|
+
|
|
89
97
|
// Try multiple approaches to list assets
|
|
90
98
|
try {
|
|
91
|
-
console.log('[list_assets] Starting asset listing for directory:',
|
|
99
|
+
console.log('[list_assets] Starting asset listing for directory:', normDir);
|
|
92
100
|
|
|
93
|
-
// First try: Use Python for most reliable listing
|
|
101
|
+
// First try: Use Python for most reliable listing (recursive if /Game)
|
|
94
102
|
const pythonCode = `
|
|
95
103
|
import unreal
|
|
96
104
|
import json
|
|
97
105
|
|
|
98
|
-
directory = '${
|
|
106
|
+
directory = '${normDir || '/Game'}'
|
|
99
107
|
# Use recursive for /Game to find assets in subdirectories, but limit depth
|
|
100
108
|
recursive = True if directory == '/Game' else False
|
|
101
109
|
|
|
@@ -197,8 +205,9 @@ except Exception as e:
|
|
|
197
205
|
const searchResult = await tools.bridge.httpCall('/remote/search/assets', 'PUT', {
|
|
198
206
|
Query: '', // Empty query to match all (wildcard doesn't work)
|
|
199
207
|
Filter: {
|
|
200
|
-
PackagePaths: [
|
|
201
|
-
|
|
208
|
+
PackagePaths: [normDir || '/Game'],
|
|
209
|
+
// Recursively search so we actually find assets in subfolders
|
|
210
|
+
RecursivePaths: true,
|
|
202
211
|
ClassNames: [], // Empty to get all types
|
|
203
212
|
RecursiveClasses: true
|
|
204
213
|
},
|
|
@@ -222,7 +231,7 @@ except Exception as e:
|
|
|
222
231
|
functionName: 'ExecuteConsoleCommand',
|
|
223
232
|
parameters: {
|
|
224
233
|
WorldContextObject: null,
|
|
225
|
-
Command: `AssetRegistry.DumpAssets ${
|
|
234
|
+
Command: `AssetRegistry.DumpAssets ${normDir || '/Game'}`,
|
|
226
235
|
SpecificPlayer: null
|
|
227
236
|
},
|
|
228
237
|
generateTransaction: false
|
|
@@ -244,6 +253,24 @@ except Exception as e:
|
|
|
244
253
|
|
|
245
254
|
// Include full asset list with details in the message
|
|
246
255
|
console.log('[list_assets] Formatting message - result has assets?', !!(result && result.assets), 'count:', result?.assets?.length);
|
|
256
|
+
if (result && result.assets && result.assets.length > 0) {
|
|
257
|
+
// If Python/HTTP gives only paths, generate Name from path
|
|
258
|
+
result.assets = result.assets.map((asset: any) => {
|
|
259
|
+
if (!asset.Name && asset.Path) {
|
|
260
|
+
const base = String(asset.Path).split('/').pop() || '';
|
|
261
|
+
const name = base.includes('.') ? base.split('.').pop() : base;
|
|
262
|
+
return { ...asset, Name: name };
|
|
263
|
+
}
|
|
264
|
+
return asset;
|
|
265
|
+
});
|
|
266
|
+
// Group assets by type for better organization
|
|
267
|
+
result.assets = result.assets.map((a: any) => {
|
|
268
|
+
if (a && !a.Path && a.AssetPath) {
|
|
269
|
+
return { ...a, Path: a.AssetPath, PackagePath: a.AssetPath.split('/').slice(0, -1).join('/') };
|
|
270
|
+
}
|
|
271
|
+
return a;
|
|
272
|
+
});
|
|
273
|
+
}
|
|
247
274
|
if (result && result.assets && result.assets.length > 0) {
|
|
248
275
|
// Group assets by type for better organization
|
|
249
276
|
const assetsByType: { [key: string]: any[] } = {};
|
|
@@ -257,7 +284,7 @@ except Exception as e:
|
|
|
257
284
|
});
|
|
258
285
|
|
|
259
286
|
// Format output with proper structure
|
|
260
|
-
let assetDetails = `📁 Asset Directory: ${
|
|
287
|
+
let assetDetails = `📁 Asset Directory: ${normDir || '/Game'}\n`;
|
|
261
288
|
assetDetails += `📊 Total Assets: ${result.assets.length}\n\n`;
|
|
262
289
|
|
|
263
290
|
// Sort types alphabetically
|
|
@@ -287,7 +314,7 @@ except Exception as e:
|
|
|
287
314
|
|
|
288
315
|
// Also keep the structured data in the result for programmatic access
|
|
289
316
|
} else {
|
|
290
|
-
message = `No assets found in ${
|
|
317
|
+
message = `No assets found in ${normDir || '/Game'}`;
|
|
291
318
|
}
|
|
292
319
|
break;
|
|
293
320
|
|
|
@@ -611,7 +638,12 @@ print(f"RESULT:{json.dumps(result)}")
|
|
|
611
638
|
// Landscape Tools
|
|
612
639
|
case 'create_landscape':
|
|
613
640
|
result = await tools.landscapeTools.createLandscape(args);
|
|
614
|
-
|
|
641
|
+
// Never claim success unless the tool says so; prefer error/message from UE/Python
|
|
642
|
+
if (result && typeof result === 'object') {
|
|
643
|
+
message = result.message || result.error || (result.success ? `Landscape ${args.name} created` : `Failed to create landscape ${args.name}`);
|
|
644
|
+
} else {
|
|
645
|
+
message = `Failed to create landscape ${args.name}`;
|
|
646
|
+
}
|
|
615
647
|
break;
|
|
616
648
|
|
|
617
649
|
case 'sculpt_landscape':
|