@uemcp/server 1.10.0 → 1.11.0

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 (3) hide show
  1. package/README.md +29 -0
  2. package/dist/index.mjs +834 -4
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -131,6 +131,14 @@ The MCP tool surface currently exposes:
131
131
  - `scaffold_class_template`
132
132
  - `get_live_compile_details`
133
133
  - `run_editor_python`
134
+ - `set_navmesh_settings`
135
+ - `set_nav_agents`
136
+ - `set_crowd_settings`
137
+ - `create_nav_area`
138
+ - `add_nav_modifier_volume`
139
+ - `add_nav_link`
140
+ - `find_path`
141
+ - `test_reachability`
134
142
 
135
143
  ## Project Identity
136
144
 
@@ -661,6 +669,27 @@ This is intended to let an MCP client resolve the canonical Unreal project ident
661
669
  - An editor whose Python Script Plugin is absent or disabled returns `state: 'unsupported'` with the reason, which is a different answer from a script that ran and failed
662
670
  - The whole script runs inside one `FScopedTransaction`, so a successful run is a single editor undo; a failed run cancels the transaction rather than leaving half its effects behind
663
671
  - `executionMode` is `script` (default: a whole block of Python, or a `.py` path with arguments), `statement` (exactly one statement) or `evaluate` (one expression, whose value comes back in `result`). `script` is the default because the engine reports a traceback line by line only in that mode; the two statement modes put it in `result` instead. Commands are capped at 16,384 characters, and output and error lines at 200 lines each, with `truncated` set
672
+ ### `set_navmesh_settings` / `set_nav_agents` / `set_crowd_settings`
673
+
674
+ - Navmesh generation settings are written onto the level's `RecastNavMesh` actor and only reach the navmesh on the next build, so the response reports `rebuildRequired` and the caller follows with `build_navigation`. Rebuilding here instead would be a minutes-long job on a socket with a seconds-long read budget
675
+ - `cellSize`, `cellHeight` and `agentMaxStepHeight` live per resolution since UE 5.4 — the same-named members on the actor are deprecated and no longer read by the generator — so `resolution` names which of the three sets is being written, and `appliedSettings` reports exactly which fields the write touched
676
+ - The response reports every setting as it stands **after** the write, read back off the actor, so a value the navmesh clamped is visible rather than echoed back as requested
677
+ - `set_nav_agents` replaces the project's whole `SupportedAgents` list, which is what gives a level one navmesh per agent size. It is read once when the navigation system starts, so the response reports `restartRequired` rather than pretending a running editor picked it up
678
+ - `set_crowd_settings` writes the Detour crowd manager and the RVO avoidance manager, both config defaults rather than per-level state. Only the manager a request actually names is saved, so a crowd-only call leaves the avoidance section alone
679
+
680
+ ### `create_nav_area` / `add_nav_modifier_volume` / `add_nav_link`
681
+
682
+ - `create_nav_area` makes a nav area Blueprint under `NavArea` (or one of the stock parents) and reports `generatedClassPath` — the class, not the asset, is what a modifier volume or a link references
683
+ - `add_nav_modifier_volume` places an `ANavModifierVolume` and builds its cube brush through the same actor factory the place-actor panel uses. Without that brush the volume covers nothing, so a non-positive extent is refused rather than placed
684
+ - `add_nav_link` replaces the proxy's default link with the ones the request carries. `left` and `right` are offsets from the actor, the space the level editor's own link handles move in, and the response reports them in world space so a link and the `find_path` that crosses it can be compared directly
685
+ - All three leave the navmesh untouched until the next `build_navigation`, and say so through `rebuildRequired`
686
+
687
+ ### `find_path` / `test_reachability`
688
+
689
+ - Synchronous navmesh queries against the editor world, which is what makes "is this level traversable" answerable without entering PIE
690
+ - A destination nothing can reach comes back as `reachable: false` with a partial path, not as an error: that is the answer, and a tool that threw would make the check unusable in a sweep. `queryResult` carries the engine's own `ENavigationQueryResult` so an off-navmesh endpoint stays distinguishable from a walled-off one
691
+ - `reachable` means a path that actually arrives. A partial path proves the goal is **not** reachable however far along it got, so it never counts as reachable in `find_path`
692
+ - `test_reachability` answers a batch of pairs without returning path geometry, and fails one pair rather than the request when an actor path no longer resolves — a sweep of spawn points against objectives is worth answering for the pairs that did resolve
664
693
 
665
694
  ## MCP Resources
666
695
 
package/dist/index.mjs CHANGED
@@ -362,6 +362,18 @@ const TOOL_METADATA = {
362
362
  "source",
363
363
  "build.cs"
364
364
  ]),
365
+ add_nav_link: mutates("level", "add_nav_link", [
366
+ "navmesh",
367
+ "navigation",
368
+ "nav link",
369
+ "jump"
370
+ ]),
371
+ add_nav_modifier_volume: mutates("level", "add_nav_modifier_volume", [
372
+ "navmesh",
373
+ "navigation",
374
+ "nav area",
375
+ "block"
376
+ ]),
365
377
  add_post_process_material: mutates("fx", "add_post_process_material"),
