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.
@@ -4,7 +4,18 @@ export const toolDefinitions = [
4
4
  // Asset Tools
5
5
  {
6
6
  name: 'list_assets',
7
- description: 'List all assets in a directory',
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: 'Import an asset from file system',
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: 'Spawn a new actor in the level',
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: 'Delete an actor from the level',
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: 'Create a new material asset',
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: 'Apply a material to an actor in the level',
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: 'Start Play In Editor (PIE) mode',
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: 'Stop Play In Editor (PIE) mode',
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: 'Set viewport camera position and rotation',
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: 'Create an animation blueprint',
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: 'Play an animation montage on an actor',
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: 'Setup ragdoll physics for a skeletal mesh',
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: 'Apply force to an actor',
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: 'Create a Niagara particle effect',
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: 'Spawn a Niagara system in the level',
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: 'Create a new blueprint',
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: 'Add a component to a blueprint',
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: 'Load a level',
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: 'Save the current level',
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: 'Stream a level in or out',
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: 'Create a light in the level',
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: 'Build lighting for the current level',
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: 'Create a new landscape',
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: 'Sculpt the landscape',
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: 'Add a foliage type',
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: 'Paint foliage on landscape',
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: 'Draw a debug shape',
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: 'Set the viewport view mode',
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: 'Start performance profiling',
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: 'Show FPS counter',
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: 'Set scalability settings',
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: 'Play a sound',
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: 'Create an ambient sound',
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: 'Create a UI widget',
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: 'Show or hide a widget',
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: 'Create a HUD',
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: 'Execute any console command in Unreal Engine',
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:', args.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 = '${args.directory || '/Game'}'
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: [args.directory || '/Game'],
201
- RecursivePaths: false, // Always non-recursive
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 ${args.directory || '/Game'}`,
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: ${args.directory || '/Game'}\n`;
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 ${args.directory || '/Game'}`;
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
- message = result.message || `Landscape ${args.name} created`;
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':