unreal-engine-mcp-server 0.2.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.
Files changed (155) hide show
  1. package/.dockerignore +57 -0
  2. package/.env.production +25 -0
  3. package/.eslintrc.json +54 -0
  4. package/.github/workflows/publish-mcp.yml +75 -0
  5. package/Dockerfile +54 -0
  6. package/LICENSE +21 -0
  7. package/Public/icon.png +0 -0
  8. package/README.md +209 -0
  9. package/claude_desktop_config_example.json +13 -0
  10. package/dist/cli.d.ts +3 -0
  11. package/dist/cli.js +7 -0
  12. package/dist/index.d.ts +31 -0
  13. package/dist/index.js +484 -0
  14. package/dist/prompts/index.d.ts +14 -0
  15. package/dist/prompts/index.js +38 -0
  16. package/dist/python-utils.d.ts +29 -0
  17. package/dist/python-utils.js +54 -0
  18. package/dist/resources/actors.d.ts +13 -0
  19. package/dist/resources/actors.js +83 -0
  20. package/dist/resources/assets.d.ts +23 -0
  21. package/dist/resources/assets.js +245 -0
  22. package/dist/resources/levels.d.ts +17 -0
  23. package/dist/resources/levels.js +94 -0
  24. package/dist/tools/actors.d.ts +51 -0
  25. package/dist/tools/actors.js +459 -0
  26. package/dist/tools/animation.d.ts +196 -0
  27. package/dist/tools/animation.js +579 -0
  28. package/dist/tools/assets.d.ts +21 -0
  29. package/dist/tools/assets.js +304 -0
  30. package/dist/tools/audio.d.ts +170 -0
  31. package/dist/tools/audio.js +416 -0
  32. package/dist/tools/blueprint.d.ts +144 -0
  33. package/dist/tools/blueprint.js +652 -0
  34. package/dist/tools/build_environment_advanced.d.ts +66 -0
  35. package/dist/tools/build_environment_advanced.js +484 -0
  36. package/dist/tools/consolidated-tool-definitions.d.ts +2598 -0
  37. package/dist/tools/consolidated-tool-definitions.js +607 -0
  38. package/dist/tools/consolidated-tool-handlers.d.ts +2 -0
  39. package/dist/tools/consolidated-tool-handlers.js +1050 -0
  40. package/dist/tools/debug.d.ts +185 -0
  41. package/dist/tools/debug.js +265 -0
  42. package/dist/tools/editor.d.ts +88 -0
  43. package/dist/tools/editor.js +365 -0
  44. package/dist/tools/engine.d.ts +30 -0
  45. package/dist/tools/engine.js +36 -0
  46. package/dist/tools/foliage.d.ts +155 -0
  47. package/dist/tools/foliage.js +525 -0
  48. package/dist/tools/introspection.d.ts +98 -0
  49. package/dist/tools/introspection.js +683 -0
  50. package/dist/tools/landscape.d.ts +158 -0
  51. package/dist/tools/landscape.js +375 -0
  52. package/dist/tools/level.d.ts +110 -0
  53. package/dist/tools/level.js +362 -0
  54. package/dist/tools/lighting.d.ts +159 -0
  55. package/dist/tools/lighting.js +1179 -0
  56. package/dist/tools/materials.d.ts +34 -0
  57. package/dist/tools/materials.js +146 -0
  58. package/dist/tools/niagara.d.ts +145 -0
  59. package/dist/tools/niagara.js +289 -0
  60. package/dist/tools/performance.d.ts +163 -0
  61. package/dist/tools/performance.js +412 -0
  62. package/dist/tools/physics.d.ts +189 -0
  63. package/dist/tools/physics.js +784 -0
  64. package/dist/tools/rc.d.ts +110 -0
  65. package/dist/tools/rc.js +363 -0
  66. package/dist/tools/sequence.d.ts +112 -0
  67. package/dist/tools/sequence.js +675 -0
  68. package/dist/tools/tool-definitions.d.ts +4919 -0
  69. package/dist/tools/tool-definitions.js +891 -0
  70. package/dist/tools/tool-handlers.d.ts +47 -0
  71. package/dist/tools/tool-handlers.js +830 -0
  72. package/dist/tools/ui.d.ts +171 -0
  73. package/dist/tools/ui.js +337 -0
  74. package/dist/tools/visual.d.ts +29 -0
  75. package/dist/tools/visual.js +67 -0
  76. package/dist/types/env.d.ts +10 -0
  77. package/dist/types/env.js +18 -0
  78. package/dist/types/index.d.ts +323 -0
  79. package/dist/types/index.js +28 -0
  80. package/dist/types/tool-types.d.ts +274 -0
  81. package/dist/types/tool-types.js +13 -0
  82. package/dist/unreal-bridge.d.ts +126 -0
  83. package/dist/unreal-bridge.js +992 -0
  84. package/dist/utils/cache-manager.d.ts +64 -0
  85. package/dist/utils/cache-manager.js +176 -0
  86. package/dist/utils/error-handler.d.ts +66 -0
  87. package/dist/utils/error-handler.js +243 -0
  88. package/dist/utils/errors.d.ts +133 -0
  89. package/dist/utils/errors.js +256 -0
  90. package/dist/utils/http.d.ts +26 -0
  91. package/dist/utils/http.js +135 -0
  92. package/dist/utils/logger.d.ts +12 -0
  93. package/dist/utils/logger.js +32 -0
  94. package/dist/utils/normalize.d.ts +17 -0
  95. package/dist/utils/normalize.js +49 -0
  96. package/dist/utils/response-validator.d.ts +34 -0
  97. package/dist/utils/response-validator.js +121 -0
  98. package/dist/utils/safe-json.d.ts +4 -0
  99. package/dist/utils/safe-json.js +97 -0
  100. package/dist/utils/stdio-redirect.d.ts +2 -0
  101. package/dist/utils/stdio-redirect.js +20 -0
  102. package/dist/utils/validation.d.ts +50 -0
  103. package/dist/utils/validation.js +173 -0
  104. package/mcp-config-example.json +14 -0
  105. package/package.json +63 -0
  106. package/server.json +60 -0
  107. package/src/cli.ts +7 -0
  108. package/src/index.ts +543 -0
  109. package/src/prompts/index.ts +51 -0
  110. package/src/python/editor_compat.py +181 -0
  111. package/src/python-utils.ts +57 -0
  112. package/src/resources/actors.ts +92 -0
  113. package/src/resources/assets.ts +251 -0
  114. package/src/resources/levels.ts +83 -0
  115. package/src/tools/actors.ts +480 -0
  116. package/src/tools/animation.ts +713 -0
  117. package/src/tools/assets.ts +305 -0
  118. package/src/tools/audio.ts +548 -0
  119. package/src/tools/blueprint.ts +736 -0
  120. package/src/tools/build_environment_advanced.ts +526 -0
  121. package/src/tools/consolidated-tool-definitions.ts +619 -0
  122. package/src/tools/consolidated-tool-handlers.ts +1093 -0
  123. package/src/tools/debug.ts +368 -0
  124. package/src/tools/editor.ts +360 -0
  125. package/src/tools/engine.ts +32 -0
  126. package/src/tools/foliage.ts +652 -0
  127. package/src/tools/introspection.ts +778 -0
  128. package/src/tools/landscape.ts +523 -0
  129. package/src/tools/level.ts +410 -0
  130. package/src/tools/lighting.ts +1316 -0
  131. package/src/tools/materials.ts +148 -0
  132. package/src/tools/niagara.ts +312 -0
  133. package/src/tools/performance.ts +549 -0
  134. package/src/tools/physics.ts +924 -0
  135. package/src/tools/rc.ts +437 -0
  136. package/src/tools/sequence.ts +791 -0
  137. package/src/tools/tool-definitions.ts +907 -0
  138. package/src/tools/tool-handlers.ts +941 -0
  139. package/src/tools/ui.ts +499 -0
  140. package/src/tools/visual.ts +60 -0
  141. package/src/types/env.ts +27 -0
  142. package/src/types/index.ts +414 -0
  143. package/src/types/tool-types.ts +343 -0
  144. package/src/unreal-bridge.ts +1118 -0
  145. package/src/utils/cache-manager.ts +213 -0
  146. package/src/utils/error-handler.ts +320 -0
  147. package/src/utils/errors.ts +312 -0
  148. package/src/utils/http.ts +184 -0
  149. package/src/utils/logger.ts +30 -0
  150. package/src/utils/normalize.ts +54 -0
  151. package/src/utils/response-validator.ts +145 -0
  152. package/src/utils/safe-json.ts +112 -0
  153. package/src/utils/stdio-redirect.ts +18 -0
  154. package/src/utils/validation.ts +212 -0
  155. package/tsconfig.json +33 -0