366
378
  add_reflected_member: mutates("build", void 0, [
367
379
  "uproperty",
@@ -480,6 +492,12 @@ const TOOL_METADATA = {
480
492
  create_metasound: mutates("audio", "create_metasound"),
481
493
  create_montage: mutates("anim", "create_montage"),
482
494
  create_pcg_graph: mutates("fx", "create_pcg_graph"),
495
+ create_nav_area: mutates("level", "create_nav_area", [
496
+ "navmesh",
497
+ "navigation",
498
+ "nav area",
499
+ "cost"
500
+ ]),
483
501
  create_post_process_volume: mutates("fx", "create_post_process_volume"),
484
502
  create_sound_cue: mutates("audio", "create_sound_cue"),
485
503
  create_state_tree: mutates("ai", "create_state_tree"),
@@ -532,6 +550,13 @@ const TOOL_METADATA = {
532
550
  "registry"
533
551
  ]),
534
552
  find_blueprint_references: readOnly("blueprint", "find_blueprint_references"),
553
+ find_path: readOnly("level", "find_path", [
554
+ "navmesh",
555
+ "navigation",
556
+ "path",
557
+ "pathfinding",
558
+ "reachable"
559
+ ]),
535
560
  find_symbol: readOnly("build", void 0, [
536
561
  "symbol",
537
562
  "definition",
@@ -720,7 +745,25 @@ const TOOL_METADATA = {
720
745
  set_import_settings: idempotentMutates("asset", "set_import_settings"),
721
746
  set_material_params: idempotentMutates("fx", "set_material_params"),
722
747
  set_metasound_graph: idempotentMutates("audio", "set_metasound_graph"),
748
+ set_crowd_settings: idempotentMutates("level", "set_crowd_settings", [
749
+ "crowd",
750
+ "avoidance",
751
+ "rvo",
752
+ "detour"
753
+ ]),
723
754
  set_montage_sections: idempotentMutates("anim", "set_montage_sections"),
755
+ set_nav_agents: idempotentMutates("level", "set_nav_agents", [
756
+ "navmesh",
757
+ "navigation",
758
+ "agent",
759
+ "radius"
760
+ ]),
761
+ set_navmesh_settings: idempotentMutates("level", "set_navmesh_settings", [
762
+ "navmesh",
763
+ "navigation",
764
+ "recast",
765
+ "cell size"
766
+ ]),
724
767
  set_niagara_params: idempotentMutates("fx", "set_niagara_params"),
725
768
  set_pin_default: idempotentMutates("blueprint", "set_pin_default"),
726
769
  set_post_process_settings: idempotentMutates("fx", "set_post_process_settings"),
@@ -751,6 +794,12 @@ const TOOL_METADATA = {
751
794
  "output",
752
795
  "tail"
753
796
  ]),
797
+ test_reachability: readOnly("level", "test_reachability", [
798
+ "navmesh",
799
+ "navigation",
800
+ "reachable",
801
+ "sweep"
802
+ ]),
754
803
  toggle_show_flags: idempotentMutates("level", "toggle_show_flags"),
755
804
  trace_state_tree: mutates("ai", "trace_state_tree", [
756
805
  "pie",
@@ -3300,11 +3349,11 @@ const createClassJobIdSchema = z.string().trim().min(1);
3300
3349
  const classNameSchema = z.string().trim().min(1).max(128).regex(/^[A-Za-z_][A-Za-z0-9_]*$/);
3301
3350
  const parentClassSchema = z.string().trim().min(1).max(128);
3302
3351
  const moduleNameSchema = z.string().trim().min(1).max(128);
3303
- const classPathSchema = z.string().trim().min(1).max(512);
3352
+ const classPathSchema$1 = z.string().trim().min(1).max(512);
3304
3353
  const sourceFilePathSchema = z.string().trim().min(1);
3305
3354
  const bridgeCreateCppClassRequestSchema = z.object({
3306
3355
  className: classNameSchema,
3307
- classPath: classPathSchema.optional(),
3356
+ classPath: classPathSchema$1.optional(),
3308
3357
  moduleName: moduleNameSchema.optional(),
3309
3358
  parentClass: parentClassSchema,
3310
3359
  requestId: requestIdSchema,
@@ -10483,8 +10532,492 @@ function createBridgeSetDefaultGamemodeRequest(scope, gameModePath, options = {}
10483
10532
  });
10484
10533
  }
10485
10534
  //#endregion
10535
+ //#region src/protocol/navigation.ts
10536
+ const classPathSchema = z.string().trim().min(1).max(512);
10537
+ const BRIDGE_SET_NAVMESH_SETTINGS_REQUEST_TYPE = "set_navmesh_settings";
10538
+ const BRIDGE_SET_NAV_AGENTS_REQUEST_TYPE = "set_nav_agents";
10539
+ const BRIDGE_SET_CROWD_SETTINGS_REQUEST_TYPE = "set_crowd_settings";
10540
+ const BRIDGE_CREATE_NAV_AREA_REQUEST_TYPE = "create_nav_area";
10541
+ const BRIDGE_ADD_NAV_MODIFIER_VOLUME_REQUEST_TYPE = "add_nav_modifier_volume";
10542
+ const BRIDGE_ADD_NAV_LINK_REQUEST_TYPE = "add_nav_link";
10543
+ const BRIDGE_FIND_PATH_REQUEST_TYPE = "find_path";
10544
+ const BRIDGE_TEST_REACHABILITY_REQUEST_TYPE = "test_reachability";
10545
+ const BRIDGE_NAV_RUNTIME_GENERATION_MODES = [
10546
+ "static",
10547
+ "dynamic_modifiers_only",
10548
+ "dynamic"
10549
+ ];
10550
+ const BRIDGE_NAV_DATA_RESOLUTIONS = [
10551
+ "low",
10552
+ "default",
10553
+ "high"
10554
+ ];
10555
+ const BRIDGE_NAV_LINK_DIRECTIONS = [
10556
+ "both_ways",
10557
+ "left_to_right",
10558
+ "right_to_left"
10559
+ ];
10560
+ const BRIDGE_NAV_QUERY_RESULTS = [
10561
+ "invalid",
10562
+ "error",
10563
+ "fail",
10564
+ "success"
10565
+ ];
10566
+ const BRIDGE_NAV_QUERY_STATES = ["reported", "unsupported"];
10567
+ const BRIDGE_NAV_MAX_AGENT_SIZE = 1e5;
10568
+ const BRIDGE_NAV_MAX_CELL_SIZE = 1024;
10569
+ const BRIDGE_NAV_MAX_TILE_SIZE = 1e5;
10570
+ const BRIDGE_NAV_MAX_REGION_SIZE = 1e7;
10571
+ const BRIDGE_NAV_MAX_AREA_COST = 1e6;
10572
+ const navRuntimeGenerationSchema = z.enum(BRIDGE_NAV_RUNTIME_GENERATION_MODES);
10573
+ const navDataResolutionSchema = z.enum(BRIDGE_NAV_DATA_RESOLUTIONS);
10574
+ const navLinkDirectionSchema = z.enum(BRIDGE_NAV_LINK_DIRECTIONS);
10575
+ const navQueryResultSchema = z.enum(BRIDGE_NAV_QUERY_RESULTS);
10576
+ const navQueryStateSchema = z.enum(BRIDGE_NAV_QUERY_STATES);
10577
+ const navPointSchema = z.object({
10578
+ x: z.number(),
10579
+ y: z.number(),
10580
+ z: z.number()
10581
+ });
10582
+ const navAgentSizeSchema = z.number().min(0).max(BRIDGE_NAV_MAX_AGENT_SIZE);
10583
+ const navCellSchema = z.number().min(1).max(BRIDGE_NAV_MAX_CELL_SIZE);
10584
+ const navRegionSizeSchema = z.number().min(0).max(BRIDGE_NAV_MAX_REGION_SIZE);
10585
+ const navAreaCostSchema = z.number().min(0).max(BRIDGE_NAV_MAX_AREA_COST);
10586
+ const navStepHeightSchema = z.number().min(0).max(1e4);
10587
+ const navColorChannelSchema = z.number().int().min(0).max(255);
10588
+ const navColorSchema = z.object({
10589
+ a: navColorChannelSchema.default(255),
10590
+ b: navColorChannelSchema,
10591
+ g: navColorChannelSchema,
10592
+ r: navColorChannelSchema
10593
+ });
10594
+ const navColorResponseSchema = z.object({
10595
+ a: navColorChannelSchema,
10596
+ b: navColorChannelSchema,
10597
+ g: navColorChannelSchema,
10598
+ r: navColorChannelSchema
10599
+ });
10600
+ const navExtentSchema = z.object({
10601
+ x: z.number().positive().default(200),
10602
+ y: z.number().positive().default(200),
10603
+ z: z.number().positive().default(200)
10604
+ });
10605
+ const bridgeSetNavmeshSettingsRequestFieldsSchema = z.object({
10606
+ agentHeight: navAgentSizeSchema.optional(),
10607
+ agentMaxSlope: z.number().min(0).max(89).optional(),
10608
+ agentMaxStepHeight: navStepHeightSchema.optional(),
10609
+ agentRadius: navAgentSizeSchema.optional(),
10610
+ cellHeight: navCellSchema.optional(),
10611
+ cellSize: navCellSchema.optional(),
10612
+ mergeRegionSize: navRegionSizeSchema.optional(),
10613
+ minRegionArea: navRegionSizeSchema.optional(),
10614
+ navMeshActorPath: actorPathSchema.optional(),
10615
+ requestId: requestIdSchema,
10616
+ resolution: navDataResolutionSchema.default("default"),
10617
+ runtimeGeneration: navRuntimeGenerationSchema.optional(),
10618
+ tileSizeUU: z.number().min(300).max(BRIDGE_NAV_MAX_TILE_SIZE).optional(),
10619
+ type: z.literal(BRIDGE_SET_NAVMESH_SETTINGS_REQUEST_TYPE),
10620
+ version: z.literal(2)
10621
+ });
10622
+ const bridgeSetNavmeshSettingsRequestSchema = bridgeSetNavmeshSettingsRequestFieldsSchema.refine((request) => request.agentHeight !== void 0 || request.agentMaxSlope !== void 0 || request.agentMaxStepHeight !== void 0 || request.agentRadius !== void 0 || request.cellHeight !== void 0 || request.cellSize !== void 0 || request.mergeRegionSize !== void 0 || request.minRegionArea !== void 0 || request.runtimeGeneration !== void 0 || request.tileSizeUU !== void 0, { message: "A set_navmesh_settings request must carry at least one setting to write." });
10623
+ const bridgeNavAgentSchema = z.object({
10624
+ height: navAgentSizeSchema,
10625
+ maxStepHeight: navStepHeightSchema.optional(),
10626
+ name: requiredBoundedStringSchema,
10627
+ navDataClass: classPathSchema.optional(),
10628
+ radius: navAgentSizeSchema
10629
+ });
10630
+ const bridgeSetNavAgentsRequestSchema = z.object({
10631
+ agents: z.array(bridgeNavAgentSchema).min(1).max(16),
10632
+ requestId: requestIdSchema,
10633
+ type: z.literal(BRIDGE_SET_NAV_AGENTS_REQUEST_TYPE),
10634
+ version: z.literal(2)
10635
+ });
10636
+ const bridgeCrowdSettingsSchema = z.object({
10637
+ maxAgentRadius: z.number().min(0).max(1e4).optional(),
10638
+ maxAgents: z.number().int().min(1).max(1e4).optional(),
10639
+ maxAvoidedAgents: z.number().int().min(0).max(64).optional(),
10640
+ maxAvoidedWalls: z.number().int().min(0).max(64).optional(),
10641
+ navmeshCheckInterval: z.number().min(0).max(60).optional(),
10642
+ pathOffsetRadiusMultiplier: z.number().min(0).max(100).optional(),
10643
+ pathOptimizationInterval: z.number().min(0).max(60).optional(),
10644
+ resolveCollisions: z.boolean().optional(),
10645
+ separationDirClamp: z.number().min(-1).max(1).optional()
10646
+ });
10647
+ const bridgeRvoSettingsSchema = z.object({
10648
+ artificialRadiusExpansion: z.number().min(0).max(100).optional(),
10649
+ defaultTimeToLive: z.number().min(0).max(600).optional(),
10650
+ deltaTimeToPredict: z.number().min(0).max(60).optional(),
10651
+ heightCheckMargin: z.number().min(0).max(1e3).optional(),
10652
+ lockTimeAfterAvoid: z.number().min(0).max(60).optional(),
10653
+ lockTimeAfterClean: z.number().min(0).max(60).optional()
10654
+ });
10655
+ const bridgeSetCrowdSettingsRequestFieldsSchema = z.object({
10656
+ crowd: bridgeCrowdSettingsSchema.optional(),
10657
+ requestId: requestIdSchema,
10658
+ rvo: bridgeRvoSettingsSchema.optional(),
10659
+ type: z.literal(BRIDGE_SET_CROWD_SETTINGS_REQUEST_TYPE),
10660
+ version: z.literal(2)
10661
+ });
10662
+ const bridgeSetCrowdSettingsRequestSchema = bridgeSetCrowdSettingsRequestFieldsSchema.refine((request) => Object.values(request.crowd ?? {}).some((value) => value !== void 0) || Object.values(request.rvo ?? {}).some((value) => value !== void 0), { message: "A set_crowd_settings request must carry at least one crowd or rvo setting." });
10663
+ const bridgeCreateNavAreaRequestSchema = z.object({
10664
+ assetName: requiredBoundedStringSchema,
10665
+ defaultCost: navAreaCostSchema.optional(),
10666
+ drawColor: navColorSchema.optional(),
10667
+ fixedAreaEnteringCost: navAreaCostSchema.optional(),
10668
+ packagePath: requiredBoundedStringSchema,
10669
+ parentClass: classPathSchema.default("NavArea"),
10670
+ requestId: requestIdSchema,
10671
+ type: z.literal(BRIDGE_CREATE_NAV_AREA_REQUEST_TYPE),
10672
+ version: z.literal(2)
10673
+ });
10674
+ const bridgeAddNavModifierVolumeRequestSchema = z.object({
10675
+ actorLabel: boundedStringSchema.optional(),
10676
+ areaClass: classPathSchema,
10677
+ areaClassToReplace: classPathSchema.optional(),
10678
+ extent: navExtentSchema.default({
10679
+ x: 200,
10680
+ y: 200,
10681
+ z: 200
10682
+ }),
10683
+ folderPath: boundedStringSchema.optional(),
10684
+ location: vectorInputSchema.default({
10685
+ x: 0,
10686
+ y: 0,
10687
+ z: 0
10688
+ }),
10689
+ requestId: requestIdSchema,
10690
+ rotation: rotatorInputSchema.default({
10691
+ pitch: 0,
10692
+ roll: 0,
10693
+ yaw: 0
10694
+ }),
10695
+ type: z.literal(BRIDGE_ADD_NAV_MODIFIER_VOLUME_REQUEST_TYPE),
10696
+ version: z.literal(2)
10697
+ });
10698
+ const bridgeNavLinkSchema = z.object({
10699
+ areaClass: classPathSchema.optional(),
10700
+ description: boundedStringSchema.optional(),
10701
+ direction: navLinkDirectionSchema.default("both_ways"),
10702
+ left: vectorInputSchema.default({
10703
+ x: 0,
10704
+ y: -50,
10705
+ z: 0
10706
+ }),
10707
+ leftProjectHeight: z.number().min(0).max(1e4).optional(),
10708
+ maxFallDownLength: z.number().min(0).max(1e4).optional(),
10709
+ right: vectorInputSchema.default({
10710
+ x: 0,
10711
+ y: 50,
10712
+ z: 0
10713
+ }),
10714
+ snapHeight: z.number().min(1).max(1e4).optional(),
10715
+ snapRadius: z.number().min(1).max(1e4).optional()
10716
+ });
10717
+ const bridgeAddNavLinkRequestSchema = z.object({
10718
+ actorLabel: boundedStringSchema.optional(),
10719
+ folderPath: boundedStringSchema.optional(),
10720
+ links: z.array(bridgeNavLinkSchema).min(1).max(16),
10721
+ location: vectorInputSchema.default({
10722
+ x: 0,
10723
+ y: 0,
10724
+ z: 0
10725
+ }),
10726
+ requestId: requestIdSchema,
10727
+ rotation: rotatorInputSchema.default({
10728
+ pitch: 0,
10729
+ roll: 0,
10730
+ yaw: 0
10731
+ }),
10732
+ smartLinkEnabled: z.boolean().default(false),
10733
+ type: z.literal(BRIDGE_ADD_NAV_LINK_REQUEST_TYPE),
10734
+ version: z.literal(2)
10735
+ });
10736
+ const navEndpointFields = {
10737
+ end: navPointSchema.optional(),
10738
+ endActorPath: actorPathSchema.optional(),
10739
+ start: navPointSchema.optional(),
10740
+ startActorPath: actorPathSchema.optional()
10741
+ };
10742
+ const addNavEndpointIssues = (endpoints, ctx, pathPrefix) => {
10743
+ if (endpoints.start === void 0 === (endpoints.startActorPath === void 0)) ctx.addIssue({
10744
+ code: z.ZodIssueCode.custom,
10745
+ message: "Give exactly one of start or startActorPath.",
10746
+ path: [...pathPrefix, "start"]
10747
+ });
10748
+ if (endpoints.end === void 0 === (endpoints.endActorPath === void 0)) ctx.addIssue({
10749
+ code: z.ZodIssueCode.custom,
10750
+ message: "Give exactly one of end or endActorPath.",
10751
+ path: [...pathPrefix, "end"]
10752
+ });
10753
+ };
10754
+ const bridgeFindPathRequestFieldsSchema = z.object({
10755
+ ...navEndpointFields,
10756
+ allowPartial: z.boolean().default(true),
10757
+ maxPathPoints: z.number().int().min(1).max(256).default(64),
10758
+ navMeshActorPath: actorPathSchema.optional(),
10759
+ requestId: requestIdSchema,
10760
+ type: z.literal(BRIDGE_FIND_PATH_REQUEST_TYPE),
10761
+ version: z.literal(2)
10762
+ });
10763
+ const bridgeFindPathRequestSchema = bridgeFindPathRequestFieldsSchema.superRefine((request, ctx) => {
10764
+ addNavEndpointIssues(request, ctx, []);
10765
+ });
10766
+ const bridgeReachabilityPairSchema = z.object(navEndpointFields);
10767
+ const bridgeTestReachabilityRequestFieldsSchema = z.object({
10768
+ allowPartial: z.boolean().default(false),
10769
+ navMeshActorPath: actorPathSchema.optional(),
10770
+ pairs: z.array(bridgeReachabilityPairSchema).min(1).max(64),
10771
+ requestId: requestIdSchema,
10772
+ type: z.literal(BRIDGE_TEST_REACHABILITY_REQUEST_TYPE),
10773
+ version: z.literal(2)
10774
+ });
10775
+ const bridgeTestReachabilityRequestSchema = bridgeTestReachabilityRequestFieldsSchema.superRefine((request, ctx) => {
10776
+ request.pairs.forEach((pair, index) => {
10777
+ addNavEndpointIssues(pair, ctx, ["pairs", index]);
10778
+ });
10779
+ });
10780
+ const bridgeSetNavmeshSettingsSuccessResponseSchema = z.object({
10781
+ agentHeight: z.number(),
10782
+ agentMaxSlope: z.number(),
10783
+ agentMaxStepHeight: z.number(),
10784
+ agentRadius: z.number(),
10785
+ appliedSettings: z.array(z.string()).max(32),
10786
+ cellHeight: z.number(),
10787
+ cellSize: z.number(),
10788
+ mergeRegionSize: z.number(),
10789
+ message: nonEmptyStringSchema.optional(),
10790
+ minRegionArea: z.number(),
10791
+ navMeshActorPath: z.string(),
10792
+ ok: z.literal(true),
10793
+ packageDirty: z.boolean(),
10794
+ rebuildRequired: z.boolean(),
10795
+ requestId: requestIdSchema,
10796
+ resolution: navDataResolutionSchema,
10797
+ runtimeGeneration: navRuntimeGenerationSchema,
10798
+ state: creativeEditStateSchema,
10799
+ tileSizeUU: z.number(),
10800
+ type: z.literal(BRIDGE_SET_NAVMESH_SETTINGS_REQUEST_TYPE),
10801
+ version: z.literal(2)
10802
+ });
10803
+ const bridgeSetNavAgentsSuccessResponseSchema = z.object({
10804
+ agentCount: z.number().int().min(0),
10805
+ agents: z.array(z.object({
10806
+ height: z.number(),
10807
+ name: z.string(),
10808
+ radius: z.number()
10809
+ })).max(16),
10810
+ configFilePath: z.string(),
10811
+ message: nonEmptyStringSchema.optional(),
10812
+ ok: z.literal(true),
10813
+ requestId: requestIdSchema,
10814
+ restartRequired: z.boolean(),
10815
+ state: creativeEditStateSchema,
10816
+ type: z.literal(BRIDGE_SET_NAV_AGENTS_REQUEST_TYPE),
10817
+ version: z.literal(2)
10818
+ });
10819
+ const bridgeSetCrowdSettingsSuccessResponseSchema = z.object({
10820
+ appliedCount: z.number().int().min(0),
10821
+ configFilePaths: z.array(z.string()).max(2),
10822
+ failureCount: z.number().int().min(0),
10823
+ items: z.array(bridgeAuthoringItemResultSchema).max(32),
10824
+ message: nonEmptyStringSchema.optional(),
10825
+ ok: z.literal(true),
10826
+ packageDirty: z.boolean(),
10827
+ requestId: requestIdSchema,
10828
+ restartRequired: z.boolean(),
10829
+ state: creativeEditStateSchema,
10830
+ type: z.literal(BRIDGE_SET_CROWD_SETTINGS_REQUEST_TYPE),
10831
+ version: z.literal(2)
10832
+ });
10833
+ const bridgeCreateNavAreaSuccessResponseSchema = z.object({
10834
+ ...createdUserAssetResponseFields,
10835
+ defaultCost: z.number(),
10836
+ drawColor: navColorResponseSchema,
10837
+ fixedAreaEnteringCost: z.number(),
10838
+ generatedClassPath: z.string(),
10839
+ parentClass: z.string(),
10840
+ type: z.literal(BRIDGE_CREATE_NAV_AREA_REQUEST_TYPE)
10841
+ });
10842
+ const bridgeAddNavModifierVolumeSuccessResponseSchema = z.object({
10843
+ actorPath: z.string(),
10844
+ areaClass: z.string(),
10845
+ areaClassToReplace: z.string().optional(),
10846
+ extent: navPointSchema,
10847
+ location: navPointSchema,
10848
+ message: nonEmptyStringSchema.optional(),
10849
+ ok: z.literal(true),
10850
+ packageDirty: z.boolean(),
10851
+ rebuildRequired: z.boolean(),
10852
+ requestId: requestIdSchema,
10853
+ state: creativeEditStateSchema,
10854
+ type: z.literal(BRIDGE_ADD_NAV_MODIFIER_VOLUME_REQUEST_TYPE),
10855
+ version: z.literal(2)
10856
+ });
10857
+ const bridgeAddNavLinkSuccessResponseSchema = z.object({
10858
+ actorPath: z.string(),
10859
+ linkCount: z.number().int().min(0),
10860
+ links: z.array(z.object({
10861
+ direction: navLinkDirectionSchema,
10862
+ left: navPointSchema,
10863
+ right: navPointSchema
10864
+ })).max(16),
10865
+ message: nonEmptyStringSchema.optional(),
10866
+ ok: z.literal(true),
10867
+ packageDirty: z.boolean(),
10868
+ rebuildRequired: z.boolean(),
10869
+ requestId: requestIdSchema,
10870
+ smartLinkEnabled: z.boolean(),
10871
+ state: creativeEditStateSchema,
10872
+ type: z.literal(BRIDGE_ADD_NAV_LINK_REQUEST_TYPE),
10873
+ version: z.literal(2)
10874
+ });
10875
+ const bridgeFindPathSuccessResponseSchema = z.object({
10876
+ endLocation: navPointSchema,
10877
+ message: nonEmptyStringSchema.optional(),
10878
+ ok: z.literal(true),
10879
+ partial: z.boolean(),
10880
+ pathCost: z.number(),
10881
+ pathLength: z.number(),
10882
+ pathPointCount: z.number().int().min(0),
10883
+ pathPoints: z.array(navPointSchema).max(256),
10884
+ queryResult: navQueryResultSchema,
10885
+ reachable: z.boolean(),
10886
+ requestId: requestIdSchema,
10887
+ startLocation: navPointSchema,
10888
+ state: navQueryStateSchema,
10889
+ truncated: z.boolean(),
10890
+ type: z.literal(BRIDGE_FIND_PATH_REQUEST_TYPE),
10891
+ version: z.literal(2)
10892
+ });
10893
+ const bridgeTestReachabilitySuccessResponseSchema = z.object({
10894
+ message: nonEmptyStringSchema.optional(),
10895
+ ok: z.literal(true),
10896
+ pairs: z.array(z.object({
10897
+ error: z.string().optional(),
10898
+ index: z.number().int().min(0),
10899
+ partial: z.boolean(),
10900
+ pathLength: z.number(),
10901
+ reachable: z.boolean()
10902
+ })).max(64),
10903
+ reachableCount: z.number().int().min(0),
10904
+ requestId: requestIdSchema,
10905
+ state: navQueryStateSchema,
10906
+ type: z.literal(BRIDGE_TEST_REACHABILITY_REQUEST_TYPE),
10907
+ unreachableCount: z.number().int().min(0),
10908
+ version: z.literal(2)
10909
+ });
10910
+ const bridgeSetNavmeshSettingsResponseSchema = z.union([bridgeSetNavmeshSettingsSuccessResponseSchema, bridgeErrorResponseSchema]);
10911
+ const bridgeSetNavAgentsResponseSchema = z.union([bridgeSetNavAgentsSuccessResponseSchema, bridgeErrorResponseSchema]);
10912
+ const bridgeSetCrowdSettingsResponseSchema = z.union([bridgeSetCrowdSettingsSuccessResponseSchema, bridgeErrorResponseSchema]);
10913
+ const bridgeCreateNavAreaResponseSchema = z.union([bridgeCreateNavAreaSuccessResponseSchema, bridgeErrorResponseSchema]);
10914
+ const bridgeAddNavModifierVolumeResponseSchema = z.union([bridgeAddNavModifierVolumeSuccessResponseSchema, bridgeErrorResponseSchema]);
10915
+ const bridgeAddNavLinkResponseSchema = z.union([bridgeAddNavLinkSuccessResponseSchema, bridgeErrorResponseSchema]);
10916
+ const bridgeFindPathResponseSchema = z.union([bridgeFindPathSuccessResponseSchema, bridgeErrorResponseSchema]);
10917
+ const bridgeTestReachabilityResponseSchema = z.union([bridgeTestReachabilitySuccessResponseSchema, bridgeErrorResponseSchema]);
10918
+ function createBridgeSetNavmeshSettingsRequest(options = {}, requestId = randomUUID()) {
10919
+ return bridgeSetNavmeshSettingsRequestSchema.parse({
10920
+ agentHeight: options.agentHeight,
10921
+ agentMaxSlope: options.agentMaxSlope,
10922
+ agentMaxStepHeight: options.agentMaxStepHeight,
10923
+ agentRadius: options.agentRadius,
10924
+ cellHeight: options.cellHeight,
10925
+ cellSize: options.cellSize,
10926
+ mergeRegionSize: options.mergeRegionSize,
10927
+ minRegionArea: options.minRegionArea,
10928
+ navMeshActorPath: options.navMeshActorPath,
10929
+ requestId,
10930
+ resolution: options.resolution,
10931
+ runtimeGeneration: options.runtimeGeneration,
10932
+ tileSizeUU: options.tileSizeUU,
10933
+ type: BRIDGE_SET_NAVMESH_SETTINGS_REQUEST_TYPE,
10934
+ version: 2
10935
+ });
10936
+ }
10937
+ function createBridgeSetNavAgentsRequest(agents, requestId = randomUUID()) {
10938
+ return bridgeSetNavAgentsRequestSchema.parse({
10939
+ agents,
10940
+ requestId,
10941
+ type: BRIDGE_SET_NAV_AGENTS_REQUEST_TYPE,
10942
+ version: 2
10943
+ });
10944
+ }
10945
+ function createBridgeSetCrowdSettingsRequest(options = {}, requestId = randomUUID()) {
10946
+ return bridgeSetCrowdSettingsRequestSchema.parse({
10947
+ crowd: options.crowd,
10948
+ requestId,
10949
+ rvo: options.rvo,
10950
+ type: BRIDGE_SET_CROWD_SETTINGS_REQUEST_TYPE,
10951
+ version: 2
10952
+ });
10953
+ }
10954
+ function createBridgeCreateNavAreaRequest(assetName, packagePath, options = {}, requestId = randomUUID()) {
10955
+ return bridgeCreateNavAreaRequestSchema.parse({
10956
+ assetName,
10957
+ defaultCost: options.defaultCost,
10958
+ drawColor: options.drawColor,
10959
+ fixedAreaEnteringCost: options.fixedAreaEnteringCost,
10960
+ packagePath,
10961
+ parentClass: options.parentClass,
10962
+ requestId,
10963
+ type: BRIDGE_CREATE_NAV_AREA_REQUEST_TYPE,
10964
+ version: 2
10965
+ });
10966
+ }
10967
+ function createBridgeAddNavModifierVolumeRequest(areaClass, options = {}, requestId = randomUUID()) {
10968
+ return bridgeAddNavModifierVolumeRequestSchema.parse({
10969
+ actorLabel: options.actorLabel,
10970
+ areaClass,
10971
+ areaClassToReplace: options.areaClassToReplace,
10972
+ extent: options.extent,
10973
+ folderPath: options.folderPath,
10974
+ location: options.location,
10975
+ requestId,
10976
+ rotation: options.rotation,
10977
+ type: BRIDGE_ADD_NAV_MODIFIER_VOLUME_REQUEST_TYPE,
10978
+ version: 2
10979
+ });
10980
+ }
10981
+ function createBridgeAddNavLinkRequest(links, options = {}, requestId = randomUUID()) {
10982
+ return bridgeAddNavLinkRequestSchema.parse({
10983
+ actorLabel: options.actorLabel,
10984
+ folderPath: options.folderPath,
10985
+ links,
10986
+ location: options.location,
10987
+ requestId,
10988
+ rotation: options.rotation,
10989
+ smartLinkEnabled: options.smartLinkEnabled,
10990
+ type: BRIDGE_ADD_NAV_LINK_REQUEST_TYPE,
10991
+ version: 2
10992
+ });
10993
+ }
10994
+ function createBridgeFindPathRequest(endpoints, options = {}, requestId = randomUUID()) {
10995
+ return bridgeFindPathRequestSchema.parse({
10996
+ allowPartial: options.allowPartial,
10997
+ end: endpoints.end,
10998
+ endActorPath: endpoints.endActorPath,
10999
+ maxPathPoints: options.maxPathPoints,
11000
+ navMeshActorPath: options.navMeshActorPath,
11001
+ requestId,
11002
+ start: endpoints.start,
11003
+ startActorPath: endpoints.startActorPath,
11004
+ type: BRIDGE_FIND_PATH_REQUEST_TYPE,
11005
+ version: 2
11006
+ });
11007
+ }
11008
+ function createBridgeTestReachabilityRequest(pairs, options = {}, requestId = randomUUID()) {
11009
+ return bridgeTestReachabilityRequestSchema.parse({
11010
+ allowPartial: options.allowPartial,
11011
+ navMeshActorPath: options.navMeshActorPath,
11012
+ pairs,
11013
+ requestId,
11014
+ type: BRIDGE_TEST_REACHABILITY_REQUEST_TYPE,
11015
+ version: 2
11016
+ });
11017
+ }
11018
+ //#endregion
10486
11019
  //#region src/version.ts
10487
- const SERVER_VERSION = "1.10.0";
11020
+ const SERVER_VERSION = "1.11.0";
10488
11021
  //#endregion
10489
11022
  //#region src/bridgeSocketClient.ts
10490
11023
  var BridgeSocketError = class extends Error {
@@ -11416,6 +11949,30 @@ async function sendBridgeSetStateTreeGlobalsRequest(request, options) {
11416
11949
  async function sendBridgeTraceStateTreeRequest(request, options) {
11417
11950
  return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeTraceStateTreeResponseSchema, request.requestId);
11418
11951
  }
11952
+ async function sendBridgeSetNavmeshSettingsRequest(request, options) {
11953
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeSetNavmeshSettingsResponseSchema, request.requestId);
11954
+ }
11955
+ async function sendBridgeSetNavAgentsRequest(request, options) {
11956
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeSetNavAgentsResponseSchema, request.requestId);
11957
+ }
11958
+ async function sendBridgeSetCrowdSettingsRequest(request, options) {
11959
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeSetCrowdSettingsResponseSchema, request.requestId);
11960
+ }
11961
+ async function sendBridgeCreateNavAreaRequest(request, options) {
11962
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeCreateNavAreaResponseSchema, request.requestId);
11963
+ }
11964
+ async function sendBridgeAddNavModifierVolumeRequest(request, options) {
11965
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeAddNavModifierVolumeResponseSchema, request.requestId);
11966
+ }
11967
+ async function sendBridgeAddNavLinkRequest(request, options) {
11968
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeAddNavLinkResponseSchema, request.requestId);
11969
+ }
11970
+ async function sendBridgeFindPathRequest(request, options) {
11971
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeFindPathResponseSchema, request.requestId);
11972
+ }
11973
+ async function sendBridgeTestReachabilityRequest(request, options) {
11974
+ return parseBridgeResponse(await exchangeBridgeMessage(encodeBridgeFrame(request), options), bridgeTestReachabilityResponseSchema, request.requestId);
11975
+ }
11419
11976
  //#endregion
11420
11977
  //#region src/enginePing.ts
11421
11978
  async function pingRegistryEntry$1(entry, options) {
@@ -22476,6 +23033,278 @@ const meshToolDomain = {
22476
23033
  ]
22477
23034
  };
22478
23035
  //#endregion
23036
+ //#region src/tools/navigation.ts
23037
+ const setNavmeshSettingsInputSchema = {
23038
+ agentHeight: bridgeSetNavmeshSettingsRequestFieldsSchema.shape.agentHeight.describe("Height of the tallest agent that will path on this navmesh, in cm."),
23039
+ agentMaxSlope: bridgeSetNavmeshSettingsRequestFieldsSchema.shape.agentMaxSlope.describe("Steepest ground an agent can walk, in degrees from horizontal (0-89)."),
23040
+ agentMaxStepHeight: bridgeSetNavmeshSettingsRequestFieldsSchema.shape.agentMaxStepHeight.describe("Tallest step an agent can climb, in cm. Written into the resolution named by resolution."),
23041
+ agentRadius: bridgeSetNavmeshSettingsRequestFieldsSchema.shape.agentRadius.describe("Radius of the smallest agent that will path on this navmesh, in cm. Widening it pulls the navmesh further from every wall."),
23042
+ cellHeight: bridgeSetNavmeshSettingsRequestFieldsSchema.shape.cellHeight.describe("Vertical voxel size, in cm. Written into the resolution named by resolution."),
23043
+ cellSize: bridgeSetNavmeshSettingsRequestFieldsSchema.shape.cellSize.describe("Horizontal voxel size, in cm. Smaller is more precise and much slower to build."),
23044
+ mergeRegionSize: bridgeSetNavmeshSettingsRequestFieldsSchema.shape.mergeRegionSize.describe("Regions up to this size are merged into a bigger neighbour (watershed partitioning only)."),
23045
+ minRegionArea: bridgeSetNavmeshSettingsRequestFieldsSchema.shape.minRegionArea.describe("Islands smaller than this are discarded instead of becoming unreachable navmesh."),
23046
+ navMeshActorPath: bridgeSetNavmeshSettingsRequestFieldsSchema.shape.navMeshActorPath.describe("Actor path of the RecastNavMesh to write. Omit to use the level's main navigation data."),
23047
+ projectId: creativeProjectIdSchema,
23048
+ resolution: bridgeSetNavmeshSettingsRequestFieldsSchema.shape.resolution.describe("Which resolution's voxel parameters cellSize, cellHeight and agentMaxStepHeight are written into. Defaults to 'default'."),
23049
+ runtimeGeneration: bridgeSetNavmeshSettingsRequestFieldsSchema.shape.runtimeGeneration.describe("'static' bakes once, 'dynamic_modifiers_only' rebuilds for nav modifiers, 'dynamic' rebuilds for geometry changes too."),
23050
+ tileSizeUU: bridgeSetNavmeshSettingsRequestFieldsSchema.shape.tileSizeUU.describe("Side of one navmesh tile, in cm. Smaller tiles rebuild faster but cost more memory.")
23051
+ };
23052
+ const setNavAgentsInputSchema = {
23053
+ agents: bridgeSetNavAgentsRequestSchema.shape.agents.describe(`Supported agent types, each { name, radius, height, maxStepHeight?, navDataClass? } (max ${String(16)}). This replaces the project's whole list.`),
23054
+ projectId: creativeProjectIdSchema
23055
+ };
23056
+ const setCrowdSettingsInputSchema = {
23057
+ crowd: bridgeSetCrowdSettingsRequestFieldsSchema.shape.crowd.describe("Detour crowd manager settings: maxAgents, maxAgentRadius, maxAvoidedAgents, maxAvoidedWalls, navmeshCheckInterval, pathOptimizationInterval, separationDirClamp, pathOffsetRadiusMultiplier, resolveCollisions."),
23058
+ projectId: creativeProjectIdSchema,
23059
+ rvo: bridgeSetCrowdSettingsRequestFieldsSchema.shape.rvo.describe("RVO avoidance manager settings: defaultTimeToLive, lockTimeAfterAvoid, lockTimeAfterClean, deltaTimeToPredict, artificialRadiusExpansion, heightCheckMargin.")
23060
+ };
23061
+ const createNavAreaInputSchema = {
23062
+ assetName: bridgeCreateNavAreaRequestSchema.shape.assetName.describe("Name of the new nav area, e.g. 'NA_Mud'."),
23063
+ defaultCost: bridgeCreateNavAreaRequestSchema.shape.defaultCost.describe("Travel cost multiplier for distance through this area. 1 is neutral; higher makes pathfinding avoid it."),
23064
+ drawColor: bridgeCreateNavAreaRequestSchema.shape.drawColor.describe("Colour this area is drawn in the navigation view, as { r, g, b, a? } 0-255."),
23065
+ fixedAreaEnteringCost: bridgeCreateNavAreaRequestSchema.shape.fixedAreaEnteringCost.describe("Flat cost paid once on entering the area, independent of how far the path runs through it."),
23066
+ packagePath: bridgeCreateNavAreaRequestSchema.shape.packagePath.describe("Content folder to create the nav area Blueprint in."),
23067
+ parentClass: bridgeCreateNavAreaRequestSchema.shape.parentClass.describe("Nav area class to derive from: 'NavArea' (default), 'NavArea_Null', 'NavArea_Obstacle', 'NavArea_LowHeight', or the class path of another one."),
23068
+ projectId: creativeProjectIdSchema
23069
+ };
23070
+ const addNavModifierVolumeInputSchema = {
23071
+ actorLabel: bridgeAddNavModifierVolumeRequestSchema.shape.actorLabel.describe("Display label for the placed volume."),
23072
+ areaClass: bridgeAddNavModifierVolumeRequestSchema.shape.areaClass.describe("Nav area to apply inside the volume — 'NavArea_Null' to cut the navmesh away, 'NavArea_Obstacle' to make it expensive, or a class path from create_nav_area."),
23073
+ areaClassToReplace: bridgeAddNavModifierVolumeRequestSchema.shape.areaClassToReplace.describe("When given, only surfaces already marked with this area are replaced by areaClass instead of everything inside the volume."),
23074
+ extent: bridgeAddNavModifierVolumeRequestSchema.shape.extent.describe("Box half-extent of the volume in cm. Every axis must be positive."),
23075
+ folderPath: bridgeAddNavModifierVolumeRequestSchema.shape.folderPath.describe("World Outliner folder to place the volume in."),
23076
+ location: bridgeAddNavModifierVolumeRequestSchema.shape.location.describe("World location of the volume centre."),
23077
+ projectId: creativeProjectIdSchema,
23078
+ rotation: bridgeAddNavModifierVolumeRequestSchema.shape.rotation.describe("World rotation of the volume.")
23079
+ };
23080
+ const addNavLinkInputSchema = {
23081
+ actorLabel: bridgeAddNavLinkRequestSchema.shape.actorLabel.describe("Display label for the placed link actor."),
23082
+ folderPath: bridgeAddNavLinkRequestSchema.shape.folderPath.describe("World Outliner folder to place the link actor in."),
23083
+ links: bridgeAddNavLinkRequestSchema.shape.links.describe(`Point links carried by this actor (max ${String(16)}), each { left, right, direction?, snapRadius?, snapHeight?, leftProjectHeight?, maxFallDownLength?, areaClass?, description? }. left and right are offsets from the actor, not world positions.`),
23084
+ location: bridgeAddNavLinkRequestSchema.shape.location.describe("World location of the link actor."),
23085
+ projectId: creativeProjectIdSchema,
23086
+ rotation: bridgeAddNavLinkRequestSchema.shape.rotation.describe("World rotation of the link actor."),
23087
+ smartLinkEnabled: bridgeAddNavLinkRequestSchema.shape.smartLinkEnabled.describe("Mark the smart link component on this actor navigation-relevant, so it can be toggled at runtime without a rebuild.")
23088
+ };
23089
+ const findPathInputSchema = {
23090
+ allowPartial: bridgeFindPathRequestFieldsSchema.shape.allowPartial.describe("Accept a path that stops short of the goal. Defaults to true, so a blocked destination reports partial rather than nothing."),
23091
+ end: bridgeFindPathRequestFieldsSchema.shape.end.describe("World location to path to. Give this or endActorPath."),
23092
+ endActorPath: bridgeFindPathRequestFieldsSchema.shape.endActorPath.describe("Actor whose location is the goal. Give this or end."),
23093
+ maxPathPoints: bridgeFindPathRequestFieldsSchema.shape.maxPathPoints.describe(`Maximum path points to return (1-${String(256)}). pathPointCount stays the full count and truncated says whether the list was cut.`),
23094
+ navMeshActorPath: bridgeFindPathRequestFieldsSchema.shape.navMeshActorPath.describe("Actor path of the RecastNavMesh to query. Omit to use the level's main navigation data."),
23095
+ projectId: creativeProjectIdSchema,
23096
+ start: bridgeFindPathRequestFieldsSchema.shape.start.describe("World location to path from. Give this or startActorPath."),
23097
+ startActorPath: bridgeFindPathRequestFieldsSchema.shape.startActorPath.describe("Actor whose location is the start. Give this or start.")
23098
+ };
23099
+ const testReachabilityInputSchema = {
23100
+ allowPartial: bridgeTestReachabilityRequestFieldsSchema.shape.allowPartial.describe("Report how far an unreachable pair got, as pathLength on a partial path. Defaults to false. A partial path is reported unreachable either way."),
23101
+ navMeshActorPath: bridgeTestReachabilityRequestFieldsSchema.shape.navMeshActorPath.describe("Actor path of the RecastNavMesh to query. Omit to use the level's main navigation data."),
23102
+ pairs: bridgeTestReachabilityRequestFieldsSchema.shape.pairs.describe(`Start/end pairs to test (max ${String(64)}), each naming exactly one of start/startActorPath and one of end/endActorPath.`),
23103
+ projectId: creativeProjectIdSchema
23104
+ };
23105
+ async function setNavmeshSettings(input, dependencies) {
23106
+ return await exchangeCreativeRequest(createBridgeSetNavmeshSettingsRequest({
23107
+ agentHeight: input.agentHeight,
23108
+ agentMaxSlope: input.agentMaxSlope,
23109
+ agentMaxStepHeight: input.agentMaxStepHeight,
23110
+ agentRadius: input.agentRadius,
23111
+ cellHeight: input.cellHeight,
23112
+ cellSize: input.cellSize,
23113
+ mergeRegionSize: input.mergeRegionSize,
23114
+ minRegionArea: input.minRegionArea,
23115
+ navMeshActorPath: input.navMeshActorPath,
23116
+ resolution: input.resolution,
23117
+ runtimeGeneration: input.runtimeGeneration,
23118
+ tileSizeUU: input.tileSizeUU
23119
+ }), sendBridgeSetNavmeshSettingsRequest, BRIDGE_SET_NAVMESH_SETTINGS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23120
+ }
23121
+ async function setNavAgents(input, dependencies) {
23122
+ return await exchangeCreativeRequest(createBridgeSetNavAgentsRequest(input.agents), sendBridgeSetNavAgentsRequest, BRIDGE_SET_NAV_AGENTS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23123
+ }
23124
+ async function setCrowdSettings(input, dependencies) {
23125
+ return await exchangeCreativeRequest(createBridgeSetCrowdSettingsRequest({
23126
+ crowd: input.crowd,
23127
+ rvo: input.rvo
23128
+ }), sendBridgeSetCrowdSettingsRequest, BRIDGE_SET_CROWD_SETTINGS_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23129
+ }
23130
+ async function createNavArea(input, dependencies) {
23131
+ return await exchangeCreativeRequest(createBridgeCreateNavAreaRequest(input.assetName, input.packagePath, {
23132
+ defaultCost: input.defaultCost,
23133
+ drawColor: input.drawColor,
23134
+ fixedAreaEnteringCost: input.fixedAreaEnteringCost,
23135
+ parentClass: input.parentClass
23136
+ }), sendBridgeCreateNavAreaRequest, BRIDGE_CREATE_NAV_AREA_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23137
+ }
23138
+ async function addNavModifierVolume(input, dependencies) {
23139
+ return await exchangeCreativeRequest(createBridgeAddNavModifierVolumeRequest(input.areaClass, {
23140
+ actorLabel: input.actorLabel,
23141
+ areaClassToReplace: input.areaClassToReplace,
23142
+ extent: input.extent,
23143
+ folderPath: input.folderPath,
23144
+ location: input.location,
23145
+ rotation: input.rotation
23146
+ }), sendBridgeAddNavModifierVolumeRequest, BRIDGE_ADD_NAV_MODIFIER_VOLUME_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23147
+ }
23148
+ async function addNavLink(input, dependencies) {
23149
+ return await exchangeCreativeRequest(createBridgeAddNavLinkRequest(input.links, {
23150
+ actorLabel: input.actorLabel,
23151
+ folderPath: input.folderPath,
23152
+ location: input.location,
23153
+ rotation: input.rotation,
23154
+ smartLinkEnabled: input.smartLinkEnabled
23155
+ }), sendBridgeAddNavLinkRequest, BRIDGE_ADD_NAV_LINK_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23156
+ }
23157
+ async function findPath(input, dependencies) {
23158
+ return await exchangeCreativeRequest(createBridgeFindPathRequest({
23159
+ end: input.end,
23160
+ endActorPath: input.endActorPath,
23161
+ start: input.start,
23162
+ startActorPath: input.startActorPath
23163
+ }, {
23164
+ allowPartial: input.allowPartial,
23165
+ maxPathPoints: input.maxPathPoints,
23166
+ navMeshActorPath: input.navMeshActorPath
23167
+ }), sendBridgeFindPathRequest, BRIDGE_FIND_PATH_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23168
+ }
23169
+ async function testReachability(input, dependencies) {
23170
+ return await exchangeCreativeRequest(createBridgeTestReachabilityRequest(input.pairs, {
23171
+ allowPartial: input.allowPartial,
23172
+ navMeshActorPath: input.navMeshActorPath
23173
+ }), sendBridgeTestReachabilityRequest, BRIDGE_TEST_REACHABILITY_REQUEST_TYPE, projectIdSchema.parse(input.projectId), dependencies);
23174
+ }
23175
+ function registerNavigationTools(server, dependencies) {
23176
+ server.registerTool("set_navmesh_settings", {
23177
+ description: "Write the level's navmesh generation settings — agent radius and height, max slope and step height, voxel cell size, tile size and runtime generation mode. The values only reach the navmesh on the next build, so follow this with build_navigation. Returns every setting as it stands after the write, so a clamped value is visible.",
23178
+ inputSchema: setNavmeshSettingsInputSchema,
23179
+ title: "Set Navmesh Settings"
23180
+ }, async ({ agentHeight, agentMaxSlope, agentMaxStepHeight, agentRadius, cellHeight, cellSize, mergeRegionSize, minRegionArea, navMeshActorPath, projectId, resolution, runtimeGeneration, tileSizeUU }) => {
23181
+ return toToolSuccess(await setNavmeshSettings({
23182
+ agentHeight,
23183
+ agentMaxSlope,
23184
+ agentMaxStepHeight,
23185
+ agentRadius,
23186
+ cellHeight,
23187
+ cellSize,
23188
+ mergeRegionSize,
23189
+ minRegionArea,
23190
+ navMeshActorPath,
23191
+ projectId,
23192
+ resolution,
23193
+ runtimeGeneration,
23194
+ tileSizeUU
23195
+ }, dependencies));
23196
+ });
23197
+ server.registerTool("set_nav_agents", {
23198
+ description: "Replace the project's list of supported navigation agents, each with its own radius, height and step height. One navmesh is generated per agent type, so this is how a level gets separate navigation for, say, a human and a vehicle. Written to DefaultEngine.ini and read once at startup, so it reports restartRequired.",
23199
+ inputSchema: setNavAgentsInputSchema,
23200
+ title: "Set Nav Agents"
23201
+ }, async ({ agents, projectId }) => {
23202
+ return toToolSuccess(await setNavAgents({
23203
+ agents,
23204
+ projectId
23205
+ }, dependencies));
23206
+ });
23207
+ server.registerTool("set_crowd_settings", {
23208
+ description: "Write the project-wide Detour crowd manager and RVO avoidance settings that decide how AI agents steer around each other. Both are config defaults read at startup, so the response reports restartRequired rather than pretending a running crowd picked them up.",
23209
+ inputSchema: setCrowdSettingsInputSchema,
23210
+ title: "Set Crowd Settings"
23211
+ }, async ({ crowd, projectId, rvo }) => {
23212
+ return toToolSuccess(await setCrowdSettings({
23213
+ crowd,
23214
+ projectId,
23215
+ rvo
23216
+ }, dependencies));
23217
+ });
23218
+ server.registerTool("create_nav_area", {
23219
+ description: "Create a nav area Blueprint with its own travel cost, entering cost and debug colour. Returns generatedClassPath, which is what add_nav_modifier_volume and add_nav_link take to reference the area.",
23220
+ inputSchema: createNavAreaInputSchema,
23221
+ title: "Create Nav Area"
23222
+ }, async ({ assetName, defaultCost, drawColor, fixedAreaEnteringCost, packagePath, parentClass, projectId }) => {
23223
+ return toToolSuccess(await createNavArea({
23224
+ assetName,
23225
+ defaultCost,
23226
+ drawColor,
23227
+ fixedAreaEnteringCost,
23228
+ packagePath,
23229
+ parentClass,
23230
+ projectId
23231
+ }, dependencies));
23232
+ });
23233
+ server.registerTool("add_nav_modifier_volume", {
23234
+ description: "Place a nav modifier volume that applies a nav area to whatever navmesh falls inside it — NavArea_Null to carve a hole an agent will never path through, or a custom area to make the ground expensive rather than impassable. Takes effect on the next build_navigation.",
23235
+ inputSchema: addNavModifierVolumeInputSchema,
23236
+ title: "Add Nav Modifier Volume"
23237
+ }, async ({ actorLabel, areaClass, areaClassToReplace, extent, folderPath, location, projectId, rotation }) => {
23238
+ return toToolSuccess(await addNavModifierVolume({
23239
+ actorLabel,
23240
+ areaClass,
23241
+ areaClassToReplace,
23242
+ extent,
23243
+ folderPath,
23244
+ location,
23245
+ projectId,
23246
+ rotation
23247
+ }, dependencies));
23248
+ });
23249
+ server.registerTool("add_nav_link", {
23250
+ description: "Place a nav link proxy carrying one or more point links, which is what lets an agent jump or drop between navmesh islands that do not touch. Each link names its two ends as offsets from the actor plus a direction; the response reports them in world space. Takes effect on the next build_navigation.",
23251
+ inputSchema: addNavLinkInputSchema,
23252
+ title: "Add Nav Link"
23253
+ }, async ({ actorLabel, folderPath, links, location, projectId, rotation, smartLinkEnabled }) => {
23254
+ return toToolSuccess(await addNavLink({
23255
+ actorLabel,
23256
+ folderPath,
23257
+ links,
23258
+ location,
23259
+ projectId,
23260
+ rotation,
23261
+ smartLinkEnabled
23262
+ }, dependencies));
23263
+ });
23264
+ server.registerTool("find_path", {
23265
+ description: "Run a synchronous navmesh path query in the editor world between two points or actors, returning the path points, its length and cost, and whether it reached the goal. A destination nothing can reach comes back with reachable false and a partial path rather than an error, so this is the way to prove a level is traversable before shipping it.",
23266
+ inputSchema: findPathInputSchema,
23267
+ title: "Find Path"
23268
+ }, async ({ allowPartial, end, endActorPath, maxPathPoints, navMeshActorPath, projectId, start, startActorPath }) => {
23269
+ return toToolSuccess(await findPath({
23270
+ allowPartial,
23271
+ end,
23272
+ endActorPath,
23273
+ maxPathPoints,
23274
+ navMeshActorPath,
23275
+ projectId,
23276
+ start,
23277
+ startActorPath
23278
+ }, dependencies));
23279
+ });
23280
+ server.registerTool("test_reachability", {
23281
+ description: "Answer reachable / not reachable for a batch of start-end pairs in one call, without returning any path geometry. Use it to sweep spawn points against objectives; use find_path when the route itself matters.",
23282
+ inputSchema: testReachabilityInputSchema,
23283
+ title: "Test Reachability"
23284
+ }, async ({ allowPartial, navMeshActorPath, pairs, projectId }) => {
23285
+ return toToolSuccess(await testReachability({
23286
+ allowPartial,
23287
+ navMeshActorPath,
23288
+ pairs,
23289
+ projectId
23290
+ }, dependencies));
23291
+ });
23292
+ }
23293
+ const navigationToolDomain = {
23294
+ domain: "navigation",
23295
+ register: registerNavigationTools,
23296
+ toolNames: [
23297
+ "set_navmesh_settings",
23298
+ "set_nav_agents",
23299
+ "set_crowd_settings",
23300
+ "create_nav_area",
23301
+ "add_nav_modifier_volume",
23302
+ "add_nav_link",
23303
+ "find_path",
23304
+ "test_reachability"
23305
+ ]
23306
+ };
23307
+ //#endregion
22479
23308
  //#region src/tools/pcg.ts
22480
23309
  const createPcgGraphInputSchema = {
22481
23310
  assetName: bridgeCreatePcgGraphRequestFieldsSchema.shape.assetName.describe("Name of the new PCG graph, e.g. 'PCG_Forest'."),
@@ -24464,7 +25293,8 @@ const TOOL_CATALOG = [
24464
25293
  renderToolDomain,
24465
25294
  vfxToolDomain,
24466
25295
  pcgToolDomain,
24467
- projectSettingsToolDomain
25296
+ projectSettingsToolDomain,
25297
+ navigationToolDomain
24468
25298
  ];
24469
25299
  //#endregion
24470
25300
  //#region src/mcpTools.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uemcp/server",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "description": "MCP server for making Unreal Engine and C++ development easier",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",