@@ -0,0 +1,158 @@
1
+ import { UnrealBridge } from '../unreal-bridge.js';
2
+ export declare class LandscapeTools {
3
+ private bridge;
4
+ constructor(bridge: UnrealBridge);
5
+ private _executeCommand;
6
+ createLandscape(params: {
7
+ name: string;
8
+ location?: [number, number, number];
9
+ sizeX?: number;
10
+ sizeY?: number;
11
+ quadsPerSection?: number;
12
+ sectionsPerComponent?: number;
13
+ componentCount?: number;
14
+ materialPath?: string;
15
+ enableWorldPartition?: boolean;
16
+ runtimeGrid?: string;
17
+ isSpatiallyLoaded?: boolean;
18
+ dataLayers?: string[];
19
+ }): Promise<any>;
20
+ sculptLandscape(_params: {
21
+ landscapeName: string;
22
+ tool: 'Sculpt' | 'Smooth' | 'Flatten' | 'Ramp' | 'Erosion' | 'Hydro' | 'Noise' | 'Retopologize';
23
+ brushSize?: number;
24
+ brushFalloff?: number;
25
+ strength?: number;
26
+ position?: [number, number, number];
27
+ }): Promise<{
28
+ success: boolean;
29
+ error: string;
30
+ }>;
31
+ paintLandscape(_params: {
32
+ landscapeName: string;
33
+ layerName: string;
34
+ position: [number, number, number];
35
+ brushSize?: number;
36
+ strength?: number;
37
+ targetValue?: number;
38
+ }): Promise<{
39
+ success: boolean;
40
+ error: string;
41
+ }>;
42
+ addLandscapeLayer(params: {
43
+ landscapeName: string;
44
+ layerName: string;
45
+ weightMapPath?: string;
46
+ blendMode?: 'Weight' | 'Alpha';
47
+ }): Promise<{
48
+ success: boolean;
49
+ message: string;
50
+ }>;
51
+ createLandscapeSpline(params: {
52
+ landscapeName: string;
53
+ splineName: string;
54
+ points: Array<[number, number, number]>;
55
+ width?: number;
56
+ falloffWidth?: number;
57
+ meshPath?: string;
58
+ }): Promise<{
59
+ success: boolean;
60
+ message: string;
61
+ }>;
62
+ importHeightmap(params: {
63
+ landscapeName: string;
64
+ heightmapPath: string;
65
+ scale?: [number, number, number];
66
+ }): Promise<any>;
67
+ exportHeightmap(params: {
68
+ landscapeName: string;
69
+ exportPath: string;
70
+ format?: 'PNG' | 'RAW';
71
+ }): Promise<any>;
72
+ setLandscapeLOD(params: {
73
+ landscapeName: string;
74
+ lodBias?: number;
75
+ forcedLOD?: number;
76
+ lodDistribution?: number;
77
+ }): Promise<{
78
+ success: boolean;
79
+ message: string;
80
+ }>;
81
+ createLandscapeGrass(params: {
82
+ landscapeName: string;
83
+ grassType: string;
84
+ density?: number;
85
+ minScale?: number;
86
+ maxScale?: number;
87
+ randomRotation?: boolean;
88
+ }): Promise<{
89
+ success: boolean;
90
+ message: string;
91
+ }>;
92
+ updateLandscapeCollision(params: {
93
+ landscapeName: string;
94
+ collisionMipLevel?: number;
95
+ simpleCollision?: boolean;
96
+ }): Promise<{
97
+ success: boolean;
98
+ message: string;
99
+ }>;
100
+ retopologizeLandscape(params: {
101
+ landscapeName: string;
102
+ targetTriangleCount?: number;
103
+ preserveDetails?: boolean;
104
+ }): Promise<{
105
+ success: boolean;
106
+ message: string;
107
+ }>;
108
+ createWaterBody(params: {
109
+ type: 'Ocean' | 'Lake' | 'River' | 'Stream';
110
+ name: string;
111
+ location?: [number, number, number];
112
+ size?: [number, number];
113
+ depth?: number;
114
+ }): Promise<any>;
115
+ configureWorldPartition(params: {
116
+ landscapeName: string;
117
+ enableSpatialLoading?: boolean;
118
+ runtimeGrid?: string;
119
+ dataLayers?: string[];
120
+ streamingDistance?: number;
121
+ }): Promise<any>;
122
+ setDataLayers(params: {
123
+ landscapeName: string;
124
+ dataLayerNames: string[];
125
+ operation: 'add' | 'remove' | 'set';
126
+ }): Promise<{
127
+ success: boolean;
128
+ message: string;
129
+ layers: string[];
130
+ error?: undefined;
131
+ } | {
132
+ success: boolean;
133
+ error: string;
134
+ message?: undefined;
135
+ layers?: undefined;
136
+ }>;
137
+ configureStreamingCells(params: {
138
+ landscapeName: string;
139
+ cellSize?: number;
140
+ loadingRange?: number;
141
+ enableHLOD?: boolean;
142
+ }): Promise<{
143
+ success: boolean;
144
+ message: string;
145
+ settings: {
146
+ cellSize: number | undefined;
147
+ loadingRange: number | undefined;
148
+ hlod: boolean | undefined;
149
+ };
150
+ error?: undefined;
151
+ } | {
152
+ success: boolean;
153
+ error: string;
154
+ message?: undefined;
155
+ settings?: undefined;
156
+ }>;
157
+ }
158
+ //# sourceMappingURL=landscape.d.ts.map
@@ -0,0 +1,375 @@
1
+ export class LandscapeTools {
2
+ bridge;
3
+ constructor(bridge) {
4
+ this.bridge = bridge;
5
+ }
6
+ // Execute console command
7
+ async _executeCommand(command) {
8
+ return this.bridge.httpCall('/remote/object/call', 'PUT', {
9
+ objectPath: '/Script/Engine.Default__KismetSystemLibrary',
10
+ functionName: 'ExecuteConsoleCommand',
11
+ parameters: {
12
+ WorldContextObject: null,
13
+ Command: command,
14
+ SpecificPlayer: null
15
+ },
16
+ generateTransaction: false
17
+ });
18
+ }
19
+ // Create landscape with World Partition support (UE 5.6)
20
+ async createLandscape(params) {
21
+ // Try Python API with World Partition support for UE 5.6
22
+ try {
23
+ const pythonScript = `
24
+ import unreal
25
+ import json
26
+
27
+ # Get the editor world using the proper subsystem
28
+ try:
29
+ editor_subsystem = unreal.get_editor_subsystem(unreal.UnrealEditorSubsystem)
30
+ world = editor_subsystem.get_editor_world() if hasattr(editor_subsystem, 'get_editor_world') else None
31
+ except:
32
+ # Fallback for older API
33
+ try:
34
+ world = unreal.EditorLevelLibrary.get_editor_world()
35
+ except:
36
+ world = None
37
+
38
+ is_world_partition = False
39
+ data_layer_manager = None
40
+
41
+ if world:
42
+ try:
43
+ # Check if World Partition is enabled (UE 5.6)
44
+ world_partition = world.get_world_partition()
45
+ is_world_partition = world_partition is not None
46
+ if is_world_partition:
47
+ # Get Data Layer Manager for UE 5.6
48
+ data_layer_manager = unreal.WorldPartitionBlueprintLibrary.get_data_layer_manager(world)
49
+ except:
50
+ pass
51
+
52
+ # Try to create a basic landscape using available API
53
+ try:
54
+ # Use EditorLevelLibrary to spawn a landscape actor
55
+ location = unreal.Vector(${params.location?.[0] || 0}, ${params.location?.[1] || 0}, ${params.location?.[2] || 0})
56
+ rotation = unreal.Rotator(0, 0, 0)
57
+
58
+ # Check if LandscapeSubsystem is available (not LandscapeEditorSubsystem)
59
+ landscape_subsystem = None
60
+ try:
61
+ landscape_subsystem = unreal.get_editor_subsystem(unreal.LandscapeSubsystem)
62
+ except:
63
+ pass
64
+
65
+ if landscape_subsystem:
66
+ # Use subsystem if available
67
+ result = {"success": False, "error": "LandscapeSubsystem API limited via Python", "world_partition": is_world_partition}
68
+ else:
69
+ # Landscape actors cannot be properly spawned via Python API
70
+ # The component registration issues are inherent to how landscapes work
71
+ # Direct users to the proper workflow
72
+ result = {
73
+ "success": False,
74
+ "error": "Landscape creation is not supported via Python API",
75
+ "suggestion": "Please use Landscape Mode in the Unreal Editor toolbar:",
76
+ "steps": [
77
+ "1. Click 'Modes' dropdown in toolbar",
78
+ "2. Select 'Landscape'",
79
+ "3. Configure size and materials",
80
+ "4. Click 'Create' to generate landscape"
81
+ ],
82
+ "world_partition": is_world_partition
83
+ }
84
+
85
+ print(f'RESULT:{json.dumps(result)}')
86
+ except Exception as e:
87
+ print(f'RESULT:{{"success": false, "error": "{str(e)}"}}')
88
+ `.trim();
89
+ const response = await this.bridge.executePython(pythonScript);
90
+ const output = typeof response === 'string' ? response : JSON.stringify(response);
91
+ const match = output.match(/RESULT:({.*})/);
92
+ if (match) {
93
+ try {
94
+ const result = JSON.parse(match[1]);
95
+ if (result.world_partition) {
96
+ result.message = 'World Partition detected. Manual landscape creation required in editor.';
97
+ }
98
+ return result;
99
+ }
100
+ catch { }
101
+ }
102
+ }
103
+ catch {
104
+ // Continue to fallback
105
+ }
106
+ // Fallback message with World Partition info
107
+ return {
108
+ success: false,
109
+ error: 'Landscape creation via API is limited. Please use the Unreal Editor UI to create landscapes.',
110
+ worldPartitionSupport: params.enableWorldPartition ? 'Requested' : 'Not requested',
111
+ suggestion: 'Use the Landscape Mode in the editor toolbar to create and configure landscapes'
112
+ };
113
+ }
114
+ // Sculpt landscape
115
+ async sculptLandscape(_params) {
116
+ return { success: false, error: 'sculptLandscape not implemented via Remote Control. Requires Landscape editor tools.' };
117
+ }
118
+ // Paint landscape
119
+ async paintLandscape(_params) {
120
+ return { success: false, error: 'paintLandscape not implemented via Remote Control. Requires Landscape editor tools.' };
121
+ }
122
+ // Add landscape layer
123
+ async addLandscapeLayer(params) {
124
+ const commands = [];
125
+ commands.push(`AddLandscapeLayer ${params.landscapeName} ${params.layerName}`);
126
+ if (params.weightMapPath) {
127
+ commands.push(`SetLayerWeightMap ${params.layerName} ${params.weightMapPath}`);
128
+ }
129
+ if (params.blendMode) {
130
+ commands.push(`SetLayerBlendMode ${params.layerName} ${params.blendMode}`);
131
+ }
132
+ for (const cmd of commands) {
133
+ await this.bridge.executeConsoleCommand(cmd);
134
+ }
135
+ return { success: true, message: `Layer ${params.layerName} added to landscape` };
136
+ }
137
+ // Create landscape spline
138
+ async createLandscapeSpline(params) {
139
+ const commands = [];
140
+ commands.push(`CreateLandscapeSpline ${params.landscapeName} ${params.splineName}`);
141
+ for (const point of params.points) {
142
+ commands.push(`AddSplinePoint ${params.splineName} ${point.join(' ')}`);
143
+ }
144
+ if (params.width !== undefined) {
145
+ commands.push(`SetSplineWidth ${params.splineName} ${params.width}`);
146
+ }
147
+ if (params.falloffWidth !== undefined) {
148
+ commands.push(`SetSplineFalloffWidth ${params.splineName} ${params.falloffWidth}`);
149
+ }
150
+ if (params.meshPath) {
151
+ commands.push(`SetSplineMesh ${params.splineName} ${params.meshPath}`);
152
+ }
153
+ for (const cmd of commands) {
154
+ await this.bridge.executeConsoleCommand(cmd);
155
+ }
156
+ return { success: true, message: `Landscape spline ${params.splineName} created` };
157
+ }
158
+ // Import heightmap
159
+ async importHeightmap(params) {
160
+ const scale = params.scale || [100, 100, 100];
161
+ const command = `ImportLandscapeHeightmap ${params.landscapeName} ${params.heightmapPath} ${scale.join(' ')}`;
162
+ return this.bridge.executeConsoleCommand(command);
163
+ }
164
+ // Export heightmap
165
+ async exportHeightmap(params) {
166
+ const format = params.format || 'PNG';
167
+ const command = `ExportLandscapeHeightmap ${params.landscapeName} ${params.exportPath} ${format}`;
168
+ return this.bridge.executeConsoleCommand(command);
169
+ }
170
+ // Set landscape LOD
171
+ async setLandscapeLOD(params) {
172
+ const commands = [];
173
+ if (params.lodBias !== undefined) {
174
+ commands.push(`SetLandscapeLODBias ${params.landscapeName} ${params.lodBias}`);
175
+ }
176
+ if (params.forcedLOD !== undefined) {
177
+ commands.push(`SetLandscapeForcedLOD ${params.landscapeName} ${params.forcedLOD}`);
178
+ }
179
+ if (params.lodDistribution !== undefined) {
180
+ commands.push(`SetLandscapeLODDistribution ${params.landscapeName} ${params.lodDistribution}`);
181
+ }
182
+ for (const cmd of commands) {
183
+ await this.bridge.executeConsoleCommand(cmd);
184
+ }
185
+ return { success: true, message: 'Landscape LOD settings updated' };
186
+ }
187
+ // Create landscape grass
188
+ async createLandscapeGrass(params) {
189
+ const commands = [];
190
+ commands.push(`CreateLandscapeGrass ${params.landscapeName} ${params.grassType}`);
191
+ if (params.density !== undefined) {
192
+ commands.push(`SetGrassDensity ${params.grassType} ${params.density}`);
193
+ }
194
+ if (params.minScale !== undefined && params.maxScale !== undefined) {
195
+ commands.push(`SetGrassScale ${params.grassType} ${params.minScale} ${params.maxScale}`);
196
+ }
197
+ if (params.randomRotation !== undefined) {
198
+ commands.push(`SetGrassRandomRotation ${params.grassType} ${params.randomRotation}`);
199
+ }
200
+ for (const cmd of commands) {
201
+ await this.bridge.executeConsoleCommand(cmd);
202
+ }
203
+ return { success: true, message: `Grass type ${params.grassType} created on landscape` };
204
+ }
205
+ // Landscape collision
206
+ async updateLandscapeCollision(params) {
207
+ const commands = [];
208
+ if (params.collisionMipLevel !== undefined) {
209
+ commands.push(`SetLandscapeCollisionMipLevel ${params.landscapeName} ${params.collisionMipLevel}`);
210
+ }
211
+ if (params.simpleCollision !== undefined) {
212
+ commands.push(`SetLandscapeSimpleCollision ${params.landscapeName} ${params.simpleCollision}`);
213
+ }
214
+ commands.push(`UpdateLandscapeCollision ${params.landscapeName}`);
215
+ for (const cmd of commands) {
216
+ await this.bridge.executeConsoleCommand(cmd);
217
+ }
218
+ return { success: true, message: 'Landscape collision updated' };
219
+ }
220
+ // Retopologize landscape
221
+ async retopologizeLandscape(params) {
222
+ const commands = [];
223
+ if (params.targetTriangleCount !== undefined) {
224
+ commands.push(`SetRetopologizeTarget ${params.targetTriangleCount}`);
225
+ }
226
+ if (params.preserveDetails !== undefined) {
227
+ commands.push(`SetRetopologizePreserveDetails ${params.preserveDetails}`);
228
+ }
229
+ commands.push(`RetopologizeLandscape ${params.landscapeName}`);
230
+ for (const cmd of commands) {
231
+ await this.bridge.executeConsoleCommand(cmd);
232
+ }
233
+ return { success: true, message: 'Landscape retopologized' };
234
+ }
235
+ // Create water body
236
+ async createWaterBody(params) {
237
+ const loc = params.location || [0, 0, 0];
238
+ const size = params.size || [1000, 1000];
239
+ const depth = params.depth || 100;
240
+ const command = `CreateWaterBody ${params.type} ${params.name} ${loc.join(' ')} ${size.join(' ')} ${depth}`;
241
+ return this.bridge.executeConsoleCommand(command);
242
+ }
243
+ // World Partition support for landscapes (UE 5.6)
244
+ async configureWorldPartition(params) {
245
+ try {
246
+ const pythonScript = `
247
+ import unreal
248
+
249
+ try:
250
+ # Get the landscape actor
251
+ actors = unreal.EditorLevelLibrary.get_all_level_actors()
252
+ landscape = None
253
+
254
+ for actor in actors:
255
+ if actor.get_name() == "${params.landscapeName}" or actor.get_actor_label() == "${params.landscapeName}":
256
+ if isinstance(actor, unreal.LandscapeProxy) or isinstance(actor, unreal.Landscape):
257
+ landscape = actor
258
+ break
259
+
260
+ if not landscape:
261
+ print('RESULT:{"success": false, "error": "Landscape not found"}')
262
+ else:
263
+ changes_made = []
264
+
265
+ # Configure spatial loading (UE 5.6)
266
+ if ${params.enableSpatialLoading !== undefined ? 'True' : 'False'}:
267
+ try:
268
+ landscape.set_editor_property('is_spatially_loaded', ${params.enableSpatialLoading || false})
269
+ changes_made.append("Spatial loading: ${params.enableSpatialLoading}")
270
+ except:
271
+ pass
272
+
273
+ # Set runtime grid (UE 5.6 World Partition)
274
+ if "${params.runtimeGrid || ''}":
275
+ try:
276
+ landscape.set_editor_property('runtime_grid', unreal.Name("${params.runtimeGrid}"))
277
+ changes_made.append("Runtime grid: ${params.runtimeGrid}")
278
+ except:
279
+ pass
280
+
281
+ # Configure data layers (UE 5.6)
282
+ if ${params.dataLayers ? 'True' : 'False'}:
283
+ try:
284
+ world = unreal.EditorLevelLibrary.get_editor_world()
285
+ data_layer_manager = unreal.WorldPartitionBlueprintLibrary.get_data_layer_manager(world)
286
+ if data_layer_manager:
287
+ # Note: Full data layer API requires additional setup
288
+ changes_made.append("Data layers: Requires manual configuration")
289
+ except:
290
+ pass
291
+
292
+ if changes_made:
293
+ print('RESULT:{"success": true, "message": "World Partition configured", "changes": ' + str(changes_made).replace("'", '"') + '}')
294
+ else:
295
+ print('RESULT:{"success": false, "error": "No World Partition changes applied"}')
296
+
297
+ except Exception as e:
298
+ print(f'RESULT:{{"success": false, "error": "{str(e)}"}}')
299
+ `.trim();
300
+ const response = await this.bridge.executePython(pythonScript);
301
+ const output = typeof response === 'string' ? response : JSON.stringify(response);
302
+ const match = output.match(/RESULT:({.*})/);
303
+ if (match) {
304
+ try {
305
+ return JSON.parse(match[1]);
306
+ }
307
+ catch { }
308
+ }
309
+ return { success: true, message: 'World Partition configuration attempted' };
310
+ }
311
+ catch (err) {
312
+ return { success: false, error: `Failed to configure World Partition: ${err}` };
313
+ }
314
+ }
315
+ // Set landscape data layers (UE 5.6)
316
+ async setDataLayers(params) {
317
+ try {
318
+ const commands = [];
319
+ // Use console commands for data layer management
320
+ if (params.operation === 'set' || params.operation === 'add') {
321
+ for (const layerName of params.dataLayerNames) {
322
+ commands.push(`wp.Runtime.SetDataLayerRuntimeState Loaded ${layerName}`);
323
+ }
324
+ }
325
+ else if (params.operation === 'remove') {
326
+ for (const layerName of params.dataLayerNames) {
327
+ commands.push(`wp.Runtime.SetDataLayerRuntimeState Unloaded ${layerName}`);
328
+ }
329
+ }
330
+ // Execute commands
331
+ for (const cmd of commands) {
332
+ await this.bridge.executeConsoleCommand(cmd);
333
+ }
334
+ return {
335
+ success: true,
336
+ message: `Data layers ${params.operation === 'add' ? 'added' : params.operation === 'remove' ? 'removed' : 'set'} for landscape`,
337
+ layers: params.dataLayerNames
338
+ };
339
+ }
340
+ catch (err) {
341
+ return { success: false, error: `Failed to manage data layers: ${err}` };
342
+ }
343
+ }
344
+ // Configure landscape streaming cells (UE 5.6 World Partition)
345
+ async configureStreamingCells(params) {
346
+ const commands = [];
347
+ // World Partition runtime commands
348
+ if (params.loadingRange !== undefined) {
349
+ commands.push(`wp.Runtime.OverrideRuntimeSpatialHashLoadingRange -grid=0 -range=${params.loadingRange}`);
350
+ }
351
+ if (params.enableHLOD !== undefined) {
352
+ commands.push(`wp.Runtime.HLOD ${params.enableHLOD ? '1' : '0'}`);
353
+ }
354
+ // Debug visualization commands
355
+ commands.push('wp.Runtime.ToggleDrawRuntimeHash2D'); // Show 2D grid
356
+ try {
357
+ for (const cmd of commands) {
358
+ await this.bridge.executeConsoleCommand(cmd);
359
+ }
360
+ return {
361
+ success: true,
362
+ message: 'Streaming cells configured for World Partition',
363
+ settings: {
364
+ cellSize: params.cellSize,
365
+ loadingRange: params.loadingRange,
366
+ hlod: params.enableHLOD
367
+ }
368
+ };
369
+ }
370
+ catch (err) {
371
+ return { success: false, error: `Failed to configure streaming cells: ${err}` };
372
+ }
373
+ }
374
+ }
375
+ //# sourceMappingURL=landscape.js.map
@@ -0,0 +1,110 @@
1
+ import { UnrealBridge } from '../unreal-bridge.js';
2
+ export declare class LevelTools {
3
+ private bridge;
4
+ constructor(bridge: UnrealBridge);
5
+ private _executeCommand;
6
+ loadLevel(params: {
7
+ levelPath: string;
8
+ streaming?: boolean;
9
+ position?: [number, number, number];
10
+ }): Promise<any>;
11
+ saveLevel(_params: {
12
+ levelName?: string;
13
+ savePath?: string;
14
+ }): Promise<{
15
+ success: boolean;
16
+ message: string;
17
+ error?: undefined;
18
+ } | {
19
+ success: boolean;
20
+ error: any;
21
+ message?: undefined;
22
+ }>;
23
+ createLevel(params: {
24
+ levelName: string;
25
+ template?: 'Empty' | 'Default' | 'VR' | 'TimeOfDay';
26
+ savePath?: string;
27
+ }): Promise<{
28
+ success: boolean;
29
+ message: any;
30
+ error?: undefined;
31
+ } | {
32
+ success: boolean;
33
+ error: any;
34
+ message?: undefined;
35
+ }>;
36
+ streamLevel(params: {
37
+ levelName: string;
38
+ shouldBeLoaded: boolean;
39
+ shouldBeVisible: boolean;
40
+ position?: [number, number, number];
41
+ }): Promise<any>;
42
+ setupWorldComposition(params: {
43
+ enableComposition: boolean;
44
+ tileSize?: number;
45
+ distanceStreaming?: boolean;
46
+ streamingDistance?: number;
47
+ }): Promise<{
48
+ success: boolean;
49
+ message: string;
50
+ }>;
51
+ editLevelBlueprint(params: {
52
+ eventType: 'BeginPlay' | 'EndPlay' | 'Tick' | 'Custom';
53
+ customEventName?: string;
54
+ nodes?: Array<{
55
+ nodeType: string;
56
+ position: [number, number];
57
+ connections?: string[];
58
+ }>;
59
+ }): Promise<any>;
60
+ createSubLevel(params: {
61
+ name: string;
62
+ type: 'Persistent' | 'Streaming' | 'Lighting' | 'Gameplay';
63
+ parent?: string;
64
+ }): Promise<any>;
65
+ setWorldSettings(params: {
66
+ gravity?: number;
67
+ worldScale?: number;
68
+ gameMode?: string;
69
+ defaultPawn?: string;
70
+ killZ?: number;
71
+ }): Promise<{
72
+ success: boolean;
73
+ message: string;
74
+ }>;
75
+ setLevelBounds(params: {
76
+ min: [number, number, number];
77
+ max: [number, number, number];
78
+ }): Promise<any>;
79
+ buildNavMesh(params: {
80
+ rebuildAll?: boolean;
81
+ selectedOnly?: boolean;
82
+ }): Promise<{
83
+ success: boolean;
84
+ message: any;
85
+ error?: undefined;
86
+ } | {
87
+ success: boolean;
88
+ error: any;
89
+ message?: undefined;
90
+ }>;
91
+ setLevelVisibility(params: {
92
+ levelName: string;
93
+ visible: boolean;
94
+ }): Promise<any>;
95
+ setWorldOrigin(params: {
96
+ location: [number, number, number];
97
+ }): Promise<any>;
98
+ createStreamingVolume(params: {
99
+ levelName: string;
100
+ position: [number, number, number];
101
+ size: [number, number, number];
102
+ streamingDistance?: number;
103
+ }): Promise<any>;
104
+ setLevelLOD(params: {
105
+ levelName: string;
106
+ lodLevel: number;
107
+ distance: number;
108
+ }): Promise<any>;
109
+ }
110
+ //# sourceMappingURL=level.d.ts.map